diff --git a/README.md b/README.md index 25c7fe2..0ff7f35 100644 --- a/README.md +++ b/README.md @@ -130,12 +130,13 @@ not settled), an `INFRA_ERROR`, any objective gate not green, or an exhausted budget falls back to the human sign-off pause the spec would have hit anyway. Re-dispatching all five lenses every round is the backstop that stops an editorial repair from quietly settling a design -question. When a fork was settled in-context but the seeding issue still -lists it open, `specify` records the resolution as a provenance-bearing -reconciliation comment on the issue (Step 1.5), which the `scope-fork` -juror reads via the project's issue show command — closing the blind spot where -the in-context entry path could otherwise never clear that lens. On a -clean sign the orchestrator commits the spec +question. When a fork was settled in-context, `specify` gives the +`scope-fork` juror an auditable source for it (Step 1.5): a provenance- +bearing reconciliation comment when a seeding issue exists but lags the +discussion, or a freshly created seeding issue when the cycle had none — +either read via the project's issue show command, closing the blind spot +where the in-context entry path could otherwise never clear that lens. +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 diff --git a/boss/SKILL.md b/boss/SKILL.md index caadca7..525de05 100644 --- a/boss/SKILL.md +++ b/boss/SKILL.md @@ -366,12 +366,17 @@ and defined there. The boss-side contract is just this: question in the user's place; the full re-panel each round is what stops an editorial repair from laundering one in. The gate owns this loop (`../specify/SKILL.md` Step 6) — boss only enforces the notify. - One upstream detail matters here: when a fork was settled in-context - but the seeding issue still lists it open, `specify` Step 1.5 posts a - provenance-bearing reconciliation comment on the issue so the - `scope-fork` juror ratifies the resolution from an auditable source - rather than false-blocking on the stale body. That comment records a - *user* decision; it never lets the orchestrator certify its own. + One upstream detail matters here: a fork settled in-context may be + invisible to the `scope-fork` juror, which reads the seeding issue. + `specify` Step 1.5 gives it an auditable source either way — when a + seeding issue exists but still lists the fork open, it posts a + provenance-bearing reconciliation comment; when there is *no* seeding + issue (design settled in pure chat), it creates one that records the + resolution with provenance and becomes the cycle's seeding issue. + Both record a *user* decision; neither lets the orchestrator certify + its own — no real user statement is a Step-1.5 bounce, not an artefact + to manufacture. The orchestrator writes the record; the juror checks + the provenance. - **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 diff --git a/docs/design.md b/docs/design.md index 18ce69e..547149b 100644 --- a/docs/design.md +++ b/docs/design.md @@ -123,7 +123,7 @@ The relationship: issue-tracker commands (the repo slug, list command, and single-issue-with-comments command, all in its CLAUDE.md project facts) and invokes them, and `specify` may post a reconciliation - comment via the tracker's comment command — but the plugin does - not directly call Gitea / GitHub / Linear APIs. Every read and - write goes through the configured shell command, so the plugin - remains transport-agnostic. + comment or create a seeding issue via the tracker's comment / create + commands — but the plugin does not directly call Gitea / GitHub / + Linear APIs. Every read and write goes through the configured shell + command, so the plugin remains transport-agnostic. diff --git a/docs/pipeline.md b/docs/pipeline.md index 7e95a9e..5106e1e 100644 --- a/docs/pipeline.md +++ b/docs/pipeline.md @@ -114,10 +114,11 @@ signs. A `BLOCK` is never signed over: an editorial one (`criterion` / that re-runs the objective gates and re-dispatches all five lenses each round; a design one (`scope-fork` / `grounding`), an `INFRA_ERROR`, or an exhausted budget falls back to the human sign-off pause. When the -entry is in-context and the seeding issue still lists a now-resolved -fork as open, `specify` posts a provenance-bearing reconciliation -comment on the issue (Step 1.5) so the `scope-fork` juror can ratify the -resolution instead of blocking on the stale body. See +entry is in-context, `specify` gives the `scope-fork` juror an auditable +source for an in-context fork resolution (Step 1.5) — a provenance- +bearing reconciliation comment when a seeding issue lags the discussion, +or a freshly created seeding issue when the cycle had none — so the +juror can ratify the resolution instead of blocking for lack of one. See `../specify/SKILL.md` Step 6 and `../boss/SKILL.md` §"Spec auto-sign". ### planner diff --git a/specify/SKILL.md b/specify/SKILL.md index 6330f8b..aa43982 100644 --- a/specify/SKILL.md +++ b/specify/SKILL.md @@ -162,12 +162,49 @@ Gitea writes are pre-authorized (per `~/.claude/CLAUDE.md`); post the comment without a confirmation prompt. **Issue-less in-context entry.** If the cycle has *no* tracker issue — -the design was settled in pure chat — there is no independent artefact to -comment on, and a provenance note *inside the spec* would be -self-referential (the spec asserting its own sources settle it). Do not -manufacture a weak spec-note path: under auto-sign this case falls back -to the human sign-off (the safe default), because no auditable source -exists for the juror to check against. +the design was settled in pure chat — there is no existing artefact to +comment on, so *create one*: open a new tracker issue that records the +resolved fork(s) with provenance, under the same discipline as the +reconciliation comment above. The body takes this shape: + +``` +## Design record (specify, issue-less in-context entry) +This issue seeds . The design was settled +in an in-context discussion with no prior tracker issue; this records it. +Load-bearing fork(s) resolved: +- **Fork: ** → . + Provenance: . +``` + +The body names the *work*, not the spec file — the spec does not exist +yet at Step 1.5 (its number is assigned only in Step 3). This new issue +is the cycle's seeding issue from here on: the `scope-fork` juror reads +it via the project's issue show command — its index handed to the juror +in the Step-6 carrier (the `seeding_issue` field, below) — exactly as it +reads any seeding issue. A *new issue* is the right artefact where a spec-note +is the wrong one — a provenance note *inside the spec* is +self-referential (the spec asserting its own sources settle it) and +stays banned, but a separate issue is independent (author + timestamp, +in the forward queue, juror-readable without opening the spec), as +auditable as a reconciliation comment. Creating it is what makes +auto-sign *reachable* here, instead of the old unconditional fall-back +to the human sign-off. + +The provenance gate is unchanged and load-bearing: the new issue records +*user* decisions, never fresh orchestrator ones. No real user statement +for a fork means *you* picked it — a Step-1.5 bounce, not an issue to +manufacture. You *write* the issue; the adversarial `scope-fork` juror +*checks* the provenance, and a provenance-less body buys no pass. + +Create it via the project's issue-create command (the `issue` skill's +mechanics — `tea issues create` for Gitea), title and label per the +project's vocabulary as in the Step-5 failure-mode procedure. Gitea +writes are pre-authorized, so create it without a confirmation prompt. +**Capture the new issue's index** the moment it is created and carry it +into the Step-6 panel as the `seeding_issue` field — it is the only way +the `scope-fork` juror knows which issue to read. An issue created but +never handed to the panel is invisible to the juror, which leaves the +fork looking picked and the creation pointless. ### Step 2 — Apply the project's feature-acceptance criterion @@ -366,7 +403,11 @@ CLAUDE.md project facts): 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 + `iteration_scope`, the single `lens`, and `seeding_issue` — the + index of the cycle's seeding issue (the lagging issue reconciled in + Step 1.5, the issue Step 1.5 created for an otherwise issue-less + cycle, or `none` if the cycle has neither) for the `scope-fork` + juror to read; the other four lenses ignore it. Each juror tries to *refute* the spec along its lens and returns `SOUND` / `BLOCK` / `INFRA_ERROR`. Auto-sign requires a **unanimous `SOUND`** — that never changes. What the partition below adds is a bounded path to @@ -455,7 +496,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` → `spec-skeptic` panel (Step 6, `/boss` + `spec_auto_sign` only) | `spec_path` (absolute) + `iteration_scope` + one `lens` per dispatch (five in parallel) + `seeding_issue` (index for the `scope-fork` juror to read, or `none`) | | `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 | diff --git a/specify/agents/spec-skeptic.md b/specify/agents/spec-skeptic.md index 18c3647..16cd7c5 100644 --- a/specify/agents/spec-skeptic.md +++ b/specify/agents/spec-skeptic.md @@ -75,23 +75,29 @@ In addition, every dispatch: 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. The seeding issue is reachable via the project's issue - show command (its CLAUDE.md project facts) — it MUST render the issue - WITH its comment thread (issue index appended last) — invoke it so - you read the issue **with its comment thread**, not the body alone. + built from. Your carrier names the `seeding_issue` index — append it + to the project's issue show command (its CLAUDE.md project facts, + which MUST render the issue WITH its comment thread) and invoke it so + you read the issue **with its comment thread**, not the body alone. If + `seeding_issue` is `none`, the cycle has no seeding issue and you have + only the spec to judge against — a load-bearing fork the spec leaves + unsourced is then a refutation. You judge "resolved vs picked" against what the sources actually say, not against what reads plausibly. A fork the issue *body* still lists open may have been resolved in an in-context discussion the dispatch cannot replay to you; the legitimate channel for that resolution is a - **reconciliation comment** on the issue (`specify` Step 1.5). A - reconciliation comment counts as the sources resolving the fork **only - if it carries provenance** — a record of the user's decision (a - verbatim statement, or explicit attribution + date). A bare - `decision: X` with no provenance is an orchestrator self-assertion - dressed as settled, not a source: it does **not** resolve the fork, and - a load-bearing decision whose only support is such a comment is a - refutation. If the project declares no issue show command, you have - only the body — a fork the body lists open is unresolved to you. + **provenance-bearing reconciliation record** written by `specify` Step + 1.5 — either a reconciliation *comment* on a seeding issue that lagged + the discussion, or, for a cycle that had *no* seeding issue, the + *body* of the issue `specify` created to record it. Either counts as + the sources resolving the fork **only if it carries provenance** — a + record of the user's decision (a verbatim statement, or explicit + attribution + date). A bare `decision: X` with no provenance is an + orchestrator self-assertion dressed as settled, not a source: it does + **not** resolve the fork, and a load-bearing decision whose only + support is such a record is a refutation. If the project declares no + issue show command, you have only what you can read — a fork no + provenance-bearing record resolves is unresolved to you. You do NOT read files under `docs/plans` (the plan does not yet exist). You do NOT read other specs unless the spec under review @@ -104,6 +110,7 @@ references one — and then only the referenced section. | `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` | +| `seeding_issue` | index of the cycle's seeding issue for the `scope-fork` juror to read via the project's issue show command — the lagging issue reconciled in `specify` Step 1.5, the issue Step 1.5 created for an otherwise issue-less cycle, or `none`. The other four lenses ignore it; if absent, treat as `none`. | The controller is the `specify` skill's Step 6, running inside a `/boss` session. You receive the carrier inline in the dispatch @@ -134,10 +141,10 @@ YOU DO NOT RUN THE FULL TEST SUITE. (TEST LIST, TYPE-CHECK ARE OK.) pin; your own recall does not pin). For `scope-fork`, this means listing the load-bearing decisions and checking each against the sources read via the project's issue show command (issue **with - comments**); a fork the - issue body lists open is resolved only by a reconciliation comment - that carries provenance (see the standing reading list) — a - provenance-less one does not count. For the others, read for the + comments**); a fork the issue body lists open is resolved only by a + provenance-bearing reconciliation record — a comment, or the body of + an issue `specify` created for an otherwise issue-less cycle (see the + standing reading list) — a provenance-less one does not count. 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).