feat(specify): add spec-production entry path; split brainstorm

Add `specify` as a third co-equal entry path into the dev cycle: it
produces an approved spec from already-settled sources (an exhaustive
issue, a long in-context design discussion, or a design brainstorm just
ratified) with review but no interview. This is the producing half of a
deliberate deciding/producing split — `brainstorm` shrinks to optional
discovery, `specify` becomes the sole spec-production gate before
`planner`, mirroring the RED->GREEN split that keeps tdd/debug honest.

What moved:
- brainstorm/SKILL.md: stripped of the hard-gate, the acceptance
  criterion, write-spec, self-review, grounding-check, user-review, and
  planner-handoff steps; terminal state is now handing a ratified design
  narrative to specify. Steps renumbered 1-5 (production steps left).
- specify/SKILL.md (new): the production core, with a precondition gate
  (Step 1.5) that bounces to brainstorm the moment the sources do not
  resolve a load-bearing decision — the same discipline tdd uses.
- The grounding-check agent moved brainstorm/agents/ -> specify/agents/
  (no-orphan-agents: it lives under its dispatcher), refs repointed.
- boss/SKILL.md: Entry-path reflection is now three-way (tdd / specify /
  brainstorm). specify dispatches autonomously (bounded, no interview)
  and pauses at its user-review gate; only a fresh brainstorm cycle
  stays a pre-dispatch bounce-back.
- pipeline.md, README, profile-schema, the profile template, and the
  migration layout updated so every pipeline rendering agrees; specify
  is a CORE node (not opt-in, unlike tdd) carrying gates: [planner].

Design alternative rejected: parallel sibling skills sharing a
docs/spec-production.md (extract-to-doc). Chosen extract-and-chain
instead — the shared surface is ~70%, so a shared doc would either
become the skill body or drift; chaining keeps one executed home for the
gates.

