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:
2026-06-09 18:19:28 +02:00
parent 8d375d5622
commit cbd460e242
8 changed files with 395 additions and 15 deletions
+28 -1
View File
@@ -27,7 +27,7 @@ The pipeline skills, each with the agents it primarily dispatches:
| `tdd` | Test-specifiable feature / issue (third entry path, alongside `brainstorm` and `specify`) | RED executable-spec in working tree → `implement` mini-mode | Opt-in entry path; bounces to `brainstorm` on a design fork |
| `fieldtest` | Orchestrator-dispatched post-audit | example fixtures + friction spec | Per-cycle optional; milestone fieldtest is the closing gate for a surface-touching milestone |
| `docwriter` | API surface stable across N cycles | rustdoc / docstring sweep | Optional |
| `boss` | User types `/boss` | autonomous-orchestrator session — dispatches the other skills until done-state or bounce-back | User-invoked, never auto-dispatched |
| `boss` | User types `/boss` | autonomous-orchestrator session — dispatches the other skills until done-state or bounce-back; can optionally sign specs in the user's place (opt-in, see below) | User-invoked, never auto-dispatched |
Two further **utility skills** are invoked on demand rather than as
pipeline phases: `issue` (file or update a tracker item) and `glossary`
@@ -131,6 +131,33 @@ skipped and documented, never silently trusted. See
`docs/profile-schema.md` § `spec_validation` for the shape and
`templates/project-profile.yml` for a commented example.
### Spec auto-sign (opt-in)
By default a `specify` dispatch in a `/boss` session pauses at its
user-review gate for the user's signature — the human approves every
spec before any plan is built. A project that wants `/boss` to run
unattended across spec boundaries can opt in with
`pipeline.boss.spec_auto_sign: true`.
With it on, the orchestrator may sign a spec in the user's place, but
never on its own confidence. Signing requires two stages to clear:
- **Objective gates** — the precondition gate, the parse-every-block
gate, and a `grounding-check` `PASS` with no human override.
- **A unanimous adversarial panel** — the `spec-skeptic` agent
dispatched five times in parallel, one per lens (`criterion`,
`grounding`, `scope-fork`, `ambiguity`, `plan-readiness`), each
trying to *refute* the spec. All five must return `SOUND`.
A single juror `BLOCK`, or any objective gate not green, falls back to
the human sign-off pause the spec would have hit anyway. On a clean
sign the orchestrator commits the spec (`(boss-signed)` in the
subject), sends a mandatory informational notify that names the signed
capability and invites a veto, and continues to `planner` without
stopping. A later veto is a forward correction, never a history
rewind. See `specify/SKILL.md` Step 6, `specify/agents/spec-skeptic.md`,
and `boss/SKILL.md` §"Spec auto-sign".
## Install
See `INSTALL.md`. In short: clone, run `install.sh`, then drop
+74 -6
View File
@@ -126,8 +126,9 @@ verdict ("test-specifiable → `tdd`" / "design settled → `specify`" /
exhaustive issue body, a long in-context discussion — then the design
is **settled** and `specify` owns it. Dispatch `specify`
autonomously: it is bounded (no interview), produces the spec through
all the gates, and pauses only at its own user-review gate (a
problem-state notify, not a pre-dispatch checkpoint).
all the gates, and — unless the profile enables auto-sign (see below)
— pauses at its own user-review gate (a problem-state notify, not a
pre-dispatch checkpoint).
- Writing the spec would force a choice between two or three plausible
designs with real trade-offs — a genuine design fork — then discovery
must resolve it first, and `brainstorm` owns it. Starting a fresh
@@ -140,9 +141,16 @@ fresh `brainstorm` cycle bounces back — is **not** a ranking of the
skills. It is a consequence of context budget: `tdd` and `specify` are
both bounded (no open Q&A), whereas a fresh `brainstorm` is high-context
discovery the orchestrator cannot compact on its own (see trigger 4).
`specify` dispatched in `/boss` still pauses at its own Step-6
user-review gate to take sign-off — that is a final-sign-off notify, not
a pre-dispatch checkpoint. Do not let the asymmetry harden into a reflex
`specify` dispatched in `/boss` pauses at its own Step-6 user-review
gate to take sign-off — that is a final-sign-off notify, not a
pre-dispatch checkpoint. The one exception is the opt-in auto-sign
slot (`pipeline.boss.spec_auto_sign`): when a project enables it, a
spec that clears all objective gates AND a unanimous adversarial
`spec-skeptic` panel is signed by the orchestrator without pausing,
and the run continues to `planner` — see §"Spec auto-sign" below. The
gate is built so that the orchestrator's own confidence is never what
signs; absent the slot, the human signature stays mandatory. Do not
let the asymmetry harden into a reflex
of routing borderline items to `brainstorm` "to be safe" — that is the
exact bias this reflection exists to break; apply the design-line test
honestly each time. The one principled tilt is two-sided and lives
@@ -245,7 +253,8 @@ question.
## Notifications
Two states call for a notify; nothing else does:
Two states call for a notify; nothing else does — plus a third,
narrow one that exists only when spec auto-sign is enabled:
1. **Done-state.** The autonomous queue is empty — the cycle
closed, the audit ratified, and no further iteration is
@@ -265,6 +274,16 @@ Two states call for a notify; nothing else does:
the next backlog item is a new cycle (no spec yet) and
starting it would force a fresh `brainstorm`.
3. **Auto-sign (only with `pipeline.boss.spec_auto_sign`).** The
orchestrator signed a spec in the user's place and is
continuing the run — see §"Spec auto-sign". This is the one
sanctioned mid-flow notify, and it is sanctioned *because it
carries a decision*: the spec normally needs the user's
signature, so the user retains a veto over what was signed
without them. It is not a progress ping — it is the audit
trail for a gate the user delegated. It does not stop the
loop.
A user-specified stop trigger ("until X is done, then notify")
counts as done-state only if X is truly the last actionable
item in the autonomous queue at that moment. If hitting X
@@ -321,6 +340,46 @@ watch the orchestrator work**:
checkpoint) follow the same editorial rules but carry the
actionable ask, not a wrap-up summary.
## Spec auto-sign
Off by default. A project turns it on with
`pipeline.boss.spec_auto_sign: true`. With it off, a `specify`
dispatch in `/boss` always pauses for the user's signature — the
conservative default, unchanged.
With it on, the orchestrator MAY sign a spec in the user's place,
but only through `specify`'s Step-6 auto-sign gate, which is owned
and defined there. The boss-side contract is just this:
- **The gate is not the orchestrator's judgement.** Signing requires
every objective gate green (precondition, parse, a `grounding-check`
`PASS` that needed no human override) AND a unanimous five-lens
`spec-skeptic` panel returning `SOUND`. A single `BLOCK` — or any
objective gate not green — routes the spec to the human sign-off
pause it would have hit anyway. "The spec looks good to me" is never
a signature; that confidence is the exact signal the gate refuses to
trust.
- **On a clean sign, do not stop.** Commit the spec (the auto-sign
commit subject carries `(boss-signed)` so the act is auditable in
history), fire the auto-sign notify, and continue to `planner` in
the same run. The notify is informational-with-veto, not a pause.
- **The notify must be vetoable.** It follows the same editorial rules
as a done-state notify (English, user-as-reader, no iteration codes
or crate names) with one addition forced by its purpose: it must
name, in the user's terms, *what capability the signed spec covers*,
so the user can decide whether to veto. State plainly that the spec
was signed without them, that the plan is proceeding, and that a
reply vetoes. One example shape: "Signed off the spec for <plain
capability> myself and started the implementation plan — reply to
veto." No internals, but enough identity to act on.
- **A veto is a forward correction.** If the user vetoes after the
fact, the signed spec is already a commit on `main` (forward-only).
Undo it forward — revert the spec commit, discard the downstream
working-tree work with `git checkout`, file the redirection — never
a history rewind. This is the same containment as any other
orchestrator call (§"Direction freedom"): bad calls are contained on
the forward edge, not recovered by rewinding HEAD.
## Common Rationalisations
| Excuse | Reality |
@@ -335,6 +394,9 @@ actionable ask, not a wrap-up summary.
| "Feature work, so route it to `brainstorm` — that's the safe default" | `brainstorm`, `specify`, and `tdd` are co-equal entry paths; none is the default. Routing a settled design to `brainstorm` re-litigates decided choices; routing a test-specifiable item there wastes the test path. Run the Entry-path reflection and pick by the design line. The only tilt toward `brainstorm` is a genuinely unresolved fork — and that is a fork, not a default. |
| "The issue is exhaustive but it's a new cycle, so bounce to the user before `specify`" | `specify` direct-entry is bounded and autonomously dispatchable — it is NOT the high-context `brainstorm` cycle that trigger 4 reserves for the user. Dispatch it; it will pause at its own user-review gate for sign-off. The pre-dispatch bounce is for an *open* design that needs discovery, not for a settled one that needs only production. |
| "`tdd` is opt-in / profile-gated, so it's the secondary skill" | Profile-gating is about whether the path is *available*, not about rank. Once enabled, the choice between the two is decided by fit per item, reflected on each time — not by treating `brainstorm` as primary and `tdd` as the exception. |
| "Auto-sign is on and this spec is clearly good — I'll sign it and skip the panel" | The panel IS how a spec gets signed under auto-sign; there is no signing on judgement. Your sense that it is clearly good is the precise signal the gate is built not to trust. Run the objective gates, dispatch the five jurors, require unanimity. |
| "Four jurors said SOUND, one blocked on something I think is wrong — I'll sign" | Unanimous-or-nothing. You do not overrule a juror; a single `BLOCK` routes the spec to the human sign-off it would have had anyway. Overruling the panel is signing on your own confidence by the back door. |
| "Auto-sign let me continue, so I don't need to notify — it's just progress" | The auto-sign notify is mandatory and carries a decision (the user's veto over a signature made without them). It is the one sanctioned mid-flow notify precisely because it is not progress — it is the audit trail for a delegated gate. |
## Red Flags — STOP
@@ -345,6 +407,8 @@ actionable ask, not a wrap-up summary.
- About to bounce back at every iteration boundary "just to be safe" — that's reactive deference, not direction freedom.
- About to dispatch `brainstorm` on a backlog issue that does not yet have a spec file, without first bouncing back to the user. New cycles never start autonomously.
- About to route feature work to `brainstorm` without running the Entry-path reflection — defaulting to it because it "feels safer" than `specify` or `tdd`, rather than applying the design-line test. The three are co-equal; the choice is reflected on each time. Routing a *settled* design to `brainstorm` (re-litigating decided choices) is as much a failure as skipping discovery on an open one.
- About to sign a spec under auto-sign on confidence — without all objective gates green and a unanimous `spec-skeptic` panel, or by overruling a single juror's `BLOCK`. The gate exists so the orchestrator's confidence never signs.
- About to run the auto-sign path at all when `pipeline.boss.spec_auto_sign` is not enabled, or to skip the mandatory auto-sign notify after signing.
## Cross-references
@@ -361,6 +425,10 @@ actionable ask, not a wrap-up summary.
the profile; CLI command at `git.issue_tracker.list_cmd`.
- **Glossary write-rule:** `../docs/glossary-convention.md`
record-reality discipline for the only autonomous glossary writer.
- **Spec auto-sign gate:** owned by `../specify` Step 6; the
adversarial juror is `../specify/agents/spec-skeptic.md` (dispatched
five times, one per lens). Enabled per project by
`pipeline.boss.spec_auto_sign` — see `../docs/profile-schema.md`.
- **Downstream skills dispatched:** `../brainstorm`,
`../specify` (spec-production core; autonomously dispatchable for a
settled design), `../planner`, `../implement`, `../audit`,
+2 -2
View File
@@ -74,7 +74,7 @@ plugin's agent path is enough disambiguator).
Examples: `architect`, `bencher`, `debugger`, `implementer`,
`tester`, `fieldtester`, `docwriter`, `grounding-check`,
`plan-recon`, `spec-reviewer`, `quality-reviewer`,
`spec-skeptic`, `plan-recon`, `spec-reviewer`, `quality-reviewer`,
`implement-orchestrator`.
### `description`
@@ -93,7 +93,7 @@ agents.
Common tool sets:
- Read-only review (architect, spec-reviewer, quality-reviewer,
grounding-check, plan-recon): `Read, Glob, Grep, Bash`
grounding-check, spec-skeptic, plan-recon): `Read, Glob, Grep, Bash`
- Implementation (implementer, tester, debugger, docwriter,
fieldtester, bencher): `Read, Edit, Write, Bash, Glob, Grep`
- Orchestrator (implement-orchestrator): `Read, Edit, Write,
+8
View File
@@ -104,6 +104,14 @@ interview. Bounces to `brainstorm` the moment the sources do not
resolve a load-bearing design decision. A core node, not opt-in
(unlike `tdd`).
The sign-off is the user's by default, including under `/boss`. The
one exception is the opt-in `pipeline.boss.spec_auto_sign` slot: with
it on, a `/boss` run may sign a spec in the user's place — but only
when every objective gate is green AND a unanimous five-lens
`spec-skeptic` panel passes; the orchestrator's own confidence never
signs. Any juror `BLOCK` falls back to the human sign-off pause. See
`../specify/SKILL.md` Step 6 and `../boss/SKILL.md` §"Spec auto-sign".
### planner
Hard-gate before implement. Produces a placeholder-free,
+19 -1
View File
@@ -215,11 +215,29 @@ pipeline:
alt_to: brainstorm # alternative design entry; bounces back on a design fork
boss:
user_invoked: true # autonomous-orchestrator mode, /boss
spec_auto_sign: false # opt-in: let /boss sign a spec in the user's place (default off)
```
Phases not listed are disabled for the project. A project that
does not want a `fieldtest` phase simply omits the key. `tdd` is
opt-in the same way. `specify`, by contrast, is a **core** node — it
opt-in the same way.
`boss.spec_auto_sign` is an opt-in slot, default off (a missing key
reads as `false`). With it off — the conservative default — a
`specify` dispatch in a `/boss` session always pauses at its Step-6
user-review gate for the user's signature, exactly as before. With it
**on**, the orchestrator may sign a spec in the user's place, but only
through `specify`'s auto-sign gate: every objective gate green
(precondition, parse, a `grounding-check` `PASS` with no human
override) AND a unanimous five-lens `spec-skeptic` panel. A single
juror `BLOCK`, or any objective gate not green, falls back to the
human sign-off pause. Model self-confidence alone never signs — the
gate is built specifically not to rely on it. On a clean sign the
orchestrator commits the spec (subject carries `(boss-signed)`), sends
the mandatory informational-with-veto notify, and continues to
`planner` without stopping. See `../specify/SKILL.md` Step 6 (gate
owner), `../specify/agents/spec-skeptic.md` (the juror), and
`../boss/SKILL.md` §"Spec auto-sign" (notify + veto contract). `specify`, by contrast, is a **core** node — it
is the spec-production gate before `planner` on every design path,
reachable directly from settled sources or via the optional
`brainstorm` discovery stage. `tdd` opt-in only adds the
+73 -5
View File
@@ -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
+188
View File
@@ -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
+3
View File
@@ -75,6 +75,9 @@ pipeline:
debug: { trigger: bug, red_first: true }
# tdd: { trigger: test_specifiable_feature, red_first: true, alt_to: brainstorm } # opt-in: executable-spec-first entry, alternative to brainstorm
# boss: { user_invoked: true } # autonomous orchestrator mode, /boss
# spec_auto_sign: false # opt-in: let /boss sign a spec in the user's place when all
# # objective gates are green AND a unanimous spec-skeptic panel
# # passes; default off (human signature mandatory). See profile-schema.md.
# fieldtest: { boss_only: true, when: surface_touch } # per-cycle usability test
# milestone_fieldtest: { boss_only: true, when: surface_touch, gates_close: milestone } # closing gate: end-to-end proof of the milestone's promise
# docwriter: { boss_only: true, when: api_stable_across_n_cycles }