fix(pipeline): complete the gitignored-specs refactor (review gaps)

An adversarial review of 08bc2aa found three gaps:

- templates/CLAUDE.md.fragment still described the OLD git-tracked /
  git-rm-at-close model verbatim — the worst place to miss it, since new
  projects import this fragment into their CLAUDE.md. Rewritten to the
  gitignored / shell-rm / ledger-only model.
- INSTALL.md still cited "4-digit naming" — now slug-only.
- The fieldtest cross-cycle deletion rule was self-defeating: it keyed
  the spare/delete decision on the permanent fieldtest- prefix, which
  cannot encode "spare once, then delete." Because fieldtest runs only
  AFTER audit closes, the fresh fieldtest spec never exists at the
  cycle-close sweep, so the rule is simply "audit discards every
  working-tree spec/plan"; the spent fieldtest spec present at N+1's
  close was already consumed and goes with the rest. The prefix is now
  only a working-tree label, not a delete discriminator. Reconciled
  across audit, conventions, pipeline, fieldtest, fieldtester.
This commit is contained in:
2026-07-02 11:46:29 +02:00
parent 9ca2c8ab87
commit 2bc0cf025f
7 changed files with 40 additions and 31 deletions
+1 -1
View File
@@ -47,7 +47,7 @@ $EDITOR <project-root>/CLAUDE.md # paste from templates/CLAUDE.md.fragment
```
Everything the plugin does *not* read from project facts is a fixed
convention (spec dir `docs/specs`, 4-digit naming, the pipeline graph,
convention (spec dir `docs/specs`, slug-only naming, the pipeline graph,
…) documented once in `docs/conventions.md` and `docs/pipeline.md`
not configurable per project.
+12 -9
View File
@@ -125,11 +125,12 @@ The orchestrator picks per item:
### Step 5 — Discard the cycle's spec and plan
Once the cycle is drift-clean (or the drift is ratified) and the
architect has read the spec, the cycle's spec and plan have served their
purpose. Discard them from the working tree with a plain shell `rm`:
architect has read the spec, the working-tree spec and plan have served
their purpose. Discard **every** spec/plan file present in the working
tree with a plain shell `rm`:
```
rm -f docs/specs/<slug>.md docs/plans/<slug>.md
rm -f docs/specs/*.md docs/plans/*.md
```
This is a shell delete, NOT `git rm` — the files are git-ignored and were
@@ -138,12 +139,14 @@ only code and ledger changes. **Ordering is load-bearing:** the
architect's read (Step 1) must precede this delete, because a git-ignored
spec has no `git show` recovery once it is gone.
**Spare any `fieldtest-`-prefixed spec.** A `fieldtest-<slug>.md` under
`docs/specs` belongs to the *next* cycle (it is the input to its
`planner`), so it is not this cycle's to discard — leave it for the next
cycle's close. If this cycle is itself a milestone close with no
following `planner`, discard the fieldtest spec too (see
`../fieldtest/SKILL.md`).
Deleting *everything present* is correct, not over-broad: `fieldtest`
runs only **after** audit closes clean, so this cycle's own fieldtest
spec does not exist yet at this point. The only `fieldtest-<slug>.md`
that can be present here is a spent one — written after the *previous*
cycle's close and already consumed as this cycle's `planner` input — so
it too should go. There is nothing to spare: the newly-written fieldtest
spec appears *after* this step and survives until the next cycle's close,
when this same sweep removes it.
## Handoff Contract
+4 -3
View File
@@ -77,9 +77,10 @@ and cited by nothing (see § Lifecycle), they hold at most the active
cycle's handful of files, so a slug is already unique enough — the old
scan-for-the-next-free-number ritual bought nothing and is gone. A
`fieldtest`-produced spec takes a `fieldtest-` prefix
(`fieldtest-slug.md`): that prefix is the discriminator the cycle-close
sweep uses to spare it, because it belongs to the next cycle (see
`../fieldtest/SKILL.md`).
(`fieldtest-slug.md`) so it is recognisable in the working tree as the
next cycle's planning input rather than this cycle's own spec — it is
written after audit's cycle-close sweep and discarded by the next
cycle's sweep (see `../fieldtest/SKILL.md`).
**The file name is not the cycle number.** The **cycle number** that
appears in commit subjects (`feat(NNNN)`, `audit(NNNN)`) and in `git
+4 -5
View File
@@ -213,11 +213,10 @@ review-and-commit discipline; the orchestrator inspects and commits.
Runs at cycle close. Dispatches the architect agent (read-only
drift review against the design ledger) and the bencher agent
(regression diagnostics). Reports drift and regress. Once it is
drift-clean, the orchestrator discards the cycle's spec and plan with a
plain shell `rm` (nothing to `git rm` — they were never committed),
sparing any `fieldtest-`-prefixed spec (it belongs to the next cycle);
the cycle-close commit contains only code and ledger changes (see
`conventions.md` § Lifecycle).
drift-clean, the orchestrator discards every working-tree spec and plan
with a plain shell `rm` (nothing to `git rm` — they were never
committed); the cycle-close commit contains only code and ledger changes
(see `conventions.md` § Lifecycle).
### debug
+8 -6
View File
@@ -125,12 +125,14 @@ committed as normal code** (they are consumer test assets — suggested
subject `fieldtest: <cycle> — <N> examples, <K> findings`), while the
**fieldtest spec is a git-ignored working file that is never committed**.
The fieldtest spec is written at cycle N's close but is an **input to
the next cycle's `planner`**, so it belongs to cycle N+1, not N: the
cycle-close sweep spares it (its `fieldtest-` filename prefix is the
discriminator) and it is shell-`rm`'d at N+1's close alongside N+1's own
spec and plan. If the consuming cycle closes without a `planner` (e.g. a
milestone close), the orchestrator discards it explicitly.
The fieldtest spec is written **after** cycle N's audit-close (fieldtest
runs only once audit is clean), so N's cycle-close sweep has already run
and cannot touch it — it survives naturally as an **input to the next
cycle's `planner`**. It is shell-`rm`'d at N+1's audit-close, whose sweep
removes every working-tree spec and plan (N+1's own, plus this spent
fieldtest spec). The `fieldtest-` prefix only marks it in the working
tree as the next cycle's input; it plays no part in the delete decision
(the sweep removes everything present).
## Handoff Contract
+2 -2
View File
@@ -212,8 +212,8 @@ not merged.
### Phase 5 — Write the spec, hand back
Write the fieldtest spec under `docs/specs` named
`fieldtest-slug.md` (the `fieldtest-` prefix is mandatory — it is the
discriminator that spares the spec from the cycle-close sweep; no numeric
`fieldtest-slug.md` (the `fieldtest-` prefix is mandatory — it marks the
spec in the working tree as the next cycle's planning input; no numeric
prefix, see `docs/conventions.md` § Naming). Use the spec
template below. Leave all artefacts in the working tree as unstaged
changes. You do NOT commit — the orchestrator commits the **fixtures**
+9 -5
View File
@@ -68,11 +68,15 @@ Two rules govern who touches git history and how:
## Spec/plan artefacts are ephemeral
`docs/specs/` and `docs/plans/` hold only the active cycle's spec and
plan, and they stay **git-tracked** — do not git-ignore them. Each is
committed while its cycle is live and `git rm`'d at cycle close, so it
is transient in the repo: present for its own cycle, then gone from
`HEAD` while git history keeps the full text (see
`~/dev/skills/docs/conventions.md` § Lifecycle).
plan, and they are **git-ignored** — never committed (the plugin ignores
them globally via `~/.config/git/ignore`; a project may add its own
`.gitignore` entry instead). Each is a working file: present on disk for
its own cycle, read across sessions from the working tree, and
shell-`rm`'d at cycle close by `audit` — never `git rm`'d, since it was
never tracked, so no git-history copy survives. The durable record of a
past cycle is the design ledger only, and no durable artefact cites a
spec/plan by number or path (see `~/dev/skills/docs/conventions.md`
§ Lifecycle).
## Design rationale ≠ implementation effort