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:
@@ -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`).
|
||||
Reference in New Issue
Block a user