feat: ground contracts in facts before negotiating them#1
Merged
Conversation
A building run negotiated a contract against a store the generator invented, modeled on a store the previous issue had legitimately created. The real one already existed, and the capability the issue needed was missing from it. That was the actual work, and no artifact said so. The contract survived three adversarial rounds, because the evaluator is forbidden to read source and could only record, in its residual risks, that the premise could not be checked from where it sat. A human caught it at the gate. The pipeline treated a fact about an existing system as a deferrable decision. Deferring a decision keeps options open, which is the pipeline's best idea. Deferring a fact means somebody downstream invents it, and from inside a contract, inventing and discovering look identical: for the previous issue the same move had been correct, because that store really was new. The discriminator has to be an existence check, not better prompting. So: facts are exempt from the altitude ban, decisions are not. - interview: a Grounding section in the spec records every existing system the feature consumes, found by the exploration the command already performs. - planning: the reality-check agent's findings stop being discarded. They become a grounding table, quoted into each issue's Grounding block. The phase is no longer optional outside greenfield. - building: the generator declares a `grounding` block before any criterion, each entry EXISTS with file:line evidence or NEW. The lead reproduces every EXISTS with a grep and refuses to relay a contract whose premises it could not reproduce. Any NEW persistent substrate escalates to the human before the evaluator sees the contract, gate or no gate. The evaluator gains one blocking objection, a fixture noun absent from the block, which it can raise without reading code. - the gate shows grounding and residual risks above the criteria, because a human skims what he is shown first. The evaluator keeps its isolation. It produced the note that saved the run, and an evaluator that could check the generator's premise against the generator's own fixtures would have confirmed the fabrication instead of flagging it.
The page still described a building phase with no notion of what already exists, a reality check that was optional, and a run that goes unattended end to end. None of that is true now. - interview: the spec records what it finds, it does not only park it - planning: grounding and reality check, skipped only on greenfield, and the altitude ban exempts facts - building: the grounding block precedes the criteria, the lead reproduces every EXISTS with a grep, and a NEW store stops the run for one question - the gate leads with grounding and residual risks, above the criteria - human touchpoints gains that question, and the overview no longer promises an unattended run PNG re-exported from the page at the same width.
The gate used to be opt-in, and the run that exposed the grounding gap was saved only because it happened to be gated and the human happened to read a paragraph the gate never required anyone to show him. On the default path that defect would have shipped: green criteria, a passing contract, and the next issue queued to build on the same fiction. So the pause becomes the default. The contract is the last artifact a human can correct cheaply. After it, every criterion, every builder and every sibling issue inherits its premises, and the amendment rule turns changing one into an event. --no-gate keeps the old behavior for work whose premises you already trust. The NEW-substrate question in phase 2 is unchanged and still fires either way: it asks whether the contract may invent a store, while the gate asks whether the contract is right. Diagram and README regenerated: the build flow now shows the gate between the contract and the builders, and the overview no longer promises an unattended run.
dasirra
marked this pull request as ready for review
July 10, 2026 13:58
There was a problem hiding this comment.
Pull request overview
This PR updates Forge’s PM/DEV pipeline docs to explicitly “ground” contracts in verifiable facts about existing systems before negotiating criteria, and flips /forge:building to gate-by-default (with --no-gate to opt out). It also documents the new grounding workflow across interview, planning, and building, and bumps the plugin version to reflect the contract schema change.
Changes:
- Add a Grounding (facts-not-decisions) concept to
/forge:interviewand/forge:planning, and propagate it into child issues. - Extend
/forge:buildingto require a grounding block prior to criteria, add a mechanical verification step, and make the human gate default (--no-gateto skip). - Regenerate pipeline reference docs and bump plugin version to 1.2.0.
Reviewed changes
Copilot reviewed 6 out of 7 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| README.md | Updates CLI flag naming and pipeline diagram to reflect gate-by-default + grounding-first contract flow. |
| docs/pipeline.html | Regenerated pipeline reference reflecting grounding and default gating semantics. |
| commands/planning.md | Adds Grounding as an explicit exception to the “no technical details” rule and mandates grounding/reality-check phase. |
| commands/interview.md | Adds a Grounding section to the spec template and clarifies facts vs decisions in interview guidance. |
| commands/building.md | Documents {surface, grounding, criteria} contract shape (now expanded) and introduces grounding verification + default gate behavior. |
| .claude-plugin/plugin.json | Version bump to 1.2.0 for the contract schema and behavior change. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @@ -55,7 +55,7 @@ The other two need: | |||
| |---------|----------|-------------| | |||
| | `/forge:interview [idea \| path/to/brief.md]` | PM | Relentless one-question-at-a-time grilling until you and Claude share an understanding of the idea, then synthesis into a PM-level spec. No code, no issues. | | |||
| | `/forge:planning [path/to/spec.md \| description]` | PM | A planner drafts an epic with user stories, a critic attacks it in a separate context, they iterate up to 3 rounds. Files the result as a GitHub epic with native sub-issues for async human review. No technical content: no files, no schemas, no architecture. | | |||
Comment on lines
+33
to
+37
| - `harness/contract.json`: `{surface, grounding, criteria}`. `surface` is the | ||
| evaluation surface resolved in Phase 0.5, recorded once so a resumed run never | ||
| re-derives it. `grounding` is the array of substrate the contract stands on, | ||
| each entry `{name, status: EXISTS|NEW, evidence, human_ack}`; see Phase 2. | ||
| Each criterion is |
Comment on lines
+135
to
+137
| criterion or fixture will name, each entry `{name, status: EXISTS|NEW, | ||
| evidence}`. EXISTS requires evidence: a `file:line` in the current worktree | ||
| that names the thing. NEW means this run creates it. Start from the issue's |
| states, errors, edge cases. | ||
| 1.5 **Lead verifies grounding mechanically** (you, before relaying the | ||
| contract). This is a grep, not a judgment. For each EXISTS entry, run | ||
| `git grep -n <name>` (or `test -e` for paths) and confirm the cited |
Comment on lines
188
to
189
| Write objections into the contract file. If sound, mark all criteria | ||
| `agreed`. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The failure this fixes
A
/forge:buildingrun negotiated a contract whose fixtures bound the feature to a store thegenerator invented: a JSON file behind a new environment variable, modeled on a store the previous
issue in the same epic had legitimately created.
The real store already existed, and the capability the issue needed was missing from it. Adding
that capability was the actual work of the issue. Neither the spec, nor the epic, nor the issue, nor
the contract said so.
The contract then survived three adversarial rounds. The evaluator is forbidden to read source, so
the best it could do was record, in its residual risks, that the premise could not be checked from
where it sat. A human read that note at the
--gateand asked where the store was. On the ungateddefault it would have shipped green, with the next issue queued to build on top of the fiction.
Root cause
Forge treated a fact about an existing system as a deferrable decision.
Deferring a decision keeps options open, and it is this pipeline's best idea. Deferring a fact forces
every downstream agent to rediscover it, and each rediscovery is an unreviewed chance to invent.
The violated invariant is forge's own banner: "No agent grades its own work." The generator's
premise, "the store is a JSON file", is the one consequential output that nobody grades. The
evaluator audits contract-against-issue. The critic audits plan-against-spec. Nobody audits
issue-against-reality.
Every path that could have graded it was closed by the commands themselves:
interview.md: "Do NOT ask about schemas, file paths, libraries, or architecture."planning.md, of the recon agent that had the answer in hand: "Its findings must never leak filepaths or technical detail into issue bodies." The knowledge was gathered, then discarded by rule.
building.md: "There is no technical planning phase... technical decisions belong to thebuilders." But builders arrive in Phase 4, and the substrate was already fixed in the Phase 2
fixtures, by the contract author, whose only reviewer may not read the code.
The decisive detail: for the previous issue, the identical generator move was correct, because
that store really was new. Inventing and discovering look identical from inside a contract. So the
discriminator cannot be better prompting. It has to be an existence check.
The change
Facts are exempt from the altitude ban. Decisions are not.
interview.md: a## Grounding (facts, not decisions)section in the spec, recording everyexisting system the feature consumes. The command already explores the codebase; now it writes down
what it found.
planning.md: the Light reality check becomes a Grounding phase, no longer optional outsidegreenfield. Its findings stop being discarded and become a grounding table, quoted into each child
issue's
## Groundingblock.building.md:groundingblock before any criterion: every store, path, env var,collection, table, endpoint, package, or external system a fixture will name, each
EXISTS(withfile:lineevidence) orNEW;EXISTSwithgit grepand refuses to relay acontract whose premises it could not reproduce. Any
NEWpersistent substrate escalates to thehuman with one question, gate or no gate;
raise this without reading code, because absence from a JSON block is visible in the artifact
itself;
--no-gateopts out), and it shows the grounding block and theevaluator's residual risks above the criteria. The human who caught the original defect did so
by reading a paragraph the gate never required anyone to show him, on a run that happened to be
gated. On the old default it would have shipped.
Why it works
The check is a grep plus a JSON-shape assertion, not an opinion, so it cannot drift the way a prompt
does. It is enforced twice by agents with opposed incentives: the lead checks
EXISTSagainst therepo, and the evaluator blocks ungrounded nouns from the artifact. For one to rot, the other must rot
in the same direction at the same time.
Replayed against the original failure, the invented environment variable greps to nothing, so it
cannot be
EXISTS, so the human is asked one question before three adversarial rounds harden criteriaagainst a store that does not exist. Replayed against the previous issue, where the store genuinely
was new: one question, one yes, no friction. It discriminates precisely where the generator cannot.
Explicitly rejected
precedent that misled the generator, and confirm the fabrication. Its isolation is what produced
the residual-risks note that saved the run, and later a self-audit in which it reported two of its
own earlier passes as unearned. That property is irreplaceable, and the grounding block buys the
same coverage by handing it evidence as an artifact it can demand but not fetch.
false premise. A design phase consumes premises, it does not audit them.
grep answers exactly, and fails silently when the human's mental model is stale, which is the case
grounding exists to catch. Invert it: the machine greps, and the human is interrupted only when the
contract wants to invent.
Unchanged, deliberately
The adversarial negotiation, which in the run that exposed this caught seven blocking defects, three
of which would have failed a correct implementation. The evaluator's isolation. The amendment rule,
through which the recovery ran exactly as written. The altitude discipline itself: the conclusion is
not that PM artifacts should carry architecture, it is that a fact is not a decision, and the ban's
old wording could not tell them apart.
Also regenerates
docs/pipeline.htmlandassets/pipeline.png: the page still described anoptional reality check, a building phase with no notion of what exists, and a run that goes unattended
end to end. Rendering it caught three claims the source changes had made false.
Bumps the plugin to 1.2.0, since the contract schema gains
groundingand the gate default flips.🤖 Generated with Claude Code