Forensics CLI
When entity state looks wrong, you need to know whether the snapshot drifted from the ledger and, if one timeline step caused the damage, how to reverse just that step without rewriting history by hand.
causet forensics is the sandbox CLI for those two jobs:
| Command | Purpose |
|---|---|
replay-check | Re-apply recorded ledger patches and report fields that diverge from the stored snapshot |
repair-plan | Build an inverse __SYSTEM_APPLY_PATCH__ intent from a timeline step’s captured previousValues |
repair-apply | Submit that repair intent through the normal pipeline (explicit — never auto-applied from plan) |
Full flag reference: causet forensics.
Forensics commands are sandbox-only. Prefer cloning into a fork, validating there, then promoting a release — not patching production entities in place.
Why use it
| Situation | Why forensics helps |
|---|---|
| Snapshot looks wrong vs history | replay-check tells you if storage/replication drifted — without re-running today’s product rules |
| One bad intent corrupted fields | repair-plan / repair-apply restore fields using values recorded on that step |
| You need an audit trail | Repairs are new intents tagged repair_source=generate_repair_plan, not silent DB edits |
| You’re not sure which step to undo | Pair with inspect timeline to pick the decision ID |
Do not use forensics when:
- Many entities need the same product fix → use bulk
recovery repairwith a compensating action - Ops weren’t invertible (no
previousValue) → define a compensating action in your.causetapp - You want “re-run today’s rules on old intents” → that is a different product concern (fork + new release + compensating intents)
Mental model
| Concept | Meaning |
|---|---|
| Timeline / cursor | Per-entity ordered history. Cursor N means “through decision N” for that entity |
| Decision ID | UUID primary key of one decision_routes row — the same id shown on a timeline step |
| Repair | A new intent that corrects state (inverse system patch). It does not delete the bad step |
| Replay-check | Re-apply recorded patches and compare to the snapshot. Does not re-evaluate product rules |
Repairs always go through the normal intent pipeline. System patches use __SYSTEM_APPLY_PATCH__ and require a repair_source tag — you cannot submit them as ordinary public intents.
Prerequisites
causet login
causet context show
causet context use fork sandbox # recommendedSandbox-gated: causet forensics … refuses to run outside the sandbox environment.
Interactive usage
With no subcommand (or missing flags) in a terminal, the CLI prompts:
causet forensics
# → menu: replay-check / repair-plan / repair-apply| Subcommand | Prompts for |
|---|---|
replay-check | Stream (picker), entity, from-cursor |
repair-plan | Decision / timeline step ID |
repair-apply | Decision ID or plan file path; confirms before apply when generating from a decision |
Non-interactive / --json / CI still require flags.
Detect storage drift (replay-check)
causet forensics replay-check \
--stream order_stream \
--entity order-123 \
--from-cursor 5Re-applies ledger patches from --from-cursor and compares the recomputed state to the stored snapshot at head.
| Result | Meaning |
|---|---|
| No diverged fields | Snapshot matches ledger patches |
| Diverged fields listed | Storage/replication drift — not “rules would produce a different result today” |
Undo one timeline step (repair-plan → repair-apply)
1. Find the decision ID
causet inspect timeline --entity order-123 --stream order_streamCopy the step’s id (UUID). That is the decision ID — the primary key of the decision_routes row forensics loads.
2. Generate a plan (does not apply)
causet forensics repair-plan --decision <decision-uuid>
# Optional: save for review
causet forensics repair-plan --decision <decision-uuid> --json > plan.jsonBuilds a __SYSTEM_APPLY_PATCH__ intent that restores fields using captured previous values. Review strategy, affected fields, and intent JSON before applying.
If generation fails (success=false), the strategy usually means a non-invertible op (no previousValue). Fall back to a product compensating action + bulk repair.
3. Apply explicitly
causet forensics repair-apply --decision <decision-uuid>
# or
causet forensics repair-apply --plan-file plan.jsonPlans are never auto-applied from repair-plan. Interactive apply from a decision asks for confirmation first.
Suggested workflow
causet fork createorfork branchfrommaininto sandboxcauset inspect timeline --entity …— pick the bad decision IDcauset forensics replay-checkif you suspect snapshot driftcauset forensics repair-plan→ reviewcauset forensics repair-applyon the sandbox fork- Validate with
inspect/ queries /fork diff - Correct production via a product fix + compensating action (or promote a release) — not a silent patch on
main
Choosing the right tool
| Symptom | Tool |
|---|---|
| Snapshot ≠ ledger patches | forensics replay-check |
| Undo one invertible step | forensics repair-plan → repair-apply |
| Many entities / non-invertible ops | recovery repair with app compensating action |
| Recompute stream from patches | recovery replay (sandbox) |
| What-if rewind without mutating current fork | fork branch … --entity stream:id@cursor |
| Missing projection rows after poison events | projection dlq list / dlq replay |
See also
causet forensicsCLI reference — flags, interactive behavior, examples- Timeline — how decision routes are recorded
- Replay — rebuilds, branch from cursor, projection rebuild
- Entity Inspector — scrubber and snapshot rebuild in the control plane
- Forks — isolate repair work from production