Audit Bundles
Audit Bundles
An ExaminerBundle packages a routing decision, the bitemporal evidence that informed it, and the policy version that was in effect — sealed with a content hash so anyone can verify, independently, that nothing was altered.
compliance For: governance & audit
How it works
-
Gather the material. A routing
decision, the bitemporalevidencestore it cited, and thePolicyRegistryit routed against. -
Build the bundle.
ExaminerBundle.buildseals the decision, the referenced evidence, and the policy as-of the decision into a content-hashed artifact. -
Verify integrity.
verify()recomputes the hash and raisesBundleIntegrityErrorif a byte changed. -
Transport and re-verify.
to_json/from_jsonmove it anywhere; the recipient re-runsverify()to trust it independently.
flowchart LR
A["AgentRouter.route<br/>AgentRoutingDecision"] --> D["ExaminerBundle.build"]
B["InMemoryBitemporalStore<br/>evidence_refs"] --> D
C["PolicyRegistry<br/>policy as-of decision"] --> D
D --> E["content_hash<br/>(SHA-256)"]
E --> F["to_json / from_json"]
F --> G["verify()<br/>raises on tampering"]
Install
pip install briefcase-ai[compliance]from briefcase.compliance import ExaminerBundle, BundleIntegrityErrorBuild a Bundle End to End
This ties together an AgentRouter decision, an InMemoryBitemporalStore of evidence, and a PolicyRegistry, then seals and verifies the result.
from datetime import datetime, timezone
from briefcase.bitemporal import BitemporalRecord, InMemoryBitemporalStorefrom briefcase.routing.policy import ( PolicyRegistry, PolicyVersion, PolicyRule, AgentRouter,)from briefcase.compliance import ExaminerBundle, BundleIntegrityError
# 1. Evidence: a bitemporal store of the facts that inform routing.evidence = InMemoryBitemporalStore()tier_record = BitemporalRecord.new( key="ticket:tier", valid_time=datetime(2026, 5, 1, tzinfo=timezone.utc), value="gold", source="crm",)evidence.append(tier_record)
# 2. Policy: a versioned routing policy in a bitemporal-backed registry.registry = PolicyRegistry()policy = PolicyVersion( policy_id="support_triage", version="2026.05.01", rules=[ PolicyRule( rule_id="gold-to-specialist", condition={"tier": "gold"}, choice="specialist_queue", rationale="gold-tier tickets route to specialist agents", ), ], default_choice="general_queue",)registry.publish(policy, valid_from=datetime(2026, 5, 1, tzinfo=timezone.utc))
# 3. Decision: route a request, citing the evidence that informed it.router = AgentRouter( registry, use_case="support_triage", policy_id="support_triage",)decision = router.route( {"tier": "gold"}, evidence_refs=[tier_record.record_id],)print(decision.selected) # specialist_queue
# 4. Bundle: seal decision + evidence + policy with a SHA-256 content hash.bundle = ExaminerBundle.build(decision, evidence, registry)bundle.verify() # passes — internally consistentprint(bundle.content_hash[:20]) # sha256:...build looks up the policy as-of the decision (decision.decided_at by default, overridable with as_of_transaction_time=) and pulls exactly the evidence records named in decision.evidence_refs. If a referenced record is missing from the store, build raises BundleIntegrityError. Evidence is sorted deterministically so the hash is stable.
Transport and Verify
Serialize to JSON, send it anywhere, re-import, and re-check the hash. This is what makes a bundle tamper-evident in transit: the recipient re-verifies on their own machine, and any byte changed since the build breaks the content hash, so silent edits cannot pass.
payload = bundle.to_json(indent=2)
restored = ExaminerBundle.from_json(payload)restored.verify() # ok — hash recomputed from contents matchesDetect Tampering
The hash covers the decision, policy, evidence, and the as-of timestamp. Change any of them and verify() raises.
restored.evidence[0]["value"] = "platinum"
try: restored.verify()except BundleIntegrityError as exc: print("tamper detected:", exc)Key Classes
| Symbol | Why it matters |
|---|---|
ExaminerBundle.build(decision, evidence_store, policy_registry, *, as_of_transaction_time=None, metadata=None) | Seals the decision, its evidence, and the as-of policy into one artifact. |
ExaminerBundle.verify() | Recomputes the hash; raises BundleIntegrityError on any change. |
ExaminerBundle.to_json() / from_json() | Move the bundle between systems without losing the integrity check. |
ExaminerBundle.content_hash | SHA-256 digest — the tamper-evidence anchor. |
BundleIntegrityError | Raised by build (missing evidence) and verify (hash mismatch). |
Bundles are built from AgentRoutingDecision records (see Versioned Routing Policy) and BitemporalRecord evidence (see Bitemporal Storage).