Hand over the M3a plan: 22 tasks, their files, and the check record

Task files, the files they copy in (byte-identical to the reference on
m3a-ref), each area's check record, and a README with the per-task
table of what each check exposed. The handoff note is done with.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-18 23:45:43 -07:00
co-authored by Claude Opus 5
parent 69f0a0a218
commit e3f37da232
180 changed files with 17219 additions and 292 deletions
+103
View File
@@ -0,0 +1,103 @@
# M3a task 21: the runbook gate check
**Branch:** `m3a` (run `git switch m3a`; `git status --short` must be empty, otherwise stop)
**Commit subject:** `Check that every runbook pointer has an entry`
## Goal
Every message for a fail-closed state ends with `see docs/runbook.md#<anchor>`. A new gate script
fails if the code names an entry that `docs/runbook.md` does not have.
## Files
- Copy: `scripts/test-gate-scripts.sh`, and `Makefile` from `docs/plans/M3a/files/Makefile-task21`
(`files/Makefile` is task 22's, with a line that needs a test this task does not have yet)
- Create: `scripts/check-runbook.sh`
- Modify: `docs/implementer-log.md`
You never edit `docs/runbook.md`. If the script finds a missing entry in the real tree, the
pointer in the code is wrong, or the entry is missing: stop and report which.
## What the script does
`sh scripts/check-runbook.sh [ROOT]`, `ROOT` defaulting to `.`, in POSIX `sh` like the other
scripts in `scripts/`. Read `scripts/check-lines.sh` first for the style.
1. A **pointer** is the text `docs/runbook.md#` followed by zero or more characters of
`[A-Za-z0-9_-]`, anywhere in a `*.rs` file under `ROOT/crates`. Files under any `target/`
directory are ignored (`find ... -type d -name target -prune -o -type f -name '*.rs' -print`).
Test files count. A line can hold more than one pointer, and each counts.
2. The pointer's **anchor** is what follows the `#`. Its **entry** is a line of
`ROOT/docs/runbook.md` that is exactly `## <anchor>`: the whole line, nothing before or after
it (`grep -q -x -F -e "## $anchor"`). `### grants-invalid`, `## grants-invalid and more`, a
mention in prose and `## Grants-Invalid` are not the entry for `grants-invalid`.
3. Exit status 0 if every anchor has its entry. Otherwise 1.
Every way it can fail, each with a message on stderr that starts with `check-runbook:`:
| Condition | Why |
|---|---|
| `ROOT/crates` is not a directory | nothing to check: fail closed |
| `ROOT/docs/runbook.md` is not a file | nothing to check against |
| `find`, `awk`, `sort` or `mktemp` fails, or a file cannot be read | a check that cannot do its job fails |
| `grep` exits with a status other than 0 or 1 | 1 means "no such line"; 2 means `grep` itself failed |
| no pointer is found anywhere | the harness has fail-closed states, so the search is broken |
| an anchor is empty, as in `docs/runbook.md#{anchor}` or `docs/runbook.md#<anchor>` | the script cannot read an anchor that is not written out |
| an anchor has no entry | the point of the script |
Rules from earlier reviews, which the self-test checks:
- **Report every problem, not only the first.** Go through all the anchors, print a message for
each one that is missing, and exit 1 at the end. Do not `exit` inside the loop over anchors. For
each missing anchor, name the files that point to it.
- **Never hide an error.** No `2>/dev/null`, no `|| true`. Test each command's exit status.
- A `while read` loop at the end of a pipeline runs in a subshell, and an `exit` or a variable
set inside it is lost. Write the list to a file made with `mktemp -d` and read it with
`while IFS= read -r line; do ...; done < "$file"`. Remove the directory with a `trap ... EXIT`.
- `grep -o` is not POSIX. Take the pointers out of a line with `awk`:
```sh
awk '{
s = $0
while (match(s, /docs\/runbook\.md#[A-Za-z0-9_-]*/)) {
printf "%s\t%s\n", substr(s, RSTART + 16, RLENGTH - 16), FILENAME
s = substr(s, RSTART + RLENGTH)
}
}' "$f"
```
`docs/runbook.md#` is 16 characters, so this prints the anchor, a tab, and the file.
## The Makefile
The copied `Makefile` runs `sh scripts/check-runbook.sh` in `gate`, after `check-dep-docs.sh`.
## Steps
- [ ] **1. Copy.** `git switch m3a`, then
`cp docs/plans/M3a/files/scripts/test-gate-scripts.sh scripts/ && cp docs/plans/M3a/files/Makefile-task21 Makefile`
- [ ] **2. See the self-test fail.** `sh scripts/test-gate-scripts.sh`. Expected: failures that
name `check-runbook.sh` cases, and exit status 1.
- [ ] **3. Write `scripts/check-runbook.sh`.**
- [ ] **4. See the self-test pass.** `sh scripts/test-gate-scripts.sh`. Expected:
`test-gate-scripts: ok`.
- [ ] **5. Prove the self-test has teeth.** Change `-x` to nothing in your `grep` line and run the
self-test: it must fail with "the entry is the whole line, at level two". Change it back. Then
put `exit 1` where a missing anchor is reported and run it: it must fail with "both missing
entries and their files are reported". Change it back. Write both results in the log's Notes.
- [ ] **6. Run it on the real tree.** `sh scripts/check-runbook.sh; echo $?`. Expected: no output
and `0`. If it names a missing entry, stop and report: do not edit the runbook, the pointer or
a copied test.
- [ ] **7. Run the gate.** `make gate`. Expected last line: `gate: ok`.
- [ ] **8. Log and commit.**
`git add scripts/check-runbook.sh scripts/test-gate-scripts.sh Makefile docs/implementer-log.md && git commit`
## Done when
- `sh scripts/test-gate-scripts.sh` prints `test-gate-scripts: ok`; `sh scripts/check-runbook.sh`
exits 0 on the repository; `make gate` prints `gate: ok`.
## Stop and report if
- Step 6 reports a missing entry or an empty anchor.
- `sh` on this machine lacks something the task relies on (`mktemp -d`, `awk`'s `match`).