aboutsummaryrefslogtreecommitdiff
path: root/docs/specs
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-07-01 22:55:42 -0400
committerCraig Jennings <c@cjennings.net>2026-07-01 22:55:42 -0400
commit43cecd4eec7d1c061ca546b50a3d095a6d01f524 (patch)
tree5d5c7594ad967fc75bfa0a2f847f4b8514f1cd4d /docs/specs
parentb163637008996031f5a16d4703d384209c4ace76 (diff)
downloadrulesets-43cecd4eec7d1c061ca546b50a3d095a6d01f524.tar.gz
rulesets-43cecd4eec7d1c061ca546b50a3d095a6d01f524.zip
docs(spec): fold in verify-pass nits on the docs-lifecycle spec
Scope the zero-id-links acceptance check to links the sort actually rewrote (prose mentions of the syntax already exist and would false-positive a naive grep), add untracked-copy cleanup to the mid-apply recovery recipe, and refresh two stale prose spots (nudge skip condition, bats case list).
Diffstat (limited to 'docs/specs')
-rw-r--r--docs/specs/2026-07-01-docs-lifecycle-spec.org9
1 files changed, 5 insertions, 4 deletions
diff --git a/docs/specs/2026-07-01-docs-lifecycle-spec.org b/docs/specs/2026-07-01-docs-lifecycle-spec.org
index bd7ad74..5509bff 100644
--- a/docs/specs/2026-07-01-docs-lifecycle-spec.org
+++ b/docs/specs/2026-07-01-docs-lifecycle-spec.org
@@ -8,6 +8,7 @@
:PROPERTIES:
:ID: 80b0787b-4a60-4c82-8a16-b383d3e3c8f2
:END:
+- 2026-07-01 Wed @ 22:54:41 -0400 — verify pass on the second responder round: all five fixes held, findings 1-9 unregressed, verdict ready; three minor nits folded in (scoped id-link criterion, untracked-copy cleanup in the recovery recipe, two stale prose spots). Stays DRAFT pending the reviewers' flip.
- 2026-07-01 Wed @ 22:46:52 -0400 — second responder pass: all five re-review findings fixed (fourteen of fourteen closed); stays DRAFT — the READY flip belongs to the reviewers this round.
- 2026-07-01 Wed @ 22:41:33 -0400 — READY → DRAFT: Codex re-review found five new blocking implementation-readiness gaps after the response pass.
- 2026-07-01 Wed @ 22:41:21 -0400 — DRAFT → READY: dual independent review (Codex + fresh-context Claude agent, both initially Not ready), all nine findings fixed, verify pass by the original reviewer returned ready; flip authorized by Craig.
@@ -131,7 +132,7 @@ A synced helper, =spec-sort=, run once per project. *Canonical placement:* like
- *Safety:* dry-run report is the default; =--apply= writes, under a fail-safe contract sized to the fact that one run mutates filenames, links, headers, and =.ai/notes.org= together:
- *Clean-worktree preflight.* =--apply= refuses on a dirty git tree (=git status --porcelain= non-empty) unless =--allow-dirty= is passed, which prints exactly what recovery loses. A clean tree is what makes recovery trivially safe.
- *Validate, then write.* The full move + relink plan — every source, destination, and link edit — is computed and validated first (every link parses, every target is unambiguous, every destination path is free), written to a plan file for inspection, and only then executed from that recorded plan. Ambiguous cases (two candidates sharing a basename, an unparseable link) block validation: listed, untouched, non-zero exit until each is resolved or explicitly waived.
- - *Failure mid-apply is not a shrug.* Any write failure or a failed post-apply residue grep stops the run, names what was and wasn't applied (from the plan), and prints the recovery recipe — =git restore= over the plan's touched paths, safe by construction because preflight required a clean tree. The project is never silently left half-migrated.
+ - *Failure mid-apply is not a shrug.* Any write failure or a failed post-apply residue grep stops the run, names what was and wasn't applied (from the plan), and prints the recovery recipe — =git restore= over the plan's touched paths *plus* deletion of the plan's newly-created destination paths (=git restore= reverts tracked edits but doesn't remove untracked copies the move created). Safe by construction because preflight required a clean tree; the project is never silently left half-migrated.
- After a successful apply, the residue grep for each old path across the rewritten roots must return zero or =spec-sort= exits non-zero naming the residue.
4. *Stamp* =:LAST_SPEC_SORT: YYYY-MM-DD= in =.ai/notes.org='s =* Workflow State= section — the same surface as =:LAST_AUDIT:= and =:LAST_INBOX_PROCESS:=, created idempotently (append the section if the file lacks it) exactly as task-audit already does.
@@ -145,7 +146,7 @@ A synced helper, =spec-sort=, run once per project. *Canonical placement:* like
(The probe also fires on stray =docs/*-spec.org= root files, so a project whose only misfiled specs sit at the =docs/= root still gets nudged.)
-Phase C surfaces one line when the probe printed ("this project's docs pile has never been spec-sorted — say 'run spec-sort' to sort it") and stays silent otherwise. Projects without a =docs/design/= never see it; a stamped marker permanently clears it.
+Phase C surfaces one line when the probe printed ("this project's docs pile has never been spec-sorted — say 'run spec-sort' to sort it") and stays silent otherwise. Projects with nothing to sort — no =docs/design/= and no stray root specs — never see it; a stamped marker permanently clears it.
* Alternatives Considered
@@ -280,7 +281,7 @@ Add the Phase A probe + Phase C nudge line (the concrete contract in the Design
- [ ] Every helper/workflow artifact of this feature lives canonical-side (=claude-templates/.ai/=, =claude-rules/=) with the mirror in sync — =scripts/sync-check.sh= exits clean after the build commits.
- [ ] A =DOING= spec whose =:SPEC_ID:=-bound parent task is closed or missing is flagged by task-audit's reconcile pass (exercised in the pilot or a fixture).
- [ ] =spec-sort --apply= on a dirty worktree refuses (absent the override); a forced mid-apply failure in the bats suite yields the named-recovery output, not a half-migrated tree.
-- [ ] After the pilot, zero =[[id:...]]= links exist in rewritten roots (conversion is the gated follow-up); every rewritten link is a resolving =file:= link.
+- [ ] After the pilot, no link the sort *rewrote* uses =[[id:...]]= form and no rewritten root gained a new =id:= link targeting a spec (conversion is the gated follow-up); every rewritten link is a resolving =file:= link. The check scopes to actual rewritten and spec-target links — literal prose mentions of the id syntax (which already exist in =todo.org= and older specs) don't count, so a naive whole-file grep is the wrong implementation.
- [ ] A project with an unsorted =docs/design/= gets the startup nudge; one confirmed =spec-sort= run clears it via =:LAST_SPEC_SORT:=.
* Readiness dimensions
@@ -303,7 +304,7 @@ Add the Phase A probe + Phase C nudge line (the concrete contract in the Design
- *Keyword vocabulary drift* between this spec, the rule, and spec-create's template. Dodge: the rule names the vocabulary once and the others link it.
* Testing / Verification / Rollout
-bats for =spec-sort= (classification, move, relink, idempotence, confirm gate, marker stamp). The pilot run on rulesets is the live verification; the post-move residue grep is the acceptance check. Rollout is per-project via the startup nudge, each run human-confirmed.
+bats for =spec-sort= (classification, the evidence/confirm gate, plan validation, move + rename, relink, the clean-worktree preflight, forced mid-apply failure recovery output, idempotence, marker stamp). The pilot run on rulesets is the live verification; the post-move residue grep is the acceptance check. Rollout is per-project via the startup nudge, each run human-confirmed.
* References / Appendix
- Source proposal: [[file:../design/2026-06-15-spec-storage-lifecycle-proposal.org]] (.emacs.d handoff, 2026-06-15).