This starts chapter E5. Its course guide is E5 in the Function E course guide →
Not recorded yet. The lesson below is complete and runnable today — the video is added later without touching this page.
recordings/E5.1.mp4Non-determinism as an evidentiary problem.
Log at design time what replay will need.
Replay an agent run for a regulator-grade record.
Forensics on a non-deterministic actor asks a question classical forensics never had to: not just what it did, but what it saw and what it decided. If the context was not recorded, the decision cannot be reconstructed at all.
reconstruct() and adds the evidentiary question the red team did not have to ask. Two things are explicitly not evidence: a rerun of the agent, because non-determinism makes it a different run, and the agent's own account, because that is a claim by the subject of the investigation.Replay as reconstruction from the record rather than a rerun, with the two things that are explicitly not evidence about the run that happened: a second run, and the agent's own account of the first.
Miss one of the four runtime constants and you can describe what happened but never demonstrate it.
Log at design time what a replay will need: prompts, tool results, model version, sampling.
Runs that reproduce identically. The model version is the field most often missing and the one that invalidates the rest.
Measure this
| what to measure | denominator or target |
|---|---|
| runs that reproduce identically | share of runs; the model version is the field most often missing |
classical forensics agentic forensics +------------------+ +----------------------------+ | what did it do | | what did it do | | | | what did it SEE | | | | what did it DECIDE, and why| +------------------+ +----------------------------+ if the context was not recorded, the decision cannot be reconstructed
Forensics for an agent means answering: why did it do that?
For ordinary software the answer is in the code. For an agent the answer is in the run — the prompts, the tool results it saw, the model version, the sampling. Reproduce those four and the run is deterministic. Miss one and you can describe what happened but never demonstrate it, which matters the moment anyone disputes your conclusion.
The field teams miss most often is the model version, and it is the one that silently invalidates everything else: a provider-side upgrade changes the behaviour with no change on your side, so a reconstruction performed after the upgrade does not reproduce the incident that happened before it.
Anchor → E1.0. Recovery starts from a run you can reproduce. Miss one of the four fields — most often the model version — and you can describe what happened but never demonstrate it, which is the moment the interval stops being yours to close.
Replaying a run needs five inputs. A typical production run records three.
The skill checks all five against a real record, then replays the run under two later model versions.
Watch what happens when the model gives a different answer. The original decision then cannot be reproduced at all — not disagreed with, not re-checked. There is no way back to it.
The skill — skills/response/run-replayability-audit/SKILL.md
name: run-replayability-audit
description: >-
Check whether an incident run can be replayed at all — model version, seed,
prompt, tool results, retrieved context — and what a later model version does
to the replay. Use when forensics needs to know why the agent did what it did.
allowed-tools: Read, Grep, Glob"Why did the agent do that" is answerable only if the run can be re-run under the conditions it ran in. That needs the model version, the sampling parameters and seed, the exact prompt, every tool result and the retrieved context. A typical production run records enough to see what happened and not enough to reproduce it.
Before an incident, as a readiness check, and during one, to establish honestly whether the reconstruction is possible.
1 — List the five inputs and check each against a real run record. Model version and seed are the two usually missing, and their absence is decisive rather than inconvenient.
2 — Attempt the replay. If any input is missing, say what the replay can and cannot establish. A partial replay is still useful for the tool path and useless for the reasoning.
3 — Replay under later model versions. The provider has probably upgraded. Record whether the action changes: if it does, the original decision cannot be reproduced at all, and that is a finding about the estate rather than about the incident.
4 — Cost full instrumentation. Storage and latency for recording everything, against the incidents where you needed it. Present both; the answer is usually to instrument the high-tier agents only, and that is a defensible decision when the numbers are attached.
5 — Record what the estate has chosen. Which agents are replayable and which are not, so nobody assumes during an incident.
Input — the fixture committed at the top of scripts/run_replayability_audit.py. Edit it and re-run: the buckets, counts and verdicts below are derived from it, not hard-coded.
Output — the opening lines of a real run:
fully instrumented replayable=True
typical production replayable=False
✗ model version — a silent upgrade changes the output
✗ seed — sampling makes the run unrepeatable
prompts only replayable=False
✗ tool results — the agent saw a world you cannot rebuild
✗ model version — a silent upgrade changes the output
✗ seed — sampling makes the run unrepeatable
The run continues past this. test_skills.py executes the script on every build, with no model configured — so what CI proves is that it runs and refuses legibly, not that it prints these lines. The output above is a recorded run against a real model, and nothing re-diffs it: a model's answer is not reproducible, and this repository does not claim otherwise anywhere it can be checked.
{
"inputs": [{"name": "str", "recorded": false}],
"replay": {"possible": false, "establishes": ["str"], "cannot_establish": ["str"]},
"version_drift": [{"version": "str", "action": "str", "same_as_original": false}],
"cost": {"storage_per_run": "str", "latency_ms": 0},
"policy": [{"tier": "str", "fully_instrumented": true}]
}
Three ways to do this lesson. Pick one. They run the same procedure against the same code — what changes is who drives it, and how much you see.
The agent reads the lesson, explains the idea, fetches the code, runs the check and answers your questions as you go. This is the one to take if you are here to learn.
Install it, once. From the folder you cloned. --all does every agent it finds on your machine:
python3 scripts/install_skills.py --all --lessons E5.1Then restart your agent and open it in that folder. On Windows, if python3 says Python was not found, use python instead.
Then pick e5-1-replay-and-forensics:
| agent | install just for this agent | start it |
|---|---|---|
| Claude Code | python3 scripts/install_skills.py --tool claude --lessons E5.1 | type /e5-1-replay-and-forensics |
| GitHub Copilot (VS Code) | python3 scripts/install_skills.py --tool copilot --lessons E5.1 | type /e5-1-replay-and-forensics in Chat |
| Cursor | python3 scripts/install_skills.py --tool cursor --lessons E5.1 | type / in Agent chat and search for it |
| Codex | python3 scripts/install_skills.py --tool agents --lessons E5.1 | type $e5-1-replay-and-forensics, or run /skills |
No agent, no conversation. The same lesson executes and prints the same readback. Take this one if you have no assistant, if you are reviewing rather than learning, or if you want the result without the teaching around it.
python3 scripts/lesson.py E5.1Neither of the above, and no model needed. The first command writes CyberTravels exactly as it stood at the end of this lesson; the second prints the diff — the lines this lesson added or changed, and nothing from any later one.
python3 scripts/checkpoint.py --at E5.1 --out work/cybertravels
python3 scripts/checkpoint.py --at E5.1 --diffOn Windows, type python wherever these say python3 — and use \ instead of / in the paths. Everything else is identical. A0.0 step 2 explains why.
Ways 1 and 2 need a model; way 3 does not. A signed-in Claude Code CLI needs no API key, and any OpenAI-compatible endpoint works too. With neither, the audit exits 2 and says so rather than inventing an answer. A0.0 sets this up.
Ways 1 and 2 both end with the same readback: What I did, What changed, The number and Read this next. A step that was skipped or refused is reported as exactly that, never as a pass.
If you did the last lesson’s challenge, expect this to stop. Most challenges ask you to edit the code, and ways 1 and 2 will not overwrite your edits: you get stopped, not a failure, with two options — --out for a fresh folder that keeps your work, or --force to discard it and start this lesson clean.
Only the fully instrumented run is replayable; the typical production run is missing the model version and seed. Replaying the incident under two later model versions produces a different action, so the original run does not reproduce. Adding the two cheapest fields (model version and seed) makes the typical production run replayable.
Add model version and seed to your agent's run records this week. Both are one field each, and together they are the difference between forensics and storytelling.
Tools used
Skill source: skills/response/run-replayability-audit