Summary
Implement the TrustRecord dataclass and the mapping function from a closed AGT session to a TRACE v0.2 Trust Record payload. This is the data model layer -- no signing, no sink, no config yet.
Scope
New file: agent-governance-python/agent-mesh/src/agentmesh/governance/trace_model.py
Fields to map:
| TRACE field |
Source |
eat_profile |
Constant "tag:agentrust.io,2026:trace-v0.1" |
iat |
AuditEntry.timestamp (latest entry) converted to Unix epoch seconds |
subject |
session.agent_did directly (TRACE v0.2 accepts did: natively -- no SPIFFE config needed) |
model |
Config-injected dict (provider, model_id, version, weights_digest) |
runtime |
Config-injected; platform: "software-only", measurement: "sha256:" + "0"*64 |
policy.bundle_hash |
SHA-256 of Cedar policy bundle bytes, captured at PolicyInterceptor load time |
policy.enforcement_mode |
Config: "enforce" or "advisory" |
data_class |
SessionState.monotonic_data_class |
build_provenance |
Config-injected (slsa_level, builder, digest) |
appraisal.status |
"affirming" if zero deny decisions in session, else "contraindicated" |
appraisal.verifier |
Config-injected URI |
transparency |
Empty string for Phase 1 |
tool_transcript.hash |
sha256: + SHA-256 of RFC 8785 JCS-canonical JSON of the AuditEntry list |
tool_transcript.call_count |
Count of tool_invocation entries in the chain |
Change to PolicyInterceptor: capture policy_bundle_hash at load time (hashlib.sha256(bundle_bytes).hexdigest()) and store on the interceptor instance so the sink can read it at session close.
No changes to AuditEntry, MerkleAuditChain, or SessionState structure.
Acceptance criteria
References
Summary
Implement the
TrustRecorddataclass and the mapping function from a closed AGT session to a TRACE v0.2 Trust Record payload. This is the data model layer -- no signing, no sink, no config yet.Scope
New file:
agent-governance-python/agent-mesh/src/agentmesh/governance/trace_model.pyFields to map:
eat_profile"tag:agentrust.io,2026:trace-v0.1"iatAuditEntry.timestamp(latest entry) converted to Unix epoch secondssubjectsession.agent_diddirectly (TRACE v0.2 acceptsdid:natively -- no SPIFFE config needed)modelruntimeplatform: "software-only",measurement: "sha256:" + "0"*64policy.bundle_hashPolicyInterceptorload timepolicy.enforcement_mode"enforce"or"advisory"data_classSessionState.monotonic_data_classbuild_provenanceappraisal.status"affirming"if zero deny decisions in session, else"contraindicated"appraisal.verifiertransparencytool_transcript.hashsha256:+ SHA-256 of RFC 8785 JCS-canonical JSON of theAuditEntrylisttool_transcript.call_counttool_invocationentries in the chainChange to
PolicyInterceptor: capturepolicy_bundle_hashat load time (hashlib.sha256(bundle_bytes).hexdigest()) and store on the interceptor instance so the sink can read it at session close.No changes to
AuditEntry,MerkleAuditChain, orSessionStatestructure.Acceptance criteria
TrustRecorddataclass with all 11 required TRACE fieldssession_to_trust_record(session, config) -> dictmapping functionPolicyInterceptorstorespolicy_bundle_hashat load timesubjectis derived fromsession.agent_did(e.g.did:mesh:spiffe://...)appraisal.status = "contraindicated"References