feat(plan): read Files by the 1.9 grammar, warn on unticked paths below it [skip-docs]

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-10-12 16:09:25 +02:00
commit 3e1a811c60
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q
6 changed files with 330 additions and 16 deletions

View file

@ -302,6 +302,9 @@ The strongest validation in the entire pipeline. Phase 5.5 (planning-orchestrato
| `PLAN_STEP_REGRESSION_NOT_RUNNABLE` | K10, any version: a step's `Regression:` is not one command the allowlist runs (a pipe, `&&`, no backticks, an unknown runner) | One backticked runner call (`npm test`); a wider check goes in `bash tests/<script>.sh` |
| `PLAN_STEP_ON_FAILURE_UNKNOWN` | K11, any version, warning: `On failure:` does not open with revert / retry / skip / escalate | Open with the word, then the specifics |
| `PLAN_STEP_TESTS_ONLY` | Any version, warning: every file in the step's `Files:` is a test, so the step can never be proven red | Move the test into the step that builds the behaviour |
| `PLAN_STEP_PATH_NOT_FIRST` | 1.9: a `Files:` entry does not open with a backticked path (also `none`, and an empty or absent `Files:`: the step names no file); error, a warning under `--soft` | Open each entry with its backticked path(s), then the description: `` `src/a.mjs` - the parser `` |
| `PLAN_STEP_PATH_NOT_A_PATH` | 1.9: a `Files:` entry opens with a backticked span that is no path (a call `parse()`, an option, a URL); error, a warning under `--soft` | Put the path first; the span goes in the description |
| `PLAN_STEP_PATH_UNTICKED` | Below 1.9, warning: the `Files:` reader found a path outside backticks; the plan is read as before (a warning under `--strict` too) | Backtick the path; from 1.9 an unticked path is refused |
**The plan gate (K3).** `node lib/validators/plan-gate.mjs <plan.md> [--json]` decides whether a plan may go on: **0** = it validates strict, its `## Critic Verdict` matches the current text, no BLOCKER is open, and every open MAJOR was accepted by the operator; **1** = stop, with `reasons` (`PLAN_GATE_INVALID_PLAN`, `PLAN_GATE_VERSION` — below plan_version 1.8, `PLAN_GATE_NO_VERDICT`, `PLAN_GATE_VERDICT_MALFORMED`, `PLAN_GATE_VERDICT_STALE`, `PLAN_GATE_OPEN_BLOCKER`, `PLAN_GATE_ROUNDS_EXHAUSTED`, `PLAN_GATE_OPEN_MAJOR` — rounds left: revise, `PLAN_GATE_OPEN_MAJOR_FINAL` — after the last round: ask the operator) and `warnings` (`PLAN_GATE_OPEN_MAJOR` for majors the operator accepted); **2** = could not read the plan. `--hash <plan.md>` prints the operative hash; Phase 9 takes it before the reviewers read the plan. `--record <plan.md> --reviewed <hash>` reads plan-review-dedup output on stdin (which lists the reviewers that delivered, `sources`) and writes the next round; exit 2 when a reviewer is missing or the plan changed since `--hash`; it refuses round 4 (exit 1, stop and ask) unless `--extra-round` follows the operator's yes, and refuses that flag before the cap is spent. Unrated findings count as blockers. The review log is excluded from the hash only up to its first other heading, so a step placed under it is hashed. `--accept-open <plan.md>` records the operator's "build as is" for the current round's open MAJORs (`accepted_open` in the verdict block, bound to the round and the plan hash; only after the last round; never for a BLOCKER; exit 1 when rounds are left, the verdict is stale, a blocker is open or no major is). Operator decision 2026-10-08: open majors used to be warnings, and a weakness the critics named was built and came back from `/trekreview` as MAJOR. plan-critic and scope-guardian rate on the review catalogue's tiers. The verdict is a trace of the review, not a signature.