Mechanism 1 of 4 · Spec → done
An unanswered question is not a resolved one.
The absence this makes loud: a question nobody answered.
A spec that was never sharpened doesn't produce a warning — it produces work that looks exactly like work against a good spec, right up until you deliver the wrong thing. So Graphban won't let a spec reach "approved" while a dimension of it is still blank.
The grill
Four dimensions, graded — and the grade is not yours to set.
Grilling is a conversation that sharpens a PRD before anyone builds it: unstated assumptions, scope boundaries, failure modes. The server owns it as state, not the client as a chat log — so the record of what was asked and what was actually answered survives the session.
Every grill is graded against the same four dimensions. Each comes back resolved, deferred, or unanswered. Grading is a separate call from the conversation, run at temperature zero, and when the model is unavailable it falls back to a deterministic stub rather than silently passing.
| Dimension | The question it refuses to leave blank |
|---|---|
| scope_edges | What is explicitly out of scope for the first version? |
| failure_modes | What happens on the failure path — bad input, missing data, timeout? |
| contracts | What is the exact shape of the inputs and outputs at the boundary? |
| open_decisions | Which decisions are still open, and which need a prototype to settle? |
Earned, not set
update_prd(status="approved") is a request, not a switch.
The refusal lives in the service layer, not in a route handler, so the REST API, the web UI and the MCP surface are all covered by one check. That placement is the whole point: this call is otherwise exactly how an agent would freeze an intent baseline that nobody had read.
Two more guards sit behind it. A verdict must cite a grill turn that actually resolves the dimension it claims — a citation that doesn't dereference is rejected as malformed. And if the grading standard itself is later found broken, it retroactively invalidates the approvals it granted, because an approval is only as good as the process that granted it.
Zero answers never grades as approved
A grill with no recorded answers is incomplete whatever any model says about it. Without that floor, an empty conversation grades straight through — which is the failure mode this entire mechanism exists to prevent, arriving through the mechanism itself.
The baseline
Approval freezes a version. That version is what the tickets mean.
The moment a PRD earns approval, its body is frozen as a baseline version carrying the per-dimension grill outcomes — so a deferral is visible on the baseline itself, not just in a transcript. Re-approving an unchanged spec is idempotent: it never mints a second "original intent".
decompose_prd then creates one work item per uncovered ## section. The section is the atom of intent, and that choice buys rename detection for free — retitle a section and the work linked under it keeps its identity, so a rename can never manufacture a false absence.
The intent hold
You cannot miss the hold, because it is not a notification.
An agent claims an item, then the spec moves underneath it. Nothing about the item changes. The classic fix is to send a notice — which works exactly as well as everyone remembering to read their notices.
Rebaselining
A rebaseline is a new link in a chain, not an edit.
When intent genuinely moves, you ask for a new baseline in your own words. The request does not approve anything — it re-opens the grill, and the existing baseline keeps governing until a new one is earned on its own answers.
- Append-only. The new baseline points back at the old one; the old one is never touched, so what you promised in March is still readable in August.
- It cannot add sections. New scope is a successor PRD, not a quiet expansion of an approved one — and the refusal fires at the edit that introduces the violation, not at the end of a whole grill you then have to redo.
- It marks prior work classifications stale, recomputed lazily, so a rebaseline on a large PRD never blocks on a hundred model calls.
Verdicts
A verdict cites, and the citation is dereferenced.
Judging whether a section was actually delivered is a job for something holding the repo — so Graphban doesn't guess. It takes a verdict from an agent that does, and then checks the agent's homework by resolving what it cited.
Signing off work you claimed yourself is flagged, not refused — and the separation check has three states, not two: independent, not-independent, and unverifiable. That third state exists because "we have no record of who did the work" must never render as a clean pass.
Completeness
completeness will never tell you it is complete.
Classifying the work that exists can only ever find drift and stowaway scope. It can never surface work that was never done — and "is this PRD finished" is entirely a question about what is missing.
Four things it deliberately refuses to do:
- It does not read the live PRD body, only the frozen baseline — measuring delivery against a spec that moves is how drift becomes definitionally zero.
- It does not judge sufficiency. A linked done item counts as delivered; whether the work actually satisfies the section is the auditing agent's call, because that agent has the repo.
- It does not emit a percentage.
- It does not drop framing sections. The section that defines "done" being structurally exempt from every check is one of the original problems this was built to fix — so framing sections are reported and flagged, not filtered away.
Closing
You close a PRD by deciding, not by finishing.
Closing is terminal and irreversible — no edit, no reopen, no rebaseline afterwards. And it is gated on disposition, never on delivery.
You are allowed to close a PRD having built four of nine sections. You are not allowed to close one without saying what happened to the other five. The close report then measures against the original intent, not the latest rebaseline — so a spec that quietly shrank to match what got built still reads as a spec that shrank.
The library shipped
A spec is more than the PRD file.
The nav calls this Specs. The list is the PRD, its preamble, and the design-set documents, plus the folder they sync to.
Baselined bodies, unless you ask for more
search_docs searches baselined PRD bodies. Drafts and design rows stay out of the result until the call opts in.
A finding stays open until the canvas passes
A set compiles a prompt from the PRD, the constraints, the preamble, and the confirmed tier. put_canvas stores the screen. file_finding can attach a canvas check, and resolve_finding applied stays refused until the bound canvas for the latest compiled prompt passes it.