Not recorded yet. The lesson below is complete and runnable today — the video is added later without touching this page.
recordings/E5.5.mp4The lesson from the incident lives in a postmortem document nobody reads, and the policy that permitted it is unchanged.
A policy change proposal generated from the root cause record, as a diff with the incident as its evidence.
Generate a policy diff from a root cause record and review what it would have prevented.
The incident produced a fix to what is deployed and no change at all to what is allowed. So the next system built under the same policy reproduces the same conditions, and the postmortem sits in a folder being correct.
propose() will not construct without does_not_fix. A proposal presented as closing the whole class is one nobody reads carefully, and this one says plainly that it leaves the direct API path D1.9 measured. The diff is the deliverable; the postmortem is the reasoning behind it and changes nothing on its own.The policy change as a diff generated from the root cause record, carrying the incident as its evidence and stating what it does not fix — because a change presented as closing everything is one nobody scrutinises.
Most incidents change what is deployed and leave what is allowed untouched, so the next system reproduces the conditions.
State the change as a policy diff with the incident's numbers as the reason, and name what the diff does not fix.
Clauses changed, and the indicators no policy change can fix — which are engineering items, named so they do not fall between functions.
Measure this
| what to measure | denominator or target |
|---|---|
| policy clauses changed | count |
| indicators no policy change can fix | count, named as engineering items |
root cause record
|
v
+--------------------------------------------------------------+
| clause from -> to why |
| mcp.vendor.tool_descriptions trusted -> pinned the |
| tool.call.provenance when present -> altered |
| required, else refuse desc |
| payments.refund.approval >500 -> every amount KCI-03 |
+--------------------------------------------------------------+
|
v
NOT addressed: KCI-04
the policy already required 15 minutes. the control was never built
to meet it -> engineering item, named here so it is not lost between
the two functionsMost incidents end with a change to what is deployed. The policy that permitted the incident is usually untouched — so the next system built under it reproduces the conditions.
Stated as a diff, with the clause as it stands, the new text, and the incident as the reason, the change can be argued with. Stated as a postmortem paragraph, it cannot.
Anchor → E1.0. Recovery that changes only what is deployed leaves the policy that permitted the incident intact, so the next system built under it reproduces the conditions. The diff is what stops the same intervals being measured again next quarter.
The proposal here changes three clauses and explicitly fails to address one indicator — because no policy change can. The policy already required detection within fifteen minutes; the control was simply never built to meet it.
That is an engineering item, not a policy item, and saying so in the proposal is what stops it falling between the two functions forever.
Every 'why' column is a measured number from the incident. A proposal argued on opinions gets decided by whoever is loudest.
The skill — skills/grc/policy-change-proposal/SKILL.md
name: policy-change-proposal
description: >-
Turn a root cause record into a reviewable policy diff with the incident
attached as evidence, and name what the diff does not fix. Use at the end of an
incident, when a postmortem's lessons never reach the policy, or when a
proposed control change needs to be argued on evidence rather than opinion.
allowed-tools: Read, Grep, GlobMost incidents end with a change to what is deployed. The policy that permitted the incident is usually untouched, so the next system built under it reproduces the conditions.
Stated as a diff — clause, old value, new value, and the incident as the reason — the change can be argued with. Stated as a postmortem paragraph, it cannot.
After root-cause-record and kci-fix-validation, with both in hand. Before the incident is closed, because the appetite for a policy change decays fast.
1 — Quote the clause as it stands. A proposal that paraphrases the current policy is arguing with something nobody wrote.
2 — Write the new value as text that could be adopted. Not a direction of travel — the words.
3 — Put the measured number in the "why". "41% of calls carried provenance during the incident" ends an argument that "we should tighten provenance" starts.
4 — Name what the diff does NOT address. A KCI that no policy change fixes is an engineering item, and saying so stops it falling between the two.
5 — Expect the expensive clause to be refused, and say so. A proposal whose every line is easy did not come from a real incident.
Input — a root cause record and four policy clauses, in scripts/policy_change_proposal.py.
Output — one change from a real run:
tool.call.provenance
- recorded when present
+ required; a call without it is refused
why: 41% of calls carried provenance during the incident, so it was optional
{
"incident": "str",
"changes": [{"clause": "str", "from": "str", "to": "str", "why": "str"}],
"unaddressed": ["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 E5.5Then restart your agent and open it in that folder. On Windows, if python3 says Python was not found, use python instead.
Then pick e5-5-proposing-the-policy-change:
| agent | install just for this agent | start it |
|---|---|---|
| Claude Code | python3 scripts/install_skills.py --tool claude --lessons E5.5 | type /e5-5-proposing-the-policy-change |
| GitHub Copilot (VS Code) | python3 scripts/install_skills.py --tool copilot --lessons E5.5 | type /e5-5-proposing-the-policy-change in Chat |
| Cursor | python3 scripts/install_skills.py --tool cursor --lessons E5.5 | type / in Agent chat and search for it |
| Codex | python3 scripts/install_skills.py --tool agents --lessons E5.5 | type $e5-5-proposing-the-policy-change, 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.5Neither 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.5 --out work/cybertravels
python3 scripts/checkpoint.py --at E5.5 --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.
Three clauses changed with the incident as evidence, and KCI-04 named as unaddressed because it is an engineering gap rather than a policy one.
Write the fourth clause — the one your organisation would refuse. A proposal whose every line is easy did not come from a real incident.
Tools used
Skill source: skills/grc/policy-change-proposal