UNPKG

noa-receipt

Version:

NOA Agent Action Receipt — open, offline-verifiable provenance for AI-agent actions. The governance/receipt organ only; the NOA brain is separate and proprietary.

145 lines (144 loc) • 7.47 kB
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://noatrust.com/schema/noa-receipt-0.1.schema.json", "title": "NOA Receipt v0.1", "description": "Open, offline-verifiable provenance record for an AI-agent action. Params are never carried in raw form — only their hash (paramsHash). Unknown fields are rejected (additionalProperties:false). Caller-supplied identifiers (id, scope.chain, agent.id, agent.model, approval.by, ruleId) are opaque and MUST NOT contain PII; the format cannot enforce that.", "$comment": "STRUCTURAL AID, NOT the full normative validator. JSON Schema cannot express three controls that the normative reference validators (src/schema.ts and impl-py/noa_verify.py) additionally enforce, so a receipt accepted by THIS schema may still be MALFORMED: (1) well-formed Unicode — strings containing lone UTF-16 surrogates are rejected (spec §2, threat-model T7b: surrogate→U+FFFD hash-collision channel); (2) duplicate object keys are rejected by the strict JSON parser (threat-model T8); (3) `ts` and `approval.at` must DENOTE A REAL INSTANT, not merely match the pattern below — month 01-12, the real length of that month in that year (leap years included), hour ≤ 23, minute ≤ 59, second ≤ 60 (60 is a leap second and is ACCEPTED), offset ≤ 23:59. The `pattern` here cannot say that and `format: date-time` is annotation-only in most validators, so `2026-13-45T99:99:99.000Z` passes THIS file and is MALFORMED under every conformant verifier. The four CROSS-FIELD coherence rules (spec §2 'Coherence rules') ARE expressible and are encoded in `allOf` below. For a conformant verdict, run the normative validator, not a generic JSON-Schema check.", "type": "object", "additionalProperties": false, "required": ["spec", "id", "ts", "scope", "agent", "action", "governance", "chain", "sig"], "allOf": [ { "$comment": "R1 — a receipt that names the SANDBOX SIMULATOR as the actor while denying it was a simulation is a statement that can be argued both ways after the fact. ONE-DIRECTIONAL: sandboxed:true with any other principal is legitimate and stays valid.", "if": { "required": ["agent"], "properties": { "agent": { "required": ["principal"], "properties": { "principal": { "const": "SANDBOX_SIM" } } } } }, "then": { "required": ["governance"], "properties": { "governance": { "required": ["sandboxed"], "properties": { "sandboxed": { "const": true } } } } } }, { "$comment": "R2 — the same contradiction in the OUTCOME rather than the actor: a SIMULATED verdict beside sandboxed:false.", "if": { "required": ["governance"], "properties": { "governance": { "required": ["verdict"], "properties": { "verdict": { "const": "SIMULATED" } } } } }, "then": { "properties": { "governance": { "required": ["sandboxed"], "properties": { "sandboxed": { "const": true } } } } } }, { "$comment": "R3 — an action declared impossible to undo may not carry the reference used to undo it. rollbackRef absent, or present and null, both satisfy this.", "if": { "required": ["action"], "properties": { "action": { "required": ["reversible"], "properties": { "reversible": { "const": false } } } } }, "then": { "properties": { "action": { "properties": { "rollbackRef": { "type": "null" } } } } } }, { "$comment": "R4 — a receipt may not assert that the action WAS undone while declaring it could not be.", "if": { "required": ["governance"], "properties": { "governance": { "required": ["verdict"], "properties": { "verdict": { "const": "ROLLED_BACK" } } } } }, "then": { "required": ["action"], "properties": { "action": { "required": ["reversible"], "properties": { "reversible": { "const": true } } } } } } ], "properties": { "spec": { "const": "noa.receipt/0.1" }, "id": { "type": "string", "minLength": 1, "maxLength": 128 }, "ts": { "type": "string", "format": "date-time", "pattern": "^\\d{4}-\\d{2}-\\d{2}[Tt]\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,9})?([Zz]|[+-]\\d{2}:\\d{2})$" }, "scope": { "type": "object", "additionalProperties": false, "required": ["chain"], "properties": { "tenant": { "type": "string" }, "chain": { "type": "string", "minLength": 1 } } }, "agent": { "type": "object", "additionalProperties": false, "required": ["id", "principal"], "properties": { "id": { "type": "string", "minLength": 1 }, "model": { "type": ["string", "null"] }, "principal": { "enum": ["HUMAN", "SERVICE", "POLICY", "SANDBOX_SIM"] } } }, "action": { "type": "object", "additionalProperties": false, "required": ["id", "canonical", "riskClass", "paramsHash", "reversible"], "properties": { "id": { "type": "string", "minLength": 1 }, "canonical": { "type": "string", "minLength": 1 }, "riskClass": { "enum": ["LOW", "MEDIUM", "HIGH", "CRITICAL", "IRREVERSIBLE"] }, "paramsHash": { "type": "string", "pattern": "^(sha256|hmac-sha256):[0-9a-f]{64}$" }, "reversible": { "type": "boolean" }, "rollbackRef": { "type": ["string", "null"] } } }, "governance": { "type": "object", "additionalProperties": false, "required": ["mode", "verdict", "sandboxed"], "properties": { "mode": { "enum": ["off", "shadow", "approvals_on", "on"] }, "verdict": { "enum": ["ALLOWED", "BLOCKED", "DEFERRED", "EXECUTED", "FAILED", "ROLLED_BACK", "SIMULATED"] }, "ruleId": { "type": ["string", "null"] }, "sandboxed": { "type": "boolean" }, "approval": { "type": ["object", "null"], "additionalProperties": false, "required": ["by", "at"], "properties": { "by": { "type": "string" }, "at": { "type": "string", "format": "date-time", "pattern": "^\\d{4}-\\d{2}-\\d{2}[Tt]\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,9})?([Zz]|[+-]\\d{2}:\\d{2})$" } } }, "compliance": { "type": ["object", "null"], "additionalProperties": false, "required": ["policyHash", "readSetHash", "inputsHash"], "properties": { "policyHash": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" }, "readSetHash": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" }, "inputsHash": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" }, "verdict": { "enum": ["ALLOW", "DENY"] } } } } }, "chain": { "type": "object", "additionalProperties": false, "required": ["seq", "prevHash", "hash"], "properties": { "seq": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "prevHash": { "type": ["string", "null"], "pattern": "^sha256:[0-9a-f]{64}$" }, "hash": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" } } }, "sig": { "type": "object", "additionalProperties": false, "required": ["alg", "kid", "value"], "properties": { "alg": { "const": "ed25519" }, "kid": { "type": "string", "minLength": 1 }, "value": { "type": "string", "minLength": 1 } } } } }