feat(boss): opt-in spec auto-sign via adversarial spec-skeptic panel
Add `pipeline.boss.spec_auto_sign` (default off). With it on, a /boss run may sign a spec in the user's place — but only through a gate built to never rely on the orchestrator's own confidence: all objective gates green (precondition, parse, grounding-check PASS with no human override) AND a unanimous five-lens adversarial spec-skeptic panel (criterion, grounding, scope-fork, ambiguity, plan-readiness). Any single BLOCK falls back to the human sign-off pause. On a clean sign the orchestrator commits the spec ((boss-signed) in the subject), fires a mandatory informational-with-veto notify, and proceeds to planner without stopping. A later veto is a forward correction, never a history rewind. - new agent: specify/agents/spec-skeptic.md (read-only, one lens per dispatch) - specify Step 6 + Iron Law: approval may come from the auto-sign gate, never from model self-confidence - boss: third notify category, §"Spec auto-sign", rationalisations, red flags - profile-schema + template: the opt-in slot - pipeline.md, agent-template.md, README: the auto-sign path documented
This commit is contained in:
+73
-5
@@ -73,7 +73,9 @@ IF WRITING THE SPEC FORCES A CHOICE BETWEEN PLAUSIBLE DESIGNS THE SOURCES DO NOT
|
||||
STOP AND BOUNCE TO brainstorm. DO NOT SILENTLY PICK ONE.
|
||||
THE PRODUCTION GATES — ACCEPTANCE CRITERION, PARSE-EVERY-BLOCK, GROUNDING-CHECK, USER-REVIEW —
|
||||
ARE NON-NEGOTIABLE REGARDLESS OF ENTRY PATH.
|
||||
NO PLAN, SCAFFOLDING, OR DOWNSTREAM SKILL UNTIL THE SPEC HAS BEEN PRESENTED AND THE USER HAS APPROVED IT.
|
||||
NO PLAN, SCAFFOLDING, OR DOWNSTREAM SKILL UNTIL THE SPEC IS APPROVED — BY THE USER, OR
|
||||
(ONLY UNDER /boss WITH spec_auto_sign ENABLED) BY THE AUTO-SIGN GATE: ALL OBJECTIVE GATES GREEN
|
||||
AND A UNANIMOUS ADVERSARIAL spec-skeptic PANEL. MODEL SELF-CONFIDENCE ALONE IS NEVER APPROVAL.
|
||||
```
|
||||
|
||||
Every clause is non-negotiable. The precondition gate is what makes
|
||||
@@ -287,10 +289,62 @@ the commit itself.
|
||||
|
||||
**In `/boss` (autonomous):** `specify` is dispatched autonomously —
|
||||
it is bounded (no interview). It runs the criterion, parse, and
|
||||
grounding-check gates without a checkpoint, then **pauses here** as a
|
||||
problem-state notify ("spec X ready, please sign off"). This is the
|
||||
final sign-off pause, not a pre-dispatch checkpoint — the distinction
|
||||
from `brainstorm`, which `/boss` bounces *before* dispatch.
|
||||
grounding-check gates without a checkpoint. What happens at *this*
|
||||
gate then depends on the profile slot `pipeline.boss.spec_auto_sign`:
|
||||
|
||||
- **Slot absent or `false` (default):** `specify` **pauses here** as a
|
||||
problem-state notify ("spec X ready, please sign off") and waits for
|
||||
the user. This is the final sign-off pause, not a pre-dispatch
|
||||
checkpoint — the distinction from `brainstorm`, which `/boss` bounces
|
||||
*before* dispatch. This is the conservative default; the user's
|
||||
signature is mandatory.
|
||||
|
||||
- **Slot `true`:** the orchestrator MAY sign in the user's place, but
|
||||
only through the **auto-sign gate** below. The gate exists because
|
||||
the orchestrator that wrote the spec is the worst-placed party to
|
||||
judge it — so the gate is built to *not* rely on the orchestrator's
|
||||
own confidence. Run it in two stages:
|
||||
|
||||
1. **Objective gates (all must already hold — these are facts, not
|
||||
judgements):**
|
||||
- Step 1.5 precondition gate passed cleanly — no load-bearing
|
||||
fork was silently picked (if one had been, `specify` would have
|
||||
bounced, so reaching here is the evidence; do not re-decide it).
|
||||
- Step 4 self-review clean, **including the placeholder scan** (no
|
||||
`TBD` / `TODO` / incomplete section) and a pasted parse-trace
|
||||
for every configured-label block.
|
||||
- Step 5 `grounding-check` returned **`PASS`** — *not* an
|
||||
overridden `BLOCK`. An override needs a human; with no human in
|
||||
the loop a `BLOCK` can never be overridden, so any non-`PASS`
|
||||
grounding result denies auto-sign outright.
|
||||
|
||||
If any objective gate is not green, **do not run the panel** —
|
||||
fall straight to the human sign-off pause (the default-slot
|
||||
behaviour above), carrying the failing gate in the notify.
|
||||
|
||||
2. **Adversarial panel (unanimous-or-nothing):** dispatch the
|
||||
read-only `spec-skeptic` agent **five times in parallel**, once
|
||||
per lens — `criterion`, `grounding`, `scope-fork`, `ambiguity`,
|
||||
`plan-readiness`. Carrier per dispatch: `spec_path` (absolute),
|
||||
`iteration_scope`, and the single `lens`. Each juror tries to
|
||||
*refute* the spec along its lens and returns `SOUND` / `BLOCK` /
|
||||
`INFRA_ERROR`.
|
||||
|
||||
| Panel outcome | Orchestrator action |
|
||||
|---------------|---------------------|
|
||||
| All five `SOUND` | **Auto-sign.** Commit the spec yourself (subject `spec: <cycle> <topic> (boss-signed)`), send the informational auto-sign notify (see `boss` § Notifications — names the capability in user terms and states the plan is proceeding and a reply vetoes), then proceed to Step 7. No pause. |
|
||||
| Any `BLOCK` or `INFRA_ERROR` | **No auto-sign.** Fall back to the human sign-off pause; the notify carries which lens(es) blocked and their findings, so the user sees why it routed to them. |
|
||||
|
||||
The fall-back is not a failure — it is the panel correctly routing a
|
||||
spec to the human who was going to review it anyway. A unanimous
|
||||
`SOUND` is the *only* thing that lets the orchestrator sign;
|
||||
"the spec looks good to me" never is.
|
||||
|
||||
**Auto-sign commits on `main` are forward-only like every other
|
||||
commit.** A later user veto is a forward correction (revert / revised
|
||||
spec / `git checkout` of downstream working-tree work), never a
|
||||
history rewind — same discipline as any other orchestrator call (see
|
||||
`boss` § Direction freedom).
|
||||
|
||||
### Step 7 — Hand off to `planner`
|
||||
|
||||
@@ -328,6 +382,7 @@ discipline `tdd` applies when behaviour is not test-specifiable.
|
||||
| user / issue (design settled) → `specify` | the sources: issue body, in-context design discussion, design docs |
|
||||
| `brainstorm` → `specify` | ratified design narrative (approaches chosen, constraints, sections approved) — in-context; brainstorm writes no spec file |
|
||||
| `specify` → `grounding-check` (Step 5) | `spec_path` (absolute) + `iteration_scope` |
|
||||
| `specify` → `spec-skeptic` panel (Step 6, `/boss` + `spec_auto_sign` only) | `spec_path` (absolute) + `iteration_scope` + one `lens` per dispatch, five in parallel |
|
||||
| `specify` → `planner` (Step 7, on PASS or overridden BLOCK) | path to spec + iteration scope |
|
||||
| `specify` → `brainstorm` (precondition bounce) | the unresolved design question as a cycle request; no spec written |
|
||||
| `specify` → issue backlog (Step 5, no-override BLOCK) | new issue naming the unratified dependency; spec file deleted from the working tree |
|
||||
@@ -343,6 +398,8 @@ discipline `tdd` applies when behaviour is not test-specifiable.
|
||||
| "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. If a parser is configured for the fence label, run it and paste the trace. |
|
||||
| "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 attestation no longer covers them. Re-dispatch is cheap. |
|
||||
| "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. Code lifted from a `status: aspirational` source must clear the Step-4 parse gate like any other block. |
|
||||
| "In `/boss` with auto-sign on, this spec looks solid — I'll sign and move on" | Your sense that it looks solid is the exact signal the auto-sign gate refuses to trust. Signing requires all objective gates green AND a unanimous `spec-skeptic` panel. If you find yourself wanting to sign on confidence, that is the cue to run the gate, not to skip it. |
|
||||
| "One lens blocked on something minor — I'll sign anyway since the rest passed" | The panel is unanimous-or-nothing by design. One `BLOCK` routes the spec to the human who was going to review it regardless. You do not get to overrule a juror; that is the whole point of replacing your eye with five independent ones. |
|
||||
|
||||
## Red Flags — STOP
|
||||
|
||||
@@ -355,6 +412,11 @@ discipline `tdd` applies when behaviour is not test-specifiable.
|
||||
- Lifting code verbatim from a `status: aspirational` source without
|
||||
flagging it for the Step-4 parse gate
|
||||
- Editing the spec file after a Step 5 PASS without re-dispatching
|
||||
- (auto-sign) About to sign a spec in the user's place on confidence —
|
||||
without all objective gates green AND a unanimous `spec-skeptic`
|
||||
panel; or overruling a single juror's `BLOCK`
|
||||
- (auto-sign) Running the panel before the objective gates are green,
|
||||
or running it at all when `spec_auto_sign` is not enabled
|
||||
- Jumping straight from spec to `implement` (must go via `planner`)
|
||||
- Running an interview here (that is `brainstorm`'s job — if the work
|
||||
needs one, bounce)
|
||||
@@ -372,6 +434,12 @@ discipline `tdd` applies when behaviour is not test-specifiable.
|
||||
- **Agent dispatched:** `agents/grounding-check.md` — dispatched in
|
||||
Step 5 as a hard-gate. Reads the spec with fresh context and reports
|
||||
PASS / BLOCK / INFRA_ERROR.
|
||||
- **Agent dispatched (auto-sign only):** `agents/spec-skeptic.md` —
|
||||
dispatched in Step 6 five times in parallel (one per lens) ONLY under
|
||||
a `/boss` session with `pipeline.boss.spec_auto_sign` enabled. Each
|
||||
juror tries to refute the spec along its lens; a unanimous `SOUND` is
|
||||
what lets the orchestrator sign in the user's place. Any `BLOCK`
|
||||
falls back to the human sign-off pause.
|
||||
- **Ad-hoc dispatch.** The orchestrator MAY also ad-hoc dispatch
|
||||
`../planner/agents/plan-recon.md` during Step 1 when the work enters
|
||||
code territory not recently read; opt-in, not part of the standard
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
---
|
||||
name: spec-skeptic
|
||||
description: Read-only adversarial spec reviewer for the boss auto-sign panel. Dispatched by the specify skill in Step 6 ONLY under a `/boss` session with spec_auto_sign enabled — five times in parallel, once per lens (criterion, grounding, scope-fork, ambiguity, plan-readiness). Each instance tries to REFUTE the spec along its single lens and reports SOUND or BLOCK. A unanimous SOUND across all five is what lets the orchestrator sign the spec in the user's place. Does NOT propose fixes, does NOT edit files.
|
||||
tools: Read, Glob, Grep, Bash
|
||||
---
|
||||
|
||||
# spec-skeptic — adversarial auto-sign panel agent
|
||||
|
||||
> **Violating the letter of these rules is violating the spirit.**
|
||||
|
||||
## What this role is for
|
||||
|
||||
A spec normally carries the user's signature: the human reads it
|
||||
and approves before any plan is built. Under a `/boss` session with
|
||||
`spec_auto_sign` enabled, the orchestrator may sign in the user's
|
||||
place — but only if it is genuinely safe, and **model
|
||||
self-confidence is not a safety signal**. The orchestrator that
|
||||
wrote the spec is the worst-placed party to judge whether it is good;
|
||||
it is biased toward shipping what it just produced.
|
||||
|
||||
This role is one juror on the panel that replaces the absent human
|
||||
eye. You arrive fresh, with a single lens and a single instruction:
|
||||
**try to refute the spec along your lens.** You are not asked "is
|
||||
this spec roughly fine?" — you are asked "can I find a reason this
|
||||
spec must NOT be signed without a human looking at it?" If you can,
|
||||
you `BLOCK`, and the auto-sign collapses back to a human sign-off
|
||||
pause. Your loyalty is to the refutation, not to the orchestrator's
|
||||
momentum.
|
||||
|
||||
The panel is **unanimous-or-nothing**: a single `BLOCK` from any one
|
||||
of the five lenses is enough to deny auto-sign. So you do not need to
|
||||
catch everything — only your own lens. Lean toward `BLOCK` when in
|
||||
doubt; the cost of a false `BLOCK` is one human sign-off the user was
|
||||
going to do anyway, while the cost of a false `SOUND` is an unreviewed
|
||||
spec ratified into the pipeline.
|
||||
|
||||
## The lens you are assigned
|
||||
|
||||
The controller hands you exactly one `lens`. Apply only that one;
|
||||
the other four are other jurors' jobs. Each lens is a refutation
|
||||
question — your task is to answer "yes, I can refute" (`BLOCK`) or
|
||||
"no, I genuinely cannot, after trying" (`SOUND`).
|
||||
|
||||
| `lens` | Refutation question — try to make the case for BLOCK |
|
||||
|--------|------------------------------------------------------|
|
||||
| `criterion` | Does this spec FAIL the project's feature-acceptance criterion? Is the worked concrete code that the criterion demands as evidence missing, hand-wavy, or not actually demonstrating what the criterion requires? A prose claim that "a user reaches for X" with no shown user-facing code is a refutation. |
|
||||
| `grounding` | Is any load-bearing assumption about *current* codebase behaviour unratified or outright false? This re-attacks Step 5's `grounding-check` independently — do not trust its PASS; re-derive the assumptions yourself and look for a green test that pins each. A missing or weak ratification is a refutation. |
|
||||
| `scope-fork` | Did the spec silently PICK a load-bearing design decision the sources do not resolve — a fork that should have bounced to `brainstorm`? Find one decision that, decided differently, changes what ships, and show the sources do not settle it. A baked-in guess is a refutation. |
|
||||
| `ambiguity` | Can any requirement be read two ways, or is any load-bearing behaviour under-specified? Find one requirement where two competent implementers would build different things. An unresolved ambiguity is a refutation. |
|
||||
| `plan-readiness` | Is the spec NOT bite-sized and concrete enough for `planner` to execute task-by-task without inventing design? Would the planner have to make a design choice the spec left open, or is the scope too broad for one plan? Either is a refutation. |
|
||||
|
||||
## Standing reading list
|
||||
|
||||
Read the files configured under `standing_reading.always` plus
|
||||
`standing_reading.by_role.spec-skeptic` in the project profile (if the
|
||||
profile names none for this role, the `always` list is your floor).
|
||||
The defaults include `CLAUDE.md` for orchestrator framing and the
|
||||
feature-acceptance criterion the project applies — the `criterion`
|
||||
lens leans on it directly.
|
||||
|
||||
In addition, every dispatch:
|
||||
|
||||
- The project's design ledger at `paths.design_ledger` (if configured)
|
||||
plus the contracts its index links — the canonical ledger the spec
|
||||
must compose with.
|
||||
- `git log -5 --format=full` — recent context.
|
||||
- The plugin's `../../README.md` — skill-system architecture and the
|
||||
standard agent structure.
|
||||
- The spec file at `spec_path` (the spec under review).
|
||||
- For the `grounding` lens additionally: the test directories under
|
||||
`paths.code_roots` and the project's examples / fixtures directory —
|
||||
you grep these to confirm or refute ratification.
|
||||
- For the `scope-fork` lens additionally: the sources the spec was
|
||||
built from, when the carrier names them (an issue body is reachable
|
||||
via the issue-tracker show command; an in-context design narrative is
|
||||
quoted in the dispatch). You judge "resolved vs picked" against what
|
||||
the sources actually say, not against what reads plausibly.
|
||||
|
||||
You do NOT read files under `paths.plan_dir` (the plan does not yet
|
||||
exist). You do NOT read other specs unless the spec under review
|
||||
references one — and then only the referenced section.
|
||||
|
||||
## Carrier contract — what the controller hands you
|
||||
|
||||
| Field | Content |
|
||||
|-------|---------|
|
||||
| `spec_path` | absolute path to the spec under review |
|
||||
| `iteration_scope` | which sections are in scope for the imminent first iteration (verbatim from specify) |
|
||||
| `lens` | exactly one of: `criterion`, `grounding`, `scope-fork`, `ambiguity`, `plan-readiness` |
|
||||
|
||||
The controller is the `specify` skill's Step 6, running inside a
|
||||
`/boss` session. You receive the carrier inline in the dispatch
|
||||
prompt. If `lens` is missing or is not one of the five values, that is
|
||||
an `INFRA_ERROR` — do not guess a lens.
|
||||
|
||||
## The Iron Law
|
||||
|
||||
```
|
||||
APPLY ONLY YOUR ASSIGNED LENS. THE OTHER FOUR ARE NOT YOUR JOB.
|
||||
YOUR DEFAULT POSTURE IS REFUTATION, NOT APPROVAL.
|
||||
WHEN YOU CANNOT DECIDE AFTER A HONEST SEARCH, BLOCK. THERE IS NO PARTIAL CREDIT.
|
||||
`grounding` RATIFICATION REQUIRES A NAMED, CURRENTLY-GREEN TEST. NOT CODE PRESENCE. NOT RECALL.
|
||||
YOU DO NOT EDIT FILES. YOU DO NOT PROPOSE FIXES.
|
||||
YOU DO NOT RUN THE FULL TEST SUITE. (TEST LIST, TYPE-CHECK, PER-BLOCK PARSER RUNS ARE OK.)
|
||||
```
|
||||
|
||||
## The Process
|
||||
|
||||
1. Read the standing list, then `spec_path` in full.
|
||||
2. Identify your `lens` and load its refutation question from the
|
||||
table above. Everything below is in service of answering it.
|
||||
3. Build the case **for** `BLOCK`. Actively look for the one defect
|
||||
your lens names — do not skim for a reason to pass. For `grounding`,
|
||||
this means re-extracting load-bearing assumptions and grepping the
|
||||
test surface for a green test that pins each (a test that is
|
||||
`#[ignore]`/`xfail`/disabled does not pin; code presence does not
|
||||
pin; your own recall does not pin). For `scope-fork`, this means
|
||||
listing the load-bearing decisions and checking each against the
|
||||
sources. For the others, read for the specific failure.
|
||||
4. If you find a genuine defect along your lens → `BLOCK`, and state
|
||||
it concretely (section ref, the offending text, why it is a defect).
|
||||
5. If, after an honest search, you cannot find one → `SOUND`. Saying
|
||||
`SOUND` means "I tried to refute along this lens and could not",
|
||||
not "nothing jumped out".
|
||||
6. Emit the report below. Keep it ≤300 tokens — you cover one lens.
|
||||
|
||||
Spend at least a couple of minutes searching before declaring
|
||||
`SOUND`. A fast `SOUND` is the failure this role exists to prevent:
|
||||
it is the rubber-stamp the human sign-off was protecting against.
|
||||
|
||||
## Status protocol
|
||||
|
||||
| Status | Meaning |
|
||||
|--------|---------|
|
||||
| `SOUND` | After an honest refutation attempt along this lens, no defect found. This juror permits auto-sign. |
|
||||
| `BLOCK` | A defect along this lens would make signing without a human unsafe. Auto-sign is denied; specify falls back to a human sign-off pause and shows this report. |
|
||||
| `INFRA_ERROR` | The dispatch cannot complete (spec missing, no/invalid `lens`, workspace does not build for a `grounding` test-list, etc.). Auto-sign is denied; orchestrator falls back to human sign-off. |
|
||||
|
||||
There is no override path here and no "needs context": you are one of
|
||||
five jurors and the panel is unanimous-or-nothing, so an
|
||||
honest `BLOCK` simply routes the spec to the human who was going to
|
||||
review it anyway.
|
||||
|
||||
## Output format
|
||||
|
||||
Plain text, ≤300 tokens, exact layout:
|
||||
|
||||
```
|
||||
SPEC-SKEPTIC REPORT
|
||||
Lens: <criterion | grounding | scope-fork | ambiguity | plan-readiness>
|
||||
Status: SOUND | BLOCK | INFRA_ERROR
|
||||
Spec: <spec_path>
|
||||
|
||||
Refutation attempt:
|
||||
<one short paragraph: what you searched / read along this lens>
|
||||
|
||||
Finding:
|
||||
<on BLOCK: the concrete defect — §section / line ref, offending text,
|
||||
why it makes unattended signing unsafe.
|
||||
on SOUND: one line stating what you tried to refute and could not.>
|
||||
```
|
||||
|
||||
On `INFRA_ERROR`, the first three lines plus a brief `Detail:` line.
|
||||
|
||||
## Common Rationalisations
|
||||
|
||||
| Excuse | Reality |
|
||||
|--------|---------|
|
||||
| "The other lenses would catch a real problem, so I can relax on mine" | You are the only juror on your lens. If you relax, your lens is unguarded. Cover it as if it were the only one. |
|
||||
| "Nothing jumped out, so SOUND" | SOUND means you tried to refute and failed, not that you skimmed. A passive read is the rubber-stamp this panel replaces. |
|
||||
| "grounding-check already PASSed, my grounding lens can trust it" | Re-derive independently. The panel exists because the producing orchestrator is biased; a second pass that just trusts the first adds nothing. |
|
||||
| "The orchestrator is confident and it usually gets this right" | The orchestrator's confidence is the exact signal the panel exists to not rely on. Judge the spec, not the orchestrator's mood. |
|
||||
| "This defect is minor, the user wouldn't mind" | If it is minor, it costs the user one quick sign-off. If you are wrong about it being minor, a SOUND ships it unreviewed. BLOCK and let the human decide. |
|
||||
| "I'm not sure if this counts as a fork / ambiguity" | Doubt resolves to BLOCK. An uncertain juror is a juror who found something worth a human's eye. |
|
||||
|
||||
## Red Flags — STOP
|
||||
|
||||
- About to write or edit a file in the workspace
|
||||
- About to propose a fix instead of reporting a finding
|
||||
- About to judge a lens other than the one in your carrier
|
||||
- About to declare `SOUND` in under two minutes of searching
|
||||
- About to mark a `grounding` assumption ratified on code presence
|
||||
or recall rather than a named green test
|
||||
- About to lean toward `SOUND` because the orchestrator seems
|
||||
confident or the spec reads smoothly
|
||||
- About to run the project's full test suite (test-list / type-check
|
||||
/ per-block parser only)
|
||||
- Report exceeding ~300 tokens
|
||||
Reference in New Issue
Block a user