GUIDE
Migrating from audit logs to receipts
You already log what your systems do. This guide shows you how to upgrade your highest-consequence decisions to Decision Receipts incrementally — mapping the signals you already emit to evidence sources, running in shadow first, then gating — without ripping out a single existing log line.
A log records that something happened. A receipt records why it was allowed to.
An audit log line is a timestamped statement that an event occurred: user X merged PR #42 at 14:03. It is a claim about the past with no attached proof. A Decision Receipt records what happened, on what evidence (the CI run, the review, the approval), under what rules (the policy thresholds that evaluated that evidence), reproducibly (a replay determinism check), and signed (an Ed25519 attestation, hash-chained into a ledger). That is the difference between a record you assert and a record anyone can independently verify. See admissibility for the standard a receipt has to clear, and the ledger and audit chain for how receipts link into a tamper-evident sequence.
You are not replacing your logs. Logs remain the right tool for high-volume, low-stakes events. You are adding an admissibility-grade record for the small set of decisions that warrant defensible proof — and reusing the signals your logs already carry to do it.
The staged migration
Migrate in five stages. Each stage is reversible and adds no enforcement until you decide it should.
1. Pick the highest-consequence decision points first
Do not receipt everything. Start where the cost of being wrong is highest and hardest to undo: production deploys, access changes, and other irreversible actions. Use risk scope to rank candidates — the wider the blast radius, the better the case for a receipt. The action.action_type enum gives you the natural targets: deployment, access_change, infra_change, policy_exception, and merge.
2. Map the signals you already emit to evidence sources
Every receipt carries a sources array — the evidence the policy evaluates. You are almost certainly already producing this evidence; you just emit it as logs and status checks instead of structured sources. Map what you have onto the source type enum, and point each source's uri back at the artifact it came from — including your existing log lines.
| What you emit today | Source type |
|---|---|
| CI pipeline run / build job | ci |
| Test suite result | test_result |
| Pull request review / sign-off | code_review |
| Approval gate (change ticket, manual approve) | human_approval |
| Existing audit log line | runtime_log or manual |
| Agent run trace / tool transcript | agent_trace |
| Deploy target / cloud state | infrastructure |
A source built from an existing log line looks like this — the uri points straight back at the log so the receipt and your log stay reconcilable:
SOURCE FROM AN EXISTING LOG LINE
{
"id": "evd_deploy_log_8842",
"type": "runtime_log",
"uri": "https://logs.acme.internal/deploy/8842",
"confidence": 0.8,
"content": "Deploy gate approved by on-call; change ticket CHG-8842 linked",
"provenance": {
"captured_at": "2026-06-22T14:03:00Z",
"snapshot_id": "snap_deploy_8842",
"collector": "acme-log-shipper",
"chain_of_custody": ["datadog", "decrec-client"]
}
}
3. Start in shadow mode with POST /v1/simulate
POST /v1/simulate runs a full policy evaluation and returns a verdict without persisting a receipt. Wire it into your highest-stakes decision point and send the same body you would send to /v1/evaluate. You get ALLOWED / ESCALATED / BLOCKED verdicts on real traffic while nothing is enforced and nothing is written. This is where you discover that a threshold is too strict, or that a source you assumed you had is actually missing.
SHADOW EVALUATION
curl -s https://decrec.summitcognitive.ai/v1/simulate \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-d @claim-from-deploy-8842.json | jq '.policy.verdict'
4. Flip to POST /v1/evaluate and gate on the verdict
Once the simulated numbers look right, change the endpoint to POST /v1/evaluate — same body — and act on the result. /v1/evaluate persists a signed receipt and returns it. Block the action unless policy.verdict is ALLOWED and receipt.admissibility.status is ACCEPTED; route ESCALATED to a human. The only change between shadow and enforcement is the endpoint and whether you honor the verdict.
5. Keep the receipts and reconcile against your logs
Receipts persist into the ledger. Each receipt.receipt_id corresponds to a gated decision, and because each source's uri points back at the originating log, you can reconcile the two records: every receipt should have a matching log entry, and every high-stakes log entry should, over time, have a receipt. Anyone can re-check a stored receipt with POST /v1/verify or offline against GET /v1/keys/server.
Practical notes
- Provenance is what elevates a log line into evidence. A bare
uriis a pointer; aprovenanceblock (captured_at,collector,chain_of_custody) is what makes the source defensible. SetrequireProvenance: trueinpolicyConfigonce your sources reliably carry it — that is the single biggest jump in admissibility you get from this migration. See evidence and provenance. - Start lenient, tighten via simulate. Begin with a low
minConfidenceand modestminSourcesso early claims pass, then raise thresholds and addrequireProvenance/requireReplaywhile still in/v1/simulate. You will see exactly which decisions would have flipped to BLOCKED before any of them actually do. - Map, don't rewrite. No log gets deleted in this process. Each receipt source references the artifact you already produce, so your existing observability stays intact and the receipt becomes a verifiable layer on top of it.
Both /v1/simulate and /v1/evaluate accept the same body. Build your claim mapping once, point it at /v1/simulate until the verdicts settle, then change one line to enforce.
To enforce this end-to-end on a single decision, work through gate a deploy. To tune the thresholds you simulate against, see custom policies.