diff --git a/.clusterfuzzlite/_fuzz_seeds.py b/.clusterfuzzlite/_fuzz_seeds.py index a068b19..1bdc43a 100644 --- a/.clusterfuzzlite/_fuzz_seeds.py +++ b/.clusterfuzzlite/_fuzz_seeds.py @@ -23,7 +23,7 @@ 'result_digest': {'algorithm': 'sha256', 'value': 'eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'}, 'run_id': 'run-governed-sdlc-001', - 'spec_version': '0.1.0-alpha.4', + 'spec_version': '0.1.0-alpha.5', 'target': {'id': 'example/repository', 'kind': 'git.repository'}, 'time_unix_nano': '1787079650000000000', 'workflow_id': 'workflow-build-feature'}, @@ -39,7 +39,7 @@ 'requested_at_unix_nano': '1787079500000000000', 'run_id': 'run-governed-sdlc-001', 'span_id': '00f067aa0ba902b7', - 'spec_version': '0.1.0-alpha.4', + 'spec_version': '0.1.0-alpha.5', 'time_unix_nano': '1787079580000000000', 'trace_id': '4bf92f3577b34da6a3ce929d0e0e4736'}, 'data-flow': {'agent_id': 'spiffe://example.test/agent/architect', @@ -58,7 +58,7 @@ 'run_id': 'run-governed-sdlc-001', 'size_bytes': 18342, 'source': {'id': 'requirements-graph', 'kind': 'knowledge_graph'}, - 'spec_version': '0.1.0-alpha.4', + 'spec_version': '0.1.0-alpha.5', 'time_unix_nano': '1787079400000000000', 'transformation': 'metadata_only'}, 'evidence': {'capture_profile': 'metadata_only', @@ -67,10 +67,10 @@ 'completeness': 'complete', 'event_id': '018f0f7d-7a13-7cc2-8000-000000000005', 'event_type': 'evidence.run_closed', - 'producer': {'name': 'agentrust-telemetry', 'version': '0.1.0-alpha.4'}, + 'producer': {'name': 'agentrust-telemetry', 'version': '0.1.0-alpha.5'}, 'run_id': 'run-governed-sdlc-001', 'sequence': 14, - 'spec_version': '0.1.0-alpha.4', + 'spec_version': '0.1.0-alpha.5', 'time_unix_nano': '1787079700000000000'}, 'policy-decision': {'action_type': 'repository.write', 'agent_id': 'spiffe://example.test/agent/coder', @@ -89,7 +89,7 @@ 'resource_type': 'git.repository', 'run_id': 'run-governed-sdlc-001', 'span_id': '00f067aa0ba902b7', - 'spec_version': '0.1.0-alpha.4', + 'spec_version': '0.1.0-alpha.5', 'time_unix_nano': '1787079600000000000', 'trace_id': '4bf92f3577b34da6a3ce929d0e0e4736', 'workflow_id': 'workflow-build-feature'}, @@ -108,7 +108,7 @@ 'request_model': 'example-model-2', 'run_id': 'run-governed-sdlc-001', 'scope': 'model_call', - 'spec_version': '0.1.0-alpha.4', + 'spec_version': '0.1.0-alpha.5', 'time_unix_nano': '1787079590000000000', 'workflow_id': 'workflow-build-feature'}} diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e35f9a..6bc5fdb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,38 @@ ## Unreleased +## 0.1.0-alpha.5 - 2026-09-26 + +### Fixed + +- TRACE finalization in both SDKs (`finalize_trace` in `trace_adapter.py`, and + `trace-finalizer.ts`) now recomputes the evidence chain from the snapshot entries + (sequence, previous digest, entry digest, `event_id`, `run_id`, `chain_digest`) and + refuses to sign on any mismatch. Before, an `EvidenceSnapshot` edited after sealing + could produce a signed record whose appraisal disagreed with the measurement it + carried. A malformed event inside a consistent chain now raises + `TraceFinalizationError` instead of `KeyError`. (#65) +- Python event validation rejects nesting deeper than 32 levels, non-string keys, and + NaN or Infinity with `EventValidationError`. These previously raised `RecursionError` + or `AttributeError`, or were accepted. NaN now fails at validation rather than at the + chain, as it already did in the TypeScript SDK. (#65) +- The AGT adapters (`agt.py`, `agt_audit.py`, `agt_approval.py`, `agt_data.py`) raise + `ValueError` for a list or object where a decision, kind, outcome or classification + belongs, and for an out-of-range `latency_ms`. These previously surfaced as + `TypeError` or `OverflowError`. (#65) + +### Changed + +- Add ClusterFuzzLite with three fuzz targets: event validation and projection, the + OPA and AGT policy adapters, and sealed evidence to signed TRACE. (#65) +- The OTel GenAI compatibility notes now say that the pinned upstream revision already + defines cache-read, cache-creation and reasoning token attributes. (#63) +- The version string is inside the hashed envelope, so this release moves every + evidence digest. `compatibility/golden/evidence-chain.json` and the cross-language + `tool_transcript` assertions are regenerated for it. +- CI and governance only: CODEOWNERS maintainer alignment (#64), CodeQL and CycloneDX + action bumps (#57, #59, #60, #61), `build` 1.6.1 in the release lock (#56). + ## 0.1.0-alpha.4 - 2026-09-14 ### Fixed diff --git a/LIMITATIONS.md b/LIMITATIONS.md index 18c13a4..61fe309 100644 --- a/LIMITATIONS.md +++ b/LIMITATIONS.md @@ -1,6 +1,6 @@ # Limitations -Current `0.1.0-alpha.4` limitations: +Current `0.1.0-alpha.5` limitations: - The contract and SDK are experimental and may change incompatibly. - A Python reference SDK and a TypeScript reference SDK (`packages/typescript/`) diff --git a/README.md b/README.md index f17ab0a..b477d7a 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Portable governance telemetry and verifiable evidence for AI-agent runtimes. This repository defines a backend-neutral contract for policy decisions, approval lifecycles, usage, classified data flows, and evidence lifecycle events. It composes with OpenTelemetry; it is not a tracing backend, policy engine, agent framework, or dashboard. -> **Status:** alpha contract `0.1.0-alpha.4`. No stable SDK API or compatibility guarantee exists yet. +> **Status:** alpha contract `0.1.0-alpha.5`. No stable SDK API or compatibility guarantee exists yet. ## Why diff --git a/SECURITY.md b/SECURITY.md index 89bea92..87502e7 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -26,7 +26,7 @@ Include the affected contract/SDK version, an executable reproducer where safe, ## Supported versions -No stable release exists. Only the latest `0.1.0-alpha.4` revision will receive fixes until the first published release. +No stable release exists. Only the latest `0.1.0-alpha.5` revision will receive fixes until the first published release. ## Runtime boundary diff --git a/VERSIONING.md b/VERSIONING.md index 0c01695..52be9d9 100644 --- a/VERSIONING.md +++ b/VERSIONING.md @@ -6,9 +6,9 @@ The telemetry contract uses semantic versioning independently from SDK versions, - Minor: backward-compatible optional field, event, or enum addition with defined older-consumer behavior. - Major: removal, changed meaning, new required field, or incompatible canonicalization. -The current contract version is `0.1.0-alpha.4`. Python publishes the equivalent -PEP 440 version `0.1.0a4`; npm and the Git tag use `0.1.0-alpha.4` and -`v0.1.0-alpha.4`. Pre-1.0 changes may be incompatible and must be called out +The current contract version is `0.1.0-alpha.5`. Python publishes the equivalent +PEP 440 version `0.1.0a5`; npm and the Git tag use `0.1.0-alpha.5` and +`v0.1.0-alpha.5`. Pre-1.0 changes may be incompatible and must be called out explicitly. Published GitHub releases are the sole release trigger. The release tag must diff --git a/compatibility/golden/event-factory.json b/compatibility/golden/event-factory.json index de2285e..b7a707e 100644 --- a/compatibility/golden/event-factory.json +++ b/compatibility/golden/event-factory.json @@ -1 +1 @@ -{"agent_id":"agent-1","event_id":"018f0f7d-7a13-7cc2-8000-000000000042","event_type":"usage.recorded","input_tokens":7,"operation":"chat","producer":{"name":"parity-test","version":"1.0.0"},"run_id":"run-1","scope":"model_call","spec_version":"0.1.0-alpha.4","time_unix_nano":"1787079000000000000","workflow_id":"workflow-1"} +{"agent_id":"agent-1","event_id":"018f0f7d-7a13-7cc2-8000-000000000042","event_type":"usage.recorded","input_tokens":7,"operation":"chat","producer":{"name":"parity-test","version":"1.0.0"},"run_id":"run-1","scope":"model_call","spec_version":"0.1.0-alpha.5","time_unix_nano":"1787079000000000000","workflow_id":"workflow-1"} diff --git a/compatibility/golden/evidence-chain.json b/compatibility/golden/evidence-chain.json index 4849273..424e7d9 100644 --- a/compatibility/golden/evidence-chain.json +++ b/compatibility/golden/evidence-chain.json @@ -6,13 +6,13 @@ "fixture": "policy-decision.json", "sequence": 0, "previous_digest": null, - "digest": "19b8a3bbf6f31ab89a242f3f1fb756ba7d0c6d01d75fc113b2186cb789411625" + "digest": "b48e0e0b0fe31fc276d78f6ff7dd8b620e27329f675d9971176d14a09f13b044" }, { "fixture": "usage.json", "sequence": 1, - "previous_digest": "19b8a3bbf6f31ab89a242f3f1fb756ba7d0c6d01d75fc113b2186cb789411625", - "digest": "7146bc82bcaa817689386fb45ed2d1586f67102af468b95e01fff183b8eed6bb" + "previous_digest": "b48e0e0b0fe31fc276d78f6ff7dd8b620e27329f675d9971176d14a09f13b044", + "digest": "0c0f14fcf22fb176dbfc52ba6dfc38c8258cfbfabaedb26569718fd5e1341d1e" } ] } diff --git a/conformance/fixtures/invalid/action-without-digest.json b/conformance/fixtures/invalid/action-without-digest.json index 31440a3..ea04c66 100644 --- a/conformance/fixtures/invalid/action-without-digest.json +++ b/conformance/fixtures/invalid/action-without-digest.json @@ -1,5 +1,5 @@ { - "spec_version": "0.1.0-alpha.4", + "spec_version": "0.1.0-alpha.5", "event_id": "018f0f7d-7a13-7cc2-8000-000000000096", "event_type": "action.executed", "time_unix_nano": "1787079650000000000", diff --git a/conformance/fixtures/invalid/aggregate-cost-without-rollup.json b/conformance/fixtures/invalid/aggregate-cost-without-rollup.json index 20ac318..86f1025 100644 --- a/conformance/fixtures/invalid/aggregate-cost-without-rollup.json +++ b/conformance/fixtures/invalid/aggregate-cost-without-rollup.json @@ -1 +1 @@ -{"agent_id":"agent-1","cost":{"amount":1,"currency":"USD","source":"aggregate"},"event_id":"018f0f7d-7a13-7cc2-8000-000000000009","event_type":"usage.recorded","operation":"chat","producer":{"name":"test","version":"1"},"run_id":"run-1","scope":"model_call","spec_version":"0.1.0-alpha.4","time_unix_nano":"1"} +{"agent_id":"agent-1","cost":{"amount":1,"currency":"USD","source":"aggregate"},"event_id":"018f0f7d-7a13-7cc2-8000-000000000009","event_type":"usage.recorded","operation":"chat","producer":{"name":"test","version":"1"},"run_id":"run-1","scope":"model_call","spec_version":"0.1.0-alpha.5","time_unix_nano":"1"} diff --git a/conformance/fixtures/invalid/model-call-with-rollup.json b/conformance/fixtures/invalid/model-call-with-rollup.json index a18b86b..a383bf5 100644 --- a/conformance/fixtures/invalid/model-call-with-rollup.json +++ b/conformance/fixtures/invalid/model-call-with-rollup.json @@ -1 +1 @@ -{"agent_id":"agent-1","aggregation":{"cost_coverage":0,"cost_sources":[],"event_count":1,"method":"sum","token_coverage":{"input_tokens":1}},"event_id":"018f0f7d-7a13-7cc2-8000-000000000010","event_type":"usage.recorded","input_tokens":1,"operation":"chat","producer":{"name":"test","version":"1"},"run_id":"run-1","scope":"model_call","spec_version":"0.1.0-alpha.4","time_unix_nano":"1"} +{"agent_id":"agent-1","aggregation":{"cost_coverage":0,"cost_sources":[],"event_count":1,"method":"sum","token_coverage":{"input_tokens":1}},"event_id":"018f0f7d-7a13-7cc2-8000-000000000010","event_type":"usage.recorded","input_tokens":1,"operation":"chat","producer":{"name":"test","version":"1"},"run_id":"run-1","scope":"model_call","spec_version":"0.1.0-alpha.5","time_unix_nano":"1"} diff --git a/conformance/fixtures/invalid/numeric-timestamp.json b/conformance/fixtures/invalid/numeric-timestamp.json index 4fbc92c..5231cf3 100644 --- a/conformance/fixtures/invalid/numeric-timestamp.json +++ b/conformance/fixtures/invalid/numeric-timestamp.json @@ -1 +1 @@ -{"agent_id":"agent-1","event_id":"018f0f7d-7a13-7cc2-8000-000000000011","event_type":"usage.recorded","input_tokens":1,"operation":"chat","producer":{"name":"test","version":"1"},"run_id":"run-1","scope":"model_call","spec_version":"0.1.0-alpha.4","time_unix_nano":1787079700000000000} +{"agent_id":"agent-1","event_id":"018f0f7d-7a13-7cc2-8000-000000000011","event_type":"usage.recorded","input_tokens":1,"operation":"chat","producer":{"name":"test","version":"1"},"run_id":"run-1","scope":"model_call","spec_version":"0.1.0-alpha.5","time_unix_nano":1787079700000000000} diff --git a/conformance/fixtures/invalid/raw-content.json b/conformance/fixtures/invalid/raw-content.json index 6f35447..21e7687 100644 --- a/conformance/fixtures/invalid/raw-content.json +++ b/conformance/fixtures/invalid/raw-content.json @@ -1 +1 @@ -{"agent_id":"spiffe://example.test/agent/coder","event_id":"018f0f7d-7a13-7cc2-8000-000000000006","event_type":"usage.recorded","input_tokens":10,"operation":"chat","producer":{"name":"bad-adapter","version":"0.1.0"},"prompt":"copy the production credential","run_id":"run-unsafe","scope":"model_call","spec_version":"0.1.0-alpha.4","time_unix_nano":"1787079700000000000"} +{"agent_id":"spiffe://example.test/agent/coder","event_id":"018f0f7d-7a13-7cc2-8000-000000000006","event_type":"usage.recorded","input_tokens":10,"operation":"chat","producer":{"name":"bad-adapter","version":"0.1.0"},"prompt":"copy the production credential","run_id":"run-unsafe","scope":"model_call","spec_version":"0.1.0-alpha.5","time_unix_nano":"1787079700000000000"} diff --git a/conformance/fixtures/invalid/usage-without-measurement.json b/conformance/fixtures/invalid/usage-without-measurement.json index 7e75892..69ff150 100644 --- a/conformance/fixtures/invalid/usage-without-measurement.json +++ b/conformance/fixtures/invalid/usage-without-measurement.json @@ -1 +1 @@ -{"agent_id":"agent-1","event_id":"018f0f7d-7a13-7cc2-8000-000000000008","event_type":"usage.recorded","operation":"chat","producer":{"name":"test","version":"1"},"run_id":"run-1","scope":"model_call","spec_version":"0.1.0-alpha.4","time_unix_nano":"1"} +{"agent_id":"agent-1","event_id":"018f0f7d-7a13-7cc2-8000-000000000008","event_type":"usage.recorded","operation":"chat","producer":{"name":"test","version":"1"},"run_id":"run-1","scope":"model_call","spec_version":"0.1.0-alpha.5","time_unix_nano":"1"} diff --git a/conformance/fixtures/invalid/zero-trace-id.json b/conformance/fixtures/invalid/zero-trace-id.json index 0144455..b517206 100644 --- a/conformance/fixtures/invalid/zero-trace-id.json +++ b/conformance/fixtures/invalid/zero-trace-id.json @@ -1 +1 @@ -{"action_type":"repository.read","agent_id":"agent-1","decision":"allow","enforcement_mode":"enforce","evaluation_duration_ns":1,"event_id":"018f0f7d-7a13-7cc2-8000-000000000007","event_type":"policy.decision","policy":{"engine":"opa","engine_version":"1.0"},"producer":{"name":"test","version":"1"},"resource_type":"repository","run_id":"run-1","spec_version":"0.1.0-alpha.4","time_unix_nano":"1","trace_id":"00000000000000000000000000000000"} +{"action_type":"repository.read","agent_id":"agent-1","decision":"allow","enforcement_mode":"enforce","evaluation_duration_ns":1,"event_id":"018f0f7d-7a13-7cc2-8000-000000000007","event_type":"policy.decision","policy":{"engine":"opa","engine_version":"1.0"},"producer":{"name":"test","version":"1"},"resource_type":"repository","run_id":"run-1","spec_version":"0.1.0-alpha.5","time_unix_nano":"1","trace_id":"00000000000000000000000000000000"} diff --git a/conformance/fixtures/valid/action.json b/conformance/fixtures/valid/action.json index ca5a3de..bb9ca80 100644 --- a/conformance/fixtures/valid/action.json +++ b/conformance/fixtures/valid/action.json @@ -1,5 +1,5 @@ { - "spec_version": "0.1.0-alpha.4", + "spec_version": "0.1.0-alpha.5", "event_id": "018f0f7d-7a13-7cc2-8000-000000000006", "event_type": "action.executed", "time_unix_nano": "1787079650000000000", diff --git a/conformance/fixtures/valid/approval.json b/conformance/fixtures/valid/approval.json index 771c069..1d49bb7 100644 --- a/conformance/fixtures/valid/approval.json +++ b/conformance/fixtures/valid/approval.json @@ -1 +1 @@ -{"action_digest":{"algorithm":"sha256","value":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"},"actor_id":"reviewer-7d91","actor_type":"human","agent_id":"spiffe://example.test/agent/coder","approval_id":"approval-001","event_id":"018f0f7d-7a13-7cc2-8000-000000000002","event_type":"approval.approved","producer":{"name":"example-approval-adapter","version":"0.1.0"},"requested_at_unix_nano":"1787079500000000000","run_id":"run-governed-sdlc-001","span_id":"00f067aa0ba902b7","spec_version":"0.1.0-alpha.4","time_unix_nano":"1787079580000000000","trace_id":"4bf92f3577b34da6a3ce929d0e0e4736"} +{"action_digest":{"algorithm":"sha256","value":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"},"actor_id":"reviewer-7d91","actor_type":"human","agent_id":"spiffe://example.test/agent/coder","approval_id":"approval-001","event_id":"018f0f7d-7a13-7cc2-8000-000000000002","event_type":"approval.approved","producer":{"name":"example-approval-adapter","version":"0.1.0"},"requested_at_unix_nano":"1787079500000000000","run_id":"run-governed-sdlc-001","span_id":"00f067aa0ba902b7","spec_version":"0.1.0-alpha.5","time_unix_nano":"1787079580000000000","trace_id":"4bf92f3577b34da6a3ce929d0e0e4736"} diff --git a/conformance/fixtures/valid/data-flow.json b/conformance/fixtures/valid/data-flow.json index a41c4df..2927b46 100644 --- a/conformance/fixtures/valid/data-flow.json +++ b/conformance/fixtures/valid/data-flow.json @@ -1 +1 @@ -{"agent_id":"spiffe://example.test/agent/architect","classification":{"producer":"example-dlp","taxonomy":"example.enterprise.v1","value":"confidential"},"content_digest":{"algorithm":"sha256","value":"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"},"destination":{"id":"architecture-agent","kind":"agent"},"direction":"read","event_id":"018f0f7d-7a13-7cc2-8000-000000000004","event_type":"data_flow.observed","policy_decision":"allow","producer":{"name":"example-dataflow-adapter","version":"0.1.0"},"purpose":"generate_architecture","run_id":"run-governed-sdlc-001","size_bytes":18342,"source":{"id":"requirements-graph","kind":"knowledge_graph"},"spec_version":"0.1.0-alpha.4","time_unix_nano":"1787079400000000000","transformation":"metadata_only"} +{"agent_id":"spiffe://example.test/agent/architect","classification":{"producer":"example-dlp","taxonomy":"example.enterprise.v1","value":"confidential"},"content_digest":{"algorithm":"sha256","value":"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"},"destination":{"id":"architecture-agent","kind":"agent"},"direction":"read","event_id":"018f0f7d-7a13-7cc2-8000-000000000004","event_type":"data_flow.observed","policy_decision":"allow","producer":{"name":"example-dataflow-adapter","version":"0.1.0"},"purpose":"generate_architecture","run_id":"run-governed-sdlc-001","size_bytes":18342,"source":{"id":"requirements-graph","kind":"knowledge_graph"},"spec_version":"0.1.0-alpha.5","time_unix_nano":"1787079400000000000","transformation":"metadata_only"} diff --git a/conformance/fixtures/valid/evidence.json b/conformance/fixtures/valid/evidence.json index 539f798..4c059f5 100644 --- a/conformance/fixtures/valid/evidence.json +++ b/conformance/fixtures/valid/evidence.json @@ -1 +1 @@ -{"capture_profile":"metadata_only","chain_digest":{"algorithm":"sha256","value":"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"},"completeness":"complete","event_id":"018f0f7d-7a13-7cc2-8000-000000000005","event_type":"evidence.run_closed","producer":{"name":"agentrust-telemetry","version":"0.1.0-alpha.4"},"run_id":"run-governed-sdlc-001","sequence":14,"spec_version":"0.1.0-alpha.4","time_unix_nano":"1787079700000000000"} +{"capture_profile":"metadata_only","chain_digest":{"algorithm":"sha256","value":"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"},"completeness":"complete","event_id":"018f0f7d-7a13-7cc2-8000-000000000005","event_type":"evidence.run_closed","producer":{"name":"agentrust-telemetry","version":"0.1.0-alpha.5"},"run_id":"run-governed-sdlc-001","sequence":14,"spec_version":"0.1.0-alpha.5","time_unix_nano":"1787079700000000000"} diff --git a/conformance/fixtures/valid/policy-decision.json b/conformance/fixtures/valid/policy-decision.json index 0ed1216..b0afe51 100644 --- a/conformance/fixtures/valid/policy-decision.json +++ b/conformance/fixtures/valid/policy-decision.json @@ -1 +1 @@ -{"action_type":"repository.write","agent_id":"spiffe://example.test/agent/coder","decision":"deny","enforcement_mode":"enforce","evaluation_duration_ns":182000,"event_id":"018f0f7d-7a13-7cc2-8000-000000000001","event_type":"policy.decision","policy":{"bundle_digest":{"algorithm":"sha256","value":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},"engine":"cedar","engine_version":"4.3.0","policy_id":"repo-write"},"producer":{"name":"example-policy-adapter","version":"0.1.0"},"reason_codes":["BRANCH_PROTECTED"],"resource_type":"git.repository","run_id":"run-governed-sdlc-001","span_id":"00f067aa0ba902b7","spec_version":"0.1.0-alpha.4","time_unix_nano":"1787079600000000000","trace_id":"4bf92f3577b34da6a3ce929d0e0e4736","workflow_id":"workflow-build-feature"} +{"action_type":"repository.write","agent_id":"spiffe://example.test/agent/coder","decision":"deny","enforcement_mode":"enforce","evaluation_duration_ns":182000,"event_id":"018f0f7d-7a13-7cc2-8000-000000000001","event_type":"policy.decision","policy":{"bundle_digest":{"algorithm":"sha256","value":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},"engine":"cedar","engine_version":"4.3.0","policy_id":"repo-write"},"producer":{"name":"example-policy-adapter","version":"0.1.0"},"reason_codes":["BRANCH_PROTECTED"],"resource_type":"git.repository","run_id":"run-governed-sdlc-001","span_id":"00f067aa0ba902b7","spec_version":"0.1.0-alpha.5","time_unix_nano":"1787079600000000000","trace_id":"4bf92f3577b34da6a3ce929d0e0e4736","workflow_id":"workflow-build-feature"} diff --git a/conformance/fixtures/valid/usage.json b/conformance/fixtures/valid/usage.json index 9351525..41fc5a8 100644 --- a/conformance/fixtures/valid/usage.json +++ b/conformance/fixtures/valid/usage.json @@ -1 +1 @@ -{"agent_id":"spiffe://example.test/agent/coder","cost":{"amount":0.0124,"currency":"USD","pricing_version":"provider-2026-08-01","source":"provider"},"event_id":"018f0f7d-7a13-7cc2-8000-000000000003","event_type":"usage.recorded","input_tokens":4200,"operation":"chat","output_tokens":812,"producer":{"name":"example-usage-adapter","version":"0.1.0"},"provider":"example-ai","request_model":"example-model-2","run_id":"run-governed-sdlc-001","scope":"model_call","spec_version":"0.1.0-alpha.4","time_unix_nano":"1787079590000000000","workflow_id":"workflow-build-feature"} +{"agent_id":"spiffe://example.test/agent/coder","cost":{"amount":0.0124,"currency":"USD","pricing_version":"provider-2026-08-01","source":"provider"},"event_id":"018f0f7d-7a13-7cc2-8000-000000000003","event_type":"usage.recorded","input_tokens":4200,"operation":"chat","output_tokens":812,"producer":{"name":"example-usage-adapter","version":"0.1.0"},"provider":"example-ai","request_model":"example-model-2","run_id":"run-governed-sdlc-001","scope":"model_call","spec_version":"0.1.0-alpha.5","time_unix_nano":"1787079590000000000","workflow_id":"workflow-build-feature"} diff --git a/docs/evidence-chain.md b/docs/evidence-chain.md index 35f254c..70757d1 100644 --- a/docs/evidence-chain.md +++ b/docs/evidence-chain.md @@ -1,6 +1,6 @@ # Evidence chain profile -Status: experimental `rfc8785-jcs-v1` for contract `0.1.0-alpha.4`. +Status: experimental `rfc8785-jcs-v1` for contract `0.1.0-alpha.5`. Each accepted event is validated and privacy-checked before entering the chain. Sequence numbers start at zero and represent acceptance order, not event time. diff --git a/docs/otel-genai-compatibility.md b/docs/otel-genai-compatibility.md index df11100..b427fc3 100644 --- a/docs/otel-genai-compatibility.md +++ b/docs/otel-genai-compatibility.md @@ -1,6 +1,6 @@ # OpenTelemetry GenAI compatibility -Status: pinned compatibility assessment for AgentTrust contract `0.1.0-alpha.4`. +Status: pinned compatibility assessment for AgentTrust contract `0.1.0-alpha.5`. The machine-readable matrix is [`compatibility/otel-genai.json`](../compatibility/otel-genai.json). It is pinned to OpenTelemetry's dedicated GenAI semantic-conventions repository diff --git a/docs/otel-projection.md b/docs/otel-projection.md index df408a3..3256d04 100644 --- a/docs/otel-projection.md +++ b/docs/otel-projection.md @@ -1,6 +1,6 @@ # OpenTelemetry projection profile -Status: experimental for contract `0.1.0-alpha.4`. +Status: experimental for contract `0.1.0-alpha.5`. The normalized JSON event is the source contract. OpenTelemetry is a projection, not an alternative event model. diff --git a/examples/manual_governance.py b/examples/manual_governance.py index e23a616..0c0f0db 100644 --- a/examples/manual_governance.py +++ b/examples/manual_governance.py @@ -14,7 +14,7 @@ def emit(self, record): event = { - "spec_version": "0.1.0-alpha.4", + "spec_version": "0.1.0-alpha.5", "event_id": str(uuid.uuid4()), "event_type": "policy.decision", "time_unix_nano": str(time.time_ns()), diff --git a/packages/typescript/README.md b/packages/typescript/README.md index c6cf8e1..04973a3 100644 --- a/packages/typescript/README.md +++ b/packages/typescript/README.md @@ -1,6 +1,6 @@ # `@agentrust-io/telemetry` -TypeScript reference SDK for the AgentTrust Telemetry `0.1.0-alpha.4` contract. +TypeScript reference SDK for the AgentTrust Telemetry `0.1.0-alpha.5` contract. This alpha Node package validates the same closed schemas and metadata-only privacy profile as the Python SDK. It supplies event construction, caller-owned diff --git a/packages/typescript/package-lock.json b/packages/typescript/package-lock.json index e2309c5..b5ac3d0 100644 --- a/packages/typescript/package-lock.json +++ b/packages/typescript/package-lock.json @@ -1,12 +1,12 @@ { "name": "@agentrust-io/telemetry", - "version": "0.1.0-alpha.4", + "version": "0.1.0-alpha.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@agentrust-io/telemetry", - "version": "0.1.0-alpha.4", + "version": "0.1.0-alpha.5", "license": "MIT", "dependencies": { "@opentelemetry/api": "^1.9.0", diff --git a/packages/typescript/package.json b/packages/typescript/package.json index 8f8e5c7..da6642a 100644 --- a/packages/typescript/package.json +++ b/packages/typescript/package.json @@ -1,6 +1,6 @@ { "name": "@agentrust-io/telemetry", - "version": "0.1.0-alpha.4", + "version": "0.1.0-alpha.5", "description": "TypeScript reference SDK for AgentTrust governance telemetry", "keywords": ["ai-agents", "governance", "opentelemetry", "observability", "telemetry"], "type": "module", diff --git a/packages/typescript/schemas/envelope.schema.json b/packages/typescript/schemas/envelope.schema.json index 04192b9..0a15fa4 100644 --- a/packages/typescript/schemas/envelope.schema.json +++ b/packages/typescript/schemas/envelope.schema.json @@ -4,7 +4,7 @@ "type": "object", "required": ["spec_version", "event_id", "event_type", "time_unix_nano", "run_id", "producer"], "properties": { - "spec_version": {"const": "0.1.0-alpha.4"}, + "spec_version": {"const": "0.1.0-alpha.5"}, "event_id": {"$ref": "common.schema.json#/$defs/event_id"}, "event_type": {"type": "string", "pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)+$", "maxLength": 128}, "time_unix_nano": {"$ref": "common.schema.json#/$defs/time_unix_nano"}, diff --git a/packages/typescript/src/factory.ts b/packages/typescript/src/factory.ts index 241b43e..a33da5f 100644 --- a/packages/typescript/src/factory.ts +++ b/packages/typescript/src/factory.ts @@ -26,7 +26,7 @@ export class EventFactory { if (collisions.length) throw new Error(`payload cannot override envelope fields: ${collisions.join(", ")}`); const normalizedPayload = Object.fromEntries(Object.entries(payload).map(([key, value]) => [key, key.endsWith("_at_unix_nano") ? unixNano(value) : value])); const event = { - spec_version: "0.1.0-alpha.4" as const, + spec_version: "0.1.0-alpha.5" as const, event_id: fields.eventId ?? this.eventIdFactory(), event_type: eventType, time_unix_nano: unixNano(fields.timeUnixNano ?? this.clockNs()), run_id: fields.runId, producer: structuredClone(this.#producer), ...normalizedPayload, diff --git a/packages/typescript/src/types.ts b/packages/typescript/src/types.ts index eb1d9a1..ab211c1 100644 --- a/packages/typescript/src/types.ts +++ b/packages/typescript/src/types.ts @@ -1,6 +1,6 @@ export type Scalar = string | number | boolean; export type NormalizedEvent = Record & { - spec_version: "0.1.0-alpha.4"; + spec_version: "0.1.0-alpha.5"; event_id: string; event_type: string; time_unix_nano: string; diff --git a/packages/typescript/test/trace-finalizer.test.ts b/packages/typescript/test/trace-finalizer.test.ts index 4cc4002..b7bc238 100644 --- a/packages/typescript/test/trace-finalizer.test.ts +++ b/packages/typescript/test/trace-finalizer.test.ts @@ -21,7 +21,7 @@ test("finalizer derives claims then signs, validates, and self-verifies", () => }); test("tool transcript uses the shared RFC 8785 sequence/event digest", () => { const record = finalizeTrace(snapshot([fixture("action.json")]), config, {signingKey: "private", codec: new RecordingCodec()}); - assert.deepEqual(record.tool_transcript, {hash: "sha256:a1361148f34e3ce16db7a2620572ada7c0cbe830eb7da1027f5837e00e3d5929", call_count: 1}); + assert.deepEqual(record.tool_transcript, {hash: "sha256:69ff36176ca16383fc3c7dc99b488342691a44572c7361673a5fa9fed6b46789", call_count: 1}); const changed = fixture("action.json"); changed.outcome = "error"; changed.error_type = "remote_error"; assert.notEqual((finalizeTrace(snapshot([changed]), config, {signingKey: "private", codec: new RecordingCodec()}).tool_transcript as Record).hash, (record.tool_transcript as Record).hash); }); diff --git a/pyproject.toml b/pyproject.toml index 753e42e..29b172d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "agentrust-telemetry" -version = "0.1.0a4" +version = "0.1.0a5" description = "Backend-neutral governance telemetry for AI-agent runtimes" readme = "README.md" requires-python = ">=3.10" diff --git a/spec/VERSION b/spec/VERSION index cd68566..8dc312c 100644 --- a/spec/VERSION +++ b/spec/VERSION @@ -1 +1 @@ -0.1.0-alpha.4 +0.1.0-alpha.5 diff --git a/spec/schema/envelope.schema.json b/spec/schema/envelope.schema.json index 04192b9..0a15fa4 100644 --- a/spec/schema/envelope.schema.json +++ b/spec/schema/envelope.schema.json @@ -4,7 +4,7 @@ "type": "object", "required": ["spec_version", "event_id", "event_type", "time_unix_nano", "run_id", "producer"], "properties": { - "spec_version": {"const": "0.1.0-alpha.4"}, + "spec_version": {"const": "0.1.0-alpha.5"}, "event_id": {"$ref": "common.schema.json#/$defs/event_id"}, "event_type": {"type": "string", "pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)+$", "maxLength": 128}, "time_unix_nano": {"$ref": "common.schema.json#/$defs/time_unix_nano"}, diff --git a/src/agentrust_telemetry/__init__.py b/src/agentrust_telemetry/__init__.py index ef9249b..e5f59c1 100644 --- a/src/agentrust_telemetry/__init__.py +++ b/src/agentrust_telemetry/__init__.py @@ -77,4 +77,4 @@ "finalize_trace", ] -__version__ = "0.1.0a4" +__version__ = "0.1.0a5" diff --git a/src/agentrust_telemetry/adapters/base.py b/src/agentrust_telemetry/adapters/base.py index 28541a6..269fd9e 100644 --- a/src/agentrust_telemetry/adapters/base.py +++ b/src/agentrust_telemetry/adapters/base.py @@ -55,7 +55,7 @@ def build( raise ValueError(f"payload cannot override envelope fields: {collision}") timestamp = self._clock_ns() if time_unix_nano is None else time_unix_nano event: dict[str, Any] = { - "spec_version": "0.1.0-alpha.4", + "spec_version": "0.1.0-alpha.5", "event_id": event_id or str(self._event_id_factory()), "event_type": event_type, "time_unix_nano": _unix_nano(timestamp), diff --git a/src/agentrust_telemetry/schemas/envelope.schema.json b/src/agentrust_telemetry/schemas/envelope.schema.json index 04192b9..0a15fa4 100644 --- a/src/agentrust_telemetry/schemas/envelope.schema.json +++ b/src/agentrust_telemetry/schemas/envelope.schema.json @@ -4,7 +4,7 @@ "type": "object", "required": ["spec_version", "event_id", "event_type", "time_unix_nano", "run_id", "producer"], "properties": { - "spec_version": {"const": "0.1.0-alpha.4"}, + "spec_version": {"const": "0.1.0-alpha.5"}, "event_id": {"$ref": "common.schema.json#/$defs/event_id"}, "event_type": {"type": "string", "pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)+$", "maxLength": 128}, "time_unix_nano": {"$ref": "common.schema.json#/$defs/time_unix_nano"}, diff --git a/tests/test_repository_gates.py b/tests/test_repository_gates.py index e801afc..68f0e9a 100644 --- a/tests/test_repository_gates.py +++ b/tests/test_repository_gates.py @@ -63,7 +63,7 @@ def test_contract_versions_map_to_ecosystem_spellings(self): "0.1.0-dev": ("0.1.0.dev0", "0.1.0-dev.0"), "0.1.0-alpha.1": ("0.1.0a1", "0.1.0-alpha.1"), "0.1.0-alpha.2": ("0.1.0a2", "0.1.0-alpha.2"), - "0.1.0-alpha.4": ("0.1.0a4", "0.1.0-alpha.4"), + "0.1.0-alpha.5": ("0.1.0a5", "0.1.0-alpha.5"), "0.1.0-beta.2": ("0.1.0b2", "0.1.0-beta.2"), "0.1.0-rc.3": ("0.1.0rc3", "0.1.0-rc.3"), "0.1.0": ("0.1.0", "0.1.0"), @@ -77,10 +77,10 @@ def test_contract_version_rejects_unsupported_spellings(self): check_versions.ecosystem_versions("0.1") def test_release_tag_must_match_contract(self): - self.assertEqual(check_release_tag.validate_tag("v0.1.0-alpha.4"), []) + self.assertEqual(check_release_tag.validate_tag("v0.1.0-alpha.5"), []) self.assertEqual( check_release_tag.validate_tag("v0.1.0"), - ["release tag 'v0.1.0' must equal 'v0.1.0-alpha.4'"], + ["release tag 'v0.1.0' must equal 'v0.1.0-alpha.5'"], ) def test_otel_matrix_matches_shipped_projection(self): diff --git a/tests/test_trace_adapter.py b/tests/test_trace_adapter.py index bd930ee..1be7fd1 100644 --- a/tests/test_trace_adapter.py +++ b/tests/test_trace_adapter.py @@ -74,7 +74,7 @@ def test_action_events_create_truthful_tool_transcript(self): self.assertRegex(record["tool_transcript"]["hash"], r"^sha256:[0-9a-f]{64}$") self.assertEqual( record["tool_transcript"]["hash"], - "sha256:a1361148f34e3ce16db7a2620572ada7c0cbe830eb7da1027f5837e00e3d5929", + "sha256:69ff36176ca16383fc3c7dc99b488342691a44572c7361673a5fa9fed6b46789", ) changed = fixture("action.json")