refactor(pipeline): specs/plans are gitignored working files, never committed
Per-cycle specs and plans stop being git-tracked commit-then-git-rm artefacts and become git-ignored working files: created on disk for the active cycle, read across sessions from the working tree, and shell-rm'd at cycle close by audit. Nothing is committed, so there is no git-history copy — the durable record of a cycle's intent is the design ledger only, and no durable artefact (code, test, doc, ledger) may cite a spec/plan by number or path. - conventions/pipeline/design/README: invert the git-tracked -> git-rm -> git-history-recovery model to gitignored -> shell-rm -> ledger-only. - naming: drop the NNNN file counter; files are slug.md (fieldtest specs keep a fieldtest- prefix as the cycle-close discriminator). - cycle number: separated from the (now-gone) file number, sourced from the feat(NNNN)/audit(NNNN) commit subjects, which cycle commits carry. - specify/planner/fieldtest/fieldtester: no commit step; fieldtest splits fixtures (committed as code) from its spec (gitignored), with the cross-cycle rule that a fieldtest- spec belongs to the next cycle. - boss: auto-sign auditability moves from the (boss-signed) commit subject to the run's reference issue; rollback reverts only code. - audit: new Step 5 shell-rm's the cycle spec+plan after the architect reads them, sparing fieldtest- specs. Companion machine config (outside this repo): the global git excludes (~/.config/git/ignore) gains docs/specs/ and docs/plans/ so the ignore applies to every project at once.
This commit is contained in:
+49
-24
@@ -27,6 +27,15 @@ These directories are fixed. A project that keeps specs and plans
|
||||
elsewhere is the rare exception and states the override in its
|
||||
`CLAUDE.md` project facts.
|
||||
|
||||
Both directories are **git-ignored** — their contents are transient
|
||||
working files, never committed (see § Lifecycle). The plugin ignores
|
||||
them **globally**: `docs/specs/` and `docs/plans/` live in the user's
|
||||
global git excludes (`~/.config/git/ignore`, the XDG default that
|
||||
applies to every repo), next to the other plugin-wide ignores. One
|
||||
entry set covers every project — no per-project `.gitignore` line is
|
||||
needed, though a project MAY add its own if it wants the ignore to
|
||||
travel with the repo.
|
||||
|
||||
## Lifecycle
|
||||
|
||||
`docs/specs/` and `docs/plans/` hold **only the active cycle's
|
||||
@@ -35,35 +44,51 @@ valid for the cycle that produces it; its code shapes drift the moment
|
||||
the code moves, so a stale one left lying around reads as a live API
|
||||
reference and misleads the next agent that opens it.
|
||||
|
||||
The two directories stay **git-tracked** — never git-ignored. A
|
||||
spec/plan is committed while its cycle is live, and at **cycle close** —
|
||||
after `audit` is drift-clean — the orchestrator **retires** it: `git rm`
|
||||
the spec and plan in the cycle-close commit. The deletion rides in that
|
||||
commit, so at `HEAD` the directories hold only what is still in flight,
|
||||
while the full text stays recoverable from git history
|
||||
(`git show <rev>:<path>`).
|
||||
The two directories are **git-ignored** — their contents are never
|
||||
committed. A spec/plan is a working file: present on disk while its
|
||||
cycle is live (readable across sessions, since the working tree
|
||||
persists), and at **cycle close** — after `audit` is drift-clean — the
|
||||
orchestrator **discards** it with a plain shell `rm`. There is nothing
|
||||
to `git rm` (it was never tracked) and no deletion commit is produced;
|
||||
the working tree is simply left without a stale artefact. This is the
|
||||
same shell-delete-an-uncommitted-file mechanic `specify` already uses on
|
||||
its grounding-`BLOCK` failure path.
|
||||
|
||||
A spec/plan is therefore **transient in the repo**: present for its own
|
||||
cycle, gone from `HEAD` afterwards. The durable record of a past cycle
|
||||
is the design ledger (where the rationale is lifted during audit) + the
|
||||
git history of the spec, plan, and code — never a live file under
|
||||
`docs/specs` / `docs/plans`.
|
||||
A spec/plan is therefore **transient on disk**: present for its own
|
||||
cycle, `rm`'d afterwards, and — never having been committed — leaving no
|
||||
trace in git. It is **not recoverable, by design**. The durable record
|
||||
of a past cycle's design intent is the **design ledger only** (where the
|
||||
rationale is lifted during audit); the implementation is committed as
|
||||
normal code.
|
||||
|
||||
**No durable artefact may cite a spec or plan** — not by number, not by
|
||||
path. Code, tests, docs, and ledger entries outlive the spec/plan that
|
||||
prompted them, so any reference to `docs/specs/…` or "spec NNNN" would
|
||||
dangle the moment the cycle closes. Cite the **design-ledger contract**
|
||||
instead (e.g. a `C`-id); it is the durable record the spec's rationale
|
||||
was lifted into.
|
||||
|
||||
## Naming
|
||||
|
||||
Counter-prefixed, per directory: `NNNN-slug.md`, 4-digit
|
||||
zero-padded. The counter is per directory, assigned in creation
|
||||
order, and stable for the life of the file. New files take the
|
||||
next-higher number; `brainstorm` / `specify` / `planner` scan the
|
||||
target directory for the next free number before writing.
|
||||
Files are named `slug.md` — a short kebab-case identifier of the
|
||||
cycle's topic (slug separator `-`). There is **no numeric prefix**:
|
||||
because the directories are git-ignored, shell-`rm`'d at cycle close,
|
||||
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`).
|
||||
|
||||
The number is a within-cycle handle, not a stable archival ID.
|
||||
Because the directories hold only active artefacts (see § Lifecycle),
|
||||
an emptied directory restarts at `0001` and a number freed by a
|
||||
retired file may be reused — that recycling is fine, since the durable
|
||||
record is git history, not the filename.
|
||||
|
||||
The slug separator is `-`.
|
||||
**The file name is not the cycle number.** The **cycle number** that
|
||||
appears in commit subjects (`feat(NNNN)`, `audit(NNNN)`) and in `git
|
||||
log` cycle ranges is a distinct, monotonic identifier that must survive
|
||||
spec/plan discard. Source it from the highest `NNNN` in the
|
||||
`feat(NNNN)` / `audit(NNNN)` git-log subjects, plus one — never from a
|
||||
file name (there is none) and never from a per-directory scan. Cycle
|
||||
commits therefore MUST carry the zero-padded `(NNNN)` cycle number in
|
||||
their subject.
|
||||
|
||||
## Vocabulary
|
||||
|
||||
|
||||
+7
-5
@@ -85,16 +85,18 @@ The plugin owns:
|
||||
The constants that used to be configurable but were the same in
|
||||
every project are now plugin conventions, named directly in skill
|
||||
and agent bodies and documented once in `conventions.md`:
|
||||
spec dir `docs/specs`, plan dir `docs/plans`, 4-digit per-directory
|
||||
spec dir `docs/specs`, plan dir `docs/plans`, slug-only `slug.md`
|
||||
naming, the vocabulary cycle / iteration / milestone / contract,
|
||||
standing reading (`CLAUDE.md` + `git log -10`), git discipline
|
||||
(only-orchestrator commits, main sacrosanct), Gitea + `closes #N`,
|
||||
and the whole pipeline graph (see `pipeline.md`).
|
||||
|
||||
Specs and plans are ephemeral active-cycle artefacts — the two
|
||||
directories stay git-tracked and hold only what is in flight; at cycle
|
||||
close each is `git rm`'d from the repo, kept only in git history, never
|
||||
as a durable file (see `conventions.md` § Lifecycle).
|
||||
Specs and plans are ephemeral active-cycle working files — the two
|
||||
directories are git-ignored and hold only what is in flight; at cycle
|
||||
close each is shell-`rm`'d (never committed, so nothing to `git rm` and
|
||||
no git-history copy). The durable record of a past cycle is the design
|
||||
ledger only, and no durable artefact cites a spec/plan (see
|
||||
`conventions.md` § Lifecycle).
|
||||
|
||||
## Project facts (project-specific)
|
||||
|
||||
|
||||
+17
-11
@@ -140,8 +140,9 @@ Hard-gate before plan — the spec-production core and the carrier of the
|
||||
"no plan without an approved spec" invariant. Takes a settled design
|
||||
(directly from sources, or a ratified design handed over by
|
||||
`brainstorm`), applies the feature-acceptance criterion, writes the
|
||||
spec to `docs/specs` (an ephemeral active-cycle artefact, git-tracked
|
||||
and `git rm`'d at cycle close — see `conventions.md` § Lifecycle), runs
|
||||
spec to `docs/specs` (an ephemeral active-cycle working file —
|
||||
git-ignored, never committed, shell-`rm`'d at cycle close — see
|
||||
`conventions.md` § Lifecycle), runs
|
||||
the `grounding-check` gate, and takes sign-off — with review but no
|
||||
interview. Under the bold stance it decides every load-bearing fork it
|
||||
can *derive* an answer for and records the decision in the run's
|
||||
@@ -152,9 +153,11 @@ gate before `planner` on every design path.
|
||||
Outside `/boss` the sign-off is the user's. Under `/boss` the autonomous
|
||||
signature is the **`grounding-check` `PASS`** itself: an independent
|
||||
fresh-context agent's verdict against currently-green tests, not the
|
||||
orchestrator's confidence. On `PASS` the orchestrator commits the spec
|
||||
(subject `(boss-signed)`), fires the vetoable auto-sign notify, and
|
||||
continues to `planner`; a no-override grounding `BLOCK` / `INFRA_ERROR`
|
||||
orchestrator's confidence. On `PASS` the orchestrator keeps the signed
|
||||
spec as a git-ignored working file (never committed), records the
|
||||
autonomous sign on the run's reference issue, fires the vetoable
|
||||
auto-sign notify, and continues to `planner`; a no-override grounding
|
||||
`BLOCK` / `INFRA_ERROR`
|
||||
routes to the human sign-off pause. The former obligatory five-lens
|
||||
`spec-skeptic` panel is **retired** (baseline tag `pre-autosign-rework`):
|
||||
the judgement it applied now lives upstream in Step 1.5's bold-decide
|
||||
@@ -167,9 +170,10 @@ See `../specify/SKILL.md` Step 6 and `../boss/SKILL.md` §"Spec auto-sign".
|
||||
### planner
|
||||
|
||||
Hard-gate before implement. Produces a placeholder-free,
|
||||
bite-sized implementation plan in `docs/plans` (ephemeral, retired
|
||||
alongside the spec at cycle close — see `conventions.md` § Lifecycle)
|
||||
that the implement skill can execute task-by-task. Dispatches
|
||||
bite-sized implementation plan in `docs/plans` (an ephemeral,
|
||||
git-ignored working file, shell-`rm`'d alongside the spec at cycle
|
||||
close — see `conventions.md` § Lifecycle) that the implement skill can
|
||||
execute task-by-task. Dispatches
|
||||
the plan-recon agent for read-only file-structure mapping.
|
||||
|
||||
### implement
|
||||
@@ -209,9 +213,11 @@ 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 retires the cycle's spec and plan —
|
||||
`git rm`'ing them in the cycle-close commit (see `conventions.md`
|
||||
§ Lifecycle).
|
||||
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).
|
||||
|
||||
### debug
|
||||
|
||||
|
||||
Reference in New Issue
Block a user