From 47e82b64c9f383effb64fe64fbdae75f4077b2d1 Mon Sep 17 00:00:00 2001 From: "Byron Miller (MOBB)" Date: Mon, 20 Apr 2026 09:24:48 -0500 Subject: [PATCH] Normalize governance temporal semantics and align harness runtime. Add RFC 0051 and migrate governance schemas, examples, and harness artifacts to canonical temporal fields (`observed_at`, `decided_at`, `effective_at`, `completed_at`) with explicit ordering metadata and refreshed migration docs. Made-with: Cursor --- CHANGELOG.md | 9 + README.md | 7 +- docs/architecture.md | 3 + docs/rfc-discussion-index.json | 32 +- docs/rfc-discussions.md | 7 +- docs/temporal-migration-rfc0051.md | 40 ++ examples/audit_envelope/example1.json | 47 -- examples/authority_receipt/example1.json | 23 - .../example1.json | 37 +- .../example-envelope.json | 53 ++ .../example1.json | 9 +- .../example1.json | 13 +- harness/src/agents/governed-agent.ts | 11 +- harness/src/core/trace-emitter.ts | 7 +- harness/src/governance/audit-engine.ts | 37 +- harness/src/governance/auth-broker.ts | 8 +- harness/src/governance/permission-manager.ts | 32 +- harness/src/governance/policy-evaluator.ts | 59 ++- harness/src/schemas/audit-envelope.ts | 11 +- harness/src/schemas/delegation.ts | 13 +- harness/src/schemas/permission.ts | 8 +- harness/src/schemas/receipt.ts | 11 +- harness/src/schemas/telemetry.ts | 15 +- harness/tests/governance.test.ts | 27 +- rfcs/0010-agent-memory-schema.md | 17 +- rfcs/0011-multi-agent-protocol.md | 9 +- rfcs/0023-humain-in-the-loop-schema.md | 2 + rfcs/0025-tool-marketplace-registry-format.md | 2 + ...27-distributed-agent-execution-protocol.md | 2 + rfcs/0030-agent-lifecycle-versioning.md | 23 +- rfcs/0031-agent-observability-telemtry.md | 24 +- rfcs/0032-agent-deployment-manifest.md | 2 + rfcs/0033-agent-security-threat-model.md | 2 + rfcs/0034-agent-federation-protocol.md | 6 +- rfcs/0041-policy-enforcement-schema.md | 58 +- rfcs/0042-permission-acl.md | 22 +- rfcs/0043-auditing-compliance-logs.md | 61 ++- rfcs/0047-delegation-extension.md | 56 +- ...0048-execution-receipts-audit-envelopes.md | 193 +++---- ...1-temporal-semantics-validity-extension.md | 287 ++++++++++ schemas/registry.json | 3 +- schemas/rfc-0010-memory.json | 26 +- schemas/rfc-0011-multi-agent-protocol.json | 10 +- .../rfc-0030-agent-lifecycle-versioning.json | 15 +- ...fc-0031-agent-observability-telemetry.json | 23 +- .../rfc-0034-agent-federation-protocol.json | 4 +- schemas/rfc-0041-policy-enforcement.json | 22 +- schemas/rfc-0042-permission-acl.json | 6 +- .../rfc-0043-auditing-compliance-logs.json | 34 +- schemas/rfc-0047-delegation-extension.json | 37 +- ...48-execution-receipts-audit-envelopes.json | 494 ++++++++++++++---- schemas/rfc-0050-toon-adapter.json | 47 +- schemas/rfc-0051-temporal-semantics.json | 210 ++++++++ tools/schema_lib.py | 2 + 54 files changed, 1646 insertions(+), 572 deletions(-) create mode 100644 docs/temporal-migration-rfc0051.md delete mode 100644 examples/audit_envelope/example1.json delete mode 100644 examples/authority_receipt/example1.json rename examples/{delegation => delegation_extension}/example1.json (69%) create mode 100644 examples/execution_receipts_audit_envelopes/example-envelope.json rename examples/{tool_execution_receipt => execution_receipts_audit_envelopes}/example1.json (58%) rename examples/{permission_grant => permission_acl}/example1.json (72%) create mode 100644 rfcs/0051-temporal-semantics-validity-extension.md create mode 100644 schemas/rfc-0051-temporal-semantics.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 34f0969..fef98e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,3 +17,12 @@ The project follows semantic versioning for schema and registry compatibility: - Semantic schema diff checker severity reporting. - Starter synthetic dataset and converter baseline. - Mock harness, test suite, benchmark slice, governance templates, and demo runbooks. +- RFC 0051 Temporal Semantics & Validity Extension plus generated schema (`rfc-0051-temporal-semantics.json`). +- Temporal migration guide for downstream integrators (`docs/temporal-migration-rfc0051.md`). + +### Changed + +- Breaking temporal normalization across governance RFCs: canonical fields (`observed_at`, `decided_at`, `effective_at`, `expires_at`, `started_at`, `completed_at`, `superseded_at`) replace legacy aliases. +- Governance spine schemas updated (policy, permissions, delegation, audit, receipts, lifecycle, telemetry, memory, multi-agent protocol) and registry regenerated. +- Reference harness runtime/types aligned to canonical temporal fields, logical ordering metadata, and updated governance artifacts. +- Example fixtures now use registry shortname folders for delegation, permissions, and execution/audit receipts. diff --git a/README.md b/README.md index d92da31..786fa4e 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ If reasoning, tool intent, provenance, budgets, state transitions, and delegatio | Area | Role | |------|------| -| [`rfcs/`](./rfcs/) | **49 RFCs** — normative definitions for reasoning traces, tool invocation, the governed FSM, sandboxing, budgets, permissions, policy, delegation, provenance, identity, org governance, receipts, audit, and capability manifests | +| [`rfcs/`](./rfcs/) | **51 RFCs** — normative definitions for reasoning traces, tool invocation, the governed FSM, sandboxing, budgets, permissions, policy, delegation, provenance, identity, org governance, receipts, audit, and capability manifests | | [`schemas/`](./schemas/) | Versioned JSON Schemas per RFC (`registry.json`, `rfc-*-*.json`) | | [`harness/`](./harness/) | **Reference harness** (TypeScript) — governed FSM, validation, tools, budgets, trace emission | | [`examples/`](./examples/) | Validated instance fixtures keyed by registry shortname | @@ -50,7 +50,7 @@ If reasoning, tool intent, provenance, budgets, state transitions, and delegatio For a concise layout of control plane vs data plane, see [`docs/architecture.md`](./docs/architecture.md). -**If you are evaluating quickly:** (1) read [`docs/eli5_guide.md`](./docs/eli5_guide.md), (2) run the harness tests above, (3) run `python tools/validate.py`, (4) skim RFC 0007 plus RFCs 0041, 0042, 0047, and 0048 for the governance spine. +**If you are evaluating quickly:** (1) read [`docs/eli5_guide.md`](./docs/eli5_guide.md), (2) run the harness tests above, (3) run `python tools/validate.py`, (4) skim RFC 0007 plus RFCs 0041, 0042, 0047, 0048, and 0051 for the governance and temporal spine. ## The governed execution model @@ -126,10 +126,11 @@ Reasoning **patterns** (plan–verify, debate, and similar) remain documented fo ## Current status -- **49 RFCs** and a versioned JSON Schema registry with CI validation. +- **51 RFCs** and a versioned JSON Schema registry with CI validation. - Reference harness implements the governed FSM, delegation and receipt types, budgets, sandboxed tools, and trace validation (see table above). - Cross-language checks: TypeScript-emitted traces validate under Python tooling. - Tiered examples, synthetic seed data, and experiment runbooks under [`experiments/`](./experiments/). +- Breaking temporal normalization landed in RFC 0051 (`observed_at` / `decided_at` / `effective_at` / `completed_at`); migration guide: [`docs/temporal-migration-rfc0051.md`](./docs/temporal-migration-rfc0051.md). ## Experiment cards diff --git a/docs/architecture.md b/docs/architecture.md index 0a4017b..addf829 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -24,6 +24,8 @@ Picture data moving left to right on the **happy path**: Side channels include **budget** enforcement (RFC 0038) and **sandbox** allow/deny lists (RFC 0017), which can pre-empt a transition or force `fail_safe` without giving unsafe payloads back to the model. +Temporal validity and ordering semantics (RFC 0051) are now part of the control-plane contract: governance artifacts use canonical fields (`observed_at`, `decided_at`, `effective_at`, `expires_at`, `started_at`, `completed_at`, `superseded_at`) and SHOULD carry non-wall-clock ordering metadata for replay stability. + For streamed decoding, deployments should treat budget control as an active circuit-breaker (preflight budget gate + mid-stream cancellation), not a post-hoc accounting report. The reference harness now supports this runtime pattern; see [Model adaptation for budget control](./model-adaptation-budget-control.md). ## Major components @@ -103,6 +105,7 @@ Implementers usually traverse these in order after RFC 0001 (reasoning / trace): - **RFC 0047** — Delegation requests and decisions that precede narrowed authority. - **RFC 0048** — Execution receipts plus integrity linkage into audit envelopes. - **RFC 0043** — Auditing and compliance log shapes that consume the above identifiers. +- **RFC 0051** — Cross-cutting temporal semantics, validity windows, freshness, replay handling, and supersession behavior. Additional RFCs cover identity (**RFC 0026**), provenance (**RFC 0035**), org governance (**RFC 0044**), federation, and economics; they extend the same spine rather than replacing it. diff --git a/docs/rfc-discussion-index.json b/docs/rfc-discussion-index.json index a2b4b1d..3176029 100644 --- a/docs/rfc-discussion-index.json +++ b/docs/rfc-discussion-index.json @@ -1,7 +1,7 @@ { "repository": "supernovae/open-cot", "category_slug": "ideas", - "count": 46, + "count": 51, "rfcs": { "0001": { "rfc_title": "Initial Structured Reasoning Schema", @@ -278,6 +278,36 @@ "rfc_path": "rfcs/0046-conformance-interoperability-protocol.md", "discussion_title": "RFC 0046 \u2014 Conformance & Interoperability Protocol", "discussion_url": "https://github.com/supernovae/open-cot/discussions/46" + }, + "0047": { + "rfc_title": "Delegation Extension", + "rfc_path": "rfcs/0047-delegation-extension.md", + "discussion_title": "RFC 0047 \u2014 Delegation Extension", + "discussion_url": "https://github.com/supernovae/open-cot/discussions/47" + }, + "0048": { + "rfc_title": "Execution Receipts & Audit Envelopes", + "rfc_path": "rfcs/0048-execution-receipts-audit-envelopes.md", + "discussion_title": "RFC 0048 \u2014 Execution Receipts & Audit Envelopes", + "discussion_url": "https://github.com/supernovae/open-cot/discussions/48" + }, + "0049": { + "rfc_title": "Capability Manifest", + "rfc_path": "rfcs/0049-capability-manifest.md", + "discussion_title": "RFC 0049 \u2014 Capability Manifest", + "discussion_url": "https://github.com/supernovae/open-cot/discussions/49" + }, + "0050": { + "rfc_title": "TOON Adapter: Token-Oriented Object Notation", + "rfc_path": "rfcs/0050-toon-adapter.md", + "discussion_title": "RFC 0050 \u2014 TOON Adapter: Token-Oriented Object Notation", + "discussion_url": "https://github.com/supernovae/open-cot/discussions/50" + }, + "0051": { + "rfc_title": "Temporal Semantics & Validity Extension", + "rfc_path": "rfcs/0051-temporal-semantics-validity-extension.md", + "discussion_title": "RFC 0051 \u2014 Temporal Semantics & Validity Extension", + "discussion_url": "https://github.com/supernovae/open-cot/discussions/51" } } } diff --git a/docs/rfc-discussions.md b/docs/rfc-discussions.md index e6ddfc1..525adc3 100644 --- a/docs/rfc-discussions.md +++ b/docs/rfc-discussions.md @@ -3,7 +3,7 @@ Canonical discussion threads for all Open CoT RFCs. Use these threads for normative feedback and design discussion. - Discussion policy: RFC feedback uses GitHub Discussions first; issues are for actionable tasks/bugs. -- Source mapping: `docs/rfc-discussion-index.json` (46 RFCs) +- Source mapping: `docs/rfc-discussion-index.json` (51 RFCs) | RFC | Topic | Discussion | |-----|-------|------------| @@ -53,4 +53,9 @@ Canonical discussion threads for all Open CoT RFCs. Use these threads for normat | [`RFC 0044`](../rfcs/0044-governance-organizational-controls.md) | Governance & Organizational Controls | [Open thread](https://github.com/supernovae/open-cot/discussions/44) | | [`RFC 0045`](../rfcs/0045-ethical-risk-contraints-reasoning-agents.md) | Ethical & Risk Constraints for Reasoning Agents | [Open thread](https://github.com/supernovae/open-cot/discussions/45) | | [`RFC 0046`](../rfcs/0046-conformance-interoperability-protocol.md) | Conformance & Interoperability Protocol | [Open thread](https://github.com/supernovae/open-cot/discussions/46) | +| [`RFC 0047`](../rfcs/0047-delegation-extension.md) | Delegation Extension | [Open thread](https://github.com/supernovae/open-cot/discussions/47) | +| [`RFC 0048`](../rfcs/0048-execution-receipts-audit-envelopes.md) | Execution Receipts & Audit Envelopes | [Open thread](https://github.com/supernovae/open-cot/discussions/48) | +| [`RFC 0049`](../rfcs/0049-capability-manifest.md) | Capability Manifest | [Open thread](https://github.com/supernovae/open-cot/discussions/49) | +| [`RFC 0050`](../rfcs/0050-toon-adapter.md) | TOON Adapter: Token-Oriented Object Notation | [Open thread](https://github.com/supernovae/open-cot/discussions/50) | +| [`RFC 0051`](../rfcs/0051-temporal-semantics-validity-extension.md) | Temporal Semantics & Validity Extension | [Open thread](https://github.com/supernovae/open-cot/discussions/51) | diff --git a/docs/temporal-migration-rfc0051.md b/docs/temporal-migration-rfc0051.md new file mode 100644 index 0000000..8b2c017 --- /dev/null +++ b/docs/temporal-migration-rfc0051.md @@ -0,0 +1,40 @@ +# RFC 0051 Temporal Migration Guide + +RFC 0051 introduces a breaking temporal normalization across the governance spine. This guide summarizes the required field migrations for downstream consumers. + +## Core field migrations + +| Legacy | Canonical (RFC 0051) | Notes | +|---|---|---| +| `timestamp` | `observed_at` or `decided_at` | Use `observed_at` for observations/events; `decided_at` for policy/delegation decisions. | +| `effective_from` | `effective_at` | Inclusive lower bound of validity window. | +| `effective_until` | `expires_at` | Exclusive upper bound of validity window. | +| `granted_at` | `effective_at` | Permission/receipt validity start. | +| `sealed_at` | `completed_at` | Run envelope completion instant. | +| `previous_event_id` | `parent_event_id` | Causal predecessor pointer for audit chains. | +| `time_window.start/end` | `validity_window.effective_at/expires_at` | Rule-level validity constraints in policy conditions. | + +## Ordering model updates + +Time alone is no longer sufficient for deterministic ordering in governance artifacts. + +- Audit events now carry `ordering.event_seq`. +- Causal links use `parent_event_id` and optional `causal_predecessors`. +- Consumers should order by `event_seq` first, then causal linkage, then wall-clock as tie-breaker. + +## Harness/runtime alignment + +Reference harness producers now emit the canonical temporal model: + +- Delegation request/decision/receipt use `observed_at`, `decided_at`, and `effective_at`. +- Permission lifecycle events use `observed_at`. +- Audit envelope uses `completed_at` and schema versioned temporal semantics. +- Telemetry records use `observed_at` plus logical ordering metadata. + +## Consumer upgrade checklist + +1. Update deserializers and storage columns for renamed fields. +2. Rebuild indexes/queries that used `timestamp` or `sealed_at`. +3. Enforce half-open validity windows: `effective_at <= now < expires_at`. +4. Adopt replay/freshness handling where available (`freshness.*`, `replay_window_ms`). +5. Reject mixed old/new temporal aliases in newly written records. diff --git a/examples/audit_envelope/example1.json b/examples/audit_envelope/example1.json deleted file mode 100644 index 0ef4e02..0000000 --- a/examples/audit_envelope/example1.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "envelope_id": "env-y5z6a7b8", - "run_id": "run-e5f6g7h8", - "agent_id": "agent-planner-01", - "task_hash": "sha256:3c9e2a1f7b0d6e5c8a4f2b1d9e8c7a6f5b4d3e2c1a0f9e8d7c6b5a4f3e2d1c0b", - "started_at": "2026-04-18T14:30:00Z", - "sealed_at": "2026-04-18T14:30:05Z", - "completion_status": "succeeded", - "trace_hash": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - "event_chain_head": "evt-001", - "event_chain_tail": "evt-012", - "event_count": 12, - "delegation_requests": ["req-a1b2c3d4"], - "delegation_decisions": ["dec-i9j0k1l2"], - "authority_receipts": ["rcpt-m3n4o5p6"], - "tool_execution_receipts": ["exec-u1v2w3x4"], - "delegation_summary": { - "total_requested": 1, - "total_approved": 0, - "total_denied": 0, - "total_narrowed": 1, - "total_escalated": 0 - }, - "permission_summary": { - "total_granted": 1, - "total_consumed": 1, - "total_expired": 0, - "total_revoked": 0 - }, - "budget_final": { - "tokensUsed": 4250, - "tokensRemaining": 95750, - "costUsed": 0.085, - "costRemaining": 9.915, - "stepsUsed": 8, - "stepsRemaining": 42, - "toolCallsUsed": 1, - "toolCallsRemaining": 19, - "retriesUsed": 0, - "retriesRemaining": 5 - }, - "policy_violations": [], - "integrity": { - "hash_algorithm": "sha256", - "content_hash": "c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2" - } -} diff --git a/examples/authority_receipt/example1.json b/examples/authority_receipt/example1.json deleted file mode 100644 index 86a0a70..0000000 --- a/examples/authority_receipt/example1.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "receipt_id": "rcpt-m3n4o5p6", - "decision_id": "dec-i9j0k1l2", - "request_id": "req-a1b2c3d4", - "permission_id": "perm-q7r8s9t0", - "granted_scope": { - "resource": "tool:email", - "action": "read", - "constraints": { - "allowed_fields": ["subject", "from", "date"], - "excluded_fields": ["body", "attachments"] - } - }, - "granted_at": "2026-04-18T14:30:01Z", - "expires_at": "2026-04-18T14:31:01Z", - "one_shot": true, - "forwardable": false, - "audience": "tool:email", - "integrity": { - "hash_algorithm": "sha256", - "content_hash": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2" - } -} diff --git a/examples/delegation/example1.json b/examples/delegation_extension/example1.json similarity index 69% rename from examples/delegation/example1.json rename to examples/delegation_extension/example1.json index 53eaf8f..58c61f3 100644 --- a/examples/delegation/example1.json +++ b/examples/delegation_extension/example1.json @@ -1,10 +1,11 @@ { "delegation_request": { + "schema_version": "0.2", "request_id": "req-a1b2c3d4", "requester": "agent-planner-01", "run_id": "run-e5f6g7h8", "intent": "Read email headers to find meeting invitations", - "justification": "The user asked me to check for upcoming meetings. I need to access email metadata to identify calendar invitations.", + "justification": "The user asked me to check for upcoming meetings.", "requested_scope": { "resource": "tool:email", "action": "read" @@ -12,13 +13,14 @@ "preferred_ttl_seconds": 60, "preferred_audience": "tool:email", "task_context_ref": "s-3", - "timestamp": "2026-04-18T14:30:00Z", + "observed_at": "2026-04-18T14:30:00Z", "provenance": { "trace_step_id": "s-3", "plan_version": 1 } }, "delegation_decision": { + "schema_version": "0.2", "decision_id": "dec-i9j0k1l2", "request_id": "req-a1b2c3d4", "status": "narrowed", @@ -26,18 +28,28 @@ "kind": "policy", "policy_id": "compliance-email-001" }, - "policy_refs": ["compliance-email-001"], + "policy_refs": [ + "compliance-email-001" + ], "narrowed_scope": { "resource": "tool:email", "action": "read", "constraints": { - "allowed_fields": ["subject", "from", "date"], - "excluded_fields": ["body", "attachments"] + "allowed_fields": [ + "subject", + "from", + "date" + ], + "excluded_fields": [ + "body", + "attachments" + ] } }, - "timestamp": "2026-04-18T14:30:01Z" + "decided_at": "2026-04-18T14:30:01Z" }, "authority_receipt": { + "schema_version": "0.2", "receipt_id": "rcpt-m3n4o5p6", "decision_id": "dec-i9j0k1l2", "request_id": "req-a1b2c3d4", @@ -46,11 +58,18 @@ "resource": "tool:email", "action": "read", "constraints": { - "allowed_fields": ["subject", "from", "date"], - "excluded_fields": ["body", "attachments"] + "allowed_fields": [ + "subject", + "from", + "date" + ], + "excluded_fields": [ + "body", + "attachments" + ] } }, - "granted_at": "2026-04-18T14:30:01Z", + "effective_at": "2026-04-18T14:30:01Z", "expires_at": "2026-04-18T14:31:01Z", "one_shot": true, "forwardable": false, diff --git a/examples/execution_receipts_audit_envelopes/example-envelope.json b/examples/execution_receipts_audit_envelopes/example-envelope.json new file mode 100644 index 0000000..6ec257c --- /dev/null +++ b/examples/execution_receipts_audit_envelopes/example-envelope.json @@ -0,0 +1,53 @@ +{ + "schema_version": "0.2", + "envelope_id": "11111111-2222-4333-8444-555555555555", + "run_id": "run-e5f6g7h8", + "agent_id": "agent-planner-01", + "task_hash": "3c9e2a1f7b0d6e5c8a4f2b1d9e8c7a6f5b4d3e2c1a0f9e8d7c6b5a4f3e2d1c0b", + "started_at": "2026-04-18T14:30:00Z", + "completed_at": "2026-04-18T14:30:05Z", + "completion_status": "succeeded", + "trace_hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "delegation_requests": [ + "req-a1b2c3d4" + ], + "delegation_decisions": [ + "dec-i9j0k1l2" + ], + "authority_receipts": [ + "rcpt-m3n4o5p6" + ], + "tool_execution_receipts": [ + "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa" + ], + "delegation_summary": { + "total_requested": 1, + "total_granted": 1, + "total_denied": 0, + "total_narrowed": 1, + "total_escalated": 0 + }, + "permission_summary": { + "total_granted": 1, + "total_consumed": 1, + "total_expired": 0, + "total_revoked": 0 + }, + "budget_final": { + "tokens_used": 4250, + "tokens_remaining": 95750, + "cost_used": 0.085, + "cost_remaining": 9.915, + "steps_used": 8, + "steps_remaining": 42, + "tool_calls_used": 1, + "tool_calls_remaining": 19, + "retries_used": 0, + "retries_remaining": 5 + }, + "policy_violations": [], + "integrity": { + "hash_algorithm": "sha256", + "content_hash": "c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2" + } +} diff --git a/examples/tool_execution_receipt/example1.json b/examples/execution_receipts_audit_envelopes/example1.json similarity index 58% rename from examples/tool_execution_receipt/example1.json rename to examples/execution_receipts_audit_envelopes/example1.json index 29bea1d..e96eb09 100644 --- a/examples/tool_execution_receipt/example1.json +++ b/examples/execution_receipts_audit_envelopes/example1.json @@ -1,18 +1,19 @@ { + "schema_version": "0.2", "execution_id": "exec-u1v2w3x4", "run_id": "run-e5f6g7h8", "tool_name": "email", "permission_id": "perm-q7r8s9t0", "authority_receipt_id": "rcpt-m3n4o5p6", - "input_hash": "sha256:7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069", - "output_hash": "sha256:ef2d127de37b942baad06145e54b0c619a1f22327b2ebbcfbec78f5564afe39d", + "input_hash": "7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069", + "output_hash": "ef2d127de37b942baad06145e54b0c619a1f22327b2ebbcfbec78f5564afe39d", "output_size_bytes": 342, "started_at": "2026-04-18T14:30:02Z", - "completed_at": "2026-04-18T14:30:02Z", + "completed_at": "2026-04-18T14:30:03Z", "duration_ms": 145, "status": "success", "postcondition_check": "passed", - "sandbox_state_hash": "sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", + "sandbox_state_hash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", "integrity": { "hash_algorithm": "sha256", "content_hash": "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9" diff --git a/examples/permission_grant/example1.json b/examples/permission_acl/example1.json similarity index 72% rename from examples/permission_grant/example1.json rename to examples/permission_acl/example1.json index e8c9860..95a265d 100644 --- a/examples/permission_grant/example1.json +++ b/examples/permission_acl/example1.json @@ -5,12 +5,20 @@ "resource": "tool:email", "action": "read", "constraints": { - "allowed_fields": ["subject", "from", "date"], - "excluded_fields": ["body", "attachments"] + "allowed_fields": [ + "subject", + "from", + "date" + ], + "excluded_fields": [ + "body", + "attachments" + ] } }, "audience": "tool:email", "ttl_seconds": 60, + "effective_at": "2026-04-18T14:30:01Z", "expires_at": "2026-04-18T14:31:01Z", "one_shot": true, "forwardable": false, @@ -18,7 +26,6 @@ "policy_ref": "compliance-email-001", "request_ref": "req-a1b2c3d4", "decision_ref": "dec-i9j0k1l2", - "granted_at": "2026-04-18T14:30:01Z", "status": "consumed", "consumed_at": "2026-04-18T14:30:02Z" } diff --git a/harness/src/agents/governed-agent.ts b/harness/src/agents/governed-agent.ts index ee469d8..bade29a 100644 --- a/harness/src/agents/governed-agent.ts +++ b/harness/src/agents/governed-agent.ts @@ -192,13 +192,14 @@ export async function runGovernedAgent( // --- request_authority --- const request: DelegationRequest = { + schema_version: "0.2", request_id: `req-${randomUUID().slice(0, 8)}`, requester: state.telemetry.agent_id, run_id: state.runId, intent: `Execute tool ${tc.toolName}`, justification: planResp.content.slice(0, 500), requested_scope: { resource: `tool:${tc.toolName}`, action: "execute" }, - timestamp: new Date().toISOString(), + observed_at: new Date().toISOString(), provenance: { trace_step_id: planStep.id, plan_version: state.planVersion, @@ -269,6 +270,7 @@ export async function runGovernedAgent( budget.recordToolCall(state, `tool:${tc.toolName}`); let toolResult; + const executionStartedAt = new Date().toISOString(); try { toolResult = await config.toolRegistry.call( tc.toolName, @@ -295,6 +297,7 @@ export async function runGovernedAgent( budget.recordStep(state, "observe_result"); const execReceipt: ToolExecutionReceipt = { + schema_version: "0.2", execution_id: `exec-${randomUUID().slice(0, 8)}`, run_id: state.runId, tool_name: tc.toolName, @@ -302,12 +305,14 @@ export async function runGovernedAgent( authority_receipt_id: receipt.receipt_id, input_hash: sha256(JSON.stringify(tc.arguments)), output_hash: sha256(obsText), - started_at: new Date().toISOString(), + output_size_bytes: Buffer.byteLength(obsText, "utf8"), + started_at: executionStartedAt, completed_at: new Date().toISOString(), - duration_ms: toolResult.latencyMs, + duration_ms: toolResult.latencyMs ?? 0, status: toolResult.error ? "error" : "success", error_category: toolResult.errorCategory, postcondition_check: "skipped", + sandbox_state_hash: sha256(JSON.stringify(state.sandbox)), integrity: { hash_algorithm: "sha256", content_hash: sha256(`${actionStep.id}|${obsText}`), diff --git a/harness/src/core/trace-emitter.ts b/harness/src/core/trace-emitter.ts index e077abc..6a0a65f 100644 --- a/harness/src/core/trace-emitter.ts +++ b/harness/src/core/trace-emitter.ts @@ -104,8 +104,11 @@ export function emitSummary( export function finalizeTrace(state: AgentState, answer: string): Trace { state.trace.final_answer = answer; state.trace.termination = state.completionStatus; - state.telemetry.timestamp = new Date().toISOString(); - state.telemetry.metrics.latency_ms = Date.now(); // caller can diff with start + const startedAt = Date.parse(state.telemetry.observed_at); + const endedAt = Date.now(); + state.telemetry.metrics.latency_ms = Number.isFinite(startedAt) + ? Math.max(0, endedAt - startedAt) + : endedAt; return state.trace; } diff --git a/harness/src/governance/audit-engine.ts b/harness/src/governance/audit-engine.ts index deba7fe..f11d643 100644 --- a/harness/src/governance/audit-engine.ts +++ b/harness/src/governance/audit-engine.ts @@ -52,7 +52,7 @@ function delegationSummaryFromState(state: AgentState): DelegationSummary { const decisions = state.delegationDecisions; return { total_requested: state.delegationRequests.length, - total_approved: decisions.filter((d) => d.status === "approved").length, + total_granted: decisions.filter((d) => d.status === "approved").length, total_denied: decisions.filter((d) => d.status === "denied").length, total_narrowed: decisions.filter((d) => d.status === "narrowed").length, total_escalated: decisions.filter((d) => d.status === "escalated").length, @@ -71,14 +71,20 @@ function permissionSummaryFromState(state: AgentState): PermissionSummary { type AuditEventIntegrity = { hash_algorithm: "sha256"; content_hash: string }; +interface AuditEventOrdering { + event_seq: number; + causal_predecessors?: string[]; +} + export interface AuditEvent { event_id: string; run_id: string; agent_id: string; - timestamp: string; + observed_at: string; event_type: string; details: Record; - previous_event_id: string | null; + parent_event_id: string | null; + ordering: AuditEventOrdering; integrity: AuditEventIntegrity; } @@ -95,19 +101,24 @@ export class AuditEngine { event_type: string; details: Record; }): AuditEvent { - const timestamp = new Date().toISOString(); - const previous_event_id = + const observed_at = new Date().toISOString(); + const parent_event_id = this.events.length > 0 ? this.events[this.events.length - 1]!.event_id : null; + const ordering: AuditEventOrdering = { + event_seq: this.events.length, + causal_predecessors: parent_event_id ? [parent_event_id] : undefined, + }; const event_id = randomUUID(); const hashInput = stableStringify({ event_id, run_id: args.run_id, agent_id: args.agent_id, - timestamp, + observed_at, event_type: args.event_type, details: args.details, - previous_event_id, + parent_event_id, + ordering, }); const content_hash = sha256Hex(hashInput); @@ -115,10 +126,11 @@ export class AuditEngine { event_id, run_id: args.run_id, agent_id: args.agent_id, - timestamp, + observed_at, event_type: args.event_type, details: args.details, - previous_event_id, + parent_event_id, + ordering, integrity: { hash_algorithm: "sha256", content_hash }, }; this.events.push(event); @@ -126,7 +138,7 @@ export class AuditEngine { } seal(state: AgentState): AuditEnvelope { - const sealed_at = new Date().toISOString(); + const completed_at = new Date().toISOString(); const trace_hash = sha256Hex(stableStringify(state.trace)); const task_hash = sha256Hex( stableStringify({ objective: state.objective, trace_task: state.trace.task }), @@ -140,15 +152,16 @@ export class AuditEngine { const tail = this.events.length > 0 ? this.events[this.events.length - 1]!.event_id : undefined; - const started_at = state.telemetry.timestamp; + const started_at = state.telemetry.observed_at; const body: Omit = { + schema_version: "0.3", envelope_id, run_id: state.runId, agent_id: state.telemetry.agent_id, task_hash, started_at, - sealed_at, + completed_at, completion_status: toEnvelopeCompletion(state), trace_hash, event_chain_head: head, diff --git a/harness/src/governance/auth-broker.ts b/harness/src/governance/auth-broker.ts index 1c4477d..6a21dc3 100644 --- a/harness/src/governance/auth-broker.ts +++ b/harness/src/governance/auth-broker.ts @@ -80,10 +80,11 @@ export class AuthBroker { const one_shot = readConstraintBool(granted_scope, "one_shot", false); const forwardable = readConstraintBool(granted_scope, "forwardable", false); + const audience = request.preferred_audience ?? granted_scope.resource; const grant = this.permissionManager.grant({ granted_to: request.requester, scope: granted_scope, - audience: request.preferred_audience, + audience, ttl_seconds, one_shot, forwardable, @@ -93,16 +94,17 @@ export class AuthBroker { decision_ref: decision.decision_id, }); - const granted_at = grant.granted_at; + const effective_at = grant.effective_at; const expires_at = grant.expires_at; const receiptBody: Omit = { + schema_version: "0.2", receipt_id: randomUUID(), decision_id: decision.decision_id, request_id: request.request_id, permission_id: grant.permission_id, granted_scope, - granted_at, + effective_at, expires_at, one_shot: grant.one_shot, forwardable: grant.forwardable, diff --git a/harness/src/governance/permission-manager.ts b/harness/src/governance/permission-manager.ts index 16d0c61..9697f34 100644 --- a/harness/src/governance/permission-manager.ts +++ b/harness/src/governance/permission-manager.ts @@ -8,7 +8,7 @@ import type { RequestedScope } from "../schemas/delegation.js"; export interface GrantParams { granted_to: string; scope: RequestedScope; - audience?: string; + audience: string; ttl_seconds: number; one_shot: boolean; forwardable: boolean; @@ -26,6 +26,10 @@ function isPastExpiry(expiresAt: string, now: string): boolean { return expiresAt <= now; } +function isBeforeEffective(effectiveAt: string, now: string): boolean { + return now < effectiveAt; +} + export class PermissionManager { private permissions = new Map(); private events: PermissionLifecycleEvent[] = []; @@ -36,9 +40,9 @@ export class PermissionManager { grant(params: GrantParams): PermissionGrant { const permission_id = randomUUID(); - const granted_at = nowIso(); + const effective_at = nowIso(); const expires_at = new Date( - Date.parse(granted_at) + params.ttl_seconds * 1000, + Date.parse(effective_at) + params.ttl_seconds * 1000, ).toISOString(); const grant: PermissionGrant = { @@ -47,6 +51,7 @@ export class PermissionManager { scope: params.scope, audience: params.audience, ttl_seconds: params.ttl_seconds, + effective_at, expires_at, one_shot: params.one_shot, forwardable: params.forwardable, @@ -54,7 +59,6 @@ export class PermissionManager { policy_ref: params.policy_ref, request_ref: params.request_ref, decision_ref: params.decision_ref, - granted_at, status: "active", }; @@ -62,7 +66,7 @@ export class PermissionManager { this.pushEvent({ event: "permission_granted", permission_id, - timestamp: granted_at, + observed_at: effective_at, details: { scope: params.scope, ttl_seconds: params.ttl_seconds }, }); @@ -75,7 +79,11 @@ export class PermissionManager { if (!grant || grant.status !== "active" || !grant.one_shot) { return false; } - if (isPastExpiry(grant.expires_at, nowIso())) { + const now = nowIso(); + if ( + isBeforeEffective(grant.effective_at, now) || + isPastExpiry(grant.expires_at, now) + ) { return false; } @@ -89,7 +97,7 @@ export class PermissionManager { this.pushEvent({ event: "permission_consumed", permission_id, - timestamp: consumed_at, + observed_at: consumed_at, }); return true; } @@ -112,7 +120,7 @@ export class PermissionManager { this.pushEvent({ event: "permission_revoked", permission_id, - timestamp: revoked_at, + observed_at: revoked_at, details: { reason }, }); return true; @@ -133,7 +141,11 @@ export class PermissionManager { if (!grant || grant.status !== "active") { return false; } - return !isPastExpiry(grant.expires_at, nowIso()); + const now = nowIso(); + return ( + !isBeforeEffective(grant.effective_at, now) && + !isPastExpiry(grant.expires_at, now) + ); } get(permission_id: string): PermissionGrant | undefined { @@ -159,7 +171,7 @@ export class PermissionManager { this.pushEvent({ event: "permission_expired", permission_id: id, - timestamp: now, + observed_at: now, details: { expires_at: grant.expires_at }, }); } diff --git a/harness/src/governance/policy-evaluator.ts b/harness/src/governance/policy-evaluator.ts index 0299196..d03ba81 100644 --- a/harness/src/governance/policy-evaluator.ts +++ b/harness/src/governance/policy-evaluator.ts @@ -12,7 +12,16 @@ export interface PolicyRule { action: "allow" | "deny" | "narrow" | "require_approval"; subject?: string; resource: string; - conditions?: Record; + conditions?: { + max_risk_level?: "low" | "medium" | "high"; + require_justification?: boolean; + validity_window?: { + effective_at: string; + expires_at: string; + }; + budget_remaining_min?: number; + [key: string]: unknown; + }; narrowing?: { allowed_fields?: string[]; excluded_fields?: string[]; @@ -27,6 +36,8 @@ export interface PolicySet { policy_type: "safety" | "compliance" | "organizational" | "ethical" | "operational"; rules: PolicyRule[]; priority: number; + effective_at?: string; + expires_at?: string; } function sha256Hex(input: string): string { @@ -63,10 +74,25 @@ function resourceMatches(scopeResource: string, pattern: string): boolean { return scopeResource === pattern; } +function isWithinHalfOpenWindow( + nowIso: string, + effectiveAt?: string, + expiresAt?: string, +): boolean { + if (effectiveAt && nowIso < effectiveAt) { + return false; + } + if (expiresAt && nowIso >= expiresAt) { + return false; + } + return true; +} + function ruleMatches( rule: PolicyRule, agentId: string, requestedScope: RequestedScope, + nowIso: string, ): boolean { const subjectPattern = rule.subject ?? "*"; if (!subjectMatches(agentId, subjectPattern)) { @@ -76,8 +102,22 @@ function ruleMatches( return false; } if (rule.conditions && Object.keys(rule.conditions).length > 0) { + const validityWindow = rule.conditions.validity_window; + if ( + validityWindow && + !isWithinHalfOpenWindow( + nowIso, + validityWindow.effective_at, + validityWindow.expires_at, + ) + ) { + return false; + } const scopeConstraints = requestedScope.constraints ?? {}; for (const [key, expected] of Object.entries(rule.conditions)) { + if (key === "validity_window") { + continue; + } if (!(key in scopeConstraints)) { return false; } @@ -133,7 +173,10 @@ export class PolicyEvaluator { } evaluate(request: DelegationRequest, agent_id: string): DelegationDecision { - const sorted = [...this.policies].sort((a, b) => a.priority - b.priority); + const nowIso = new Date().toISOString(); + const sorted = [...this.policies] + .filter((p) => isWithinHalfOpenWindow(nowIso, p.effective_at, p.expires_at)) + .sort((a, b) => a.priority - b.priority); let firstNarrow: MatchHit | undefined; let firstEscalation: MatchHit | undefined; @@ -141,7 +184,7 @@ export class PolicyEvaluator { for (const policy of sorted) { const rule = policy.rules.find((r) => - ruleMatches(r, agent_id, request.requested_scope), + ruleMatches(r, agent_id, request.requested_scope, nowIso), ); if (!rule) { continue; @@ -159,6 +202,7 @@ export class PolicyEvaluator { escalation_target: undefined, matched: { policy, rule }, outcomeKind: "deny", + decidedAt: nowIso, }); } @@ -193,6 +237,7 @@ export class PolicyEvaluator { escalation_target: undefined, matched: firstNarrow, outcomeKind: "narrow", + decidedAt: nowIso, }); } @@ -213,6 +258,7 @@ export class PolicyEvaluator { firstEscalation.policy.policy_id, matched: firstEscalation, outcomeKind: "require_approval", + decidedAt: nowIso, }); } @@ -228,6 +274,7 @@ export class PolicyEvaluator { escalation_target: undefined, matched: firstAllow, outcomeKind: "allow", + decidedAt: nowIso, }); } @@ -242,6 +289,7 @@ export class PolicyEvaluator { escalation_target: undefined, matched: undefined, outcomeKind: "default_deny", + decidedAt: nowIso, }); } @@ -256,6 +304,7 @@ export class PolicyEvaluator { escalation_target?: string; matched: MatchHit | undefined; outcomeKind: string; + decidedAt: string; }): DelegationDecision { const basis = stableStringify({ request_id: args.request.request_id, @@ -271,10 +320,12 @@ export class PolicyEvaluator { ? { policy_id: args.matched.policy.policy_id, rule_id: args.matched.rule.rule_id } : null, outcomeKind: args.outcomeKind, + decided_at: args.decidedAt, }); const decision_id = sha256Hex(basis); return { + schema_version: "0.2", decision_id, request_id: args.request.request_id, status: args.status, @@ -283,7 +334,7 @@ export class PolicyEvaluator { narrowed_scope: args.narrowed_scope, denial_reason: args.denial_reason, escalation_target: args.escalation_target, - timestamp: args.request.timestamp, + decided_at: args.decidedAt, }; } } diff --git a/harness/src/schemas/audit-envelope.ts b/harness/src/schemas/audit-envelope.ts index 8449612..595d5f8 100644 --- a/harness/src/schemas/audit-envelope.ts +++ b/harness/src/schemas/audit-envelope.ts @@ -1,5 +1,5 @@ /** - * Audit envelope types — RFC 0043 v0.2 / RFC 0048. + * Audit envelope types — RFC 0043 v0.3 / RFC 0048 v0.2. * * Sealed summary of a complete governed execution run. Immutable after * creation — any modification is detectable via hash verification. @@ -20,7 +20,7 @@ export type CompletionStatus = export interface DelegationSummary { total_requested: number; - total_approved: number; + total_granted: number; total_denied: number; total_narrowed: number; total_escalated: number; @@ -38,17 +38,18 @@ export interface PolicyViolationRecord { policy_id: string; rule_id: string; description: string; - severity: "low" | "medium" | "high" | "critical"; - timestamp: string; + severity: "info" | "low" | "medium" | "high" | "critical"; + observed_at: string; } export interface AuditEnvelope { + schema_version: "0.2" | "0.3"; envelope_id: string; run_id: string; agent_id: string; task_hash: string; started_at: string; - sealed_at: string; + completed_at: string; completion_status: CompletionStatus; trace_hash: string; event_chain_head?: string; diff --git a/harness/src/schemas/delegation.ts b/harness/src/schemas/delegation.ts index 3b19e63..d4742ff 100644 --- a/harness/src/schemas/delegation.ts +++ b/harness/src/schemas/delegation.ts @@ -1,5 +1,5 @@ /** - * Delegation types — RFC 0047. + * Delegation types — RFC 0047 v0.2. * * Typed schema objects for the authority request/decision/receipt flow. * Model-provided fields are clearly separated from harness-provided fields. @@ -22,6 +22,7 @@ export interface DelegationProvenance { * timing, and provenance. */ export interface DelegationRequest { + schema_version: "0.2"; request_id: string; /** Harness-verified agent identity — never model-provided. */ requester: string; @@ -34,7 +35,7 @@ export interface DelegationRequest { preferred_ttl_seconds?: number; preferred_audience?: string; task_context_ref?: string; - timestamp: string; + observed_at: string; provenance?: DelegationProvenance; } @@ -55,6 +56,7 @@ export interface DecidedBy { * All fields are harness-provided — the model does not participate. */ export interface DelegationDecision { + schema_version: "0.2"; decision_id: string; request_id: string; status: DelegationStatus; @@ -63,7 +65,7 @@ export interface DelegationDecision { narrowed_scope?: RequestedScope; denial_reason?: string; escalation_target?: string; - timestamp: string; + decided_at: string; } export interface ReceiptIntegrity { @@ -78,15 +80,16 @@ export interface ReceiptIntegrity { * materialized permission. Tamper-evident via integrity hash. */ export interface AuthorityReceipt { + schema_version: "0.2"; receipt_id: string; decision_id: string; request_id: string; permission_id: string; granted_scope: RequestedScope; - granted_at: string; + effective_at: string; expires_at: string; one_shot: boolean; forwardable: boolean; - audience?: string; + audience: string; integrity: ReceiptIntegrity; } diff --git a/harness/src/schemas/permission.ts b/harness/src/schemas/permission.ts index b014150..ff571f6 100644 --- a/harness/src/schemas/permission.ts +++ b/harness/src/schemas/permission.ts @@ -1,5 +1,5 @@ /** - * Permission grant types — RFC 0042 v0.2. + * Permission grant types — RFC 0042 v0.3. * * First-class permission objects with full lifecycle tracking. * The model cannot create these — only the harness/policy engine can. @@ -13,8 +13,9 @@ export interface PermissionGrant { permission_id: string; granted_to: string; scope: RequestedScope; - audience?: string; + audience: string; ttl_seconds: number; + effective_at: string; expires_at: string; one_shot: boolean; forwardable: boolean; @@ -22,7 +23,6 @@ export interface PermissionGrant { policy_ref?: string; request_ref?: string; decision_ref?: string; - granted_at: string; consumed_at?: string; revoked_at?: string; revocation_reason?: string; @@ -38,6 +38,6 @@ export type PermissionEvent = export interface PermissionLifecycleEvent { event: PermissionEvent; permission_id: string; - timestamp: string; + observed_at: string; details?: Record; } diff --git a/harness/src/schemas/receipt.ts b/harness/src/schemas/receipt.ts index 4f6648e..75561ad 100644 --- a/harness/src/schemas/receipt.ts +++ b/harness/src/schemas/receipt.ts @@ -1,5 +1,5 @@ /** - * Execution receipt types — RFC 0048. + * Execution receipt types — RFC 0048 v0.2. * * Tamper-evident records proving what happened during tool execution. * Receipts contain hashes, not raw data — safe for compliance sharing. @@ -13,6 +13,7 @@ export type ReceiptStatus = "success" | "error" | "timeout" | "quarantined"; export type PostconditionResult = "passed" | "failed" | "skipped"; export interface ToolExecutionReceipt { + schema_version: "0.2"; execution_id: string; run_id: string; tool_name: string; @@ -20,14 +21,14 @@ export interface ToolExecutionReceipt { authority_receipt_id: string; input_hash: string; output_hash: string; - output_size_bytes?: number; + output_size_bytes: number; started_at: string; - completed_at?: string; - duration_ms?: number; + completed_at: string; + duration_ms: number; status: ReceiptStatus; error_category?: ErrorCategory; postcondition_check: PostconditionResult; postcondition_violation?: string; - sandbox_state_hash?: string; + sandbox_state_hash: string; integrity: ReceiptIntegrity; } diff --git a/harness/src/schemas/telemetry.ts b/harness/src/schemas/telemetry.ts index 19a3de6..dd8845b 100644 --- a/harness/src/schemas/telemetry.ts +++ b/harness/src/schemas/telemetry.ts @@ -13,18 +13,27 @@ export interface TelemetryMetrics { [key: string]: number; } +export interface TelemetryOrdering { + event_seq: number; + parent_event_id?: string; +} + export interface TelemetryRecord { version: string; agent_id: string; - timestamp: string; + observed_at: string; + ordering: TelemetryOrdering; metrics: TelemetryMetrics; } export function createInitialTelemetry(agentId: string): TelemetryRecord { return { - version: "0.1", + version: "0.2", agent_id: agentId, - timestamp: new Date().toISOString(), + observed_at: new Date().toISOString(), + ordering: { + event_seq: 0, + }, metrics: { steps: 0, tool_calls: 0, diff --git a/harness/tests/governance.test.ts b/harness/tests/governance.test.ts index 30a6e8b..b389cd9 100644 --- a/harness/tests/governance.test.ts +++ b/harness/tests/governance.test.ts @@ -14,13 +14,14 @@ const sampleScope = { function makeRequest(overrides?: Partial): DelegationRequest { return { + schema_version: "0.2", request_id: "req-test-1", requester: "agent-test", run_id: "run-test", intent: "Search the web", justification: "Need external facts", requested_scope: sampleScope, - timestamp: new Date().toISOString(), + observed_at: new Date().toISOString(), ...overrides, }; } @@ -31,6 +32,7 @@ describe("PermissionManager", () => { const grant = pm.grant({ granted_to: "agent-1", scope: sampleScope, + audience: "tool:search", ttl_seconds: 3600, one_shot: false, forwardable: false, @@ -49,6 +51,7 @@ describe("PermissionManager", () => { const grant = pm.grant({ granted_to: "agent-1", scope: sampleScope, + audience: "tool:search", ttl_seconds: 3600, one_shot: true, forwardable: false, @@ -63,6 +66,7 @@ describe("PermissionManager", () => { const grant = pm.grant({ granted_to: "agent-1", scope: sampleScope, + audience: "tool:search", ttl_seconds: 3600, one_shot: false, forwardable: false, @@ -77,6 +81,7 @@ describe("PermissionManager", () => { const grant = pm.grant({ granted_to: "agent-1", scope: sampleScope, + audience: "tool:search", ttl_seconds: 0, one_shot: false, forwardable: false, @@ -91,6 +96,7 @@ describe("PermissionManager", () => { const grant = pm.grant({ granted_to: "agent-1", scope: sampleScope, + audience: "tool:search", ttl_seconds: 3600, one_shot: false, forwardable: false, @@ -107,6 +113,7 @@ describe("PermissionManager", () => { const a = pm.grant({ granted_to: "agent-1", scope: sampleScope, + audience: "tool:search", ttl_seconds: 3600, one_shot: false, forwardable: false, @@ -115,6 +122,7 @@ describe("PermissionManager", () => { const b = pm.grant({ granted_to: "agent-2", scope: { resource: "tool:calc", action: "execute" }, + audience: "tool:calc", ttl_seconds: 3600, one_shot: false, forwardable: false, @@ -130,6 +138,7 @@ describe("PermissionManager", () => { const grant = pm.grant({ granted_to: "agent-1", scope: sampleScope, + audience: "tool:search", ttl_seconds: 3600, one_shot: true, forwardable: false, @@ -305,13 +314,14 @@ describe("AuthBroker", () => { const broker = new AuthBroker(new PermissionManager()); const request = makeRequest({ request_id: "req-denied" }); const decision: DelegationDecision = { + schema_version: "0.2", decision_id: "dec-deny", request_id: request.request_id, status: "denied", decided_by: { kind: "harness" }, policy_refs: [], denial_reason: "no", - timestamp: request.timestamp, + decided_at: request.observed_at, }; expect(() => broker.materialize(decision, request)).toThrow( /approved or narrowed/, @@ -340,9 +350,12 @@ describe("AuditEngine", () => { event_type: "test.c", details: { n: 3 }, }); - expect(e1.previous_event_id).toBeNull(); - expect(e2.previous_event_id).toBe(e1.event_id); - expect(e3.previous_event_id).toBe(e2.event_id); + expect(e1.parent_event_id).toBeNull(); + expect(e2.parent_event_id).toBe(e1.event_id); + expect(e3.parent_event_id).toBe(e2.event_id); + expect(e1.ordering.event_seq).toBe(0); + expect(e2.ordering.event_seq).toBe(1); + expect(e3.ordering.event_seq).toBe(2); expect(e1.integrity.content_hash).toMatch(/^[0-9a-f]{64}$/); }); @@ -358,8 +371,8 @@ describe("AuditEngine", () => { expect(envelope.trace_hash).toMatch(/^[0-9a-f]{64}$/); expect(envelope.integrity.content_hash).toMatch(/^[0-9a-f]{64}$/); expect(envelope.integrity.hash_algorithm).toBe("sha256"); - expect(envelope.started_at).toBe(state.telemetry.timestamp); - expect(Date.parse(envelope.sealed_at)).not.toBeNaN(); + expect(envelope.started_at).toBe(state.telemetry.observed_at); + expect(Date.parse(envelope.completed_at)).not.toBeNaN(); expect(AuditEngine.verify(envelope)).toBe(true); }); }); diff --git a/rfcs/0010-agent-memory-schema.md b/rfcs/0010-agent-memory-schema.md index ee6920c..b807371 100644 --- a/rfcs/0010-agent-memory-schema.md +++ b/rfcs/0010-agent-memory-schema.md @@ -125,7 +125,7 @@ Examples: "properties": { "version": { "type": "string", - "enum": ["0.1"], + "enum": ["0.2"], "description": "Schema version." }, @@ -143,7 +143,7 @@ Examples: "key": { "type": "string" }, "value": {}, "type": { "type": "string" }, - "expires_at": { "type": "string" } + "expires_at": { "type": "string", "format": "date-time" } }, "required": ["key", "value"] } @@ -158,7 +158,8 @@ Examples: "key": { "type": "string" }, "value": {}, "type": { "type": "string" }, - "updated_at": { "type": "string" }, + "observed_at": { "type": "string", "format": "date-time" }, + "superseded_at": { "type": "string", "format": "date-time" }, "confidence": { "type": "number" } }, "required": ["key", "value"] @@ -172,11 +173,11 @@ Examples: "type": "object", "properties": { "episode_id": { "type": "string" }, - "timestamp": { "type": "string" }, + "observed_at": { "type": "string", "format": "date-time" }, "summary": { "type": "string" }, "metadata": { "type": "object" } }, - "required": ["episode_id", "timestamp"] + "required": ["episode_id", "observed_at"] } }, @@ -187,7 +188,7 @@ Examples: "type": "object", "properties": { "state": { "type": "object" }, - "last_used": { "type": "string" } + "observed_at": { "type": "string", "format": "date-time" } } } } @@ -225,7 +226,7 @@ Examples: "key": "preferred_units", "value": "metric", "type": "preference", - "updated_at": "2026-04-10T09:00:00Z", + "observed_at": "2026-04-10T09:00:00Z", "confidence": 0.95 } ] @@ -244,7 +245,7 @@ Examples: "cached_city": "Austin", "cached_result": "Clear skies, 72F" }, - "last_used": "2026-04-14T11:30:00Z" + "observed_at": "2026-04-14T11:30:00Z" } } } diff --git a/rfcs/0011-multi-agent-protocol.md b/rfcs/0011-multi-agent-protocol.md index 8926bb3..2669a7e 100644 --- a/rfcs/0011-multi-agent-protocol.md +++ b/rfcs/0011-multi-agent-protocol.md @@ -79,11 +79,11 @@ A multi‑agent system consists of: ```json { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "OpenCoT Multi-Agent Protocol v0.1", + "title": "OpenCoT Multi-Agent Protocol v0.2", "type": "object", "properties": { - "version": { "type": "string", "enum": ["0.1"] }, + "version": { "type": "string", "enum": ["0.2"] }, "agents": { "type": "array", @@ -106,11 +106,11 @@ A multi‑agent system consists of: "message_id": { "type": "string" }, "sender": { "type": "string" }, "receiver": { "type": "string" }, - "timestamp": { "type": "string" }, + "observed_at": { "type": "string", "format": "date-time" }, "content": { "type": "string" }, "metadata": { "type": "object" } }, - "required": ["message_id", "sender", "receiver", "content"] + "required": ["message_id", "sender", "receiver", "observed_at", "content"] } }, @@ -138,6 +138,7 @@ A multi‑agent system consists of: "message_id": "m1", "sender": "planner", "receiver": "coder", + "observed_at": "2026-04-14T11:32:12Z", "content": "Implement function f(x)." } ] diff --git a/rfcs/0023-humain-in-the-loop-schema.md b/rfcs/0023-humain-in-the-loop-schema.md index 9496fc7..645bc6a 100644 --- a/rfcs/0023-humain-in-the-loop-schema.md +++ b/rfcs/0023-humain-in-the-loop-schema.md @@ -1,5 +1,7 @@ # RFC 0023 — Human-in-the-Loop Interaction Schema, Status: Draft, Author: Open CoT Community, Created: 2026-04-14 +**Discussion:** https://github.com/supernovae/open-cot/discussions/23 + ## 1. Summary This RFC defines the **Human-in-the-Loop (HITL) Interaction Schema** for Open-CoT, the cognitive control plane for governed agent execution. It standardizes how agents **request** human judgment (`approval`, `clarification`, `review`, `override`), how supervisors **respond**, and how responses **resume** execution. Payloads are transport-agnostic (UIs, tickets, chatops, async queues). diff --git a/rfcs/0025-tool-marketplace-registry-format.md b/rfcs/0025-tool-marketplace-registry-format.md index 646d549..e02a052 100644 --- a/rfcs/0025-tool-marketplace-registry-format.md +++ b/rfcs/0025-tool-marketplace-registry-format.md @@ -1,5 +1,7 @@ # RFC 0025 — Tool Marketplace & Registry Format, Status: Draft, Author: Open CoT Community, Created: 2026-04-14 +**Discussion:** https://github.com/supernovae/open-cot/discussions/25 + ## 1. Summary This RFC defines the **Tool Marketplace & Registry Format** for Open-CoT: a versioned **`tool_registry`** catalog of **`tool_registry_entry`** records for publishing and discovering tools under governance. Entries include **input** / **output** JSON Schemas, **`required_permissions[]`**, **`risk_level`**, **`cost_estimate`**, **`timeout_default_ms`**, **`categories[]`**, **`author`**, **`documentation_url`**, and optional **`health_check_endpoint`**. diff --git a/rfcs/0027-distributed-agent-execution-protocol.md b/rfcs/0027-distributed-agent-execution-protocol.md index a6e2d65..714b46d 100644 --- a/rfcs/0027-distributed-agent-execution-protocol.md +++ b/rfcs/0027-distributed-agent-execution-protocol.md @@ -1,5 +1,7 @@ # RFC 0027 — Distributed Agent Execution Protocol, Status: Draft, Author: Open CoT Community, Created: 2026-04-14 +**Discussion:** https://github.com/supernovae/open-cot/discussions/27 + ## 1. Summary This RFC defines the **Distributed Agent Execution Protocol** for Open-CoT: **`execution_node`** advertisements, **`task_assignment`** with explicit **`delegated_scope`**, and terminal **`execution_result`** records (hashes, trace pointers, **`receipt_refs[]`**). Each node runs its own governed FSM ([RFC 0007](0007-agent-loop-protocol.md)); coordination is explicit. diff --git a/rfcs/0030-agent-lifecycle-versioning.md b/rfcs/0030-agent-lifecycle-versioning.md index efbbe1a..3cda454 100644 --- a/rfcs/0030-agent-lifecycle-versioning.md +++ b/rfcs/0030-agent-lifecycle-versioning.md @@ -1,5 +1,7 @@ # RFC 0030 — Agent Lifecycle & Versioning, Status: Draft, Author: Open CoT Community, Created: 2026-04-14 +**Discussion:** https://github.com/supernovae/open-cot/discussions/30 + ## 1. Summary This RFC defines **agent lifecycle states** and **versioning** of agent configurations for Open-CoT. Long-running governed agents need a model where **configuration can evolve** (prompts, tools, policies) without silently mutating in-flight runs or breaking permission grants. The **`agent_lifecycle`** record binds an **`agent_id`** to a semantic **`version`**, a **`lifecycle_state`**, capability and policy references, and a **`configuration_hash`** for reproducibility. **`version_transition`** documents approved rollout strategies (**rolling**, **blue-green**, **canary**) and whether **rollback** is permitted. @@ -26,11 +28,11 @@ This RFC does not define CI/CD mechanics, container image formats, or canary met | `deprecated` | Still runnable for compatibility but SHOULD not start new long-lived sessions; migrations encouraged. | | `retired` | MUST NOT schedule new work; historical traces remain addressable. | -**`created_at`** / **`updated_at`** are RFC 3339 timestamps. **`configuration_hash`** hashes the canonical serialized bundle (system prompt, tool allow list, model route, feature flags) so two hosts can verify they run identical configs. **`capabilities[]`** mirrors outward-facing skills for routing ([RFC 0021](0021-agent-capability-declaration.md) may elaborate). **`policy_refs[]`** lists attached policy documents or snapshots ([RFC 0041](0041-policy-enforcement-schema.md)). **`governance_ref`** points to organizational controls ([RFC 0044](0044-governance-organizational-controls.md))—team ownership, data classes, approval workflow ids. +**`created_at`** / **`observed_at`** are RFC 3339 timestamps. **`configuration_hash`** hashes the canonical serialized bundle (system prompt, tool allow list, model route, feature flags) so two hosts can verify they run identical configs. **`capabilities[]`** mirrors outward-facing skills for routing ([RFC 0021](0021-agent-capability-declaration.md) may elaborate). **`policy_refs[]`** lists attached policy documents or snapshots ([RFC 0041](0041-policy-enforcement-schema.md)). **`governance_ref`** points to organizational controls ([RFC 0044](0044-governance-organizational-controls.md))—team ownership, data classes, approval workflow ids. ### 3.2 `version_transition` -**`from_version`** / **`to_version`** describe the movement between semver strings. **`migration_strategy`** selects rollout mechanics: **`rolling`** (gradual instance replacement), **`blue-green`** (atomic switch), **`canary`** (percentage traffic). **`rollback_allowed`** documents whether automated or manual rollback to `from_version` remains approved. **`approved_by`** is a human or system principal id; **`timestamp`** records the decision instant. +**`from_version`** / **`to_version`** describe the movement between semver strings. **`migration_strategy`** selects rollout mechanics: **`rolling`** (gradual instance replacement), **`blue-green`** (atomic switch), **`canary`** (percentage traffic). **`rollback_allowed`** documents whether automated or manual rollback to `from_version` remains approved. **`approved_by`** is a human or system principal id; **`decided_at`** records the decision instant. `version_order` provides deterministic transition ordering independent of wall-clock drift. ### 3.3 Permissions and governance coupling @@ -42,7 +44,7 @@ Permission grants ([RFC 0042](0042-permission-acl.md)) SHOULD include optional ` ```json { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://opencot.dev/schema/agent-lifecycle/v0.1", + "$id": "https://opencot.dev/schema/agent-lifecycle/v0.2", "title": "Open CoT RFC 0030 — Agent Lifecycle", "definitions": { "agent_lifecycle": { @@ -53,7 +55,7 @@ Permission grants ([RFC 0042](0042-permission-acl.md)) SHOULD include optional ` "version", "lifecycle_state", "created_at", - "updated_at", + "observed_at", "configuration_hash", "capabilities", "policy_refs", @@ -67,7 +69,7 @@ Permission grants ([RFC 0042](0042-permission-acl.md)) SHOULD include optional ` "enum": ["draft", "active", "suspended", "deprecated", "retired"] }, "created_at": { "type": "string", "format": "date-time" }, - "updated_at": { "type": "string", "format": "date-time" }, + "observed_at": { "type": "string", "format": "date-time" }, "configuration_hash": { "type": "string", "minLength": 1 }, "capabilities": { "type": "array", @@ -89,7 +91,8 @@ Permission grants ([RFC 0042](0042-permission-acl.md)) SHOULD include optional ` "migration_strategy", "rollback_allowed", "approved_by", - "timestamp" + "decided_at", + "version_order" ], "properties": { "from_version": { "type": "string", "minLength": 1 }, @@ -100,7 +103,8 @@ Permission grants ([RFC 0042](0042-permission-acl.md)) SHOULD include optional ` }, "rollback_allowed": { "type": "boolean" }, "approved_by": { "type": "string", "minLength": 1 }, - "timestamp": { "type": "string", "format": "date-time" } + "decided_at": { "type": "string", "format": "date-time" }, + "version_order": { "type": "integer", "minimum": 0 } } } }, @@ -122,7 +126,7 @@ Permission grants ([RFC 0042](0042-permission-acl.md)) SHOULD include optional ` "version": "3.6.0", "lifecycle_state": "active", "created_at": "2026-03-01T09:00:00Z", - "updated_at": "2026-04-14T08:15:00Z", + "observed_at": "2026-04-14T08:15:00Z", "configuration_hash": "sha256:9aa7…21", "capabilities": ["ticketing.read", "email.summarize", "kb.search"], "policy_refs": [ @@ -142,7 +146,8 @@ Permission grants ([RFC 0042](0042-permission-acl.md)) SHOULD include optional ` "migration_strategy": "canary", "rollback_allowed": true, "approved_by": "alice@example.com", - "timestamp": "2026-04-13T17:45:00Z" + "decided_at": "2026-04-13T17:45:00Z", + "version_order": 42 } ``` diff --git a/rfcs/0031-agent-observability-telemtry.md b/rfcs/0031-agent-observability-telemtry.md index 13b1aba..3fe4729 100644 --- a/rfcs/0031-agent-observability-telemtry.md +++ b/rfcs/0031-agent-observability-telemtry.md @@ -1,4 +1,4 @@ -# RFC 0031 — Agent Observability & Telemetry (v0.1) +# RFC 0031 — Agent Observability & Telemetry (v0.2) **Status:** Draft **Author:** Byron / Open CoT Community **Created:** 2026-04-14 @@ -35,9 +35,18 @@ It extends: "title": "Open CoT RFC 0031 — Agent Observability and Telemetry", "type": "object", "properties": { - "version": { "type": "string", "enum": ["0.1"] }, + "version": { "type": "string", "enum": ["0.2"] }, "agent_id": { "type": "string" }, - "timestamp": { "type": "string", "format": "date-time" }, + "observed_at": { "type": "string", "format": "date-time" }, + "ordering": { + "type": "object", + "additionalProperties": false, + "properties": { + "event_seq": { "type": "integer", "minimum": 0 }, + "parent_event_id": { "type": "string" } + }, + "required": ["event_seq"] + }, "metrics": { "type": "object", "properties": { @@ -50,7 +59,7 @@ It extends: "additionalProperties": true } }, - "required": ["version", "agent_id", "timestamp", "metrics"] + "required": ["version", "agent_id", "observed_at", "ordering", "metrics"] } ``` @@ -60,9 +69,12 @@ It extends: ```json { - "version": "0.1", + "version": "0.2", "agent_id": "planner", - "timestamp": "2026-04-14T11:30:00Z", + "observed_at": "2026-04-14T11:30:00Z", + "ordering": { + "event_seq": 1042 + }, "metrics": { "steps": 42, "tool_calls": 5, diff --git a/rfcs/0032-agent-deployment-manifest.md b/rfcs/0032-agent-deployment-manifest.md index 5b37a61..c20b1d2 100644 --- a/rfcs/0032-agent-deployment-manifest.md +++ b/rfcs/0032-agent-deployment-manifest.md @@ -1,5 +1,7 @@ # RFC 0032 — Agent Deployment Manifest, Status: Draft, Author: Open CoT Community, Created: 2026-04-14 +**Discussion:** https://github.com/supernovae/open-cot/discussions/32 + ## 1. Summary This RFC defines the **`deployment_manifest`**: a declarative document for running Open-CoT–governed agents with fixed runtime, resources, policy bindings, governance reference, sandbox ([RFC 0017](0017-agent-safety-sandboxing.md)), default budgets ([RFC 0038](0038-cost-aware-reasoning-budget.md)), tools, dependencies, health checks, and scaling. It is **infrastructure-as-code** for governed agents so rollouts are reproducible and provably aligned with org policy before the FSM ([RFC 0007](0007-agent-loop-protocol.md)) starts. diff --git a/rfcs/0033-agent-security-threat-model.md b/rfcs/0033-agent-security-threat-model.md index 9928575..5a164b3 100644 --- a/rfcs/0033-agent-security-threat-model.md +++ b/rfcs/0033-agent-security-threat-model.md @@ -1,5 +1,7 @@ # RFC 0033 — Agent Security & Threat Model, Status: Draft, Author: Open CoT Community, Created: 2026-04-14 +**Discussion:** https://github.com/supernovae/open-cot/discussions/33 + ## 1. Summary This RFC documents the **security threat landscape** for governed agents on the Open-CoT cognitive control plane and explains how architectural choices—especially the separation of **proposal** (model) from **authorization** (harness, policy, brokers)—reduce impact for each major threat class. It introduces a machine-readable **`threat_catalog`**: a versioned collection of **`threat_entry`** records linking each threat to severities, mitigations (by RFC or mechanism), and honest **residual risk** statements for security reviewers and auditors. diff --git a/rfcs/0034-agent-federation-protocol.md b/rfcs/0034-agent-federation-protocol.md index 54b50f7..10c39f9 100644 --- a/rfcs/0034-agent-federation-protocol.md +++ b/rfcs/0034-agent-federation-protocol.md @@ -1,5 +1,7 @@ # RFC 0034 — Agent Federation Protocol, Status: Draft, Author: Open CoT Community, Created: 2026-04-14 +**Discussion:** https://github.com/supernovae/open-cot/discussions/34 + ## 1. Summary This RFC defines how **independent Open-CoT deployments** (“peers”) interoperate when agents must delegate work across organizational or network boundaries while **retaining local policy sovereignty**. Each peer runs its own policy engine and identity plane; federation adds a **trust framework** for verifying peers, constraining accepted delegation scopes, and exchanging **`federation_request`** / **`federation_response`** messages that embed the standard **`delegation_request`** and **`delegation_decision`** objects from [RFC 0047](0047-delegation-extension.md). The result is cross-tenant collaboration without a single global “god” policy service—only negotiated trust and cryptographic verification. @@ -67,7 +69,7 @@ Multi-cluster and multi-company agent workflows are inevitable (support handoffs "source_peer_id": { "type": "string", "minLength": 1 }, "target_peer_id": { "type": "string", "minLength": 1 }, "delegation_request": { - "$ref": "https://opencot.dev/schema/rfc0047/delegation-extension.json#/$defs/delegation_request" + "$ref": "https://opencot.dev/schema/rfc0047/delegation-extension-v0.2.json#/$defs/delegation_request" }, "trust_chain": { "type": "array", "items": { "type": "string", "minLength": 1 }, "minItems": 1 } }, @@ -84,7 +86,7 @@ Multi-cluster and multi-company agent workflows are inevitable (support handoffs "enum": ["accepted", "rejected", "narrowed"] }, "delegation_decision": { - "$ref": "https://opencot.dev/schema/rfc0047/delegation-extension.json#/$defs/delegation_decision" + "$ref": "https://opencot.dev/schema/rfc0047/delegation-extension-v0.2.json#/$defs/delegation_decision" }, "response_integrity": { "$ref": "#/$defs/integrity" } }, diff --git a/rfcs/0041-policy-enforcement-schema.md b/rfcs/0041-policy-enforcement-schema.md index e47d1fe..4d8380d 100644 --- a/rfcs/0041-policy-enforcement-schema.md +++ b/rfcs/0041-policy-enforcement-schema.md @@ -1,4 +1,4 @@ -# RFC 0041 — Policy Enforcement Schema (v0.2) +# RFC 0041 — Policy Enforcement Schema (v0.3) **Status:** Draft **Author:** Byron / Open CoT Community @@ -10,9 +10,9 @@ ## 1. Summary -This RFC defines the **Policy Enforcement Schema (v0.2)** for Open-CoT, a cognitive control plane for governed agent execution. The policy engine decides when a model may invoke tools, access data or memory, or perform other governed operations. Given a **delegation request** (RFC 0047) and active policies, it returns **`allow`**, **`deny`**, **`narrow`**, or **`require_approval`**, with optional `narrowing` constraints, denial reasons, or escalation targets. +This RFC defines the **Policy Enforcement Schema (v0.3)** for Open-CoT, a cognitive control plane for governed agent execution. The policy engine decides when a model may invoke tools, access data or memory, or perform other governed operations. Given a **delegation request** (RFC 0047) and active policies, it returns **`allow`**, **`deny`**, **`narrow`**, or **`require_approval`**, with optional `narrowing` constraints, denial reasons, or escalation targets. -v0.2 adds **`narrow`**: approval under **reduced scope** (for example, mailbox reads limited to headers). It formalizes **`conditions`** (risk, justification, time window, budget), **temporal validity**, **policy `priority`**, **composable narrowing** across policies, and the **`policy_evaluation_result`** record for audit and permission handoff (RFC 0042). It extends RFC 0017 (Safety & Sandboxing) and RFC 0026 (Agent Identity) and aligns with RFC 0007 (governed FSM). +v0.3 preserves **`narrow`** and introduces canonical temporal naming from RFC 0051: policy validity bounds use `effective_at` / `expires_at`, condition windows use `validity_window`, and evaluation records use `decided_at`. It formalizes deterministic temporal validity semantics while retaining composable narrowing and policy priority behavior. --- @@ -50,7 +50,7 @@ Operators need typed policies, graduated responses (`narrow`, `require_approval` ## 5. Decisions and actions -Rule `action` and result `decision` share: **`allow`** (grant as narrowed so far), **`deny`** (reject), **`narrow`** (approve only under `narrowing` / merged `narrowed_scope`), **`require_approval`** (defer; `escalation_target` SHOULD name queue or role). **`narrow`** is the v0.2 extension for data minimization without a hard deny. +Rule `action` and result `decision` share: **`allow`** (grant as narrowed so far), **`deny`** (reject), **`narrow`** (approve only under `narrowing` / merged `narrowed_scope`), **`require_approval`** (defer; `escalation_target` SHOULD name queue or role). **`narrow`** remains the data minimization path without a hard deny. --- @@ -62,24 +62,24 @@ Resources SHOULD use prefixes: `tool:` (RFC 0003), `data:`, `memory: ## 7. Conditions and narrowing -**`conditions`** (all present sub-fields must pass for a match): `max_risk_level` (`low` ≤ `medium` ≤ `high`), `require_justification`, `time_window` (`start`/`end` ISO 8601, UTC), `budget_remaining_min`. Omitted keys impose no constraint from that key. +**`conditions`** (all present sub-fields must pass for a match): `max_risk_level` (`low` ≤ `medium` ≤ `high`), `require_justification`, `validity_window` (`effective_at`/`expires_at` ISO 8601 UTC; half-open), `budget_remaining_min`. Omitted keys impose no constraint from that key. **`narrowing`**: `allowed_fields`, `excluded_fields`, `max_results`, `max_response_size_bytes`. If `action` is `narrow`, `narrowing` SHOULD be present; if not `narrow`, ignore `narrowing`. Empty intersection of allowed vs excluded fields MUST yield **`deny`**; otherwise apply intersection rules in §10. --- -## 8. Normative JSON Schema — Policy document (v0.2) +## 8. Normative JSON Schema — Policy document (v0.3) ```json { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://opencot.dev/schema/policy/v0.2", + "$id": "https://opencot.dev/schema/policy/v0.3", "title": "Open CoT RFC 0041 — Policy Document", "type": "object", "additionalProperties": false, "properties": { - "version": { "type": "string", "enum": ["0.2"] }, + "version": { "type": "string", "enum": ["0.3"] }, "policy_id": { "type": "string", "minLength": 1 }, "policy_type": { "type": "string", @@ -88,21 +88,21 @@ Resources SHOULD use prefixes: `tool:` (RFC 0003), `data:`, `memory: "description": { "type": "string" }, "priority": { "type": "integer", "description": "Lower = higher precedence across policies." }, "rules": { "type": "array", "items": { "$ref": "#/definitions/policyRule" }, "minItems": 1 }, - "effective_from": { "type": "string", "format": "date-time" }, - "effective_until": { "type": "string", "format": "date-time" } + "effective_at": { "type": "string", "format": "date-time" }, + "expires_at": { "type": "string", "format": "date-time" } }, "required": ["version", "policy_id", "policy_type", "priority", "rules"], "definitions": { "riskLevel": { "type": "string", "enum": ["low", "medium", "high"] }, "ruleAction": { "type": "string", "enum": ["allow", "deny", "narrow", "require_approval"] }, - "timeWindow": { + "validityWindow": { "type": "object", "additionalProperties": false, "properties": { - "start": { "type": "string", "format": "date-time" }, - "end": { "type": "string", "format": "date-time" } + "effective_at": { "type": "string", "format": "date-time" }, + "expires_at": { "type": "string", "format": "date-time" } }, - "required": ["start", "end"] + "required": ["effective_at", "expires_at"] }, "conditions": { "type": "object", @@ -110,7 +110,7 @@ Resources SHOULD use prefixes: `tool:` (RFC 0003), `data:`, `memory: "properties": { "max_risk_level": { "$ref": "#/definitions/riskLevel" }, "require_justification": { "type": "boolean" }, - "time_window": { "$ref": "#/definitions/timeWindow" }, + "validity_window": { "$ref": "#/definitions/validityWindow" }, "budget_remaining_min": { "type": "number" } } }, @@ -154,7 +154,7 @@ Engines MUST emit one object per evaluated `(request_id, policy_id)` or define a ```json { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://opencot.dev/schema/policy_evaluation_result/v0.2", + "$id": "https://opencot.dev/schema/policy_evaluation_result/v0.3", "title": "Open CoT RFC 0041 — Policy Evaluation Result", "type": "object", "additionalProperties": false, @@ -167,7 +167,7 @@ Engines MUST emit one object per evaluated `(request_id, policy_id)` or define a "narrowed_scope": { "type": "object", "additionalProperties": true }, "denial_reason": { "type": "string" }, "escalation_target": { "type": "string" }, - "timestamp": { "type": "string", "format": "date-time" }, + "decided_at": { "type": "string", "format": "date-time" }, "context": { "type": "object", "additionalProperties": false, @@ -179,7 +179,7 @@ Engines MUST emit one object per evaluated `(request_id, policy_id)` or define a } } }, - "required": ["evaluation_id", "request_id", "policy_id", "decision", "timestamp"] + "required": ["evaluation_id", "request_id", "policy_id", "decision", "decided_at"] } ``` @@ -188,7 +188,7 @@ Engines MUST emit one object per evaluated `(request_id, policy_id)` or define a ## 10. Evaluation semantics -**Temporal validity.** Policy is active at `t` if `effective_from` is absent or `t` ≥ `effective_from`, and `effective_until` is absent or `t` < `effective_until` (half-open on end). Inactive policies MUST NOT affect the outcome. +**Temporal validity.** Policy is active at `t` if `effective_at` is absent or `t` ≥ `effective_at`, and `expires_at` is absent or `t` < `expires_at` (half-open on end). Inactive policies MUST NOT affect the outcome. **Intra-policy.** Among rules whose `subject`, `resource`, and `conditions` match, the **first entry in `rules`** wins. No match ⇒ this policy contributes **no match** (not `allow`). @@ -206,12 +206,12 @@ Engines MUST emit one object per evaluated `(request_id, policy_id)` or define a ```json { - "version": "0.2", + "version": "0.3", "policy_id": "safety_no_shell", "policy_type": "safety", "description": "Block shell for autonomous runs.", "priority": 10, - "effective_from": "2026-04-14T00:00:00Z", + "effective_at": "2026-04-14T00:00:00Z", "rules": [ { "rule_id": "deny_shell", "action": "deny", "subject": "*", "resource": "tool:shell", "reason": "Unattended shell out of scope." }, { "rule_id": "allow_search", "action": "allow", "subject": "*", "resource": "tool:search" } @@ -223,7 +223,7 @@ Engines MUST emit one object per evaluated `(request_id, policy_id)` or define a ```json { - "version": "0.2", + "version": "0.3", "policy_id": "compliance_email_minimization", "policy_type": "compliance", "description": "Headers/metadata only for mailbox reads.", @@ -249,7 +249,7 @@ Engines MUST emit one object per evaluated `(request_id, policy_id)` or define a ```json { - "version": "0.2", + "version": "0.3", "policy_id": "ops_db_write_gate", "policy_type": "operational", "description": "Human approval for DB mutations.", @@ -260,7 +260,7 @@ Engines MUST emit one object per evaluated `(request_id, policy_id)` or define a "subject": "*", "resource": "tool:db_write", "conditions": { - "time_window": { "start": "2026-04-14T00:00:00Z", "end": "2099-12-31T23:59:59Z" }, + "validity_window": { "effective_at": "2026-04-14T00:00:00Z", "expires_at": "2099-12-31T23:59:59Z" }, "budget_remaining_min": 0 }, "escalation_target": "queue:dba-oncall", @@ -284,7 +284,7 @@ Engines MUST emit one object per evaluated `(request_id, policy_id)` or define a "max_results": 50, "max_response_size_bytes": 1048576 }, - "timestamp": "2026-04-18T12:34:56Z", + "decided_at": "2026-04-18T12:34:56Z", "context": { "agent_id": "agent/analyst-7", "run_id": "run_19c0", @@ -302,12 +302,12 @@ Fail-closed default limits accidental over-permissioning. **`narrow`** is unsafe ## 13. Open questions resolution -| Topic | v0.2 resolution | +| Topic | v0.3 resolution | |--------|------------------| | Partial approval / minimization | `narrow` + `narrowing` / `narrowed_scope`. | | Multi-policy | Deterministic sort; precedence **deny > narrow > require_approval > allow**. | | No rule match | Fail-closed **`deny`**. | -| Audit trail | `policy_evaluation_result` + `evaluation_id`, `timestamp`, `request_id`. | +| Audit trail | `policy_evaluation_result` + `evaluation_id`, `decided_at`, `request_id`. | | Conditions / hooks | `conditions` + `context.budget_snapshot`, `risk_assessment`. | | Rule vs policy order | Policy `priority` + Unicode `policy_id`; rules by **array order**. | @@ -315,6 +315,6 @@ Fail-closed default limits accidental over-permissioning. **`narrow`** is unsafe ## 14. Acceptance criteria and conclusion -A conforming engine **MUST**: (1) validate policy documents against §8 with `version` `0.2` unless documented otherwise; (2) emit §9 results with required fields for each evaluation; (3) implement §10 including temporal filter, first-match rules, fail-closed default, merge precedence, narrowing intersection, determinism; (4) populate `denial_reason` / `narrowed_scope` / `escalation_target` when emitting the corresponding decisions (document any optional omissions). Authors **SHOULD** set `description`, per-rule `reason`, and `effective_*` for shared policies. +A conforming engine **MUST**: (1) validate policy documents against §8 with `version` `0.3` unless documented otherwise; (2) emit §9 results with required fields for each evaluation; (3) implement §10 including temporal filter, first-match rules, fail-closed default, merge precedence, narrowing intersection, determinism; (4) populate `denial_reason` / `narrowed_scope` / `escalation_target` when emitting the corresponding decisions (document any optional omissions). Authors **SHOULD** set `description`, per-rule `reason`, and explicit validity bounds (`effective_at` / `expires_at`) for shared policies. -RFC 0041 v0.2 normatively specifies policy documents, the **`narrow`** decision, evaluation results, and deterministic merge semantics—forming the **decision layer** with RFC 0026 (identity) and RFC 0047 (delegation). +RFC 0041 v0.3 normatively specifies policy documents, the **`narrow`** decision, canonical temporal semantics, evaluation results, and deterministic merge semantics—forming the **decision layer** with RFC 0026 (identity), RFC 0047 (delegation), and RFC 0051 (temporal semantics). diff --git a/rfcs/0042-permission-acl.md b/rfcs/0042-permission-acl.md index 611ce88..253f4d4 100644 --- a/rfcs/0042-permission-acl.md +++ b/rfcs/0042-permission-acl.md @@ -1,4 +1,4 @@ -# RFC 0042 — Permissions & Access Control (v0.2) +# RFC 0042 — Permissions & Access Control (v0.3) **Status:** Draft **Author:** Byron / Open CoT Community @@ -28,7 +28,7 @@ Open CoT is a **cognitive control plane**: reasoning, tools, memory, and policy 2. **Deny by default.** No matching active grant for `audience` + `scope` ⇒ execution MUST fail closed. 3. **Least privilege in the grant.** Persisted `scope` is the **post-policy** narrowed scope, not the model’s raw intent. 4. **Explicit binding.** `audience` ties the capability to a specific tool/service key. -5. **Time-bounded.** Every grant has `ttl_seconds` and `expires_at`; expired grants are unusable (`expired`). +5. **Time-bounded.** Every grant has `effective_at`, `ttl_seconds`, and `expires_at`; expired grants are unusable (`expired`). 6. **Observable transitions.** Every lifecycle change MUST emit a structured audit event (§9). --- @@ -56,7 +56,7 @@ Open CoT is a **cognitive control plane**: reasoning, tools, memory, and policy ## 6. TTL and expiry -Every grant MUST have `ttl_seconds` (integer ≥ 1) and `expires_at` (RFC 3339). The harness sets `expires_at` from `granted_at` + TTL at issuance. The executor MUST check `now < expires_at` on the harness clock domain before each use. **Recommended defaults (non-normative):** 60s for tool calls; 300s for session-scoped reads/lists when policy allows. On expiry, set `expired` and log `permission_expired`. +Every grant MUST have `effective_at`, `ttl_seconds` (integer >= 1), and `expires_at` (RFC 3339). The harness sets `expires_at` from `effective_at` + TTL at issuance. The executor MUST check `effective_at <= now < expires_at` on the harness clock domain before each use. **Recommended defaults (non-normative):** 60s for tool calls; 300s for session-scoped reads/lists when policy allows. On expiry, set `expired` and log `permission_expired`. --- @@ -90,7 +90,7 @@ Every state change MUST log: **`permission_granted`** (scope, TTL, audience, `gr ```json { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://opencot.dev/schema/permission-grant/0.2", + "$id": "https://opencot.dev/schema/permission-grant/0.3", "title": "Open CoT RFC 0042 — Permission Grant", "type": "object", "additionalProperties": false, @@ -126,7 +126,7 @@ Every state change MUST log: **`permission_granted`** (scope, TTL, audience, `gr "policy_ref": { "type": "string", "minLength": 1 }, "request_ref": { "type": "string", "minLength": 1 }, "decision_ref": { "type": "string", "minLength": 1 }, - "granted_at": { "type": "string", "format": "date-time" }, + "effective_at": { "type": "string", "format": "date-time" }, "consumed_at": { "type": "string", "format": "date-time" }, "revoked_at": { "type": "string", "format": "date-time" }, "revocation_reason": { "type": "string" }, @@ -134,7 +134,7 @@ Every state change MUST log: **`permission_granted`** (scope, TTL, audience, `gr }, "required": [ "permission_id", "granted_to", "scope", "audience", "ttl_seconds", "expires_at", - "one_shot", "granted_by", "policy_ref", "request_ref", "decision_ref", "granted_at", "status" + "one_shot", "granted_by", "policy_ref", "request_ref", "decision_ref", "effective_at", "status" ], "allOf": [ { "if": { "properties": { "status": { "const": "consumed" } }, "required": ["status"] }, @@ -178,7 +178,7 @@ Before execution: verify `status == active`, audience match, not expired, `scope "policy_ref": "policy:org-contracts-v3", "request_ref": "deleg_req:7f2c9a1b-4d3e-4f5a-9b0c-111111111111", "decision_ref": "deleg_dec:88aa99bb-0cc1-4dd2-9ee3-222222222222", - "granted_at": "2026-04-18T14:30:22Z", + "effective_at": "2026-04-18T14:30:22Z", "status": "active" } ``` @@ -205,7 +205,7 @@ First committed `tool:filesystem` write ⇒ `consumed` + `permission_consumed`. "policy_ref": "policy:safe-search-v1", "request_ref": "deleg_req:aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "decision_ref": "deleg_dec:ffffffff-0000-1111-2222-333333333333", - "granted_at": "2026-04-18T14:35:00Z", + "effective_at": "2026-04-18T14:35:00Z", "status": "active" } ``` @@ -234,7 +234,7 @@ First committed `tool:filesystem` write ⇒ `consumed` + `permission_consumed`. "policy_ref": "policy:pii-minimize-v2", "request_ref": "deleg_req:11111111-2222-3333-4444-555555555555", "decision_ref": "deleg_dec:66666666-7777-8888-9999-aaaaaaaaaaaa", - "granted_at": "2026-04-18T15:00:05Z", + "effective_at": "2026-04-18T15:00:05Z", "status": "active" } ``` @@ -255,7 +255,7 @@ Executor MUST enforce headers-only regardless of model prompts. ## 15. Open questions resolution -| Topic | Resolution (v0.2) | +| Topic | Resolution (v0.3) | |-------|---------------------| | RBAC vs capabilities | Capabilities at execution; RBAC feeds policy only. | | Clock skew | `expires_at` authoritative; harness clock or documented skew budget. | @@ -273,4 +273,4 @@ Conformant implementations: (1) issue grants only post-validated decision with i ## 17. Conclusion -RFC 0042 v0.2 specifies **first-class permission grants** with audience binding, TTL, optional reuse, forwardability rules, and audited lifecycle—closing the loop from RFC 0026 / 0041 identity and policy to safe execution on the Open CoT control plane (RFC 0007, RFC 0047). +RFC 0042 v0.3 specifies **first-class permission grants** with audience binding, canonical temporal validity (`effective_at`/`expires_at`), TTL, optional reuse, forwardability rules, and audited lifecycle—closing the loop from RFC 0026 / 0041 identity and policy to safe execution on the Open CoT control plane (RFC 0007, RFC 0047, RFC 0051). diff --git a/rfcs/0043-auditing-compliance-logs.md b/rfcs/0043-auditing-compliance-logs.md index 4d20642..4e8896c 100644 --- a/rfcs/0043-auditing-compliance-logs.md +++ b/rfcs/0043-auditing-compliance-logs.md @@ -1,4 +1,4 @@ -# RFC 0043 — Auditing & Compliance Logs (v0.2) +# RFC 0043 — Auditing & Compliance Logs (v0.3) **Status:** Draft **Author:** Byron / Open CoT Community @@ -22,7 +22,7 @@ Two schema objects apply: **`audit_event`** (append-only chain links) and **`aud **Non-Goals:** storage technology, KMS/HSM integration details, PII classification policy (deployments apply their own), and alerting rule engines (RFC 0031). -**Terms:** **Run** = one `run_id`. **Event chain** = ordered `audit_event` list linked by `previous_event_id`. **Genesis** = first event (`previous_event_id: null`). **Sealing** = terminal `trace_sealed` plus `audit_envelope` (RFC 0007 `audit_seal`). +**Terms:** **Run** = one `run_id`. **Event chain** = ordered `audit_event` list linked by `parent_event_id`. **Genesis** = first event (`parent_event_id: null`). **Sealing** = terminal `trace_sealed` plus `audit_envelope` (RFC 0007 `audit_seal`). ## 3. Data Model @@ -35,23 +35,23 @@ Two schema objects apply: **`audit_event`** (append-only chain links) and **`aud `event_type` MUST be one of: `run_started`, `policy_evaluated`, `permission_granted`, `permission_consumed`, `permission_expired`, `permission_revoked`, `tool_executed`, `delegation_requested`, `delegation_decided`, `escalation_initiated`, `escalation_resolved`, `postcondition_violated`, `denial_recorded`, `budget_warning`, `budget_exhausted`, `run_completed`, `run_failed`, `trace_sealed`. -`details` is a structured object whose keys depend on `event_type` (policy ids, permission ids, tool names, receipt refs per RFC 0048, delegation refs per RFC 0047, etc.). v0.2 keeps `details` **open** in JSON Schema (`additionalProperties: true`) so implementations can evolve; profiles MAY constrain keys per event type in a later revision. +`details` is a structured object whose keys depend on `event_type` (policy ids, permission ids, tool names, receipt refs per RFC 0048, delegation refs per RFC 0047, etc.). v0.3 keeps `details` **open** in JSON Schema (`additionalProperties: true`) so implementations can evolve; profiles MAY constrain keys per event type in a later revision. ## 5. Field Semantics (Concise) -**`audit_event`:** `event_id` (UUID), `run_id`, `agent_id`, `timestamp` (RFC 3339 UTC), `event_type`, `details`, `previous_event_id` (UUID or `null` for genesis), `integrity` (`hash_algorithm`, `content_hash`). +**`audit_event`:** `event_id` (UUID), `run_id`, `agent_id`, `observed_at` (RFC 3339 UTC), `event_type`, `details`, `parent_event_id` (UUID or `null` for genesis), `ordering.event_seq` (monotonic sequence per run), and `integrity` (`hash_algorithm`, `content_hash`). -**`audit_envelope`:** `envelope_id`, `run_id`, `agent_id` (primary), `started_at`, `sealed_at`, `completion_status`, `trace_hash`, `event_chain_head`, `event_chain_tail`, `event_count`, `delegation_summary`, `permission_summary`, `budget_final` (RFC 0038 snapshot shape), `policy_violations[]`, `integrity` (hash required; `signature_algorithm` / `signature` optional). +**`audit_envelope`:** `envelope_id`, `run_id`, `agent_id` (primary), `started_at`, `completed_at`, `completion_status`, `trace_hash`, `event_chain_head`, `event_chain_tail`, `event_count`, `delegation_summary`, `permission_summary`, `budget_final` (RFC 0038 snapshot shape), `policy_violations[]`, `integrity` (hash required; `signature_algorithm` / `signature` optional). **`completion_status`:** `succeeded` | `failed` | `denied` | `budget_exhausted` | `external_stop` | `escalation_timeout` | `fail_safe`. -**`policy_violations[]` items:** `violation_id`, `policy_id`, optional `rule_id`, `occurred_at`, `severity`, `description`, optional `related_event_id`. +**`policy_violations[]` items:** `violation_id`, `policy_id`, optional `rule_id`, `observed_at`, `severity`, `description`, optional `related_event_id`. ## 6. Hash Chaining and Integrity **Per-event `content_hash`:** SHA-256 over **canonical JSON** of the event with the **`integrity` object omitted**. Canonical rules: UTF-8, lexicographic key order, no insignificant whitespace, explicit `null`. Digest hex-encoded lowercase in `integrity.content_hash`. -**Chain:** Genesis uses `previous_event_id: null`. Each later event sets `previous_event_id` to the **predecessor’s `event_id`**. If any event body is altered or removed, that event’s hash fails verification and/or chain pointers no longer match stored order. +**Chain:** Genesis uses `parent_event_id: null`. Each later event sets `parent_event_id` to the **predecessor’s `event_id`**. If any event body is altered or removed, that event’s hash fails verification and/or chain pointers no longer match stored order. **Envelope `content_hash`:** Same algorithm; hashed material is the canonical representation of the envelope **excluding `integrity`**, plus the deployment-defined binding of **ordered event list + `trace_hash`** (implementations MUST document the exact serialization of “chain + trace” in the deployment profile). Optional **detached signature** on the envelope attests the digest without changing verifiers that only check hashes. @@ -73,25 +73,34 @@ Two schema objects apply: **`audit_event`** (append-only chain links) and **`aud "type": "object", "additionalProperties": false, "properties": { - "schema_version": { "type": "string", "enum": ["0.2"] }, + "schema_version": { "type": "string", "enum": ["0.3"] }, "event_id": { "type": "string", "format": "uuid" }, "run_id": { "type": "string", "minLength": 1 }, "agent_id": { "type": "string", "minLength": 1 }, - "timestamp": { "type": "string", "format": "date-time" }, + "observed_at": { "type": "string", "format": "date-time" }, "event_type": { "type": "string", "enum": ["run_started","policy_evaluated","permission_granted","permission_consumed","permission_expired","permission_revoked","tool_executed","delegation_requested","delegation_decided","escalation_initiated","escalation_resolved","postcondition_violated","denial_recorded","budget_warning","budget_exhausted","run_completed","run_failed","trace_sealed"] }, "details": { "type": "object", "additionalProperties": true }, - "previous_event_id": { "type": ["string", "null"], "format": "uuid" }, + "parent_event_id": { "type": ["string", "null"], "format": "uuid" }, + "ordering": { + "type": "object", + "additionalProperties": false, + "properties": { + "event_seq": { "type": "integer", "minimum": 0 }, + "causal_predecessors": { "type": "array", "items": { "type": "string", "format": "uuid" }, "uniqueItems": true } + }, + "required": ["event_seq"] + }, "integrity": { "type": "object", "additionalProperties": false, "properties": { - "hash_algorithm": { "type": "string", "enum": ["sha-256"] }, + "hash_algorithm": { "type": "string", "enum": ["sha256"] }, "content_hash": { "type": "string", "pattern": "^[a-f0-9]{64}$" } }, "required": ["hash_algorithm", "content_hash"] } }, - "required": ["schema_version","event_id","run_id","agent_id","timestamp","event_type","details","previous_event_id","integrity"] + "required": ["schema_version","event_id","run_id","agent_id","observed_at","event_type","details","parent_event_id","ordering","integrity"] } ``` @@ -106,12 +115,12 @@ Two schema objects apply: **`audit_event`** (append-only chain links) and **`aud "type": "object", "additionalProperties": false, "properties": { - "schema_version": { "type": "string", "enum": ["0.2"] }, + "schema_version": { "type": "string", "enum": ["0.3"] }, "envelope_id": { "type": "string", "format": "uuid" }, "run_id": { "type": "string", "minLength": 1 }, "agent_id": { "type": "string", "minLength": 1 }, "started_at": { "type": "string", "format": "date-time" }, - "sealed_at": { "type": "string", "format": "date-time" }, + "completed_at": { "type": "string", "format": "date-time" }, "completion_status": { "type": "string", "enum": ["succeeded","failed","denied","budget_exhausted","external_stop","escalation_timeout","fail_safe"] }, "trace_hash": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, "event_chain_head": { "type": "string", "format": "uuid" }, @@ -164,19 +173,19 @@ Two schema objects apply: **`audit_event`** (append-only chain links) and **`aud "violation_id": { "type": "string", "format": "uuid" }, "policy_id": { "type": "string", "minLength": 1 }, "rule_id": { "type": "string" }, - "occurred_at": { "type": "string", "format": "date-time" }, + "observed_at": { "type": "string", "format": "date-time" }, "severity": { "type": "string", "enum": ["info","low","medium","high","critical"] }, "description": { "type": "string", "minLength": 1 }, "related_event_id": { "type": "string", "format": "uuid" } }, - "required": ["violation_id","policy_id","occurred_at","severity","description"] + "required": ["violation_id","policy_id","observed_at","severity","description"] } }, "integrity": { "type": "object", "additionalProperties": false, "properties": { - "hash_algorithm": { "type": "string", "enum": ["sha-256"] }, + "hash_algorithm": { "type": "string", "enum": ["sha256"] }, "content_hash": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, "signature_algorithm": { "type": "string" }, "signature": { "type": "string" } @@ -184,7 +193,7 @@ Two schema objects apply: **`audit_event`** (append-only chain links) and **`aud "required": ["hash_algorithm", "content_hash"] } }, - "required": ["schema_version","envelope_id","run_id","agent_id","started_at","sealed_at","completion_status","trace_hash","event_chain_head","event_chain_tail","event_count","delegation_summary","permission_summary","budget_final","policy_violations","integrity"] + "required": ["schema_version","envelope_id","run_id","agent_id","started_at","completed_at","completion_status","trace_hash","event_chain_head","event_chain_tail","event_count","delegation_summary","permission_summary","budget_final","policy_violations","integrity"] } ``` @@ -196,13 +205,13 @@ Two schema objects apply: **`audit_event`** (append-only chain links) and **`aud Illustrative `content_hash`; verifiers recompute from canonical bytes with `integrity` removed. ```json -{"schema_version":"0.2","event_id":"a1b2c3d4-e5f6-4789-a012-3456789abcde","run_id":"run_20260414T153012Z_planner_01","agent_id":"planner.primary","timestamp":"2026-04-14T15:30:18.421Z","event_type":"permission_granted","details":{"permission_id":"perm_search_readonly_01","scope":{"tools":["tool:web_search"],"resources":["urn:opencot:corp_kb:public"]},"ttl_seconds":900,"grantor":"policy_engine@v0.7","policy_binding":{"policy_id":"corp_safe_search","policy_version":"2026.04.1"}},"previous_event_id":"00000000-0000-4000-8000-000000000001","integrity":{"hash_algorithm":"sha-256","content_hash":"7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069"}} +{"schema_version":"0.3","event_id":"a1b2c3d4-e5f6-4789-a012-3456789abcde","run_id":"run_20260414T153012Z_planner_01","agent_id":"planner.primary","observed_at":"2026-04-14T15:30:18.421Z","event_type":"permission_granted","details":{"permission_id":"perm_search_readonly_01","scope":{"tools":["tool:web_search"],"resources":["urn:opencot:corp_kb:public"]},"ttl_seconds":900,"grantor":"policy_engine@v0.7","policy_binding":{"policy_id":"corp_safe_search","policy_version":"2026.04.1"}},"parent_event_id":"00000000-0000-4000-8000-000000000001","ordering":{"event_seq":3},"integrity":{"hash_algorithm":"sha256","content_hash":"7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069"}} ``` ### 10.2 `audit_envelope` — delegation, tools, success ```json -{"schema_version":"0.2","envelope_id":"f47ac10b-58cc-4372-a567-0e02b2c3d479","run_id":"run_20260414T153012Z_planner_01","agent_id":"planner.primary","started_at":"2026-04-14T15:30:12.000Z","sealed_at":"2026-04-14T15:31:02.883Z","completion_status":"succeeded","trace_hash":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","event_chain_head":"00000000-0000-4000-8000-000000000001","event_chain_tail":"99999999-9999-4999-8999-999999999999","event_count":14,"delegation_summary":{"total_requested":1,"total_granted":1,"total_denied":0,"total_narrowed":1},"permission_summary":{"total_granted":2,"total_consumed":2,"total_expired":0,"total_revoked":0},"budget_final":{"tokens_used":4120,"tokens_remaining":880,"cost_used":0.042,"cost_remaining":0.058,"steps_used":6,"steps_remaining":4,"tool_calls_used":3,"tool_calls_remaining":7,"retries_used":0,"retries_remaining":2},"policy_violations":[],"integrity":{"hash_algorithm":"sha-256","content_hash":"2c624232cdd221699294d012d04dfb23f036edaedd441b52e063bd86ba4a3b74","signature_algorithm":"ed25519","signature":"BASE64_DETACHED_SIGNATURE_PLACEHOLDER"}} +{"schema_version":"0.3","envelope_id":"f47ac10b-58cc-4372-a567-0e02b2c3d479","run_id":"run_20260414T153012Z_planner_01","agent_id":"planner.primary","started_at":"2026-04-14T15:30:12.000Z","completed_at":"2026-04-14T15:31:02.883Z","completion_status":"succeeded","trace_hash":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","event_chain_head":"00000000-0000-4000-8000-000000000001","event_chain_tail":"99999999-9999-4999-8999-999999999999","event_count":14,"delegation_summary":{"total_requested":1,"total_granted":1,"total_denied":0,"total_narrowed":1},"permission_summary":{"total_granted":2,"total_consumed":2,"total_expired":0,"total_revoked":0},"budget_final":{"tokens_used":4120,"tokens_remaining":880,"cost_used":0.042,"cost_remaining":0.058,"steps_used":6,"steps_remaining":4,"tool_calls_used":3,"tool_calls_remaining":7,"retries_used":0,"retries_remaining":2},"policy_violations":[],"integrity":{"hash_algorithm":"sha256","content_hash":"2c624232cdd221699294d012d04dfb23f036edaedd441b52e063bd86ba4a3b74","signature_algorithm":"ed25519","signature":"BASE64_DETACHED_SIGNATURE_PLACEHOLDER"}} ``` ## 11. Cross-References @@ -220,18 +229,18 @@ Illustrative `content_hash`; verifiers recompute from canonical bytes with `inte ## 12. Open Questions Resolution -| Topic | Resolution (v0.2) | +| Topic | Resolution (v0.3) | |-------|-------------------| -| Chain link | `previous_event_id` → predecessor **`event_id`**; tamper evidence from per-event `content_hash` + envelope binding. | -| Per-event signatures | Out of scope for v0.2; optional **envelope** signature only. | +| Chain link | `parent_event_id` → predecessor **`event_id`**; tamper evidence from per-event `content_hash` + envelope binding. | +| Per-event signatures | Out of scope for v0.3; optional **envelope** signature only. | | Strict `details` typing | Deferred; `additionalProperties: true` until stable cross-vendor shapes exist. | | Multi-agent | Each event carries its **`agent_id`**; envelope `agent_id` is the run’s primary agent. | -| Clock skew | `timestamp` is writer clock; NTP recommended; no logical clocks in schema. | +| Clock skew | `observed_at` is writer clock; NTP recommended; ordering uses `event_seq` first. | ## 13. Acceptance Criteria 1. Emit required lifecycle and governance events (§4) for every governed run. -2. Maintain a single valid `previous_event_id` chain per `run_id`. +2. Maintain a single valid `parent_event_id` chain per `run_id`, with monotonic `ordering.event_seq`. 3. Verify each event’s `integrity.content_hash` per §6; verify envelope hash per deployment profile. 4. On seal, emit one `audit_envelope` consistent with chain head/tail/count and `trace_hash`. 5. Reconcile `delegation_summary` and `permission_summary` against `delegation_*` and `permission_*` events. @@ -239,4 +248,4 @@ Illustrative `content_hash`; verifiers recompute from canonical bytes with `inte ## 14. Conclusion -RFC 0043 v0.2 specifies **`audit_event`** and **`audit_envelope`**: a hash-chained evidentiary stream and a sealed run summary for forensic, compliance, and integration use—aligned with the governed execution model and sibling RFCs on policy, permissions, delegation, receipts, budget, provenance, and observability. +RFC 0043 v0.3 specifies **`audit_event`** and **`audit_envelope`** with canonical temporal semantics (`observed_at`, `completed_at`) and explicit logical ordering (`event_seq`), yielding a stronger hash-chained evidentiary stream for forensic, compliance, and integration use. diff --git a/rfcs/0047-delegation-extension.md b/rfcs/0047-delegation-extension.md index 7f41081..480e33d 100644 --- a/rfcs/0047-delegation-extension.md +++ b/rfcs/0047-delegation-extension.md @@ -1,4 +1,4 @@ -# RFC 0047 — Delegation Extension (v0.1) +# RFC 0047 — Delegation Extension (v0.2) **Status:** Draft **Author:** Byron / Open CoT Community **Created:** 2026-04-18 @@ -27,7 +27,7 @@ This RFC defines three JSON objects: | Zone | Who writes | Guarantees | |------|------------|--------------| | Model-adjacent | Model output supplies **intent**, **justification**, **requested_scope** preferences, TTL/audience **preferences**, and **task_context_ref** only. | Untrusted text and structure proposals. | -| Harness | Fills `request_id`, `requester`, `run_id`, `timestamp`, `provenance`; merges model fields after validation. | `requester` MUST match verified identity ([RFC 0026](0026-agent-identity-auth.md)). | +| Harness | Fills `request_id`, `requester`, `run_id`, `observed_at`, `provenance`; merges model fields after validation. | `requester` MUST match verified identity ([RFC 0026](0026-agent-identity-auth.md)). | | Policy | Emits **`delegation_decision`** exclusively. | Model MUST NOT emit or alter decisions. | | Auth broker | Emits **`authority_receipt`**; computes **integrity** over all other receipt fields. | Receipt is **tamper-evident**; executors verify hash (and signature when configured) before dispatch. | @@ -39,9 +39,9 @@ This RFC defines three JSON objects: **Model-provided (merged by harness):** `intent`, `justification`, `requested_scope`, `preferred_ttl_seconds`, `preferred_audience`, `task_context_ref`. -**Harness-provided:** `request_id`, `requester` (verified `agent_id`), `run_id`, `timestamp`, `provenance` (`trace_step_id`, `plan_version`). +**Harness-provided:** `request_id`, `requester` (verified `agent_id`), `run_id`, `observed_at`, `provenance` (`trace_step_id`, `plan_version`). -**Required fields:** `request_id`, `requester`, `run_id`, `requested_scope`, `timestamp`. +**Required fields:** `request_id`, `requester`, `run_id`, `requested_scope`, `observed_at`. `requested_scope` is an object with: @@ -63,7 +63,7 @@ All fields are **harness/policy-provided**. The model does not participate in au | `narrowed_scope` | Present when `status` is `narrowed` (or when approved but scope reduced—see §7). | | `denial_reason` | Present when `status` is `denied`. | | `escalation_target` | Present when `status` is `escalated` (queue, role, ticket system ref). | -| `timestamp` | RFC 3339 decision time. | +| `decided_at` | RFC 3339 decision time. | ### 3.3 `authority_receipt` @@ -108,7 +108,7 @@ Implementers integrating with OAuth2-style systems MAY map fields as follows. Th ```json { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://opencot.dev/schema/rfc0047/delegation-extension.json", + "$id": "https://opencot.dev/schema/rfc0047/delegation-extension-v0.2.json", "title": "Open CoT RFC 0047 — Delegation Extension", "type": "object", "additionalProperties": false, @@ -128,33 +128,33 @@ Implementers integrating with OAuth2-style systems MAY map fields as follows. Th "additionalProperties": false, "properties": { "trace_step_id": { "type": "string" }, - "plan_version": { "type": "string" } + "plan_version": { "type": "integer", "minimum": 0 } } }, "delegation_request": { "type": "object", "additionalProperties": false, "properties": { - "schema_version": { "type": "string", "enum": ["0.1"] }, + "schema_version": { "type": "string", "enum": ["0.2"] }, "request_id": { "type": "string", "minLength": 1 }, "requester": { "type": "string", "minLength": 1 }, "run_id": { "type": "string", "minLength": 1 }, - "timestamp": { "type": "string", "format": "date-time" }, + "observed_at": { "type": "string", "format": "date-time" }, "intent": { "type": "string" }, "justification": { "type": "string" }, "requested_scope": { "$ref": "#/$defs/scope" }, "preferred_ttl_seconds": { "type": "integer", "minimum": 1 }, - "preferred_audience": { "type": "array", "items": { "type": "string", "minLength": 1 } }, + "preferred_audience": { "type": "string", "minLength": 1 }, "task_context_ref": { "type": "string" }, "provenance": { "$ref": "#/$defs/provenance" } }, - "required": ["schema_version", "request_id", "requester", "run_id", "requested_scope", "timestamp"] + "required": ["schema_version", "request_id", "requester", "run_id", "requested_scope", "observed_at"] }, "delegation_decision": { "type": "object", "additionalProperties": false, "properties": { - "schema_version": { "type": "string", "enum": ["0.1"] }, + "schema_version": { "type": "string", "enum": ["0.2"] }, "decision_id": { "type": "string", "minLength": 1 }, "request_id": { "type": "string", "minLength": 1 }, "status": { @@ -175,9 +175,9 @@ Implementers integrating with OAuth2-style systems MAY map fields as follows. Th "narrowed_scope": { "$ref": "#/$defs/scope" }, "denial_reason": { "type": "string" }, "escalation_target": { "type": "string" }, - "timestamp": { "type": "string", "format": "date-time" } + "decided_at": { "type": "string", "format": "date-time" } }, - "required": ["schema_version", "decision_id", "request_id", "status", "decided_by", "policy_refs", "timestamp"] + "required": ["schema_version", "decision_id", "request_id", "status", "decided_by", "policy_refs", "decided_at"] }, "integrity": { "type": "object", @@ -194,20 +194,20 @@ Implementers integrating with OAuth2-style systems MAY map fields as follows. Th "type": "object", "additionalProperties": false, "properties": { - "schema_version": { "type": "string", "enum": ["0.1"] }, + "schema_version": { "type": "string", "enum": ["0.2"] }, "receipt_id": { "type": "string", "minLength": 1 }, "decision_id": { "type": "string", "minLength": 1 }, "request_id": { "type": "string", "minLength": 1 }, "permission_id": { "type": "string", "minLength": 1 }, "granted_scope": { "$ref": "#/$defs/scope" }, - "granted_at": { "type": "string", "format": "date-time" }, + "effective_at": { "type": "string", "format": "date-time" }, "expires_at": { "type": "string", "format": "date-time" }, "one_shot": { "type": "boolean" }, "forwardable": { "type": "boolean" }, - "audience": { "type": "array", "items": { "type": "string", "minLength": 1 } }, + "audience": { "type": "string", "minLength": 1 }, "integrity": { "$ref": "#/$defs/integrity" } }, - "required": ["schema_version", "receipt_id", "decision_id", "request_id", "permission_id", "granted_scope", "granted_at", "expires_at", "one_shot", "forwardable", "audience", "integrity"] + "required": ["schema_version", "receipt_id", "decision_id", "request_id", "permission_id", "granted_scope", "effective_at", "expires_at", "one_shot", "forwardable", "audience", "integrity"] } }, "properties": { @@ -229,11 +229,11 @@ The model asks to read full messages; policy narrows to **headers only**; broker ```json { - "schema_version": "0.1", + "schema_version": "0.2", "request_id": "dr_email_9f3a", "requester": "agent:org/acme/exec-worker-07", "run_id": "run_20260418_0412", - "timestamp": "2026-04-18T04:12:01Z", + "observed_at": "2026-04-18T04:12:01Z", "intent": "Summarize unread customer threads for Q2 report", "justification": "User approved inbox analysis task in session ctx-88", "requested_scope": { @@ -242,9 +242,9 @@ The model asks to read full messages; policy narrows to **headers only**; broker "constraints": { "folders": ["INBOX"], "max_messages": 50 } }, "preferred_ttl_seconds": 900, - "preferred_audience": ["api://mail.acme.internal"], + "preferred_audience": "api://mail.acme.internal", "task_context_ref": "ctx://sessions/88/plan_step_4", - "provenance": { "trace_step_id": "ts_4412", "plan_version": "pv_12" } + "provenance": { "trace_step_id": "ts_4412", "plan_version": 12 } } ``` @@ -252,7 +252,7 @@ The model asks to read full messages; policy narrows to **headers only**; broker ```json { - "schema_version": "0.1", + "schema_version": "0.2", "decision_id": "dd_email_9f3a_01", "request_id": "dr_email_9f3a", "status": "narrowed", @@ -263,7 +263,7 @@ The model asks to read full messages; policy narrows to **headers only**; broker "action": "email.read_headers", "constraints": { "folders": ["INBOX"], "max_messages": 50, "strip": ["body", "attachments"] } }, - "timestamp": "2026-04-18T04:12:01Z" + "decided_at": "2026-04-18T04:12:01Z" } ``` @@ -271,7 +271,7 @@ The model asks to read full messages; policy narrows to **headers only**; broker ```json { - "schema_version": "0.1", + "schema_version": "0.2", "receipt_id": "ar_email_9f3a_01", "decision_id": "dd_email_9f3a_01", "request_id": "dr_email_9f3a", @@ -281,11 +281,11 @@ The model asks to read full messages; policy narrows to **headers only**; broker "action": "email.read_headers", "constraints": { "folders": ["INBOX"], "max_messages": 50, "strip": ["body", "attachments"] } }, - "granted_at": "2026-04-18T04:12:02Z", + "effective_at": "2026-04-18T04:12:02Z", "expires_at": "2026-04-18T04:27:02Z", "one_shot": false, "forwardable": false, - "audience": ["api://mail.acme.internal"], + "audience": "api://mail.acme.internal", "integrity": { "hash_algorithm": "sha256", "content_hash": "sha256:canonical_payload_hex_omitted_for_brevity" @@ -317,4 +317,4 @@ The model asks to read full messages; policy narrows to **headers only**; broker ## 10. Conclusion -RFC 0047 v0.1 formalizes **delegation as data**: requests capture intent, decisions capture policy outcomes, and receipts capture brokered grants with tamper-evident integrity—preserving the invariant that **only the harness ecosystem authorizes**, while remaining mappable to familiar token-exchange deployments. +RFC 0047 v0.2 formalizes **delegation as data** with canonical temporal semantics (`observed_at`, `decided_at`, `effective_at`/`expires_at`): requests capture intent, decisions capture policy outcomes, and receipts capture brokered grants with tamper-evident integrity. diff --git a/rfcs/0048-execution-receipts-audit-envelopes.md b/rfcs/0048-execution-receipts-audit-envelopes.md index 29a4214..be9140e 100644 --- a/rfcs/0048-execution-receipts-audit-envelopes.md +++ b/rfcs/0048-execution-receipts-audit-envelopes.md @@ -1,4 +1,4 @@ -# RFC 0048 — Execution Receipts & Audit Envelopes (v0.1) +# RFC 0048 — Execution Receipts & Audit Envelopes (v0.2) **Status:** Draft **Author:** Byron / Open CoT Community @@ -16,128 +16,128 @@ Produced by the tool executor after every tool call. Fields: `execution_id` (uui ## 3. `audit_envelope` -Sealed summary of a governed run (RFC 0043 introduces auditing; this RFC specifies the envelope schema and lifecycle). Fields: `envelope_id` (uuid), `run_id`, `agent_id`, `task_hash`, `started_at`, `sealed_at`, `completion_status` ∈ {`succeeded`,`failed`,`denied`,`budget_exhausted`,`external_stop`,`escalation_timeout`,`fail_safe`}, `trace_hash`, `delegation_requests` / `delegation_decisions` (string IDs), `authority_receipts` / `tool_execution_receipts` (ID arrays), `delegation_summary` (`total_requested`, `total_approved`, `total_denied`, `total_narrowed`, `total_escalated`), `permission_summary` (`total_granted`, `total_consumed`, `total_expired`, `total_revoked`), `budget_final` (RFC 0038 `BudgetSnapshot`), `policy_violations` (`violation_id`, `policy_id`, `rule_id`, `description`, `severity`, `timestamp`), `integrity` (`hash_algorithm`, `content_hash`, optional `signature`, `signing_key_id`). `content_hash` covers all fields **except** `integrity`. +Sealed summary of a governed run (RFC 0043 introduces auditing; this RFC specifies the envelope schema and lifecycle). Fields: `envelope_id` (uuid), `run_id`, `agent_id`, `task_hash`, `started_at`, `completed_at`, `completion_status` ∈ {`succeeded`,`failed`,`denied`,`budget_exhausted`,`external_stop`,`escalation_timeout`,`fail_safe`}, `trace_hash`, `delegation_requests` / `delegation_decisions` (string IDs), `authority_receipts` / `tool_execution_receipts` (ID arrays), `delegation_summary` (`total_requested`, `total_granted`, `total_denied`, `total_narrowed`, `total_escalated`), `permission_summary` (`total_granted`, `total_consumed`, `total_expired`, `total_revoked`), `budget_final` (RFC 0038 `BudgetSnapshot`), `policy_violations` (`violation_id`, `policy_id`, `rule_id`, `description`, `severity`, `observed_at`), `integrity` (`hash_algorithm`, `content_hash`, optional `signature`, `signing_key_id`). `content_hash` covers all fields **except** `integrity`. -## 4. JSON Schema — `tool_execution_receipt` +## 4. JSON Schema — receipt and envelope bundle (normative) ```json { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://opencot.dev/schema/v0.8/tool_execution_receipt.json", - "title": "Open CoT RFC 0048 — tool_execution_receipt", + "$id": "https://opencot.dev/schema/v0.9/execution-receipts-audit-envelopes.json", + "title": "Open CoT RFC 0048 — execution receipts and audit envelopes", "type": "object", - "additionalProperties": false, - "properties": { - "execution_id": { "type": "string", "format": "uuid" }, - "run_id": { "type": "string", "minLength": 1 }, - "tool_name": { "type": "string", "minLength": 1 }, - "permission_id": { "type": "string", "minLength": 1 }, - "authority_receipt_id": { "type": "string", "minLength": 1 }, - "input_hash": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, - "output_hash": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, - "output_size_bytes": { "type": "integer", "minimum": 0 }, - "started_at": { "type": "string", "format": "date-time" }, - "completed_at": { "type": "string", "format": "date-time" }, - "duration_ms": { "type": "integer", "minimum": 0 }, - "status": { "type": "string", "enum": ["success", "error", "timeout", "quarantined"] }, - "error_category": { "type": "string", "enum": ["timeout", "invalid_input", "not_found", "permission_denied", "rate_limit", "internal_error"] }, - "postcondition_check": { "type": "string", "enum": ["passed", "failed", "skipped"] }, - "postcondition_violation": { "type": "string" }, - "sandbox_state_hash": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, + "oneOf": [ + { "$ref": "#/$defs/tool_execution_receipt" }, + { "$ref": "#/$defs/audit_envelope" } + ], + "$defs": { "integrity": { "type": "object", "additionalProperties": false, "properties": { "hash_algorithm": { "type": "string", "const": "sha256" }, - "content_hash": { "type": "string", "pattern": "^[a-f0-9]{64}$" } + "content_hash": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, + "signature": { "type": "string" }, + "signing_key_id": { "type": "string" } }, "required": ["hash_algorithm", "content_hash"] - } - }, - "required": ["execution_id", "run_id", "tool_name", "permission_id", "authority_receipt_id", "input_hash", "output_hash", "output_size_bytes", "started_at", "completed_at", "duration_ms", "status", "postcondition_check", "sandbox_state_hash", "integrity"] -} -``` - - -## 5. JSON Schema — `audit_envelope` - - -```json -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://opencot.dev/schema/v0.8/audit_envelope.json", - "title": "Open CoT RFC 0048 — audit_envelope", - "type": "object", - "additionalProperties": false, - "definitions": { + }, "budget_snapshot_rfc0038": { "type": "object", "additionalProperties": false, "properties": { - "tokens_used": { "type": "integer", "minimum": 0 }, "tokens_remaining": { "type": "integer" }, - "cost_used": { "type": "number", "minimum": 0 }, "cost_remaining": { "type": "number" }, - "steps_used": { "type": "integer", "minimum": 0 }, "steps_remaining": { "type": "integer" }, - "tool_calls_used": { "type": "integer", "minimum": 0 }, "tool_calls_remaining": { "type": "integer" }, - "retries_used": { "type": "integer", "minimum": 0 }, "retries_remaining": { "type": "integer" } + "tokens_used": { "type": "integer", "minimum": 0 }, + "tokens_remaining": { "type": "integer" }, + "cost_used": { "type": "number", "minimum": 0 }, + "cost_remaining": { "type": "number" }, + "steps_used": { "type": "integer", "minimum": 0 }, + "steps_remaining": { "type": "integer" }, + "tool_calls_used": { "type": "integer", "minimum": 0 }, + "tool_calls_remaining": { "type": "integer" }, + "retries_used": { "type": "integer", "minimum": 0 }, + "retries_remaining": { "type": "integer" } }, "required": ["tokens_used", "tokens_remaining", "cost_used", "cost_remaining", "steps_used", "steps_remaining", "tool_calls_used", "tool_calls_remaining", "retries_used", "retries_remaining"] }, "policy_violation_entry": { - "type": "object", - "additionalProperties": false, - "properties": { - "violation_id": { "type": "string", "minLength": 1 }, "policy_id": { "type": "string", "minLength": 1 }, - "rule_id": { "type": "string", "minLength": 1 }, "description": { "type": "string" }, - "severity": { "type": "string", "enum": ["info", "low", "medium", "high", "critical"] }, - "timestamp": { "type": "string", "format": "date-time" } - }, - "required": ["violation_id", "policy_id", "rule_id", "description", "severity", "timestamp"] - } - }, - "properties": { - "envelope_id": { "type": "string", "format": "uuid" }, - "run_id": { "type": "string", "minLength": 1 }, - "agent_id": { "type": "string", "minLength": 1 }, - "task_hash": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, - "started_at": { "type": "string", "format": "date-time" }, - "sealed_at": { "type": "string", "format": "date-time" }, - "completion_status": { "type": "string", "enum": ["succeeded", "failed", "denied", "budget_exhausted", "external_stop", "escalation_timeout", "fail_safe"] }, - "trace_hash": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, - "delegation_requests": { "type": "array", "items": { "type": "string", "minLength": 1 } }, - "delegation_decisions": { "type": "array", "items": { "type": "string", "minLength": 1 } }, - "authority_receipts": { "type": "array", "items": { "type": "string", "minLength": 1 } }, - "tool_execution_receipts": { "type": "array", "items": { "type": "string", "format": "uuid" } }, - "delegation_summary": { "type": "object", "additionalProperties": false, "properties": { - "total_requested": { "type": "integer", "minimum": 0 }, "total_approved": { "type": "integer", "minimum": 0 }, - "total_denied": { "type": "integer", "minimum": 0 }, "total_narrowed": { "type": "integer", "minimum": 0 }, - "total_escalated": { "type": "integer", "minimum": 0 } + "violation_id": { "type": "string", "minLength": 1 }, + "policy_id": { "type": "string", "minLength": 1 }, + "rule_id": { "type": "string", "minLength": 1 }, + "description": { "type": "string" }, + "severity": { "type": "string", "enum": ["info", "low", "medium", "high", "critical"] }, + "observed_at": { "type": "string", "format": "date-time" } }, - "required": ["total_requested", "total_approved", "total_denied", "total_narrowed", "total_escalated"] + "required": ["violation_id", "policy_id", "rule_id", "description", "severity", "observed_at"] }, - "permission_summary": { - "type": "object", "additionalProperties": false, + "tool_execution_receipt": { + "type": "object", + "additionalProperties": false, "properties": { - "total_granted": { "type": "integer", "minimum": 0 }, "total_consumed": { "type": "integer", "minimum": 0 }, - "total_expired": { "type": "integer", "minimum": 0 }, "total_revoked": { "type": "integer", "minimum": 0 } + "schema_version": { "type": "string", "enum": ["0.2"] }, + "execution_id": { "type": "string", "format": "uuid" }, + "run_id": { "type": "string", "minLength": 1 }, + "tool_name": { "type": "string", "minLength": 1 }, + "permission_id": { "type": "string", "minLength": 1 }, + "authority_receipt_id": { "type": "string", "minLength": 1 }, + "input_hash": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, + "output_hash": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, + "output_size_bytes": { "type": "integer", "minimum": 0 }, + "started_at": { "type": "string", "format": "date-time" }, + "completed_at": { "type": "string", "format": "date-time" }, + "duration_ms": { "type": "integer", "minimum": 0 }, + "status": { "type": "string", "enum": ["success", "error", "timeout", "quarantined"] }, + "error_category": { "type": "string", "enum": ["timeout", "invalid_input", "not_found", "permission_denied", "rate_limit", "internal_error"] }, + "postcondition_check": { "type": "string", "enum": ["passed", "failed", "skipped"] }, + "postcondition_violation": { "type": "string" }, + "sandbox_state_hash": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, + "integrity": { "$ref": "#/$defs/integrity" } }, - "required": ["total_granted", "total_consumed", "total_expired", "total_revoked"] + "required": ["schema_version", "execution_id", "run_id", "tool_name", "permission_id", "authority_receipt_id", "input_hash", "output_hash", "output_size_bytes", "started_at", "completed_at", "duration_ms", "status", "postcondition_check", "sandbox_state_hash", "integrity"] }, - "budget_final": { "$ref": "#/definitions/budget_snapshot_rfc0038" }, - "policy_violations": { "type": "array", "items": { "$ref": "#/definitions/policy_violation_entry" } }, - "integrity": { - "type": "object", "additionalProperties": false, + "audit_envelope": { + "type": "object", + "additionalProperties": false, "properties": { - "hash_algorithm": { "type": "string", "const": "sha256" }, - "content_hash": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, - "signature": { "type": "string" }, "signing_key_id": { "type": "string" } + "schema_version": { "type": "string", "enum": ["0.2"] }, + "envelope_id": { "type": "string", "format": "uuid" }, + "run_id": { "type": "string", "minLength": 1 }, + "agent_id": { "type": "string", "minLength": 1 }, + "task_hash": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, + "started_at": { "type": "string", "format": "date-time" }, + "completed_at": { "type": "string", "format": "date-time" }, + "completion_status": { "type": "string", "enum": ["succeeded", "failed", "denied", "budget_exhausted", "external_stop", "escalation_timeout", "fail_safe"] }, + "trace_hash": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, + "delegation_requests": { "type": "array", "items": { "type": "string", "minLength": 1 } }, + "delegation_decisions": { "type": "array", "items": { "type": "string", "minLength": 1 } }, + "authority_receipts": { "type": "array", "items": { "type": "string", "minLength": 1 } }, + "tool_execution_receipts": { "type": "array", "items": { "type": "string", "format": "uuid" } }, + "delegation_summary": { + "type": "object", "additionalProperties": false, + "properties": { + "total_requested": { "type": "integer", "minimum": 0 }, "total_granted": { "type": "integer", "minimum": 0 }, + "total_denied": { "type": "integer", "minimum": 0 }, "total_narrowed": { "type": "integer", "minimum": 0 }, + "total_escalated": { "type": "integer", "minimum": 0 } + }, + "required": ["total_requested", "total_granted", "total_denied", "total_narrowed", "total_escalated"] + }, + "permission_summary": { + "type": "object", "additionalProperties": false, + "properties": { + "total_granted": { "type": "integer", "minimum": 0 }, "total_consumed": { "type": "integer", "minimum": 0 }, + "total_expired": { "type": "integer", "minimum": 0 }, "total_revoked": { "type": "integer", "minimum": 0 } + }, + "required": ["total_granted", "total_consumed", "total_expired", "total_revoked"] + }, + "budget_final": { "$ref": "#/$defs/budget_snapshot_rfc0038" }, + "policy_violations": { "type": "array", "items": { "$ref": "#/$defs/policy_violation_entry" } }, + "integrity": { "$ref": "#/$defs/integrity" } }, - "required": ["hash_algorithm", "content_hash"] + "required": ["schema_version", "envelope_id", "run_id", "agent_id", "task_hash", "started_at", "completed_at", "completion_status", "trace_hash", "delegation_requests", "delegation_decisions", "authority_receipts", "tool_execution_receipts", "delegation_summary", "permission_summary", "budget_final", "policy_violations", "integrity"] } - }, - "required": ["envelope_id", "run_id", "agent_id", "task_hash", "started_at", "sealed_at", "completion_status", "trace_hash", "delegation_requests", "delegation_decisions", "authority_receipts", "tool_execution_receipts", "delegation_summary", "permission_summary", "budget_final", "policy_violations", "integrity"] + } } ``` @@ -180,6 +180,7 @@ Synthetic 64-char lowercase hex stands in for real SHA-256; conforming `content_ ```json { + "schema_version": "0.2", "execution_id": "a1b2c3d4-e5f6-47a8-9c0d-1e2f3a4b5c6d", "run_id": "run_20260418_01", "tool_name": "web_search", @@ -202,6 +203,7 @@ Synthetic 64-char lowercase hex stands in for real SHA-256; conforming `content_ ```json { + "schema_version": "0.2", "execution_id": "f6e5d4c3-b2a1-4098-8765-43210fedcba9", "run_id": "run_20260418_02", "tool_name": "filesystem_read", @@ -225,19 +227,20 @@ Synthetic 64-char lowercase hex stands in for real SHA-256; conforming `content_ ```json { + "schema_version": "0.2", "envelope_id": "11111111-2222-4333-8444-555555555555", "run_id": "run_20260418_03", "agent_id": "planner-alpha", "task_hash": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "started_at": "2026-04-18T11:59:00.000Z", - "sealed_at": "2026-04-18T12:10:00.000Z", + "completed_at": "2026-04-18T12:10:00.000Z", "completion_status": "succeeded", "trace_hash": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "delegation_requests": ["dreq_01"], "delegation_decisions": ["ddec_01"], "authority_receipts": ["authrecv_99"], "tool_execution_receipts": ["aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa", "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb"], - "delegation_summary": { "total_requested": 1, "total_approved": 1, "total_denied": 0, "total_narrowed": 1, "total_escalated": 0 }, + "delegation_summary": { "total_requested": 1, "total_granted": 1, "total_denied": 0, "total_narrowed": 1, "total_escalated": 0 }, "permission_summary": { "total_granted": 2, "total_consumed": 2, "total_expired": 0, "total_revoked": 0 }, "budget_final": { "tokens_used": 4200, "tokens_remaining": 800, "cost_used": 0.04, "cost_remaining": 0.06, @@ -261,7 +264,7 @@ Synthetic 64-char lowercase hex stands in for real SHA-256; conforming `content_ ## 11. Open Questions & Resolution -| # | Question | v0.1 stance | +| # | Question | v0.2 stance | |---|----------|-------------| | A | Canonical serialization for hashed payloads? | Document and version per harness; future RFC MAY mandate JCS. | | B | Mandatory signature algorithm? | Signatures optional; algorithm tied to `signing_key_id` registry. | @@ -270,7 +273,7 @@ Synthetic 64-char lowercase hex stands in for real SHA-256; conforming `content_ ## 12. Acceptance Criteria -- [ ] Both JSON Schemas validate instances (examples need real computed `content_hash` values). +- [ ] The bundled schema validates both `tool_execution_receipt` and `audit_envelope` instances (examples need real computed `content_hash` values). - [ ] Harness emits one receipt per governed tool execution and one sealed envelope per terminal run. - [ ] Verifiers mark **INVALID** on hash or signature mismatch. - [ ] No raw tool I/O in receipts or envelopes. diff --git a/rfcs/0051-temporal-semantics-validity-extension.md b/rfcs/0051-temporal-semantics-validity-extension.md new file mode 100644 index 0000000..bffa086 --- /dev/null +++ b/rfcs/0051-temporal-semantics-validity-extension.md @@ -0,0 +1,287 @@ +# RFC 0051 — Temporal Semantics & Validity Extension (v0.1) + +**Status:** Draft +**Author:** Byron / Open CoT Community +**Created:** 2026-04-20 +**Target Version:** Schema v0.9 +**Discussion:** https://github.com/supernovae/open-cot/discussions/51 + +--- + +## 1. Summary + +Open CoT already carries many time-like fields (`timestamp`, `started_at`, `completed_at`, `expires_at`, `effective_from`, `effective_until`) but lacks one cross-cutting temporal model. This RFC defines that model for governed execution. + +The extension standardizes: + +- canonical temporal fields and meanings, +- ordering semantics beyond wall-clock sorting, +- validity, freshness, and replay-window requirements, +- supersession semantics for append-only governance, +- temporal uncertainty and clock-domain provenance. + +This RFC is control-plane focused: it standardizes artifact semantics and enforcement obligations, not internal model cognition. + +--- + +## 2. Scope and non-goals + +**In scope** + +- Control-plane semantics for temporal fields across policy, delegation, permissions, receipts, audit, memory, lifecycle, telemetry, and governed execution. +- Normative ordering rules that remain stable under clock skew and distributed runtimes. +- Replay/freshness/supersession guarantees for auditable execution. + +**Out of scope** + +- Human-style temporal reasoning within model chain-of-thought. +- Transformer architecture changes, sequence-modeling research, or training-only behavior guarantees. +- Replacing RFC 0007 state-machine governance with timestamp-only ordering. + +--- + +## 3. Canonical temporal fields + +Implementations MUST use these canonical semantics when fields appear: + +| Field | Meaning | Typical producer | +|------|---------|------------------| +| `observed_at` | When evidence/observation became known to the harness | tool executor, observation path | +| `decided_at` | When an authority/policy decision was finalized | policy engine, harness | +| `effective_at` | Inclusive start time when an artifact becomes valid | policy, grants, approvals | +| `expires_at` | Exclusive end time when validity ends | policy, grants, approvals | +| `started_at` | Start time of an execution span | tool executor, run lifecycle | +| `completed_at` | End time of an execution span | tool executor, run lifecycle | +| `superseded_at` | Time an artifact revision was superseded by another | harness or governance service | + +If an artifact has validity bounds, it MUST use `effective_at` + `expires_at` (half-open interval: `[effective_at, expires_at)`). + +--- + +## 4. Ordering semantics + +Temporal ordering MUST NOT rely on wall-clock time alone. + +Implementations MUST evaluate order using this precedence: + +1. **Logical sequence order** (`ordering.event_seq`) when present. +2. **Causal linkage** (`ordering.parent_event_id` and/or `ordering.causal_predecessors`) when sequence ties or is absent. +3. **Version transition order** (`ordering.version_order`) for lifecycle-governed revisions. +4. **Wall clock order** (`*.at` fields) only as a tie-breaker. + +Normative requirement: artifacts used for governance/audit decisions MUST carry at least one non-wall-clock ordering signal (`event_seq`, causal predecessor, or version order). + +--- + +## 5. Validity, freshness, and replay + +### 5.1 Validity windows + +- `effective_at` is inclusive. +- `expires_at` is exclusive. +- Artifact is valid at time `t` iff `effective_at <= t < expires_at`. +- If `effective_at` is omitted, validity starts immediately when emitted. +- If `expires_at` is omitted, validity is unbounded unless constrained by policy. + +### 5.2 Freshness requirements + +When freshness is specified: + +- `freshness.max_staleness_ms` defines allowed age of observed evidence at decision/execution time. +- `freshness.max_observation_lag_ms` bounds delay between real-world event and `observed_at`. +- If freshness cannot be proven, implementations MUST fail closed (`deny`, `escalate`, or `fail_safe` per governing RFC). + +### 5.3 Replay windows + +- `freshness.replay_window_ms` bounds reuse of replay-sensitive artifacts (receipts, approvals, delegation artifacts). +- If artifact age exceeds replay window, it MUST be rejected as stale for privileged operations. + +--- + +## 6. Supersession model + +Supersession is append-only and provenance-preserving. + +When an artifact revision replaces prior intent/constraints: + +- new artifact MUST reference predecessor via `supersession.supersedes_id`, +- predecessor MAY be marked with `superseded_at`, +- historical records MUST remain immutable and auditable. + +Supersession MUST NOT destructively erase prior approved intent, grant lineage, or provenance evidence. + +--- + +## 7. Temporal uncertainty and clock domains + +Each canonical instant SHOULD carry source metadata using `time_instant`: + +- `source` in `{harness_recorded, source_reported, inferred, unknown}`, +- `clock_domain` in `{harness_wall_clock, source_wall_clock, logical_only}`, +- optional uncertainty interval (`lower_bound_at`, `upper_bound_at`) when exact time is unknown. + +If `source` is `unknown`, exact `at` MAY be omitted but ordering and governance constraints still require non-wall-clock ordering metadata. + +--- + +## 8. Migration from legacy fields (breaking) + +This RFC defines a breaking normalization: + +| Legacy field | Canonical target | +|-------------|------------------| +| `timestamp` (generic) | one of `observed_at`, `decided_at`, or lifecycle span fields with explicit semantics | +| `effective_from` | `effective_at` | +| `effective_until` | `expires_at` | +| `granted_at` | `effective_at` (grant validity start) | +| `sealed_at` | `completed_at` for sealing span OR explicit terminal lifecycle event timestamp | +| policy rule `time_window.start` | `effective_at` | +| policy rule `time_window.end` | `expires_at` | + +Implementations adopting v0.9 MUST emit canonical names and MUST NOT emit deprecated aliases in new artifacts. + +--- + +## 9. Cross-RFC integration targets + +This extension is cross-cutting for: + +- RFC 0007 (governed FSM), +- RFC 0010 (memory), +- RFC 0030 (lifecycle/versioning), +- RFC 0031 (telemetry), +- RFC 0041 (policy), +- RFC 0042 (permissions), +- RFC 0043 (audit logs), +- RFC 0047 (delegation), +- RFC 0048 (execution receipts/audit envelopes), +- RFC 0049 (capability manifest freshness projection). + +--- + +## 10. Normative JSON Schema + + +```json +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://opencot.dev/schema/rfc0051/temporal-semantics.json", + "title": "Open CoT RFC 0051 - Temporal Semantics and Validity Extension", + "type": "object", + "additionalProperties": false, + "$defs": { + "isoDateTime": { + "type": "string", + "format": "date-time" + }, + "timeSource": { + "type": "string", + "enum": ["harness_recorded", "source_reported", "inferred", "unknown"] + }, + "clockDomain": { + "type": "string", + "enum": ["harness_wall_clock", "source_wall_clock", "logical_only"] + }, + "timeUncertainty": { + "type": "object", + "additionalProperties": false, + "properties": { + "lower_bound_at": { "$ref": "#/$defs/isoDateTime" }, + "upper_bound_at": { "$ref": "#/$defs/isoDateTime" } + }, + "required": ["lower_bound_at", "upper_bound_at"] + }, + "timeInstant": { + "type": "object", + "additionalProperties": false, + "properties": { + "at": { "$ref": "#/$defs/isoDateTime" }, + "source": { "$ref": "#/$defs/timeSource" }, + "clock_domain": { "$ref": "#/$defs/clockDomain" }, + "uncertainty": { "$ref": "#/$defs/timeUncertainty" } + }, + "required": ["source", "clock_domain"], + "allOf": [ + { + "if": { + "properties": { "source": { "const": "unknown" } }, + "required": ["source"] + }, + "then": { + "not": { "required": ["at"] } + }, + "else": { + "required": ["at"] + } + } + ] + }, + "ordering": { + "type": "object", + "additionalProperties": false, + "properties": { + "event_seq": { "type": "integer", "minimum": 0 }, + "parent_event_id": { "type": "string", "minLength": 1 }, + "causal_predecessors": { + "type": "array", + "items": { "type": "string", "minLength": 1 }, + "uniqueItems": true + }, + "version_order": { "type": "integer", "minimum": 0 } + } + }, + "validityWindow": { + "type": "object", + "additionalProperties": false, + "properties": { + "effective_at": { "$ref": "#/$defs/isoDateTime" }, + "expires_at": { "$ref": "#/$defs/isoDateTime" } + } + }, + "freshness": { + "type": "object", + "additionalProperties": false, + "properties": { + "max_staleness_ms": { "type": "integer", "minimum": 0 }, + "max_observation_lag_ms": { "type": "integer", "minimum": 0 }, + "replay_window_ms": { "type": "integer", "minimum": 0 } + } + }, + "supersession": { + "type": "object", + "additionalProperties": false, + "properties": { + "supersedes_id": { "type": "string", "minLength": 1 }, + "superseded_at": { "$ref": "#/$defs/isoDateTime" }, + "reason": { "type": "string" } + }, + "required": ["supersedes_id", "superseded_at"] + } + }, + "properties": { + "observed_at": { "$ref": "#/$defs/timeInstant" }, + "decided_at": { "$ref": "#/$defs/timeInstant" }, + "effective_at": { "$ref": "#/$defs/isoDateTime" }, + "expires_at": { "$ref": "#/$defs/isoDateTime" }, + "started_at": { "$ref": "#/$defs/isoDateTime" }, + "completed_at": { "$ref": "#/$defs/isoDateTime" }, + "superseded_at": { "$ref": "#/$defs/isoDateTime" }, + "ordering": { "$ref": "#/$defs/ordering" }, + "validity": { "$ref": "#/$defs/validityWindow" }, + "freshness": { "$ref": "#/$defs/freshness" }, + "supersession": { "$ref": "#/$defs/supersession" } + } +} +``` + + +--- + +## 11. Acceptance criteria + +- Governance artifacts use canonical temporal names and semantics. +- Non-wall-clock ordering metadata is present for audit/governance records. +- Freshness and replay-window checks are enforceable at runtime. +- Supersession preserves predecessor links and immutable history. +- Cross-schema validation succeeds with regenerated registry artifacts. + diff --git a/schemas/registry.json b/schemas/registry.json index d0b20f0..d683617 100644 --- a/schemas/registry.json +++ b/schemas/registry.json @@ -51,6 +51,7 @@ "delegation_extension": "schemas/rfc-0047-delegation-extension.json", "execution_receipts_audit_envelopes": "schemas/rfc-0048-execution-receipts-audit-envelopes.json", "capability_manifest": "schemas/rfc-0049-capability-manifest.json", - "toon_adapter": "schemas/rfc-0050-toon-adapter.json" + "toon_adapter": "schemas/rfc-0050-toon-adapter.json", + "temporal_semantics": "schemas/rfc-0051-temporal-semantics.json" } } diff --git a/schemas/rfc-0010-memory.json b/schemas/rfc-0010-memory.json index 8d4eca2..ab9f026 100644 --- a/schemas/rfc-0010-memory.json +++ b/schemas/rfc-0010-memory.json @@ -6,7 +6,7 @@ "version": { "type": "string", "enum": [ - "0.1" + "0.2" ], "description": "Schema version." }, @@ -28,7 +28,8 @@ "type": "string" }, "expires_at": { - "type": "string" + "type": "string", + "format": "date-time" } }, "required": [ @@ -50,8 +51,13 @@ "type": { "type": "string" }, - "updated_at": { - "type": "string" + "observed_at": { + "type": "string", + "format": "date-time" + }, + "superseded_at": { + "type": "string", + "format": "date-time" }, "confidence": { "type": "number" @@ -72,8 +78,9 @@ "episode_id": { "type": "string" }, - "timestamp": { - "type": "string" + "observed_at": { + "type": "string", + "format": "date-time" }, "summary": { "type": "string" @@ -84,7 +91,7 @@ }, "required": [ "episode_id", - "timestamp" + "observed_at" ] } }, @@ -97,8 +104,9 @@ "state": { "type": "object" }, - "last_used": { - "type": "string" + "observed_at": { + "type": "string", + "format": "date-time" } } } diff --git a/schemas/rfc-0011-multi-agent-protocol.json b/schemas/rfc-0011-multi-agent-protocol.json index 1955419..6e09871 100644 --- a/schemas/rfc-0011-multi-agent-protocol.json +++ b/schemas/rfc-0011-multi-agent-protocol.json @@ -1,12 +1,12 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "OpenCoT Multi-Agent Protocol v0.1", + "title": "OpenCoT Multi-Agent Protocol v0.2", "type": "object", "properties": { "version": { "type": "string", "enum": [ - "0.1" + "0.2" ] }, "agents": { @@ -47,8 +47,9 @@ "receiver": { "type": "string" }, - "timestamp": { - "type": "string" + "observed_at": { + "type": "string", + "format": "date-time" }, "content": { "type": "string" @@ -61,6 +62,7 @@ "message_id", "sender", "receiver", + "observed_at", "content" ] } diff --git a/schemas/rfc-0030-agent-lifecycle-versioning.json b/schemas/rfc-0030-agent-lifecycle-versioning.json index 925e353..0d2ec42 100644 --- a/schemas/rfc-0030-agent-lifecycle-versioning.json +++ b/schemas/rfc-0030-agent-lifecycle-versioning.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://opencot.dev/schema/agent-lifecycle/v0.1", + "$id": "https://opencot.dev/schema/agent-lifecycle/v0.2", "title": "Open CoT RFC 0030 — Agent Lifecycle", "definitions": { "agent_lifecycle": { @@ -11,7 +11,7 @@ "version", "lifecycle_state", "created_at", - "updated_at", + "observed_at", "configuration_hash", "capabilities", "policy_refs", @@ -40,7 +40,7 @@ "type": "string", "format": "date-time" }, - "updated_at": { + "observed_at": { "type": "string", "format": "date-time" }, @@ -77,7 +77,8 @@ "migration_strategy", "rollback_allowed", "approved_by", - "timestamp" + "decided_at", + "version_order" ], "properties": { "from_version": { @@ -103,9 +104,13 @@ "type": "string", "minLength": 1 }, - "timestamp": { + "decided_at": { "type": "string", "format": "date-time" + }, + "version_order": { + "type": "integer", + "minimum": 0 } } } diff --git a/schemas/rfc-0031-agent-observability-telemetry.json b/schemas/rfc-0031-agent-observability-telemetry.json index 789c3b4..327d0f5 100644 --- a/schemas/rfc-0031-agent-observability-telemetry.json +++ b/schemas/rfc-0031-agent-observability-telemetry.json @@ -6,16 +6,32 @@ "version": { "type": "string", "enum": [ - "0.1" + "0.2" ] }, "agent_id": { "type": "string" }, - "timestamp": { + "observed_at": { "type": "string", "format": "date-time" }, + "ordering": { + "type": "object", + "additionalProperties": false, + "properties": { + "event_seq": { + "type": "integer", + "minimum": 0 + }, + "parent_event_id": { + "type": "string" + } + }, + "required": [ + "event_seq" + ] + }, "metrics": { "type": "object", "properties": { @@ -46,7 +62,8 @@ "required": [ "version", "agent_id", - "timestamp", + "observed_at", + "ordering", "metrics" ], "$id": "https://opencot.dev/schemas/rfc-0031-agent-observability-telemetry.json", diff --git a/schemas/rfc-0034-agent-federation-protocol.json b/schemas/rfc-0034-agent-federation-protocol.json index eb06ba7..4417a5a 100644 --- a/schemas/rfc-0034-agent-federation-protocol.json +++ b/schemas/rfc-0034-agent-federation-protocol.json @@ -104,7 +104,7 @@ "minLength": 1 }, "delegation_request": { - "$ref": "https://opencot.dev/schema/rfc0047/delegation-extension.json#/$defs/delegation_request" + "$ref": "https://opencot.dev/schema/rfc0047/delegation-extension-v0.2.json#/$defs/delegation_request" }, "trust_chain": { "type": "array", @@ -147,7 +147,7 @@ ] }, "delegation_decision": { - "$ref": "https://opencot.dev/schema/rfc0047/delegation-extension.json#/$defs/delegation_decision" + "$ref": "https://opencot.dev/schema/rfc0047/delegation-extension-v0.2.json#/$defs/delegation_decision" }, "response_integrity": { "$ref": "#/$defs/integrity" diff --git a/schemas/rfc-0041-policy-enforcement.json b/schemas/rfc-0041-policy-enforcement.json index 301adaa..9e6aa53 100644 --- a/schemas/rfc-0041-policy-enforcement.json +++ b/schemas/rfc-0041-policy-enforcement.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://opencot.dev/schema/policy/v0.2", + "$id": "https://opencot.dev/schema/policy/v0.3", "title": "Open CoT RFC 0041 — Policy Document", "type": "object", "additionalProperties": false, @@ -8,7 +8,7 @@ "version": { "type": "string", "enum": [ - "0.2" + "0.3" ] }, "policy_id": { @@ -39,11 +39,11 @@ }, "minItems": 1 }, - "effective_from": { + "effective_at": { "type": "string", "format": "date-time" }, - "effective_until": { + "expires_at": { "type": "string", "format": "date-time" } @@ -73,22 +73,22 @@ "require_approval" ] }, - "timeWindow": { + "validityWindow": { "type": "object", "additionalProperties": false, "properties": { - "start": { + "effective_at": { "type": "string", "format": "date-time" }, - "end": { + "expires_at": { "type": "string", "format": "date-time" } }, "required": [ - "start", - "end" + "effective_at", + "expires_at" ] }, "conditions": { @@ -101,8 +101,8 @@ "require_justification": { "type": "boolean" }, - "time_window": { - "$ref": "#/definitions/timeWindow" + "validity_window": { + "$ref": "#/definitions/validityWindow" }, "budget_remaining_min": { "type": "number" diff --git a/schemas/rfc-0042-permission-acl.json b/schemas/rfc-0042-permission-acl.json index 5754544..912c0ba 100644 --- a/schemas/rfc-0042-permission-acl.json +++ b/schemas/rfc-0042-permission-acl.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://opencot.dev/schema/permission-grant/0.2", + "$id": "https://opencot.dev/schema/permission-grant/0.3", "title": "Open CoT RFC 0042 — Permission Grant", "type": "object", "additionalProperties": false, @@ -101,7 +101,7 @@ "type": "string", "minLength": 1 }, - "granted_at": { + "effective_at": { "type": "string", "format": "date-time" }, @@ -138,7 +138,7 @@ "policy_ref", "request_ref", "decision_ref", - "granted_at", + "effective_at", "status" ], "allOf": [ diff --git a/schemas/rfc-0043-auditing-compliance-logs.json b/schemas/rfc-0043-auditing-compliance-logs.json index ef6a9c7..e36d9e2 100644 --- a/schemas/rfc-0043-auditing-compliance-logs.json +++ b/schemas/rfc-0043-auditing-compliance-logs.json @@ -7,7 +7,7 @@ "schema_version": { "type": "string", "enum": [ - "0.2" + "0.3" ] }, "event_id": { @@ -22,7 +22,7 @@ "type": "string", "minLength": 1 }, - "timestamp": { + "observed_at": { "type": "string", "format": "date-time" }, @@ -53,13 +53,34 @@ "type": "object", "additionalProperties": true }, - "previous_event_id": { + "parent_event_id": { "type": [ "string", "null" ], "format": "uuid" }, + "ordering": { + "type": "object", + "additionalProperties": false, + "properties": { + "event_seq": { + "type": "integer", + "minimum": 0 + }, + "causal_predecessors": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "uniqueItems": true + } + }, + "required": [ + "event_seq" + ] + }, "integrity": { "type": "object", "additionalProperties": false, @@ -67,7 +88,7 @@ "hash_algorithm": { "type": "string", "enum": [ - "sha-256" + "sha256" ] }, "content_hash": { @@ -86,10 +107,11 @@ "event_id", "run_id", "agent_id", - "timestamp", + "observed_at", "event_type", "details", - "previous_event_id", + "parent_event_id", + "ordering", "integrity" ], "$id": "https://opencot.dev/schemas/rfc-0043-auditing-compliance-logs.json", diff --git a/schemas/rfc-0047-delegation-extension.json b/schemas/rfc-0047-delegation-extension.json index a49bf9d..7b8845f 100644 --- a/schemas/rfc-0047-delegation-extension.json +++ b/schemas/rfc-0047-delegation-extension.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://opencot.dev/schema/rfc0047/delegation-extension.json", + "$id": "https://opencot.dev/schema/rfc0047/delegation-extension-v0.2.json", "title": "Open CoT RFC 0047 — Delegation Extension", "type": "object", "additionalProperties": false, @@ -34,7 +34,8 @@ "type": "string" }, "plan_version": { - "type": "string" + "type": "integer", + "minimum": 0 } } }, @@ -45,7 +46,7 @@ "schema_version": { "type": "string", "enum": [ - "0.1" + "0.2" ] }, "request_id": { @@ -60,7 +61,7 @@ "type": "string", "minLength": 1 }, - "timestamp": { + "observed_at": { "type": "string", "format": "date-time" }, @@ -78,11 +79,8 @@ "minimum": 1 }, "preferred_audience": { - "type": "array", - "items": { - "type": "string", - "minLength": 1 - } + "type": "string", + "minLength": 1 }, "task_context_ref": { "type": "string" @@ -97,7 +95,7 @@ "requester", "run_id", "requested_scope", - "timestamp" + "observed_at" ] }, "delegation_decision": { @@ -107,7 +105,7 @@ "schema_version": { "type": "string", "enum": [ - "0.1" + "0.2" ] }, "decision_id": { @@ -166,7 +164,7 @@ "escalation_target": { "type": "string" }, - "timestamp": { + "decided_at": { "type": "string", "format": "date-time" } @@ -178,7 +176,7 @@ "status", "decided_by", "policy_refs", - "timestamp" + "decided_at" ] }, "integrity": { @@ -212,7 +210,7 @@ "schema_version": { "type": "string", "enum": [ - "0.1" + "0.2" ] }, "receipt_id": { @@ -234,7 +232,7 @@ "granted_scope": { "$ref": "#/$defs/scope" }, - "granted_at": { + "effective_at": { "type": "string", "format": "date-time" }, @@ -249,11 +247,8 @@ "type": "boolean" }, "audience": { - "type": "array", - "items": { - "type": "string", - "minLength": 1 - } + "type": "string", + "minLength": 1 }, "integrity": { "$ref": "#/$defs/integrity" @@ -266,7 +261,7 @@ "request_id", "permission_id", "granted_scope", - "granted_at", + "effective_at", "expires_at", "one_shot", "forwardable", diff --git a/schemas/rfc-0048-execution-receipts-audit-envelopes.json b/schemas/rfc-0048-execution-receipts-audit-envelopes.json index 3e55317..24d48d5 100644 --- a/schemas/rfc-0048-execution-receipts-audit-envelopes.json +++ b/schemas/rfc-0048-execution-receipts-audit-envelopes.json @@ -1,125 +1,423 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://opencot.dev/schema/v0.8/tool_execution_receipt.json", - "title": "Open CoT RFC 0048 — tool_execution_receipt", + "$id": "https://opencot.dev/schema/v0.9/execution-receipts-audit-envelopes.json", + "title": "Open CoT RFC 0048 — execution receipts and audit envelopes", "type": "object", - "additionalProperties": false, - "properties": { - "execution_id": { - "type": "string", - "format": "uuid" + "oneOf": [ + { + "$ref": "#/$defs/tool_execution_receipt" }, - "run_id": { - "type": "string", - "minLength": 1 - }, - "tool_name": { - "type": "string", - "minLength": 1 - }, - "permission_id": { - "type": "string", - "minLength": 1 - }, - "authority_receipt_id": { - "type": "string", - "minLength": 1 - }, - "input_hash": { - "type": "string", - "pattern": "^[a-f0-9]{64}$" - }, - "output_hash": { - "type": "string", - "pattern": "^[a-f0-9]{64}$" - }, - "output_size_bytes": { - "type": "integer", - "minimum": 0 - }, - "started_at": { - "type": "string", - "format": "date-time" - }, - "completed_at": { - "type": "string", - "format": "date-time" - }, - "duration_ms": { - "type": "integer", - "minimum": 0 - }, - "status": { - "type": "string", - "enum": [ - "success", - "error", - "timeout", - "quarantined" + { + "$ref": "#/$defs/audit_envelope" + } + ], + "$defs": { + "integrity": { + "type": "object", + "additionalProperties": false, + "properties": { + "hash_algorithm": { + "type": "string", + "const": "sha256" + }, + "content_hash": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "signature": { + "type": "string" + }, + "signing_key_id": { + "type": "string" + } + }, + "required": [ + "hash_algorithm", + "content_hash" ] }, - "error_category": { - "type": "string", - "enum": [ - "timeout", - "invalid_input", - "not_found", - "permission_denied", - "rate_limit", - "internal_error" + "budget_snapshot_rfc0038": { + "type": "object", + "additionalProperties": false, + "properties": { + "tokens_used": { + "type": "integer", + "minimum": 0 + }, + "tokens_remaining": { + "type": "integer" + }, + "cost_used": { + "type": "number", + "minimum": 0 + }, + "cost_remaining": { + "type": "number" + }, + "steps_used": { + "type": "integer", + "minimum": 0 + }, + "steps_remaining": { + "type": "integer" + }, + "tool_calls_used": { + "type": "integer", + "minimum": 0 + }, + "tool_calls_remaining": { + "type": "integer" + }, + "retries_used": { + "type": "integer", + "minimum": 0 + }, + "retries_remaining": { + "type": "integer" + } + }, + "required": [ + "tokens_used", + "tokens_remaining", + "cost_used", + "cost_remaining", + "steps_used", + "steps_remaining", + "tool_calls_used", + "tool_calls_remaining", + "retries_used", + "retries_remaining" ] }, - "postcondition_check": { - "type": "string", - "enum": [ - "passed", - "failed", - "skipped" + "policy_violation_entry": { + "type": "object", + "additionalProperties": false, + "properties": { + "violation_id": { + "type": "string", + "minLength": 1 + }, + "policy_id": { + "type": "string", + "minLength": 1 + }, + "rule_id": { + "type": "string", + "minLength": 1 + }, + "description": { + "type": "string" + }, + "severity": { + "type": "string", + "enum": [ + "info", + "low", + "medium", + "high", + "critical" + ] + }, + "observed_at": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "violation_id", + "policy_id", + "rule_id", + "description", + "severity", + "observed_at" ] }, - "postcondition_violation": { - "type": "string" - }, - "sandbox_state_hash": { - "type": "string", - "pattern": "^[a-f0-9]{64}$" + "tool_execution_receipt": { + "type": "object", + "additionalProperties": false, + "properties": { + "schema_version": { + "type": "string", + "enum": [ + "0.2" + ] + }, + "execution_id": { + "type": "string", + "format": "uuid" + }, + "run_id": { + "type": "string", + "minLength": 1 + }, + "tool_name": { + "type": "string", + "minLength": 1 + }, + "permission_id": { + "type": "string", + "minLength": 1 + }, + "authority_receipt_id": { + "type": "string", + "minLength": 1 + }, + "input_hash": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "output_hash": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "output_size_bytes": { + "type": "integer", + "minimum": 0 + }, + "started_at": { + "type": "string", + "format": "date-time" + }, + "completed_at": { + "type": "string", + "format": "date-time" + }, + "duration_ms": { + "type": "integer", + "minimum": 0 + }, + "status": { + "type": "string", + "enum": [ + "success", + "error", + "timeout", + "quarantined" + ] + }, + "error_category": { + "type": "string", + "enum": [ + "timeout", + "invalid_input", + "not_found", + "permission_denied", + "rate_limit", + "internal_error" + ] + }, + "postcondition_check": { + "type": "string", + "enum": [ + "passed", + "failed", + "skipped" + ] + }, + "postcondition_violation": { + "type": "string" + }, + "sandbox_state_hash": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "integrity": { + "$ref": "#/$defs/integrity" + } + }, + "required": [ + "schema_version", + "execution_id", + "run_id", + "tool_name", + "permission_id", + "authority_receipt_id", + "input_hash", + "output_hash", + "output_size_bytes", + "started_at", + "completed_at", + "duration_ms", + "status", + "postcondition_check", + "sandbox_state_hash", + "integrity" + ] }, - "integrity": { + "audit_envelope": { "type": "object", "additionalProperties": false, "properties": { - "hash_algorithm": { + "schema_version": { "type": "string", - "const": "sha256" + "enum": [ + "0.2" + ] }, - "content_hash": { + "envelope_id": { + "type": "string", + "format": "uuid" + }, + "run_id": { + "type": "string", + "minLength": 1 + }, + "agent_id": { + "type": "string", + "minLength": 1 + }, + "task_hash": { "type": "string", "pattern": "^[a-f0-9]{64}$" + }, + "started_at": { + "type": "string", + "format": "date-time" + }, + "completed_at": { + "type": "string", + "format": "date-time" + }, + "completion_status": { + "type": "string", + "enum": [ + "succeeded", + "failed", + "denied", + "budget_exhausted", + "external_stop", + "escalation_timeout", + "fail_safe" + ] + }, + "trace_hash": { + "type": "string", + "pattern": "^[a-f0-9]{64}$" + }, + "delegation_requests": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + } + }, + "delegation_decisions": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + } + }, + "authority_receipts": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + } + }, + "tool_execution_receipts": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + }, + "delegation_summary": { + "type": "object", + "additionalProperties": false, + "properties": { + "total_requested": { + "type": "integer", + "minimum": 0 + }, + "total_granted": { + "type": "integer", + "minimum": 0 + }, + "total_denied": { + "type": "integer", + "minimum": 0 + }, + "total_narrowed": { + "type": "integer", + "minimum": 0 + }, + "total_escalated": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "total_requested", + "total_granted", + "total_denied", + "total_narrowed", + "total_escalated" + ] + }, + "permission_summary": { + "type": "object", + "additionalProperties": false, + "properties": { + "total_granted": { + "type": "integer", + "minimum": 0 + }, + "total_consumed": { + "type": "integer", + "minimum": 0 + }, + "total_expired": { + "type": "integer", + "minimum": 0 + }, + "total_revoked": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "total_granted", + "total_consumed", + "total_expired", + "total_revoked" + ] + }, + "budget_final": { + "$ref": "#/$defs/budget_snapshot_rfc0038" + }, + "policy_violations": { + "type": "array", + "items": { + "$ref": "#/$defs/policy_violation_entry" + } + }, + "integrity": { + "$ref": "#/$defs/integrity" } }, "required": [ - "hash_algorithm", - "content_hash" + "schema_version", + "envelope_id", + "run_id", + "agent_id", + "task_hash", + "started_at", + "completed_at", + "completion_status", + "trace_hash", + "delegation_requests", + "delegation_decisions", + "authority_receipts", + "tool_execution_receipts", + "delegation_summary", + "permission_summary", + "budget_final", + "policy_violations", + "integrity" ] } }, - "required": [ - "execution_id", - "run_id", - "tool_name", - "permission_id", - "authority_receipt_id", - "input_hash", - "output_hash", - "output_size_bytes", - "started_at", - "completed_at", - "duration_ms", - "status", - "postcondition_check", - "sandbox_state_hash", - "integrity" - ], "x-opencot": { "rfc": "0048", "shortname": "execution_receipts_audit_envelopes", diff --git a/schemas/rfc-0050-toon-adapter.json b/schemas/rfc-0050-toon-adapter.json index a40e528..8bf0210 100644 --- a/schemas/rfc-0050-toon-adapter.json +++ b/schemas/rfc-0050-toon-adapter.json @@ -1,41 +1,14 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://opencot.dev/schema/v0.8/toon_adapter.json", - "title": "Open CoT RFC 0050 — TOON Adapter Configuration", - "description": "Configuration for the TOON (Token-Oriented Object Notation) adapter. Controls wire format selection and TOON-specific serialization options.", + "title": "RFC 0050 — Toon Adapter (stub)", + "description": "Placeholder JSON Schema for RFC 0050. The RFC does not yet contain an extractable JSON Schema block; evolve this file as the RFC stabilizes.", "type": "object", - "additionalProperties": false, - "required": ["wire_format"], - "properties": { - "wire_format": { - "type": "string", - "enum": ["json", "compact-text", "toon"], - "default": "compact-text", - "description": "Serialization format for model-facing context injection. 'json' uses minified JSON, 'compact-text' uses the existing hand-coded compact serializer, 'toon' uses Token-Oriented Object Notation." - }, - "toon_options": { - "type": "object", - "additionalProperties": false, - "description": "Options specific to the TOON wire format. Ignored when wire_format is not 'toon'.", - "properties": { - "include_headers": { - "type": "boolean", - "default": true, - "description": "Whether to include inline schema headers for arrays. Headers cost a few tokens but help the model parse and validate structure." - }, - "delimiter": { - "type": "string", - "default": "|", - "description": "Column delimiter for tabular array rows." - }, - "indent": { - "type": "integer", - "default": 2, - "minimum": 1, - "maximum": 4, - "description": "Number of spaces per indentation level for nested objects." - } - } - } - } + "additionalProperties": true, + "x-opencot": { + "rfc": "0050", + "shortname": "toon_adapter", + "status": "stub", + "source_rfc": "rfcs/0050-toon-adapter.md" + }, + "$id": "https://opencot.dev/schemas/rfc-0050-toon-adapter.json" } diff --git a/schemas/rfc-0051-temporal-semantics.json b/schemas/rfc-0051-temporal-semantics.json new file mode 100644 index 0000000..e3e7942 --- /dev/null +++ b/schemas/rfc-0051-temporal-semantics.json @@ -0,0 +1,210 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://opencot.dev/schema/rfc0051/temporal-semantics.json", + "title": "Open CoT RFC 0051 - Temporal Semantics and Validity Extension", + "type": "object", + "additionalProperties": false, + "$defs": { + "isoDateTime": { + "type": "string", + "format": "date-time" + }, + "timeSource": { + "type": "string", + "enum": [ + "harness_recorded", + "source_reported", + "inferred", + "unknown" + ] + }, + "clockDomain": { + "type": "string", + "enum": [ + "harness_wall_clock", + "source_wall_clock", + "logical_only" + ] + }, + "timeUncertainty": { + "type": "object", + "additionalProperties": false, + "properties": { + "lower_bound_at": { + "$ref": "#/$defs/isoDateTime" + }, + "upper_bound_at": { + "$ref": "#/$defs/isoDateTime" + } + }, + "required": [ + "lower_bound_at", + "upper_bound_at" + ] + }, + "timeInstant": { + "type": "object", + "additionalProperties": false, + "properties": { + "at": { + "$ref": "#/$defs/isoDateTime" + }, + "source": { + "$ref": "#/$defs/timeSource" + }, + "clock_domain": { + "$ref": "#/$defs/clockDomain" + }, + "uncertainty": { + "$ref": "#/$defs/timeUncertainty" + } + }, + "required": [ + "source", + "clock_domain" + ], + "allOf": [ + { + "if": { + "properties": { + "source": { + "const": "unknown" + } + }, + "required": [ + "source" + ] + }, + "then": { + "not": { + "required": [ + "at" + ] + } + }, + "else": { + "required": [ + "at" + ] + } + } + ] + }, + "ordering": { + "type": "object", + "additionalProperties": false, + "properties": { + "event_seq": { + "type": "integer", + "minimum": 0 + }, + "parent_event_id": { + "type": "string", + "minLength": 1 + }, + "causal_predecessors": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + }, + "uniqueItems": true + }, + "version_order": { + "type": "integer", + "minimum": 0 + } + } + }, + "validityWindow": { + "type": "object", + "additionalProperties": false, + "properties": { + "effective_at": { + "$ref": "#/$defs/isoDateTime" + }, + "expires_at": { + "$ref": "#/$defs/isoDateTime" + } + } + }, + "freshness": { + "type": "object", + "additionalProperties": false, + "properties": { + "max_staleness_ms": { + "type": "integer", + "minimum": 0 + }, + "max_observation_lag_ms": { + "type": "integer", + "minimum": 0 + }, + "replay_window_ms": { + "type": "integer", + "minimum": 0 + } + } + }, + "supersession": { + "type": "object", + "additionalProperties": false, + "properties": { + "supersedes_id": { + "type": "string", + "minLength": 1 + }, + "superseded_at": { + "$ref": "#/$defs/isoDateTime" + }, + "reason": { + "type": "string" + } + }, + "required": [ + "supersedes_id", + "superseded_at" + ] + } + }, + "properties": { + "observed_at": { + "$ref": "#/$defs/timeInstant" + }, + "decided_at": { + "$ref": "#/$defs/timeInstant" + }, + "effective_at": { + "$ref": "#/$defs/isoDateTime" + }, + "expires_at": { + "$ref": "#/$defs/isoDateTime" + }, + "started_at": { + "$ref": "#/$defs/isoDateTime" + }, + "completed_at": { + "$ref": "#/$defs/isoDateTime" + }, + "superseded_at": { + "$ref": "#/$defs/isoDateTime" + }, + "ordering": { + "$ref": "#/$defs/ordering" + }, + "validity": { + "$ref": "#/$defs/validityWindow" + }, + "freshness": { + "$ref": "#/$defs/freshness" + }, + "supersession": { + "$ref": "#/$defs/supersession" + } + }, + "x-opencot": { + "rfc": "0051", + "shortname": "temporal_semantics", + "source_rfc": "rfcs/0051-temporal-semantics-validity-extension.md" + } +} diff --git a/tools/schema_lib.py b/tools/schema_lib.py index de04ab3..1ecd138 100644 --- a/tools/schema_lib.py +++ b/tools/schema_lib.py @@ -65,6 +65,8 @@ "0047": "delegation_extension", "0048": "execution_receipts_audit_envelopes", "0049": "capability_manifest", + "0050": "toon_adapter", + "0051": "temporal_semantics", } # RFC ids where extraction must use explicit markers.