diff --git a/docs/FOG_ENVELOPE_CANONICALIZATION.md b/docs/FOG_ENVELOPE_CANONICALIZATION.md new file mode 100644 index 0000000..0caafc5 --- /dev/null +++ b/docs/FOG_ENVELOPE_CANONICALIZATION.md @@ -0,0 +1,100 @@ +# Fog Envelope Canonicalization and Signing Profile (v0) + +This document defines the **recommended evidence profile** for FogVault and FogCompute envelopes until the rules are promoted into first-class schema constraints and ADRs. + +## Goals + +- deterministic hashing across heterogeneous nodes +- small, auditable signing surface +- stable content references independent of transport +- explicit separation between content hashing, envelope hashing, and settlement logic + +## Canonicalization profile + +### 1. Canonical JSON + +For any JSON payload that is hashed or signed, implementations should: + +1. serialize with **JCS** (JSON Canonicalization Scheme; RFC 8785) +2. encode as UTF-8 bytes +3. hash with **SHA-256** + +This yields the canonical `payloadHash`. + +### 2. Content hashing + +Raw content referenced by `ContentRef` should be hashed over the raw bytes, not over JSON wrappers. The digest form should be: + +```text +sha256: +``` + +### 3. Signature algorithm + +The default signature algorithm for Fog envelopes and receipts should be: + +- **Ed25519** for detached signatures + +Recommended signature field encoding: + +```text +ed25519: +``` + +### 4. Domain separation + +To avoid cross-object signature confusion, signers should sign a domain-separated preimage: + +```text +SRCOS-FOG-V1\n +\n +\n + +``` + +Where: +- `` is `TopicEnvelope` or `UsageReceipt` +- `` is the object URN +- `` is the canonical SHA-256 digest string + +### 5. Encryption metadata + +When envelopes are encrypted, the authenticated additional data (AAD) should bind at least: + +- `topicId` +- `entryId` or `receiptId` +- `keyEpoch` +- `payloadType` + +Recommended default content cipher for topic payloads: + +- **XChaCha20-Poly1305** + +## Verification order + +### TopicEnvelope + +1. resolve and verify `ContentRef` digests if present +2. canonicalize `payload` +3. compute `payloadHash` +4. verify detached signature +5. only then evaluate topic semantics / policy + +### UsageReceipt + +1. canonicalize receipt body +2. compute `receiptHash` +3. verify detached signature +4. verify referenced `WorkOrder` / output refs / settlement mapping + +## What this does not settle yet + +This v0 profile does **not** yet fix: + +- key distribution / rotation mechanics +- threshold or multisignature receipts +- CBOR/COSE variants +- transport-layer framing +- receipt notarization / timestamp authority integration + +Those should land in follow-up ADRs and schema revisions. diff --git a/docs/FOG_LAYER.md b/docs/FOG_LAYER.md new file mode 100644 index 0000000..d77e3f7 --- /dev/null +++ b/docs/FOG_LAYER.md @@ -0,0 +1,29 @@ +# Fog Layer (FogVault + FogCompute) + +This document defines the **Fog Layer** contract surface for the SourceOS/SociOS ecosystem. + +The fog layer is designed for **heterogeneous, churny, citizen-fog environments** where machines appear and disappear and cannot be treated as durable infrastructure. + +## Architecture summary + +### FogVault (storage + topic substrate) + +- **Local substrate:** nodes expose fast, capacity-managed *local* storage (e.g., LVM-backed PVs via a local CSI driver such as TopoLVM). +- **Distributed meaning + replication:** durability and convergence are provided *above* local storage via **append-only Merkle-log topics** (Hypercore). "Folders" and indexes are derived views. +- **Topic contract:** a topic is an append-only channel with explicit replication policy, membership, and key epochs. + +### FogCompute (compute substrate) + +- Nodes advertise resource offers (CPU/GPU/RAM/IO windows). +- Requestors submit work orders (image digests + inputs/outputs + verification policy). +- Workers emit usage receipts (metered via OS primitives) and optional settlement events. +- Settlement (tokenization / escrow) is a **pluggable layer**; receipts are the core evidence artifact. + +## Contract status + +The Fog Layer is represented by the schema set in `schemas/`: + +- `Topic.json`, `TopicEnvelope.json`, `ReplicationPolicy.json`, `ContentRef.json` +- `Offer.json`, `WorkOrder.json`, `UsageReceipt.json`, `SettlementEvent.json` + +These are **v0 scaffolds** intended to be evolved via ADRs and semver discipline. diff --git a/examples/content_ref.json b/examples/content_ref.json new file mode 100644 index 0000000..85a6af2 --- /dev/null +++ b/examples/content_ref.json @@ -0,0 +1,9 @@ +{ + "digest": "sha256:3d62e3b4c5dd6d04e3d1a2c765a809f0f76ad6f870d13dbb4d4ef7f77e4d2d10", + "sizeBytes": 1048576, + "mediaType": "application/vnd.srcos.fog.block+json", + "uris": [ + "file:///srv/fog/topics/fog-cache-health/blocks/3d/62/e3b4", + "hyper://fog-cache-health/blocks/sha256-3d62e3b4c5dd6d04e3d1a2c765a809f0f76ad6f870d13dbb4d4ef7f77e4d2d10" + ] +} diff --git a/examples/offer.json b/examples/offer.json new file mode 100644 index 0000000..b56d99e --- /dev/null +++ b/examples/offer.json @@ -0,0 +1,34 @@ +{ + "id": "urn:srcos:offer:node-17-cpu-gpu-window-a", + "type": "Offer", + "specVersion": "2.0.0", + "provider": { + "subjectId": "urn:srcos:subject:fog-worker-node-17", + "nodeId": "node-17" + }, + "resources": { + "cpuCores": 8, + "memoryBytes": 34359738368, + "gpu": { + "count": 1, + "model": "RTX-4090" + }, + "storageBytes": 536870912000, + "networkMbps": 1000 + }, + "availability": { + "timeWindow": "2026-04-16T00:00:00Z/2026-04-16T08:00:00Z", + "maxJobSeconds": 21600 + }, + "pricing": { + "unit": "fog-credits", + "cpuSecond": 0.002, + "gpuSecond": 0.02, + "gbHour": 0.005 + }, + "policy": { + "allowWorkloadClasses": ["embedding", "indexing", "batch-inference"], + "privacyMode": "topic-encrypted-only", + "powerCapWatts": 350 + } +} diff --git a/examples/replication_policy.json b/examples/replication_policy.json new file mode 100644 index 0000000..71a67d4 --- /dev/null +++ b/examples/replication_policy.json @@ -0,0 +1,14 @@ +{ + "replicas": 3, + "minAcks": 1, + "neighborhoods": ["lan", "household", "region"], + "retention": { + "hotDays": 14, + "coldDays": 90, + "maxBytes": 53687091200 + }, + "compaction": { + "mode": "snapshot", + "intervalEntries": 50000 + } +} diff --git a/examples/settlement_event.json b/examples/settlement_event.json new file mode 100644 index 0000000..b661518 --- /dev/null +++ b/examples/settlement_event.json @@ -0,0 +1,12 @@ +{ + "id": "urn:srcos:settlement:index-qdrant-shard-20260416-01", + "type": "SettlementEvent", + "specVersion": "2.0.0", + "receiptId": "urn:srcos:receipt:usage:index-qdrant-shard-20260416-01", + "amount": { + "unit": "fog-credits", + "value": 12.84 + }, + "backend": "internal-ledger", + "txRef": "ledger://fog-credits/2026/04/16/txn-000001" +} diff --git a/examples/topic.json b/examples/topic.json new file mode 100644 index 0000000..b5785f0 --- /dev/null +++ b/examples/topic.json @@ -0,0 +1,31 @@ +{ + "id": "urn:srcos:topic:fog-cache-health", + "type": "Topic", + "specVersion": "2.0.0", + "name": "fog.cache.health", + "description": "Health/cache topic for edge-local fog state with append-only Merkle-log replication.", + "replication": { + "replicas": 3, + "minAcks": 1, + "neighborhoods": ["lan", "region"], + "retention": { + "hotDays": 7, + "coldDays": 30, + "maxBytes": 10737418240 + }, + "compaction": { + "mode": "checkpoint", + "intervalEntries": 10000 + } + }, + "encryption": { + "cipherSuite": "xchacha20poly1305", + "keyEpoch": 4, + "keyRef": "urn:srcos:key:topic:fog-cache-health:epoch:4" + }, + "members": [ + "urn:srcos:community:fog-workers", + "urn:srcos:community:fog-observers" + ], + "labels": ["fog", "cache", "ephemeral"] +} diff --git a/examples/topic_envelope.json b/examples/topic_envelope.json new file mode 100644 index 0000000..e9e84a8 --- /dev/null +++ b/examples/topic_envelope.json @@ -0,0 +1,33 @@ +{ + "entryId": "urn:srcos:topic-entry:fog-cache-health:000001", + "topicId": "urn:srcos:topic:fog-cache-health", + "specVersion": "2.0.0", + "occurredAt": "2026-04-16T02:15:00Z", + "author": { + "subjectId": "urn:srcos:subject:fog-worker-node-17", + "nodeId": "node-17" + }, + "payloadType": "PutBlob", + "payload": { + "path": "/cache/health/worker-17.json", + "contentRef": { + "digest": "sha256:3d62e3b4c5dd6d04e3d1a2c765a809f0f76ad6f870d13dbb4d4ef7f77e4d2d10", + "sizeBytes": 1048576, + "mediaType": "application/json" + } + }, + "integrity": { + "content": { + "digest": "sha256:3d62e3b4c5dd6d04e3d1a2c765a809f0f76ad6f870d13dbb4d4ef7f77e4d2d10", + "sizeBytes": 1048576, + "mediaType": "application/json" + }, + "payloadHash": "sha256:9cd8d6d35b07be7db0d8904b5bd808c95bd1ef674353abce6ebf58c480644e12", + "signature": "ed25519:example-signature-topic-entry" + }, + "encryption": { + "cipherSuite": "xchacha20poly1305", + "keyEpoch": 4, + "aad": "topic=fog.cache.health" + } +} diff --git a/examples/usage_receipt.json b/examples/usage_receipt.json new file mode 100644 index 0000000..7b2d97b --- /dev/null +++ b/examples/usage_receipt.json @@ -0,0 +1,34 @@ +{ + "id": "urn:srcos:receipt:usage:index-qdrant-shard-20260416-01", + "type": "UsageReceipt", + "specVersion": "2.0.0", + "workOrderId": "urn:srcos:workorder:index-qdrant-shard-20260416-01", + "provider": { + "subjectId": "urn:srcos:subject:fog-worker-node-17", + "nodeId": "node-17" + }, + "startedAt": "2026-04-16T02:20:00Z", + "endedAt": "2026-04-16T02:28:42Z", + "exit": { + "code": 0, + "status": "completed" + }, + "usage": { + "cpuSeconds": 3812.41, + "memoryPeakBytes": 8912896000, + "ioReadBytes": 721420288, + "ioWriteBytes": 361758720, + "gpuSeconds": 0 + }, + "outputs": [ + { + "digest": "sha256:2222222222222222222222222222222222222222222222222222222222222222", + "mediaType": "application/vnd.qdrant.snapshot", + "sizeBytes": 285212672 + } + ], + "integrity": { + "receiptHash": "sha256:3333333333333333333333333333333333333333333333333333333333333333", + "signature": "ed25519:example-signature-usage-receipt" + } +} diff --git a/examples/workorder.json b/examples/workorder.json new file mode 100644 index 0000000..58af860 --- /dev/null +++ b/examples/workorder.json @@ -0,0 +1,37 @@ +{ + "id": "urn:srcos:workorder:index-qdrant-shard-20260416-01", + "type": "WorkOrder", + "specVersion": "2.0.0", + "requestor": { + "subjectId": "urn:srcos:subject:mesh-broker-1" + }, + "workload": { + "image": "ghcr.io/socioprophet/fog-indexer@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "command": ["/app/index", "--topic", "fog.cache.health", "--shard", "17"], + "env": { + "QDRANT_URL": "http://qdrant.service.local:6333", + "TOPIC_ID": "urn:srcos:topic:fog-cache-health" + } + }, + "inputs": [ + { + "digest": "sha256:1111111111111111111111111111111111111111111111111111111111111111", + "sizeBytes": 52428800, + "mediaType": "application/x-ndjson" + } + ], + "outputs": [ + { + "digest": "sha256:2222222222222222222222222222222222222222222222222222222222222222", + "mediaType": "application/vnd.qdrant.snapshot" + } + ], + "verification": { + "mode": "replicate", + "replicas": 2 + }, + "placement": { + "requireGpu": false, + "neighborhood": "lan" + } +} diff --git a/schemas/ContentRef.json b/schemas/ContentRef.json new file mode 100644 index 0000000..768c4f7 --- /dev/null +++ b/schemas/ContentRef.json @@ -0,0 +1,34 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/ContentRef.json", + "title": "ContentRef", + "description": "A content-addressed reference to bytes (blob/chunk/manifest) used by Fog topics and work orders.", + "type": "object", + "additionalProperties": false, + "required": ["digest"], + "properties": { + "digest": { + "type": "string", + "description": "Digest string (recommended form: : e.g. sha256:...)." + }, + "sizeBytes": { + "type": "integer", + "minimum": 0, + "description": "Optional size hint in bytes." + }, + "mediaType": { + "type": ["string", "null"], + "description": "Optional IANA media type hint." + }, + "uris": { + "type": "array", + "items": {"type": "string"}, + "description": "Optional locator hints (e.g. file://, s3://, ipfs://, hyper://, https://)." + }, + "chunks": { + "type": "array", + "items": {"$ref": "ContentRef.json"}, + "description": "Optional chunk list when the content is a manifest-of-chunks." + } + } +} diff --git a/schemas/Offer.json b/schemas/Offer.json new file mode 100644 index 0000000..897e9c4 --- /dev/null +++ b/schemas/Offer.json @@ -0,0 +1,76 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/Offer.json", + "title": "Offer", + "description": "FogCompute resource offer published by a provider node/workstation.", + "type": "object", + "additionalProperties": false, + "required": ["id", "type", "specVersion", "provider", "resources"], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:offer:", + "description": "Stable URN identifier. Pattern: urn:srcos:offer:" + }, + "type": { + "const": "Offer", + "description": "Discriminator constant — always \"Offer\"." + }, + "specVersion": { + "type": "string", + "description": "Spec version of this document, e.g. \"2.0.0\"." + }, + "provider": { + "type": "object", + "additionalProperties": false, + "required": ["subjectId"], + "properties": { + "subjectId": {"type": "string", "description": "Provider subject URN."}, + "nodeId": {"type": ["string", "null"], "description": "Optional provider node identifier."} + } + }, + "resources": { + "type": "object", + "additionalProperties": false, + "properties": { + "cpuCores": {"type": "number", "minimum": 0}, + "memoryBytes": {"type": "integer", "minimum": 0}, + "gpu": { + "type": "object", + "additionalProperties": false, + "properties": { + "count": {"type": "integer", "minimum": 0}, + "model": {"type": ["string", "null"]} + } + }, + "storageBytes": {"type": "integer", "minimum": 0}, + "networkMbps": {"type": "number", "minimum": 0} + }, + "description": "Advertised resource caps." + }, + "availability": { + "type": "object", + "additionalProperties": false, + "properties": { + "timeWindow": {"type": ["string", "null"], "description": "Optional ISO-8601 interval window."}, + "maxJobSeconds": {"type": ["integer", "null"], "minimum": 0} + } + }, + "pricing": { + "type": "object", + "additionalProperties": false, + "properties": { + "unit": {"type": ["string", "null"], "description": "e.g. credits, token, usd."}, + "cpuSecond": {"type": ["number", "null"], "minimum": 0}, + "gpuSecond": {"type": ["number", "null"], "minimum": 0}, + "gbHour": {"type": ["number", "null"], "minimum": 0} + }, + "description": "Optional pricing schedule." + }, + "policy": { + "type": "object", + "additionalProperties": true, + "description": "Optional provider constraints (allow/deny workload classes, privacy mode, power caps)." + } + } +} diff --git a/schemas/ReplicationPolicy.json b/schemas/ReplicationPolicy.json new file mode 100644 index 0000000..b348fdf --- /dev/null +++ b/schemas/ReplicationPolicy.json @@ -0,0 +1,45 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/ReplicationPolicy.json", + "title": "ReplicationPolicy", + "description": "Replication and retention policy for a Fog topic. This is a v0 scaffold; fields will evolve via ADRs.", + "type": "object", + "additionalProperties": false, + "required": ["replicas"], + "properties": { + "replicas": { + "type": "integer", + "minimum": 1, + "description": "Target replica count across distinct peers/neighborhoods." + }, + "minAcks": { + "type": "integer", + "minimum": 0, + "description": "Minimum acknowledgements required for a write to be considered accepted (0 = fire-and-forget)." + }, + "neighborhoods": { + "type": "array", + "items": {"type": "string"}, + "description": "Optional locality buckets (e.g. lan, household, region, friend-mesh) used for placement diversity." + }, + "retention": { + "type": "object", + "additionalProperties": false, + "properties": { + "hotDays": {"type": "integer", "minimum": 0}, + "coldDays": {"type": "integer", "minimum": 0}, + "maxBytes": {"type": "integer", "minimum": 0} + }, + "description": "Retention hints for hot/cold storage and maximum topic size." + }, + "compaction": { + "type": "object", + "additionalProperties": false, + "properties": { + "mode": {"enum": ["none", "checkpoint", "snapshot"]}, + "intervalEntries": {"type": "integer", "minimum": 0} + }, + "description": "Compaction/checkpoint strategy for append-only growth." + } + } +} diff --git a/schemas/SettlementEvent.json b/schemas/SettlementEvent.json new file mode 100644 index 0000000..3822c7e --- /dev/null +++ b/schemas/SettlementEvent.json @@ -0,0 +1,46 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/SettlementEvent.json", + "title": "SettlementEvent", + "description": "Optional settlement event mapping a UsageReceipt to credits/tokens/escrow outcomes. Pluggable layer.", + "type": "object", + "additionalProperties": false, + "required": ["id", "type", "specVersion", "receiptId"], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:settlement:", + "description": "Stable URN identifier. Pattern: urn:srcos:settlement:" + }, + "type": { + "const": "SettlementEvent", + "description": "Discriminator constant — always \"SettlementEvent\"." + }, + "specVersion": { + "type": "string", + "description": "Spec version of this document, e.g. \"2.0.0\"." + }, + "receiptId": { + "type": "string", + "pattern": "^urn:srcos:receipt:usage:", + "description": "UsageReceipt URN." + }, + "amount": { + "type": "object", + "additionalProperties": false, + "properties": { + "unit": {"type": "string"}, + "value": {"type": "number"} + }, + "description": "Settled amount (credits/tokens)." + }, + "backend": { + "type": ["string", "null"], + "description": "Settlement backend identifier (e.g., internal-ledger, iexec, akash, golem)." + }, + "txRef": { + "type": ["string", "null"], + "description": "Optional settlement transaction reference." + } + } +} diff --git a/schemas/Topic.json b/schemas/Topic.json new file mode 100644 index 0000000..445dd34 --- /dev/null +++ b/schemas/Topic.json @@ -0,0 +1,55 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/Topic.json", + "title": "Topic", + "description": "A FogVault topic: an append-only Merkle-log channel with explicit replication policy, membership, and key epochs.", + "type": "object", + "additionalProperties": false, + "required": ["id", "type", "specVersion", "name", "replication"], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:topic:", + "description": "Stable URN identifier. Pattern: urn:srcos:topic:" + }, + "type": { + "const": "Topic", + "description": "Discriminator constant — always \"Topic\"." + }, + "specVersion": { + "type": "string", + "description": "Spec version of this document, e.g. \"2.0.0\"." + }, + "name": { + "type": "string", + "description": "Human-readable topic name (stable label)." + }, + "description": { + "type": ["string", "null"], + "description": "Optional free-text description." + }, + "replication": { + "$ref": "ReplicationPolicy.json" + }, + "encryption": { + "type": "object", + "additionalProperties": false, + "properties": { + "cipherSuite": {"type": "string"}, + "keyEpoch": {"type": "integer", "minimum": 0}, + "keyRef": {"type": ["string", "null"], "description": "Opaque reference to key material (never raw keys)."} + }, + "description": "Topic encryption metadata (epoch-based rotation)." + }, + "members": { + "type": "array", + "items": {"type": "string"}, + "description": "Optional member identities (subject URNs) authorized for this topic." + }, + "labels": { + "type": "array", + "items": {"type": "string"}, + "description": "Optional tags/labels for discovery and policy." + } + } +} diff --git a/schemas/TopicEnvelope.json b/schemas/TopicEnvelope.json new file mode 100644 index 0000000..6d6cadb --- /dev/null +++ b/schemas/TopicEnvelope.json @@ -0,0 +1,74 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/TopicEnvelope.json", + "title": "TopicEnvelope", + "description": "A FogVault append-only topic entry envelope. This is intentionally generic; concrete payload typing is expressed via specVersion + payloadType.", + "type": "object", + "additionalProperties": false, + "required": ["entryId", "topicId", "specVersion", "occurredAt", "payloadType", "payload"], + "properties": { + "entryId": { + "type": "string", + "pattern": "^urn:srcos:topic-entry:", + "description": "Stable URN identifier for this entry. Pattern: urn:srcos:topic-entry:" + }, + "topicId": { + "type": "string", + "pattern": "^urn:srcos:topic:", + "description": "Topic URN." + }, + "specVersion": { + "type": "string", + "description": "Spec version of this document, e.g. \"2.0.0\"." + }, + "occurredAt": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 date-time when this entry was produced." + }, + "author": { + "type": "object", + "additionalProperties": false, + "properties": { + "subjectId": {"type": "string"}, + "nodeId": {"type": ["string", "null"]} + }, + "description": "Producer identity (subject and optional node)." + }, + "payloadType": { + "type": "string", + "description": "Typed discriminator for the payload (e.g. PutBlob, Link, IndexHint, OfferUpserted)." + }, + "payload": { + "type": "object", + "additionalProperties": true, + "description": "Payload object typed by payloadType." + }, + "integrity": { + "type": "object", + "additionalProperties": false, + "properties": { + "content": {"$ref": "ContentRef.json"}, + "payloadHash": { + "type": ["string", "null"], + "description": "Optional hash of canonical payload bytes." + }, + "signature": { + "type": ["string", "null"], + "description": "Optional signature over payloadHash." + } + }, + "description": "Optional integrity envelope (hash and signature)." + }, + "encryption": { + "type": "object", + "additionalProperties": false, + "properties": { + "cipherSuite": {"type": ["string", "null"]}, + "keyEpoch": {"type": ["integer", "null"], "minimum": 0}, + "aad": {"type": ["string", "null"], "description": "Optional external AAD binding (encoded)."} + }, + "description": "Optional encryption metadata for encrypted payloads." + } + } +} diff --git a/schemas/UsageReceipt.json b/schemas/UsageReceipt.json new file mode 100644 index 0000000..ff0922f --- /dev/null +++ b/schemas/UsageReceipt.json @@ -0,0 +1,74 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/UsageReceipt.json", + "title": "UsageReceipt", + "description": "FogCompute usage receipt emitted by a worker for a completed work order.", + "type": "object", + "additionalProperties": false, + "required": ["id", "type", "specVersion", "workOrderId", "provider", "startedAt", "endedAt", "usage"], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:receipt:usage:", + "description": "Stable URN identifier. Pattern: urn:srcos:receipt:usage:" + }, + "type": { + "const": "UsageReceipt", + "description": "Discriminator constant — always \"UsageReceipt\"." + }, + "specVersion": { + "type": "string", + "description": "Spec version of this document, e.g. \"2.0.0\"." + }, + "workOrderId": { + "type": "string", + "pattern": "^urn:srcos:workorder:", + "description": "Associated WorkOrder URN." + }, + "provider": { + "type": "object", + "additionalProperties": false, + "required": ["subjectId"], + "properties": { + "subjectId": {"type": "string"}, + "nodeId": {"type": ["string", "null"]} + } + }, + "startedAt": {"type": "string", "format": "date-time"}, + "endedAt": {"type": "string", "format": "date-time"}, + "exit": { + "type": "object", + "additionalProperties": false, + "properties": { + "code": {"type": ["integer", "null"]}, + "status": {"type": ["string", "null"]} + } + }, + "usage": { + "type": "object", + "additionalProperties": false, + "properties": { + "cpuSeconds": {"type": "number", "minimum": 0}, + "memoryPeakBytes": {"type": "integer", "minimum": 0}, + "ioReadBytes": {"type": "integer", "minimum": 0}, + "ioWriteBytes": {"type": "integer", "minimum": 0}, + "gpuSeconds": {"type": "number", "minimum": 0} + }, + "description": "Metered usage (best-effort, OS-derived)." + }, + "outputs": { + "type": "array", + "items": {"$ref": "ContentRef.json"}, + "description": "Output content references produced by the work order." + }, + "integrity": { + "type": "object", + "additionalProperties": false, + "properties": { + "receiptHash": {"type": ["string", "null"]}, + "signature": {"type": ["string", "null"]} + }, + "description": "Optional receipt hash and signature." + } + } +} diff --git a/schemas/WorkOrder.json b/schemas/WorkOrder.json new file mode 100644 index 0000000..7f9431b --- /dev/null +++ b/schemas/WorkOrder.json @@ -0,0 +1,82 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/WorkOrder.json", + "title": "WorkOrder", + "description": "FogCompute work order: container/image digest + inputs/outputs + verification policy.", + "type": "object", + "additionalProperties": false, + "required": ["id", "type", "specVersion", "requestor", "workload"], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:workorder:", + "description": "Stable URN identifier. Pattern: urn:srcos:workorder:" + }, + "type": { + "const": "WorkOrder", + "description": "Discriminator constant — always \"WorkOrder\"." + }, + "specVersion": { + "type": "string", + "description": "Spec version of this document, e.g. \"2.0.0\"." + }, + "requestor": { + "type": "object", + "additionalProperties": false, + "required": ["subjectId"], + "properties": { + "subjectId": {"type": "string"} + }, + "description": "Requestor identity." + }, + "workload": { + "type": "object", + "additionalProperties": false, + "required": ["image"], + "properties": { + "image": { + "type": "string", + "description": "Container image reference (recommended: digest-pinned)." + }, + "command": { + "type": ["array", "null"], + "items": {"type": "string"}, + "description": "Optional argv-style command override." + }, + "env": { + "type": "object", + "additionalProperties": {"type": "string"}, + "description": "Optional environment variables." + } + } + }, + "inputs": { + "type": "array", + "items": {"$ref": "ContentRef.json"}, + "description": "Input content references." + }, + "outputs": { + "type": "array", + "items": {"$ref": "ContentRef.json"}, + "description": "Optional expected output refs (or output policy manifests)." + }, + "verification": { + "type": "object", + "additionalProperties": false, + "properties": { + "mode": {"enum": ["none", "tee", "replicate", "spotcheck", "reputation"]}, + "replicas": {"type": ["integer", "null"], "minimum": 0} + }, + "description": "Verification policy (TEE or replication-based)." + }, + "placement": { + "type": "object", + "additionalProperties": false, + "properties": { + "requireGpu": {"type": "boolean"}, + "neighborhood": {"type": ["string", "null"]} + }, + "description": "Optional placement constraints." + } + } +}