Repository navigation
v3.11.2 — the output object, typed and exercised
Four findings on the planner output, and on reading them together they are the same finding: the schema types an object nobody had ever built.
A plan could invent a prerequisite id, rewrite the title of the knowledge base row it cites, reclassify a required obligation as recommended, flip blocking to false on a real blocker, confirm a row with an evidence id naming no record, cite the same record twice, contradict its own summary counts, and declare itself ready over two known-missing blockers. Every one of those was forbidden in prose by the output contract and enforced by nothing.
What the schema can say, it says
ready requires the three blocking counts at zero. blocked requires at least one missing blocker. unknown_requires_assessment requires none missing and at least one unknown. A refusal no longer carries a source register, unknowns or assumptions: the branch already forbade seven plan fields and left four behind, which is the shape of almost every defect in this review. And an evidence id cannot appear twice on a row.
The rest is not expressible in a schema
tools/validate-plan.mjs derives the counts and the status from the rows, checks every id against the knowledge base, compares each carried row against its source for title, requirement type and blocking, resolves every accepted-evidence id against the plan's own register, and refuses a confirmation resting on neither a question nor a record. Three invariants were added to state all of it, 19 to 22.
Why all four survived
No plan object existed anywhere in the repository. The output schema had been typing something nobody had built, so nothing exercised the rules the contract had been stating for releases.
There is one now, generated from the knowledge base so it is right by construction, with thirteen mutations the validator must reject for the stated reason rather than merely reject. Removing a validator check makes its mutation pass, which is what makes the gate worth having rather than decorative.
The skill declares no execution tool, so it cannot run the validator itself. The derivation in the contract is what binds the skill; the validator proves that derivation on every plan the repository ships, and a consumer handed a plan can run it. Saying that plainly seemed better than shipping a file the skill cannot reach.
One found on the way
The fork link checker read .md and .json only, so the new reference to a .mjs file resolved to nothing in the fork and the check passed anyway. Sixth round, same blind spot: a check whose real scope is narrower than its name. It reads .mjs and the tools/ prefix now.
3552 prerequisite checks to 3566, 70 advisor gates.