Verification (prose repo, no test suite): the spec's internal-
consistency grep suite (no two-path drift, no direct brainstorm->planner
edge, specify referenced in every rendering, grounding-check single home
under specify, specify structural completeness) all green. Orchestrator
inspection additionally fixed two dead step-refs the plan under-scoped
(a "(Step 4)" lift-validation pointer and a "Skipping Step 7
self-review" red flag, both pointing at steps brainstorm no longer has)
and corrected six pre-existing brainstorm->planner renderings in
pipeline.md and tdd that predated this cycle.

Known follow-ups (non-blocking): the committed spec writes
`skills/specify/` in places (typo; skill dirs are repo-top-level) — to
be corrected separately. The grounding-check hard-gate was degenerate
for this very cycle (this repo has no profile and no test suite); the
skip is documented in the spec and the session.
This commit is contained in:
2026-06-04 23:11:07 +02:00
parent d4630a538d
commit 4f83305525
10 changed files with 575 additions and 381 deletions
+72 -303
View File
@@ -1,6 +1,6 @@
---
name: brainstorm
description: Use when a new cycle is starting — gathers requirements, explores 2-3 approaches with trade-offs, presents a sectioned design with user approval, writes the spec under paths.spec_dir. Hard-gate before any plan or code work; applies even when the user says they have a clear vision.
description: Use when a new cycle is starting and the design is NOT yet settled — gathers requirements, explores 2-3 approaches with trade-offs, presents a sectioned design with user approval, then hands the ratified design to the specify skill to produce the spec. The optional discovery front-end; when the design is already settled in the sources, skip to specify directly. Applies even when the user says they have a clear vision.
---
# brainstorm — cycle spec generator
@@ -9,14 +9,20 @@ description: Use when a new cycle is starting — gathers requirements, explores
## Overview
The spec is where the orchestrator does the design work. It
is the artefact that future iterations, the architect agent,
and any future reader read to understand WHAT the cycle
delivers and WHY. Skipping the spec means shipping the user's
intuition unfiltered, which is exactly the reactive-deference
failure mode the orchestrator discipline exists to prevent.
Discovery is where the orchestrator does the *deciding* work
surfacing requirements, exploring approaches, and ratifying a design
with the user. It is the front-end that resolves a genuine design fork
before any spec is written. Skipping it when the design is genuinely
open means shipping the user's intuition unfiltered, which is exactly
the reactive-deference failure mode the orchestrator discipline exists
to prevent.
It produces specs under the project's `paths.spec_dir`.
`brainstorm` does not write the spec. Its terminal state is handing the
ratified design to `specify` (the spec-production core), which applies
the acceptance criterion, writes the spec under `paths.spec_dir`, runs
the gates, and takes user sign-off. When the design is *already*
settled in the sources, `brainstorm` is skipped entirely and the work
enters through `specify` directly.
## When to Use / Skipping
@@ -28,37 +34,28 @@ Triggers:
- A cycle-scope spec is missing for an existing line of
work and one is needed retroactively.
**Skipping is permitted only** for:
**Skip `brainstorm` (enter through the named alternative) for:**
- A bug-fix iteration (use `debug` directly).
- A test-specifiable feature, on a project whose profile
enables the `tdd` phase (use `tdd` directly — the RED
executable-spec is the spec, no prose spec needed). The
boundary is the design line: the moment one honest minimal
assertion cannot pin the behaviour without choosing between
plausible designs, `tdd` bounces back here.
- A tidy iteration (use `audit` directly).
- A trivial mechanical edit (per the project's CLAUDE.md
"trivial mechanical edits" carve-out).
- A design already settled in the sources — an exhaustive issue, a
long in-context discussion, settled design docs. Use `specify`
directly: discovery would only re-litigate decisions the sources
already made.
- A test-specifiable feature, on a profile that enables `tdd` — use
`tdd` directly.
- A bug-fix iteration — use `debug` directly.
- A tidy iteration use `audit` directly.
- A trivial mechanical edit per the project's CLAUDE.md carve-out.
**Skipping is not permitted** for:
**Do not skip `brainstorm`** when the design is genuinely open:
- A user request framed as "I have a clear vision, just plan
it".
- A cycle described as "small, only two iterations".
- A cycle where you are confident you know what to build.
- A user request framed as "I have a clear vision, just plan it" whose
vision still hides an unresolved fork.
- A cycle where a load-bearing decision is not yet made.
## The Hard-Gate
```
NO IMPLEMENTATION, SCAFFOLDING, OR DOWNSTREAM SKILL INVOCATION
UNTIL A SPEC HAS BEEN PRESENTED AND THE USER HAS APPROVED IT.
```
The hard-gate applies regardless of perceived simplicity.
The spec can be short for a small cycle (a few sections),
but it MUST exist and be approved before any plan or code
work begins.
The discriminator is the design line: if the sources resolve every
load-bearing decision, the work belongs to `specify`; if writing the
spec would force you to *pick* one, discovery is what resolves it, and
that is `brainstorm`.
## The Process
@@ -76,7 +73,7 @@ Before asking any clarifying questions:
`validated-against` frontmatter if present: `status:
aspirational` means its code is a target, not verified fact.
Track which content you may lift from such a source — it is
flagged for lift-time validation (Step 4).
flagged for lift-time validation when `specify` writes the spec.
- `git log --oneline -20` for the chronological scan.
- Identify scope: is this one cycle, or does it need to be
decomposed into sub-cycles first? If multi-subsystem,
@@ -117,54 +114,7 @@ approach gets:
Wait for user choice before proceeding.
### Step 4 — Apply the project's feature-acceptance criterion
The project's `CLAUDE.md` declares the criterion a feature
must satisfy to ship. Apply it now, prospectively. The
typical shape is some combination of:
- the project's intended audience naturally reaches for the
feature,
- the feature measurably improves correctness or removes
redundancy,
- the feature reintroduces no class of failure the project's
core constraint exists to eliminate.
If the project does not declare a criterion, the default is
"the feature solves a real user-facing problem and does not
contradict a stated design commitment". The orchestrator
applies the criterion; do not delegate it to the user.
**The criterion is unjudgeable without concrete code.** For
any cycle with authoring or consumer surface, the spec MUST
contain the actual program / invocation / configuration a
user would write — and that example *is* the criterion's
empirical evidence. A prose assertion ("a user naturally
reaches for X") with no shown code is exactly the
unfalsifiable hand-wave the criterion exists to prevent:
write the code the user would write, then judge whether it
is in fact what the criterion demands. For an infrastructure
cycle with **no** user surface there is still concrete code:
show the actual code the cycle *delivers* — frequently a
test fixture whose correct behaviour is rejection (wrong
code must fail the relevant check) — plus a *minimal,
honest* slice of the north-star program the infrastructure
exists to serve. "This cycle has no surface so there's no
code to show" is the rationalisation to refuse: an infra
cycle that cannot be tied to concrete code is speculative
infra.
**Code lifted from an aspirational source is a hypothesis, not
evidence.** If the concrete code here is lifted from a
`design_models` file (or any source marked `status: aspirational`,
per Step 1), it carries no validation by default — the marker
exists precisely because no one has run it through the live tool.
Its `design/` location is not ratification. Treat it as the spec's
most suspect bytes: it must clear the Step-7 parse-every-block
gate before PASS. The marker tells you *which* blocks to distrust
first.
### Step 5 — Present design in sections
### Step 4 — Present design in sections
Scale each section to its complexity (a few sentences if
straightforward, up to 200-300 words if nuanced). Cover:
@@ -175,202 +125,43 @@ straightforward, up to 200-300 words if nuanced). Cover:
- Error handling
- Testing strategy
**Concrete code is the headline; the implementation shape is
supporting.** The `## Concrete code shapes` section leads
with the user-facing program (the Step-4 empirical evidence),
or — for an infra cycle — the delivered fixture and a
north-star slice. The before → after implementation shape
(struct / signature / match-arm) follows as a clearly
secondary subsection — "also useful, not the point" — never
first, never a substitute for the user-facing code. Prose may
*explain* code, never *replace* it. Exact bytes / line-
numbers remain the planner's job (planner Iron Law) — the
spec owns the *shape*, shown, with the user-facing program
foremost.
The design you present here is conceptual — the architecture,
components, data flow, error handling, and testing strategy the cycle
commits to. The concrete user-facing code and the before → after
implementation shapes are produced downstream, when `specify`
materialises this ratified design into the spec (and applies the
acceptance criterion against that worked code). Your job here is to get
the *design decision* right and ratified, not to write the artefact.
Ask after each section whether it looks right. Be ready to
revisit earlier sections if a later one surfaces a
contradiction.
### Step 6Write the spec
### Step 5Hand off to `specify`
Path: under `paths.spec_dir`, with a name per the project's
`naming.policy` (see profile schema). Determine the next
slot per the policy (e.g. for `stable_per_directory_4digit`:
look at the latest counter and add 1).
The terminal state of `brainstorm` is invoking `specify`. NO spec file
is written here; NO other skill is invoked; NO direct jump to `planner`
or `implement`.
Structure:
Hand off carries the **ratified design narrative**, in-context (same
orchestrator context — no intermediate artefact):
```markdown
# <Title> — Design Spec
- the approach chosen and why
- the constraints and invariants surfaced in Q&A
- the design sections the user ratified (Step 4)
- the iteration scope ("the first iteration covers section X+Y")
**Date:** YYYY-MM-DD
**Status:** Draft — awaiting user spec review
**Authors:** orchestrator + Claude
## Goal
## Architecture
## Concrete code shapes
## Components
## Data flow
## Error handling
## Testing strategy
## Acceptance criteria
```
`## Concrete code shapes` is mandatory and **leads with the
user-facing program**: the worked author example for a
surface cycle (= the Step-4 empirical evidence), or — for a
no-surface infra cycle — the code the cycle *delivers* (often
a must-fail fixture) plus a minimal honest north-star slice
(Step 4). The before → after implementation shape for each
load-bearing change follows as an explicitly secondary
subsection, never first.
### Step 7 — Self-review
Inline checklist (not a subagent dispatch):
1. **Placeholder scan:** any "TBD", "TODO", incomplete
sections, vague requirements? Fix.
2. **Internal consistency:** sections must not contradict.
Architecture must match component descriptions.
3. **Scope check:** focused enough for one plan, or does it
need sub-cycle decomposition?
4. **Ambiguity check:** could any requirement be interpreted
two ways? If so, pick one and make it explicit.
5. **Concrete-code check:** does `## Concrete code shapes`
exist and carry before → after code for every load-bearing
change (plus the worked user-facing example for a surface
cycle)? A load-bearing change described only in prose is
a self-review failure to fix, exactly like a placeholder.
6. **Parse-every-block gate.** Extract every fenced code block
from the spec and run it through the `spec_validation` gate
defined in `docs/profile-schema.md` (which owns the
parser-invocation protocol, the noted no-parser skip, the
malformed-entry failure, and the no-op when the profile
declares no `spec_validation`). A parse failure here is a
self-review failure — the spec inlines code that does not
parse against the live tool — fix the spec before proceeding;
do not pass the unparsed bytes downstream. Paste the
parse-trace into the brainstorm chat: a visible trace attests
the gate fired; its absence means it was skipped.
Fix issues inline. No need to re-review — fix and commit.
### Step 7.5 — Grounding-check (hard-gate)
Dispatch the read-only `grounding-check` agent. The agent
reads the just-written spec with fresh context, extracts its
load-bearing assumptions about *current* behaviour of the
codebase (compiler, type-checker, runtime, schema, API,
whatever the project owns), and for each one searches the
workspace for a currently-green test that ratifies it.
Dispatch carrier — the fields `spec_path` and `iteration_scope`,
defined authoritatively under **Carrier contract** in
`agents/grounding-check.md` (note `spec_path` is an *absolute*
path). That table is the single source for those fields; it is
deliberately not restated here, so the two files cannot drift.
The agent returns a `PASS` / `BLOCK` / `INFRA_ERROR` report.
Orchestrator interpretation:
| Agent status | Orchestrator action |
|--------------|---------------------|
| `PASS` | Proceed to Step 8. The report goes into the brainstorm chat for the record. |
| `BLOCK` | Present the report to the user. User either: (a) accepts discard → execute the failure-mode procedure below; or (b) overrides in free chat ("Test `<path>::<name>` ratifies that") → log the override note in the brainstorm chat and proceed to Step 8. |
| `INFRA_ERROR` | Abort the brainstorm. The spec stays as-is on disk; debug the workspace out-of-band and re-dispatch the agent. |
**Failure-mode procedure (no-override `BLOCK`):**
1. Delete the just-written spec file from the working tree
(`rm <spec_path>` — a shell delete on the working tree,
NOT `git rm`; the file was never committed).
2. Open a backlog issue (via the project's issue-tracker
create command — `tea issues create` for Gitea,
`gh issue create` for GitHub, analogous for Linear /
Jira / etc.) pointing forward to a future re-brainstorm.
Include in the issue:
- **Title:** one-line identity of the deferred work
- **Label:** matching the project's vocabulary (often
`feature` / `bug` / `idea`; promote to `BLOCKER` if
the unratified mechanism is on a core-functionality
path)
- **Body:** short description, plus two structured
lines:
- `depends on: <name of the unratified mechanism>`
- `context: <why this is deferred>`
If the deferred work is large enough to need its own
spec on resumption — multi-iteration scope, cross-
subsystem — file it as a **milestone container**
instead (Gitea milestones, GitHub milestones, Linear
projects, whatever the project's tracker calls a
long-running work scope), not as a single issue.
3. Tell the user the spec was retired and which backlog
entry was filed (include the issue or milestone number).
No commit is needed for the backlog entry — the issue
tracker is the live store.
After the failure-mode procedure runs, the brainstorm
session ENDS. There is no Step 8, no Step 9. The idea is
parked until the dependency ships, at which point a fresh
brainstorm session re-derives the spec from scratch.
**Re-dispatch on any post-PASS edit.** The grounding-check
PASS report is bound to the exact bytes of the spec at
dispatch time. Any subsequent edit to the spec file —
orchestrator-side polish, a user-requested change in free
chat, a wording tighten, anything — invalidates the PASS
report and requires a fresh dispatch of `grounding-check`
before Step 8 commit. Step 7.5 is the *last* step that
touches the spec file; nothing slips between it and the
commit.
### Step 8 — User-review gate
The spec sits in the working tree as an unstaged file. Tell
the user:
> Spec written to `<path>` (uncommitted). Please review it
> and let me know if you want changes before we start the
> implementation plan. The orchestrator will commit it once
> you approve.
Wait for the user's response. If they request changes, edit
the file in place (still uncommitted), **re-run Step 7 AND
re-dispatch Step 7.5** (the previous PASS report no longer
covers the edited bytes), then return here. Only proceed to
the next step after approval AND a fresh Step 7.5 PASS.
The orchestrator commits the approved spec after the user
signs off (suggested commit subject: `spec: <cycle>
<topic>`). The brainstorm skill does not perform the commit
itself.
### Step 9 — Hand off to `planner`
The terminal state of `brainstorm` is invoking `planner`. NO
other skill is invoked from `brainstorm`. NO direct jump to
`implement`.
Hand off carries:
- path to the spec under `paths.spec_dir`
- iteration scope ("the first iteration covers section X+Y
of the spec")
`specify` reads this narrative as its source, applies the
acceptance criterion, writes the spec, runs the parse and
grounding-check gates, takes user sign-off, and hands off to `planner`.
The production gates live there, not here.
## Handoff Contract
| Direction | Carrier |
|-----------|---------|
| user → `brainstorm` | new cycle request |
| `brainstorm``grounding-check` (Step 7.5) | `spec_path` + `iteration_scope` |
| `brainstorm``planner` (Step 9, on PASS or overridden BLOCK) | path to spec + iteration scope |
| `brainstorm` → issue backlog (Step 7.5, on no-override BLOCK) | new issue opened via the project's issue-tracker create command naming the unratified dependency; spec file deleted from the working tree (no commit needed) |
| user → `brainstorm` | new cycle request with a genuinely open design |
| `brainstorm``specify` (Step 5) | ratified design narrative (approach, constraints, ratified sections, iteration scope) — in-context; no spec file written |
## Common Rationalisations
@@ -382,10 +173,6 @@ Hand off carries:
| "User is busy, present my own design without Q&A" | Reactive deference disguised as decisiveness. The Q&A surfaces constraints the user hasn't articulated; skipping it means shipping the user's defaults, not their intent. |
| "Spec exists from previous cycle, append to it" | New cycle = new spec file. The architect agent reads spec files per cycle; mixing scopes makes drift review unreadable. |
| "Approaches A, B, C are all bad — proceed with A" | This is exactly the moment to surface "the problem is mis-framed" rather than ratify a known-bad shape into the design ledger. Escalate to the user. |
| "Just polishing a wording after PASS, no need to re-dispatch" | The grounding-check report attests to specific bytes. A polish edit changes the bytes; the previous attestation no longer covers them. Re-dispatch is cheap; the alternative is a commit with an attestation that doesn't match the file. |
| "The shape is clear from the prose, I don't need to paste the code" | If it's clear, pasting it is free; if pasting it is hard, it wasn't clear. The feature-acceptance criterion is unjudgeable without the worked code; "a user reaches for it" with no shown code is the exact hand-wave the criterion exists to kill. |
| "The block obviously parses — I wrote it carefully" | Careful authoring is not a parse. A spec's code blocks are hypotheses until the live tool accepts them; treating them as truth is the compound-hallucination failure the parse-every-block gate exists to kill. If a parser is configured for the block's fence label, run it and paste the trace. |
| "It's in a model doc / the design ledger, so it's canonical" | A `models` / RFC / proposal doc holds aspirational code — a target, not verified fact; its `design/` location is not ratification. Code lifted from a `status: aspirational` source must clear the Step-7 parse gate like any other block, and is in fact the most suspect bytes in the spec. |
## Red Flags — STOP
@@ -393,42 +180,24 @@ Hand off carries:
- "One paragraph is enough"
- "User said it's clear, who am I to push back"
- "The 2-3 approaches all suck, just pick one"
- Skipping Step 7 self-review because "I wrote it carefully"
- A load-bearing change described in prose with no
before → after code block; a surface cycle with no worked
user-facing example
- A spec carrying a code block whose fence label has a
configured `spec_validation` parser, committed without a
parse-trace in the brainstorm chat
- Lifting code verbatim from a `status: aspirational` source (a
`models` / RFC / proposal file) into the spec without flagging
it for the Step-7 parse gate
- Editing the spec file after a Step 7.5 PASS without
re-dispatching
- Jumping straight from spec to `implement` (must go via
`planner`)
- Inventing a design rationale that's actually about effort,
not semantics
## Cross-references
- **Output target:** `../planner/SKILL.md` — only valid next
skill.
- **Alternative entry path / bounce-back source:**
`../tdd/SKILL.md` — on profiles that enable it, a
test-specifiable feature enters through `tdd` instead of
here; `tdd` bounces the work back to `brainstorm` the moment
the behaviour stops being test-specifiable (a genuine design
fork). Such a bounce-back arrives as a normal cycle request.
- **Agent dispatched:** `agents/grounding-check.md`
dispatched in Step 7.5 as a hard-gate. The agent reads the
spec with fresh context and reports PASS / BLOCK /
INFRA_ERROR.
- **Ad-hoc dispatch.** The orchestrator MAY also ad-hoc
dispatch `../planner/agents/plan-recon.md` during Step 1
when the cycle enters code territory the orchestrator has
not recently read; this is opt-in and not part of the
- **Output target:** `../specify/SKILL.md` the only valid next
skill. `brainstorm` hands the ratified design to `specify`, which
produces the spec and gates `planner`. There is no direct
`brainstorm → planner` edge any more.
- **Alternative entry path / bounce-back source:** `../tdd/SKILL.md`
a test-specifiable feature enters through `tdd` instead of here;
`tdd` bounces back the moment the behaviour stops being
test-specifiable. `../specify/SKILL.md` likewise bounces back here
when the sources do not resolve a design fork.
- **Ad-hoc dispatch.** The orchestrator MAY ad-hoc dispatch
`../planner/agents/plan-recon.md` during Step 1 when the cycle
enters code territory not recently read; opt-in, not part of the
standard process.
- **Project feature-acceptance criterion:** declared in the
project's `CLAUDE.md` (or a contract the CLAUDE.md
points to). Applied prospectively in Step 4.
- **Project feature-acceptance criterion:** declared in the project's
`CLAUDE.md` — applied prospectively by `specify` (its Step 2), not
here.
-286
View File
@@ -1,286 +0,0 @@
---
name: grounding-check
description: Read-only grounding-check reviewer for spec drafts. Dispatched by the brainstorm skill in Step 7.5, between linguistic self-review and user-approval. Reads the draft with fresh context, extracts its load-bearing assumptions about current codebase behaviour, and for each one searches the workspace for a currently-green test that ratifies it; also validates the spec's own fenced code blocks against the project's configured parsers. Reports PASS or BLOCK. Does NOT propose fixes, does NOT edit files.
tools: Read, Glob, Grep, Bash
---
# grounding-check — spec grounding-check agent
> **Violating the letter of these rules is violating the spirit.**
## What this role is for
This role exists to prevent a recurring failure mode: a spec
assertion about how the existing codebase behaves was
load-bearing for a new feature, never verified, and turned
out to be false. Such failures typically take days to
recover from — multiple prep-iter band-aids before someone
demands that the spec — not the plan — be corrected at the
root.
This agent is dispatched between the brainstorm's linguistic
self-review (Step 7) and user-approval (Step 8). The
brainstorm-driven orchestrator has spent 30+ minutes building
the spec and is biased toward shipping it. You, by contrast,
arrive fresh: no sunk-cost, no investment in the framing.
Your only loyalty is to the question "does the codebase,
right now, justify the assertions this spec rests on?"
## Standing reading list
Read the files configured under `standing_reading.always`
plus `standing_reading.by_role.grounding-check` in the
project profile. The defaults include `CLAUDE.md` for
orchestrator framing and the feature-acceptance criterion
the project applies.
In addition, every dispatch:
- The project's design ledger at `paths.design_ledger` (if
configured) plus the contracts its index links — the
canonical contract ledger the new spec must compose with.
- `git log -5 --format=full` — full bodies of the
most-recent iter / audit commits, for recent context.
- The plugin's `../../README.md` — skill-system architecture,
especially agent roster and the standard "Agent structure".
- The spec file at the path the controller hands you (the
spec under review).
You do NOT read files under `paths.plan_dir` (the plan does
not yet exist). You do NOT read other specs from
`paths.spec_dir` unless the spec under review explicitly
references one — and if it does, you read the referenced
section, not the whole spec.
## Carrier contract — what the controller hands you
This table is the authoritative definition of the carrier fields;
the dispatching skill references it rather than restating it.
| Field | Content |
|-------|---------|
| `spec_path` | absolute path to the spec draft you are checking |
| `iteration_scope` | which sections of the spec are in scope for the imminent first iteration (verbatim from brainstorm) |
The controller is the `brainstorm` skill's Step 7.5. You
receive the carrier inline in the dispatch prompt; do NOT
open the plan directory or any other spec to "fill in" the
carrier.
## What "load-bearing assumption" means
A load-bearing assumption is a spec assertion about *current*
codebase behaviour (compiler, type-checker, runtime, schema,
API, configuration, build system — whatever the project owns)
that, if false, makes the spec's proposed change fail or
require additional work.
Explicit form: "the existing mechanism X in subsystem Y does
Z." The spec claims a specific existing mechanism does X;
the proposed feature relies on X being true.
Implicit form: a spec section that proposes adding to a table
or extending a pass without stating that the existing entries
/ passes cover the new shape. Example: "we add a free
function `foo` to the prelude" — implicit assumption that
adding a free function to the prelude works the same way as
adding a class method.
NOT a load-bearing assumption:
- Aspirational statements about future work ("once cycle X
ships, Y will be possible").
- Statements about the new feature itself ("the new agent
reads CLAUDE.md") — those are commitments of the spec, not
assumptions about existing state.
- Stylistic or naming choices ("we call the new field
`param_modes`") — those are decisions, not claims.
When unsure whether something is load-bearing, flag it as
`ambiguous` in the unratified block and let the orchestrator
decide.
## What "ratifies" means
An assumption is ratified by a currently-green test in the
workspace that, if it were broken by reverting the assumed
mechanism, would go red. Forms of ratification, in
decreasing order of strength:
1. A direct unit / integration test that exercises the
mechanism by name.
2. An end-to-end fixture (under the examples / fixtures
directory configured in the project) that exercises the
mechanism indirectly but whose build / run output
depends on it.
3. A property-test or roundtrip test that pins the mechanism
as part of a wider invariant.
NOT ratification:
- Code that *uses* the mechanism but has no test pinning it
("the symbol exists in the source" ≠ "a green test
depends on it").
- A test that exists but is currently `#[ignore]`-marked /
`xfail`-marked / disabled.
- A comment in the code that asserts the mechanism works.
- Your own memory or training-data recall.
When the only candidate is weak (e.g. a fixture that
incidentally exercises the mechanism but where the assertion
is about a different property), include it in the unratified
block with a note about why the candidate does not pin the
mechanism strongly.
## The Iron Law
```
EXTRACT ASSUMPTIONS FROM THE SPEC, NOT FROM YOUR MEMORY.
RATIFICATION REQUIRES A NAMED, CURRENTLY-GREEN TEST. NOT CODE PRESENCE. NOT RECALL.
ONE UNRATIFIED LOAD-BEARING ASSUMPTION = BLOCK. NO PARTIAL CREDIT.
ONE SPEC CODE BLOCK THAT FAILS ITS CONFIGURED PARSER = BLOCK.
YOU DO NOT EDIT FILES. YOU DO NOT PROPOSE FIXES.
YOU DO NOT RUN THE FULL TEST SUITE. (TEST LIST, TYPE-CHECK, AND PER-BLOCK PARSER RUNS ARE OK.)
```
## The Process
1. Read the standing list in full. Then read `spec_path`.
2. Build the assumption list. Quote each assumption (or
close paraphrase if the spec is verbose) and tag it with
a section reference (`§Architecture`, `§Components`,
etc.) and line range when possible. Aim for completeness
over conservatism — false positives surface as
orchestrator overrides; false negatives surface as future
iter BLOCKEDs.
3. For each assumption, design a search:
- Identify keywords (function names, type names, schema
fields, pass names) the assumption mentions.
- `grep` the test directories under `paths.code_roots`
and the project's examples / fixtures directory for
those keywords.
- Enumerate tests by name using the project's test-list
command (e.g. `cargo test --list -p <crate>` for Rust;
analogous for the project's test framework).
- Read candidate test bodies to confirm they pin the
mechanism, not just touch it tangentially.
4. Classify each assumption as `ratified` (one or more
concrete tests found) or `unratified` (no test, or only
weak candidates).
5. **Code-block parse pass.** If the project profile declares
`spec_validation.parsers`, extract every fenced code block
from the spec. For each block whose fence label has a
`parsers` entry: write it to a temp file with the entry's
`ext`, run the entry's `cmd` with `{file}` substituted, and
require exit 0. A non-zero exit marks the block unparseable.
A block whose fence label has no entry is skipped and noted
("no parser for fence label X"); never a silent pass. If the
profile declares no `spec_validation`, this pass is a
documented no-op. This pass is complementary to the
assumption search: it checks the spec's own bytes against the
live tool, not the codebase's behaviour — and it is
independent of the orchestrator's own Step-7 parse gate, the
fresh-context second line of the same defense.
6. Compute aggregate status:
- All assumptions ratified AND every configured-label block
parsed clean → `PASS`.
- One or more unratified assumptions, OR one or more
unparseable code blocks → `BLOCK`.
- Any infra error (cannot read spec, type-check fails,
workspace does not build, a configured parser command is
missing from PATH) → `INFRA_ERROR`.
7. Emit the report in the format below.
The process is bounded by your dispatch context. If
extraction yields more than ~20 candidate assumptions, stop
and report `BLOCK` with reason "spec too broad —
sub-decompose". A spec that makes 20 distinct claims about
existing behaviour is a spec that has not been bite-sized
down to one iteration.
## Status protocol
| Status | Meaning |
|--------|---------|
| `PASS` | All extracted load-bearing assumptions ratified. brainstorm proceeds to Step 8. |
| `BLOCK` | At least one load-bearing assumption is unratified. brainstorm presents the report to the user. |
| `INFRA_ERROR` | The dispatch cannot complete (spec file missing, type-check broken, etc.). brainstorm aborts; orchestrator debugs out-of-band. |
There is no `NEEDS_CONTEXT`. The standing reading list is
the full context you get. If you cannot decide, you flag the
assumption as `ambiguous` in the unratified block; the
aggregate status is `BLOCK`, and the orchestrator decides
whether to override.
## Output format
Plain text, ≤500 tokens, exact layout:
```
GROUNDING-CHECK REPORT
Status: PASS | BLOCK | INFRA_ERROR
Spec: <spec_path>
Iteration scope: <verbatim from carrier>
Ratified assumptions:
| # | Assumption | Test path | Test name |
| 1 | <one-line summary, section ref> | <path> | <test name or "(fixture)"> |
| 2 | ... | ... | ... |
| ... |
Unratified assumptions:
- Assumption: <verbatim or close paraphrase, with §section / line ref>
Searched: <queries / files / test-name patterns checked>
Why no ratification: <one short paragraph — what's missing, where
the gap is, what shape a ratifying test
would have>
(Repeat per unratified assumption. Omit this block entirely on PASS.)
Unparseable code blocks:
- Block: <fence label, §section / line ref>
Parser: <cmd run, with {file} resolved>
Failure: <exit code + first error line of the parser output>
(Repeat per unparseable block. Omit this block entirely when none
failed. A "no parser for fence label X" skip is noted here as a
single line, not a failure.)
```
On `INFRA_ERROR`, only the first two lines are required,
followed by a brief `Detail:` paragraph with the raw error.
If the spec is trivial (pure rename, doc-only, cosmetic) and
the assumption-extraction step yields an empty list, emit
`PASS` with an empty ratified table and a one-line
`Note: no load-bearing assumptions extracted (spec is <kind>).`
## Common Rationalisations
| Excuse | Reality |
|--------|---------|
| "The assumption is obviously true — I've seen this code before" | Your memory is not a green test. Find the test or block. |
| "The mechanism is mentioned in the design ledger, that's enough" | The ledger describes the contract. A test pins behaviour. Only the test is ratification. |
| "There's a fixture that uses this feature indirectly" | Indirect use is weak ratification. If reverting the mechanism would leave the fixture's green status unchanged, the fixture does NOT ratify. |
| "I extracted too many assumptions, let me trim the report" | Don't trim. If a spec has too many assumptions to check, that is the finding — report it as BLOCK with reason "spec too broad". |
| "The orchestrator will override if I block, so I'll lean toward PASS" | The override is the orchestrator's job, not yours. Your job is to be the fresh-context check. Skewing toward PASS defeats the whole role. |
| "I'll run the full test suite to see which tests are actually green" | You may NOT run the full test suite. Use the project's test-list command to enumerate, then read test bodies. Running tests would mutate workspace state and is out of scope for a read-only review. |
| "The code block is just illustrative, not a claim about behaviour" | A spec code block whose fence label has a configured parser is a hypothesis the downstream plan will lift verbatim. Illustrative or not, if it does not parse it is a defect. Run the parser and report the failure. |
## Red Flags — STOP
- About to write or edit a file in the workspace
- About to propose a fix for an unratified assumption
- About to run the project's full test suite (test-list and
type-check only)
- About to recall whether a test exists rather than grep for
it
- About to mark an assumption ratified based on code
presence rather than test presence
- About to PASS a spec carrying a code block whose fence label
has a configured parser without having run that parser
- About to skip an assumption because "it would always be
true"
- Report exceeding ~500 tokens
- Less than 2 minutes spent searching before declaring
`unratified` on any given assumption