git:20260804.913c1a8 to git:20260804.f353ae1

56 added, 2 removed. Audit A to A.

---
name: dr-spec-change
description: Translate a captured request into a concrete, bounded change specification (SPEC.md) with per-requirement acceptance checks and recorded assumptions. Use after REQUEST.md exists or gains amendments.
---
# Specify the change
Input: REQUEST.md (re-read it in FULL first, including amendments).
Output: SPEC.md mapping every requirement to concrete work with a
machine-decidable acceptance check. This is the only phase where
interpretation happens, and it happens in writing.
## Procedure
1. For EVERY R in REQUEST.md (no skips — walk the numbers in order),
write a spec item: target files, behavior before → behavior after,
and an acceptance check (a command + expected output, or an
artifact-exists-with-content check). A requirement with no
acceptance check is not specified yet.
2. Resolve each open question Q:
- If the readings differ only in minor detail: pick the smallest
reasonable one and record it under Assumptions with the words
"assumed, operator may override".
- If the readings differ materially (different files, different
behavior, >2x effort): put it in "Questions for operator" and
STOP after committing SPEC.md — present the batched questions.
Never start implementation with a material ambiguity open.
First load `dr-ask-the-right-question` and run each candidate
question through it: the record or the operator's recorded values
answer most of them, and only survivors of its dominance test
belong in the batch (each with a recommendation).
- A mechanism the request NAMES — a fixture to reuse, a file to copy,
a pattern to follow — is a suggestion, not a requirement. Verify it
actually reaches the code this change touches (trace the call path)
before adopting it. If it cannot, that is a material contradiction:
deliver the PROPERTY the requirement wants and record the
contradiction in writing, or fork to the operator. Never adopt a
named mechanism unverified, and never deviate from it silently.
(Recorded misses this rule generalizes: docs/ERRATA.md E10 — a
handover-named fixture that never executed the migrated code;
docs/ERRATA_EXECUTOR.md X11 — a false premise in the authorization
itself.)
3. Frozen-surface contact forecast — mandatory, in writing. Diff the
planned target files against `docs/map/INV-frozen-surfaces.md`'s
surface list and record the verdict in SPEC.md's "Frozen-surface
contact forecast" section; "none expected" counts, but only after
actually checking. ANY plausible contact stops the tranche HERE:
commit SPEC.md and obtain the operator's words before `dr-plan-steps`
runs. Contact discovered at validation is three commits too late —
the tranche that proved it (docs/ERRATA_EXECUTOR.md X9, XE1) was
technically perfect and still could not deliver. For changes that add
data to the typed record, one more guardrail: the absence-tolerant
READER lands before the writer emits, so every existing committed
root stays valid with the new data absent (the rung-4 guardrail
generalized; X8 is the precedent for keeping new fields out of frozen
digests entirely). And a new typed-record OBSERVABLE (field, record
type, finding) needs a sweep probe proposed for it in the spec: a
sweep that never looks at the new data reports "byte-identical"
trivially while proving nothing about it. The probe change is its own
SEPARATE commit — extending `tools/root_sweep.py` resets the
byte-identity baseline, so it never rides the same commit as the
`src/` change it would judge, gets its own before/after capture on an
unchanged tree, and follows the tool's probe rule (assert the
attribute exists before reading it). Build every proposed test,
check, and probe to `dr-execute-step`'s "Durable tests, checks, and
probes" rules — they must survive dramatic repo changes, failing
only when the guarded claim stops being true.
- 4. Set the budget: total estimated changed lines and commits. If over
+ 4. Blast-radius census — mandatory, pasted, BEFORE any fixture-drift
+ prediction. For every symbol and file the spec changes, grep what
+ already asserts on it:
+
+ grep -rn "<symbol>" tests/ docs/map/
+
+ Paste the hit list (or "no hits") into SPEC.md's "Blast-radius
+ census" section and classify EVERY hit: EXPECTED TO MOVE (the
+ design predicts it) or MUST NOT MOVE. A drift forecast written
+ without this census is recall, and recall missed in two consecutive
+ specs — under the MORE capable model both times (rung-5 PARKED P6):
+ rung 4's prediction was too narrow; rung 5's spec predicted nothing
+ and missed a test pinning "exactly one backend", the exact state
+ that rung existed to change. The full gate caught both, three
+ commits later than the census would have.
+ 5. DESIGN-AND-STOP shape. When the deliverable IS the spec (a
+ [DESIGN-AND-STOP] request), two more sections are mandatory, and
+ their discipline is measure-don't-reason (the rung-4 M1-M5
+ precedent, the one design spec that survived contact with the
+ tree unchanged):
+ - **Measurements**: every load-bearing design claim is a pasted
+ command output. A claim with no measurement is an assumption and
+ is moved to Assumptions, where the operator can see it.
+ - **Options**: every considered option priced — files touched,
+ frozen-surface contact, estimated lines, risk — and every
+ rejection cites a measurement, not a preference.
+ 6. Set the budget: total estimated changed lines and commits. If over
~300 lines, propose a split into ordered sub-tranches (each with
its own delivery) rather than one sprawling one.
- 5. Anti-invention pass: re-read SPEC.md and delete anything that does
+ 7. Anti-invention pass: re-read SPEC.md and delete anything that does
not trace to an R or C number. If it felt necessary, it is either
an assumption (record it) or scope creep (PARKED.md).
+ 8. Rubric pass — the last act before committing. Re-read the finished
+ SPEC.md as a REVIEWER, not the author; any "no" routes back to that
+ step before commit:
+ - every R has a spec item with a machine-decidable accept?
+ - blast-radius census pasted (or pasted-empty) and every hit
+ classified?
+ - frozen-surface contact forecast recorded?
+ - every mechanism the request names traced to code it actually
+ reaches?
+ - DESIGN-AND-STOP only: every claim measured, every option priced?
+ - nothing in the spec untraceable to an R/C number?
+ Record the outcome as one line in SPEC.md ("Rubric: n/n yes").
## SPEC.md template
# Spec for: <request headline>
Traces: every item cites R/C numbers. Untraceable items are bugs.
## Items
S1 (R1): <files> | before: <...> | after: <...>
accept: <command> -> <expected>
S2 (R2, C1): ...
## Assumptions (operator may override)
A1 (Q1): <chosen reading, one line, and why it is the smallest>
## Questions for operator (STOP if non-empty)
...
## Out of scope (explicit)
<nearest tempting neighbors, each with "not requested">
## Frozen-surface contact forecast
none expected — checked against INV-frozen-surfaces.md
| <surface>: <why contact is plausible> (STOP — operator words
required before dr-plan-steps)
+ ## Blast-radius census
+ <symbol/file>: <test or map check hit> -> EXPECTED TO MOVE |
+ MUST NOT MOVE
+ (every grep hit listed, none omitted; "no hits" is a valid census)
+
+ ## Measurements (DESIGN-AND-STOP only)
+ M1: <command> -> <pasted output> — supports <claim>
+
+ ## Options (DESIGN-AND-STOP only)
+ A: <files, frozen contact, ~lines, risk> | rejected: cites M<n>
+ B: ... | CHOSEN: cites M<n>
+
## Budget
~<n> lines, <n> commit(s). Frozen surfaces touched: none | <flagged>
+ Rubric: <n>/<n> yes
+
## Exit criteria
- SPEC.md committed and pushed; every R number appears in some item
(or is explicitly marked deferred with the operator's words allowing
it).
+ - The rubric pass ran and its line is in SPEC.md; a spec with no
+ "Rubric:" line was committed without its last check.
- If "Questions for operator" is non-empty: stopped and asked.
- Return to the orchestrator.