Not recorded yet. The lesson below is complete and runnable today — the video is added later without touching this page.
recordings/F3.8.mp4Trying to enumerate every failure mode of a probabilistic system.
Maturity measured by containment, detection and recovery — not prevention.
Re-score your programme on the resilience axis.
You will not prevent every failure of a probabilistic system, and a programme that promises to will be judged on that promise. Designing for recovery is both more honest and more defensible than designing for perfection.
readiness() asks four questions this curriculum has already answered with numbers — time to detect (E1.0), time to stop (E4.4), containment coverage (D1.9's 0.4), reconstructable (D1.10). A programme that cannot fill them in has been enumerating failure modes, which does not terminate, instead of measuring recovery, which does.Organising around recovery rather than around enumerating the failure modes of a probabilistic system, using four numbers this curriculum has already produced.
A programme judged on prevention is judged on something a probabilistic system cannot deliver.
Judge it on three capabilities instead: notice, stop, recover.
Containment, detection and recovery indicators — the same ones E5.4 re-reads after a fix. Prevention has no honest indicator here.
Measure this
| what to measure | denominator or target |
|---|---|
| containment, detection and recovery indicators | the same three E5.4 re-reads after a fix; prevention has no honest indicator here |
perfection resilience +------------------+ +-------------------------+ | prevent every | | detect fast | | failure | vs | contain small | | | | recover cheaply | +------------------+ | accept a named loss | judged on the promise +-------------------------+ for a probabilistic system only one of these is a promise you can keep
The last lesson, and the one that reframes everything before it.
You will not prevent every agentic failure. The systems are non-deterministic, the attack surface is novel, and the change surface bypasses your change process (E1.2). A programme judged on prevention is judged on something it cannot deliver, and it will report success right up until the first real incident.
Judge it on three capabilities instead, each independently testable, none of them prevention:
A programme with all three survives a failure it did not predict, which is the only kind that actually happens. Perfection would mean containment never fails. Resilience means the other five steps work when it does.
Anchor → F1.1. Resilience is measured by the containment, detection and recovery indicators — the same ones E5.4 re-reads after a fix. Prevention has no honest indicator on a system that changes weekly, which is why the maturity model does not use one.
Three properties for the day a control fails: drift detected, stop tested, run replayable. The skill checks each with its evidence — a measured twelve-second stop, tested 41 days ago — and reports three verdicts rather than one score.
governance/programme.py's readiness() asks four questions this curriculum has already produced numbers for — time to detect, time to stop, containment coverage, reconstructable. durable() asks the fifth, which is about the programme rather than the system: what fraction of what was learned became an artefact, and what fraction the next engagement will rediscover at full price.
The skill — skills/programme/resilience-readiness-check/SKILL.md
name: resilience-readiness-check
description: >-
Check the three properties a programme needs for the day a control fails —
drift is detected, the stop mechanism is tested, and the run is replayable —
and report which are not ready. Use as a standing readiness check rather than
after an incident.
allowed-tools: Read, Grep, GlobA programme cannot prevent every failure and does not need to. What it needs is that when a control fails, somebody notices, somebody can stop it, and somebody can reconstruct what happened. Each of the three is testable today, and each fails quietly if nobody tests it.
As a standing quarterly check, before granting unattended autonomy, and as the closing item of a programme review.
1 — Detection: compare today against the signed-off baseline. Not "do we have monitoring" — run the comparison and report the drift and any new tool. A monitor that has never been compared against a baseline is untested.
2 — Stop: check the mechanism, the measurement and the date. A named mechanism, a measured time-to-stop in seconds, and when it was last exercised. A test older than a quarter is a claim.
3 — Replay: check the run record has the five inputs — prompts, tool results, model version, seed, retrieved context — and confirm the delegation chain and the resources reached are recorded.
4 — Report each as ready or not, with the missing item named. Three booleans and three sentences. A single readiness score hides which of the three is missing, and they have different owners.
5 — Re-run after every change to any of the three. A model upgrade invalidates the drift baseline; a platform change invalidates the stop test.
Input — the fixture committed at the top of scripts/resilience_readiness_check.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:
NOTICE drift 0.500 new tools ['run_shell'] → detected
STOP 12s, tested 41d ago, survives restart True → ready
RECOVER replayable True, scope from the chain ['queue', 'repo-core', 'repo-payments'] → ready
programme containment ASR outcome when containment fails
------------------------------------------------------------------------------------------------
prevention only 0% undetected — found by a third party, weeks later
elapsed to resolution: 720h
prevention + notice 0% detected, cannot halt it — damage continues while you improvise
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.
{
"detection": {"baseline_at": "str", "drift": 0.0, "new_tools": ["str"], "ready": true},
"stop": {"mechanism": "str", "measured_seconds": 0, "last_tested": "str", "ready": true},
"replay": {"inputs_present": ["str"], "missing": ["str"], "chain_recorded": true,
"resources_recorded": true, "ready": true},
"verdict": {"ready": false, "missing": ["str"]}
}
The skill — skills/research/research-durability-check/SKILL.md
name: research-durability-check
description: >-
Separate a folklore claim from a research result, and score a finding backlog
on whether each finding became a control, a detection, or nothing. Use when
justifying a research function, or when last year's findings cannot be traced
to anything that changed.
allowed-tools: Read, Grep, GlobA finding that closed a ticket is a fix. A finding that became a control or a detection is institutional capital, and the difference is measurable — which means a research programme can be defended with a number rather than with enthusiasm.
Reviewing a research backlog, defending the function's budget, or deciding what "done" means for a finding.
1 — Test each claim for actionability. Three gaps disqualify it: no reproduction, no affected-version statement, no stated condition under which it does not hold. A card failing any of them is folklore, however true it is.
2 — Classify each closed finding by outcome. A control, a detection, an eval case, or nothing — a patch with no accompanying control counts as nothing for this purpose, because the class recurs.
3 — Compute durability. The share of findings that produced a control or a detection. It is usually about half, and the half that produced nothing is usually the more interesting work.
4 — Look at what the lost half had in common. Typically: no owner outside the research team, or a finding whose class had no control to attach to. Both are addressable and neither is about effort.
5 — Define closure to require an outcome. A finding is closed when it has a control, a detection or an explicit accepted-risk record with an owner. Anything else reopens as the same finding next year.
Input — the fixture committed at the top of scripts/research_durability_check.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:
=== folklore — actionable: False ===
CLAIM our review agent can be tricked by comments in diffs
SETUP the review agent
TRIGGER a comment
OBSERVED it approved something it shouldn't
RATE not measured
HOLDS WHEN
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.
{
"claims": [{"name": "str", "actionable": false, "gaps": ["reproduction", "versions", "conditions"]}],
"backlog": [{"finding": "str", "outcome": "control|detection|eval|none", "owner": "str|null"}],
"durability": 0.0,
"lost": {"count": 0, "common_cause": "str"},
"closure_definition": "str"
}
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 F3.8Then restart your agent and open it in that folder. On Windows, if python3 says Python was not found, use python instead.
Then pick f3-8-resilience-over-perfection:
| agent | install just for this agent | start it |
|---|---|---|
| Claude Code | python3 scripts/install_skills.py --tool claude --lessons F3.8 | type /f3-8-resilience-over-perfection |
| GitHub Copilot (VS Code) | python3 scripts/install_skills.py --tool copilot --lessons F3.8 | type /f3-8-resilience-over-perfection in Chat |
| Cursor | python3 scripts/install_skills.py --tool cursor --lessons F3.8 | type / in Agent chat and search for it |
| Codex | python3 scripts/install_skills.py --tool agents --lessons F3.8 | type $f3-8-resilience-over-perfection, 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 F3.8Neither 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 F3.8 --out work/cybertravels
python3 scripts/checkpoint.py --at F3.8 --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.
Drift is detected with run_shell as a new tool, the stop mechanism is ready at 12 seconds tested 41 days ago, and the run is replayable with a four-resource scope. All three programmes show a 0% containment ASR yet resolve a failure in 720, 96 and 6 hours respectively. The game day identifies the weakest capability for each, and the resilient programme has none.
Run a game day that assumes containment failed. Measure notice, stop and recover as three separate numbers. The weakest one is next quarter's plan — and unlike a prevention target, you can actually reach it.
What you can do now. A programme sequenced on which indicators sit furthest from target, staffed by people who can turn a control into something computable, governed by autonomy level rather than product list, with promotion as an earned event and a maturity model measured on containment, detection and recovery rather than on prevention.
What you still cannot do. Nothing here is finished, because none of it holds still. The models change, the patterns change, and the risks in B1 will not be the last fifteen. What you have is a method for the next set, not a solution to this one.
Go back to B1.1 and draw your own system again. It will be a different picture from the one you drew before Function C, and the components you left off the first time are the ones worth your next quarter.
Skill source: skills/programme/resilience-readiness-check