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 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` …) documented once in `docs/conventions.md` and `docs/pipeline.md`
not configurable per project. 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 ### Step 5 — Discard the cycle's spec and plan
Once the cycle is drift-clean (or the drift is ratified) and the 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 architect has read the spec, the working-tree spec and plan have served
purpose. Discard them from the working tree with a plain shell `rm`: 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 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 architect's read (Step 1) must precede this delete, because a git-ignored
spec has no `git show` recovery once it is gone. spec has no `git show` recovery once it is gone.
**Spare any `fieldtest-`-prefixed spec.** A `fieldtest-<slug>.md` under Deleting *everything present* is correct, not over-broad: `fieldtest`
`docs/specs` belongs to the *next* cycle (it is the input to its runs only **after** audit closes clean, so this cycle's own fieldtest
`planner`), so it is not this cycle's to discard — leave it for the next spec does not exist yet at this point. The only `fieldtest-<slug>.md`
cycle's close. If this cycle is itself a milestone close with no that can be present here is a spent one — written after the *previous*
following `planner`, discard the fieldtest spec too (see cycle's close and already consumed as this cycle's `planner` input — so
`../fieldtest/SKILL.md`). 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 ## 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 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 scan-for-the-next-free-number ritual bought nothing and is gone. A
`fieldtest`-produced spec takes a `fieldtest-` prefix `fieldtest`-produced spec takes a `fieldtest-` prefix
(`fieldtest-slug.md`): that prefix is the discriminator the cycle-close (`fieldtest-slug.md`) so it is recognisable in the working tree as the
sweep uses to spare it, because it belongs to the next cycle (see next cycle's planning input rather than this cycle's own spec — it is
`../fieldtest/SKILL.md`). 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 **The file name is not the cycle number.** The **cycle number** that
appears in commit subjects (`feat(NNNN)`, `audit(NNNN)`) and in `git 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 Runs at cycle close. Dispatches the architect agent (read-only
drift review against the design ledger) and the bencher agent drift review against the design ledger) and the bencher agent
(regression diagnostics). Reports drift and regress. Once it is (regression diagnostics). Reports drift and regress. Once it is
drift-clean, the orchestrator discards the cycle's spec and plan with a drift-clean, the orchestrator discards every working-tree spec and plan
plain shell `rm` (nothing to `git rm` — they were never committed), with a plain shell `rm` (nothing to `git rm` — they were never
sparing any `fieldtest-`-prefixed spec (it belongs to the next cycle); committed); the cycle-close commit contains only code and ledger changes
the cycle-close commit contains only code and ledger changes (see (see `conventions.md` § Lifecycle).
`conventions.md` § Lifecycle).
### debug ### 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 subject `fieldtest: <cycle> — <N> examples, <K> findings`), while the
**fieldtest spec is a git-ignored working file that is never committed**. **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 fieldtest spec is written **after** cycle N's audit-close (fieldtest
the next cycle's `planner`**, so it belongs to cycle N+1, not N: the runs only once audit is clean), so N's cycle-close sweep has already run
cycle-close sweep spares it (its `fieldtest-` filename prefix is the and cannot touch it — it survives naturally as an **input to the next
discriminator) and it is shell-`rm`'d at N+1's close alongside N+1's own cycle's `planner`**. It is shell-`rm`'d at N+1's audit-close, whose sweep
spec and plan. If the consuming cycle closes without a `planner` (e.g. a removes every working-tree spec and plan (N+1's own, plus this spent
milestone close), the orchestrator discards it explicitly. 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 ## Handoff Contract
+2 -2
View File
@@ -212,8 +212,8 @@ not merged.
### Phase 5 — Write the spec, hand back ### Phase 5 — Write the spec, hand back
Write the fieldtest spec under `docs/specs` named Write the fieldtest spec under `docs/specs` named
`fieldtest-slug.md` (the `fieldtest-` prefix is mandatory — it is the `fieldtest-slug.md` (the `fieldtest-` prefix is mandatory — it marks the
discriminator that spares the spec from the cycle-close sweep; no numeric spec in the working tree as the next cycle's planning input; no numeric
prefix, see `docs/conventions.md` § Naming). Use the spec prefix, see `docs/conventions.md` § Naming). Use the spec
template below. Leave all artefacts in the working tree as unstaged template below. Leave all artefacts in the working tree as unstaged
changes. You do NOT commit — the orchestrator commits the **fixtures** 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 ## Spec/plan artefacts are ephemeral
`docs/specs/` and `docs/plans/` hold only the active cycle's spec and `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 plan, and they are **git-ignored** — never committed (the plugin ignores
committed while its cycle is live and `git rm`'d at cycle close, so it them globally via `~/.config/git/ignore`; a project may add its own
is transient in the repo: present for its own cycle, then gone from `.gitignore` entry instead). Each is a working file: present on disk for
`HEAD` while git history keeps the full text (see its own cycle, read across sessions from the working tree, and
`~/dev/skills/docs/conventions.md` § Lifecycle). 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 ## Design rationale ≠ implementation effort