aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.ai/workflows/spec-create.org14
-rw-r--r--.ai/workflows/spec-response.org6
-rw-r--r--.ai/workflows/spec-review.org7
-rw-r--r--.ai/workflows/task-audit.org2
-rw-r--r--claude-rules/docs-lifecycle.md75
-rw-r--r--claude-templates/.ai/workflows/spec-create.org14
-rw-r--r--claude-templates/.ai/workflows/spec-response.org6
-rw-r--r--claude-templates/.ai/workflows/spec-review.org7
-rw-r--r--claude-templates/.ai/workflows/task-audit.org2
-rw-r--r--todo.org4
10 files changed, 125 insertions, 12 deletions
diff --git a/.ai/workflows/spec-create.org b/.ai/workflows/spec-create.org
index 508b969..1249181 100644
--- a/.ai/workflows/spec-create.org
+++ b/.ai/workflows/spec-create.org
@@ -82,8 +82,9 @@ This is where the spec earns a "Ready" from review: an engineer must be able to
** Phase 5 — Wire it up (conventions)
-- *Filename + location:* =docs/<problem-slug>-spec.org=. Org-mode. The slug names the *problem/feature*, not a date. Must end in =-spec.org=.
-- *Metadata header:* a small table at the top — Status, Owner, Reviewer(s), Date, Related (link to the task/ticket).
+- *Filename + location:* =docs/specs/YYYY-MM-DD-<problem-slug>-spec.org= — formal specs live in =docs/specs/=, never =docs/design/= (that's for notes, brainstorms, inventories; see =claude-rules/docs-lifecycle.md=). Org-mode. The slug names the *problem/feature*; no status suffixes ever — status lives in the file. Must end in =-spec.org=.
+- *Status heading (first element after the file header):* a top-level heading carrying the lifecycle keyword, stamped =DRAFT= at authoring — spec-create owns this flip. It holds an =:ID:= UUID (generate with =uuidgen=) and dated history lines, newest first. The keyword is authoritative; the Metadata =Status= field mirrors it in lowercase. Transitions are three lines in one file (keyword + history line + mirror): spec-review flips =READY=, spec-response flips =DOING= at decomposition, the final build task flips =IMPLEMENTED=. Terminal states always record a reason.
+- *Metadata header:* a small table at the top — Status (the lowercase mirror), Owner, Reviewer(s), Date, Related (link to the task/ticket).
- *Review-and-iteration-history stub:* add a =Review and iteration history= section at the bottom and seed it with the author's first entry. =spec-review= and =spec-response= append provenance entries here, so the heading shape is a contract: =YYYY-MM-DD Day @ HH:MM:SS -ZZZZ — Contributor — Role=, body fields What / Why / Artifacts.
- *Cross-link both ways:* the spec links its task; the task links the spec (replace the task's inline plan with a terse description + a =file:= link to the spec).
@@ -103,7 +104,14 @@ Then it's ready for =spec-review.org=. Snapshot-vs-living rule: keep the spec li
,#+TITLE: <Feature> — Spec
,#+AUTHOR: <author>
,#+DATE: <YYYY-MM-DD>
-,#+TODO: TODO | DONE SUPERSEDED CANCELLED
+,#+TODO: TODO | DONE
+,#+TODO: DRAFT READY DOING | IMPLEMENTED SUPERSEDED CANCELLED
+
+,* DRAFT <spec short name>
+:PROPERTIES:
+:ID: <uuid — generate with uuidgen>
+:END:
+- <YYYY-MM-DD Day @ HH:MM:SS -ZZZZ> — drafted.
,* Metadata
| Status | draft |
diff --git a/.ai/workflows/spec-response.org b/.ai/workflows/spec-response.org
index de5b1c8..7628e49 100644
--- a/.ai/workflows/spec-response.org
+++ b/.ai/workflows/spec-response.org
@@ -130,9 +130,11 @@ When related specs were reviewed together, two reviews can recommend opposite th
This is the *last* step of the workflow, and it runs *only after the author confirms the spec is Ready* — never during review iterations. A Ready spec nobody can act on is unfinished; this phase turns it into tracked work. It applies to every project type (library, application, service, docs set).
-1. *Decide where the tasks live.* If the work is spinning off into its own project/repo, move the parent task into that project's =todo.org= (and relocate the spec with it); otherwise use the current project's =todo.org=. One parent task owns the effort; the phase tasks hang under it.
+*This phase owns the =READY= → =DOING= lifecycle flip* (docs-lifecycle convention): when the decomposition below lands, update the spec's top-level status heading keyword to =DOING=, add a dated history line, and set the Metadata =Status= mirror to =doing= — three lines, one file.
-2. *Create one task per implementation phase* from the spec's =Implementation phases=, in dependency order, so the task set as a whole describes the *full* milestone (e.g. v1) with no gaps. Each task body names the deliverable, its tests, and how it is verified. Carry over deferred/vNext work and any publish/release steps as their own tasks.
+1. *Decide where the tasks live.* If the work is spinning off into its own project/repo, move the parent task into that project's =todo.org= (and relocate the spec with it); otherwise use the current project's =todo.org=. One parent task owns the effort; the phase tasks hang under it. *Stamp the binding:* the parent task's =:PROPERTIES:= drawer gets a =:SPEC_ID:= line holding the spec's status-heading UUID. That property is the durable join task-audit uses to police =DOING= specs (a =DOING= spec whose bound parent is closed, archived, or missing gets flagged).
+
+2. *Create one task per implementation phase* from the spec's =Implementation phases=, in dependency order, so the task set as a whole describes the *full* milestone (e.g. v1) with no gaps. Each task body names the deliverable, its tests, and how it is verified. Carry over deferred/vNext work and any publish/release steps as their own tasks. *Always end the set with the flip task:* a final "flip the spec to IMPLEMENTED (+ dated history line + mirror)" task under the same parent — the tracked obligation that closes the lifecycle loop when the build finishes. Never skip it; "a human remembers" is the failure mode this exists to prevent.
3. *Turn a critical eye on completeness.* Re-read the spec — every phase, every acceptance criterion, every named deliverable, every data-safety/principle rule — and confirm each has a home in a task. The work is not done when the tasks merely exist; it is done when nothing in the spec is left untracked. This completeness pass is mandatory regardless of project type.
diff --git a/.ai/workflows/spec-review.org b/.ai/workflows/spec-review.org
index 001238e..d4998eb 100644
--- a/.ai/workflows/spec-review.org
+++ b/.ai/workflows/spec-review.org
@@ -50,6 +50,11 @@ Run it *early* — design review exists to catch viability problems and costly m
Before Phase 1, verify the file under review ends with =-spec.org=. Every design, decision, or planning document under a project's =docs/= directory carries that suffix as its identifier. The =.org= extension alone is not enough because =docs/= holds non-spec org files too (tutorials, frozen inventories, reference material).
+*Location expectation (docs-lifecycle convention).* Formal specs live in =docs/specs/=. Whether that's enforced depends on whether the project has run its one-time =spec-sort= retrofit:
+
+- =:LAST_SPEC_SORT:= present in =.ai/notes.org= Workflow State → the project has sorted; a =-spec.org= file outside =docs/specs/= fails this precondition. Surface it: "this spec sits outside docs/specs/ — move it (and update inbound links) before review."
+- Marker absent → legacy locations (=docs/= root, =docs/design/=) stay reviewable; add one nudge line to the review output ("this project's docs pile has never been spec-sorted — say 'run spec-sort' to sort it") and proceed. No legacy spec is ever unreviewable during the transition.
+
If the file does not end with =-spec.org=, stop immediately and surface the mismatch:
#+begin_example
@@ -167,6 +172,8 @@ Assign one label consistently:
The most useful reviews move a spec from =Not ready= to =Ready with caveats= or =Ready= once decisions are captured.
+*The =Ready= verdict flips the spec's lifecycle status.* spec-review owns the =DRAFT= → =READY= transition (docs-lifecycle convention): on assigning =Ready= (or =Ready with caveats= the author accepts), update the spec's top-level status heading keyword to =READY=, add a dated history line under it naming the review that passed, and set the Metadata =Status= mirror to =ready= — three lines, one file. Any other rubric label leaves the keyword where it stands (a re-review that finds new blockers on a =READY= spec demotes it back to =DRAFT= the same three-line way, with the reason in the history line).
+
Finding severity maps to blocking power: *high-priority findings block =Ready=* — they hold the rubric at =Not ready= (or =Ready with caveats= if the author accepts and tracks them) until dispositioned; *medium-priority findings are the author's discretion* and don't block. State the blocking status on each finding so the author running spec-response knows which ones gate the rubric.
Then update the spec's review history. Specs should carry a bottom section named =Review and iteration history= (or the nearest existing equivalent) that tracks each material author/reviewer pass. Add a concise entry for this review even when the spec is ready and no findings are recorded.
diff --git a/.ai/workflows/task-audit.org b/.ai/workflows/task-audit.org
index 8dd2fb2..7d2b758 100644
--- a/.ai/workflows/task-audit.org
+++ b/.ai/workflows/task-audit.org
@@ -61,6 +61,8 @@ For each open task, read its body and cross-check its claims against the actual
- *Calendar* — did a scheduled event happen; is a SCHEDULED/DEADLINE date now past.
- *Meeting recordings* — if a task hinges on "did this conversation happen / what was said," check the recording queue (e.g. =~/sync/recordings/=) and transcribe via =process-meeting-transcript.org= if the answer lives in an un-transcribed recording. (This is exactly how a "did the interview happen?" task gets resolved instead of guessed.)
+*Spec lifecycle reconcile (docs-lifecycle convention).* If the project has a =docs/specs/=, run the =:SPEC_ID:= query as part of this phase: for each spec whose top-level status heading reads =DOING=, find the =todo.org= task whose =:SPEC_ID:= property matches the spec's =:ID:=. Flag the spec NEEDS-USER when that bound parent is =DONE=/=CANCELLED=, archived, or missing — the build finished (or evaporated) without the =IMPLEMENTED= flip, exactly the drift this check exists to catch. Check the parent's own keyword, not its children (completed children become dated entries and the final flip task is a child, so child-counting misleads).
+
Assign each task a bucket (CURRENT / STALE / NEEDS-USER) and, for STALE, the specific factual update.
*Scale tactic.* For a large open-task set, dispatch read-only investigation sub-agents over batches of tasks (parallel-safe per =subagents.md= — independent read-only domains). Each returns a per-task bucket + suggested update. *Never* let sub-agents write to =todo.org= concurrently — apply all edits serially in the main thread (concurrent writes to one file race and lose work).
diff --git a/claude-rules/docs-lifecycle.md b/claude-rules/docs-lifecycle.md
new file mode 100644
index 0000000..3906d86
--- /dev/null
+++ b/claude-rules/docs-lifecycle.md
@@ -0,0 +1,75 @@
+# Docs Lifecycle
+
+Applies to: `**/*` (any project carrying a `docs/` tree)
+
+How formal documents are separated from working notes, and how a document's
+lifecycle state stays visible without opening the file. Specs are the first
+instance of the shape; the pattern is reusable for any growing collection of
+processed artifacts. Full design: the docs-lifecycle spec in rulesets
+`docs/specs/`.
+
+## The shape (reusable)
+
+1. **Separate formal artifacts from working notes by location.** A formal
+ artifact proposes a buildable change and carries the full spine; everything
+ else is a note.
+2. **Lifecycle state lives in the artifact**, on a scannable, greppable
+ carrier — an org TODO keyword on a top-level status heading — with a dated
+ history of every transition.
+3. **Links use rename-safe identifiers** so a move or rename never orphans
+ inbound references.
+4. A collection **earns this treatment when "which of these are live?" starts
+ requiring a file-by-file read.**
+
+## The spec instance
+
+- `docs/specs/` holds formal specs only — a doc with both a `Decisions`
+ section and an `Implementation phases` section (the spec-create spine).
+ `docs/design/` holds everything else: brainstorms, proposals, inventories,
+ research notes, frozen source material. Spec filenames end `-spec.org`
+ (spec-review's precondition keys on it); no status suffixes ever.
+- Every spec opens with a top-level status heading directly after the file
+ header, carrying the lifecycle keyword, an `:ID:` UUID, and dated history
+ lines (newest first). The keyword header is two sequences, and both lines
+ are required:
+
+ #+TODO: TODO | DONE
+ #+TODO: DRAFT READY DOING | IMPLEMENTED SUPERSEDED CANCELLED
+
+ The first drives `Decisions` / `Review findings` tasks and their `[/]`
+ cookies; the second is the lifecycle. They share no keyword — never merge
+ them into one line, and never drop the first (that silently breaks the
+ cookies that gate readiness).
+- **The heading keyword is authoritative.** The Metadata table's `Status`
+ field mirrors it in lowercase; on disagreement the heading wins. A
+ transition is three lines in one file — keyword, history line, mirror — and
+ never a rename or a link edit.
+- **Every flip has a named owner:** spec-create stamps `DRAFT`; spec-review
+ flips `DRAFT` → `READY` on a passing gate; spec-response flips `READY` →
+ `DOING` when it decomposes phases into build tasks (stamping the spec's
+ UUID as a `:SPEC_ID:` property on the build parent, and always emitting a
+ final "flip the spec to IMPLEMENTED" task); task-audit flags any `DOING`
+ spec whose `:SPEC_ID:`-bound parent is closed, archived, or missing.
+ Terminal states (`IMPLEMENTED` / `SUPERSEDED` / `CANCELLED`) always carry a
+ stated reason in the history line.
+- **The status board is one grep:**
+
+ rg -H '^\* (DRAFT|READY|DOING|IMPLEMENTED|SUPERSEDED|CANCELLED) ' docs/specs/
+
+- **Legacy compatibility:** projects that haven't run the one-time `spec-sort`
+ retrofit (no `:LAST_SPEC_SORT:` marker in `.ai/notes.org` Workflow State)
+ keep their legacy spec locations reviewable; the `docs/specs/` requirement
+ hardens only after the sort runs.
+- **Cross-doc links to specs are `file:` links for now.** Specs carry `:ID:`
+ UUIDs, but conversion to `[[id:...]]` is a gated follow-up (the Emacs id
+ index has to know about project docs first) — don't convert links ad hoc.
+
+## Watch for
+
+- Editing the `#+TODO:` header down to one sequence — the `[/]` cookies stop
+ computing and readiness gates go vacuous.
+- Bare `[N/N]` tokens in prose or list items — org's cookie updater rewrites
+ them; spell counts out in words outside real cookie positions.
+- A "done" spec whose keyword still says `DOING` — that's the failure this
+ convention exists to prevent; flip it with a history line rather than
+ leaving it for the audit to catch.
diff --git a/claude-templates/.ai/workflows/spec-create.org b/claude-templates/.ai/workflows/spec-create.org
index 508b969..1249181 100644
--- a/claude-templates/.ai/workflows/spec-create.org
+++ b/claude-templates/.ai/workflows/spec-create.org
@@ -82,8 +82,9 @@ This is where the spec earns a "Ready" from review: an engineer must be able to
** Phase 5 — Wire it up (conventions)
-- *Filename + location:* =docs/<problem-slug>-spec.org=. Org-mode. The slug names the *problem/feature*, not a date. Must end in =-spec.org=.
-- *Metadata header:* a small table at the top — Status, Owner, Reviewer(s), Date, Related (link to the task/ticket).
+- *Filename + location:* =docs/specs/YYYY-MM-DD-<problem-slug>-spec.org= — formal specs live in =docs/specs/=, never =docs/design/= (that's for notes, brainstorms, inventories; see =claude-rules/docs-lifecycle.md=). Org-mode. The slug names the *problem/feature*; no status suffixes ever — status lives in the file. Must end in =-spec.org=.
+- *Status heading (first element after the file header):* a top-level heading carrying the lifecycle keyword, stamped =DRAFT= at authoring — spec-create owns this flip. It holds an =:ID:= UUID (generate with =uuidgen=) and dated history lines, newest first. The keyword is authoritative; the Metadata =Status= field mirrors it in lowercase. Transitions are three lines in one file (keyword + history line + mirror): spec-review flips =READY=, spec-response flips =DOING= at decomposition, the final build task flips =IMPLEMENTED=. Terminal states always record a reason.
+- *Metadata header:* a small table at the top — Status (the lowercase mirror), Owner, Reviewer(s), Date, Related (link to the task/ticket).
- *Review-and-iteration-history stub:* add a =Review and iteration history= section at the bottom and seed it with the author's first entry. =spec-review= and =spec-response= append provenance entries here, so the heading shape is a contract: =YYYY-MM-DD Day @ HH:MM:SS -ZZZZ — Contributor — Role=, body fields What / Why / Artifacts.
- *Cross-link both ways:* the spec links its task; the task links the spec (replace the task's inline plan with a terse description + a =file:= link to the spec).
@@ -103,7 +104,14 @@ Then it's ready for =spec-review.org=. Snapshot-vs-living rule: keep the spec li
,#+TITLE: <Feature> — Spec
,#+AUTHOR: <author>
,#+DATE: <YYYY-MM-DD>
-,#+TODO: TODO | DONE SUPERSEDED CANCELLED
+,#+TODO: TODO | DONE
+,#+TODO: DRAFT READY DOING | IMPLEMENTED SUPERSEDED CANCELLED
+
+,* DRAFT <spec short name>
+:PROPERTIES:
+:ID: <uuid — generate with uuidgen>
+:END:
+- <YYYY-MM-DD Day @ HH:MM:SS -ZZZZ> — drafted.
,* Metadata
| Status | draft |
diff --git a/claude-templates/.ai/workflows/spec-response.org b/claude-templates/.ai/workflows/spec-response.org
index de5b1c8..7628e49 100644
--- a/claude-templates/.ai/workflows/spec-response.org
+++ b/claude-templates/.ai/workflows/spec-response.org
@@ -130,9 +130,11 @@ When related specs were reviewed together, two reviews can recommend opposite th
This is the *last* step of the workflow, and it runs *only after the author confirms the spec is Ready* — never during review iterations. A Ready spec nobody can act on is unfinished; this phase turns it into tracked work. It applies to every project type (library, application, service, docs set).
-1. *Decide where the tasks live.* If the work is spinning off into its own project/repo, move the parent task into that project's =todo.org= (and relocate the spec with it); otherwise use the current project's =todo.org=. One parent task owns the effort; the phase tasks hang under it.
+*This phase owns the =READY= → =DOING= lifecycle flip* (docs-lifecycle convention): when the decomposition below lands, update the spec's top-level status heading keyword to =DOING=, add a dated history line, and set the Metadata =Status= mirror to =doing= — three lines, one file.
-2. *Create one task per implementation phase* from the spec's =Implementation phases=, in dependency order, so the task set as a whole describes the *full* milestone (e.g. v1) with no gaps. Each task body names the deliverable, its tests, and how it is verified. Carry over deferred/vNext work and any publish/release steps as their own tasks.
+1. *Decide where the tasks live.* If the work is spinning off into its own project/repo, move the parent task into that project's =todo.org= (and relocate the spec with it); otherwise use the current project's =todo.org=. One parent task owns the effort; the phase tasks hang under it. *Stamp the binding:* the parent task's =:PROPERTIES:= drawer gets a =:SPEC_ID:= line holding the spec's status-heading UUID. That property is the durable join task-audit uses to police =DOING= specs (a =DOING= spec whose bound parent is closed, archived, or missing gets flagged).
+
+2. *Create one task per implementation phase* from the spec's =Implementation phases=, in dependency order, so the task set as a whole describes the *full* milestone (e.g. v1) with no gaps. Each task body names the deliverable, its tests, and how it is verified. Carry over deferred/vNext work and any publish/release steps as their own tasks. *Always end the set with the flip task:* a final "flip the spec to IMPLEMENTED (+ dated history line + mirror)" task under the same parent — the tracked obligation that closes the lifecycle loop when the build finishes. Never skip it; "a human remembers" is the failure mode this exists to prevent.
3. *Turn a critical eye on completeness.* Re-read the spec — every phase, every acceptance criterion, every named deliverable, every data-safety/principle rule — and confirm each has a home in a task. The work is not done when the tasks merely exist; it is done when nothing in the spec is left untracked. This completeness pass is mandatory regardless of project type.
diff --git a/claude-templates/.ai/workflows/spec-review.org b/claude-templates/.ai/workflows/spec-review.org
index 001238e..d4998eb 100644
--- a/claude-templates/.ai/workflows/spec-review.org
+++ b/claude-templates/.ai/workflows/spec-review.org
@@ -50,6 +50,11 @@ Run it *early* — design review exists to catch viability problems and costly m
Before Phase 1, verify the file under review ends with =-spec.org=. Every design, decision, or planning document under a project's =docs/= directory carries that suffix as its identifier. The =.org= extension alone is not enough because =docs/= holds non-spec org files too (tutorials, frozen inventories, reference material).
+*Location expectation (docs-lifecycle convention).* Formal specs live in =docs/specs/=. Whether that's enforced depends on whether the project has run its one-time =spec-sort= retrofit:
+
+- =:LAST_SPEC_SORT:= present in =.ai/notes.org= Workflow State → the project has sorted; a =-spec.org= file outside =docs/specs/= fails this precondition. Surface it: "this spec sits outside docs/specs/ — move it (and update inbound links) before review."
+- Marker absent → legacy locations (=docs/= root, =docs/design/=) stay reviewable; add one nudge line to the review output ("this project's docs pile has never been spec-sorted — say 'run spec-sort' to sort it") and proceed. No legacy spec is ever unreviewable during the transition.
+
If the file does not end with =-spec.org=, stop immediately and surface the mismatch:
#+begin_example
@@ -167,6 +172,8 @@ Assign one label consistently:
The most useful reviews move a spec from =Not ready= to =Ready with caveats= or =Ready= once decisions are captured.
+*The =Ready= verdict flips the spec's lifecycle status.* spec-review owns the =DRAFT= → =READY= transition (docs-lifecycle convention): on assigning =Ready= (or =Ready with caveats= the author accepts), update the spec's top-level status heading keyword to =READY=, add a dated history line under it naming the review that passed, and set the Metadata =Status= mirror to =ready= — three lines, one file. Any other rubric label leaves the keyword where it stands (a re-review that finds new blockers on a =READY= spec demotes it back to =DRAFT= the same three-line way, with the reason in the history line).
+
Finding severity maps to blocking power: *high-priority findings block =Ready=* — they hold the rubric at =Not ready= (or =Ready with caveats= if the author accepts and tracks them) until dispositioned; *medium-priority findings are the author's discretion* and don't block. State the blocking status on each finding so the author running spec-response knows which ones gate the rubric.
Then update the spec's review history. Specs should carry a bottom section named =Review and iteration history= (or the nearest existing equivalent) that tracks each material author/reviewer pass. Add a concise entry for this review even when the spec is ready and no findings are recorded.
diff --git a/claude-templates/.ai/workflows/task-audit.org b/claude-templates/.ai/workflows/task-audit.org
index 8dd2fb2..7d2b758 100644
--- a/claude-templates/.ai/workflows/task-audit.org
+++ b/claude-templates/.ai/workflows/task-audit.org
@@ -61,6 +61,8 @@ For each open task, read its body and cross-check its claims against the actual
- *Calendar* — did a scheduled event happen; is a SCHEDULED/DEADLINE date now past.
- *Meeting recordings* — if a task hinges on "did this conversation happen / what was said," check the recording queue (e.g. =~/sync/recordings/=) and transcribe via =process-meeting-transcript.org= if the answer lives in an un-transcribed recording. (This is exactly how a "did the interview happen?" task gets resolved instead of guessed.)
+*Spec lifecycle reconcile (docs-lifecycle convention).* If the project has a =docs/specs/=, run the =:SPEC_ID:= query as part of this phase: for each spec whose top-level status heading reads =DOING=, find the =todo.org= task whose =:SPEC_ID:= property matches the spec's =:ID:=. Flag the spec NEEDS-USER when that bound parent is =DONE=/=CANCELLED=, archived, or missing — the build finished (or evaporated) without the =IMPLEMENTED= flip, exactly the drift this check exists to catch. Check the parent's own keyword, not its children (completed children become dated entries and the final flip task is a child, so child-counting misleads).
+
Assign each task a bucket (CURRENT / STALE / NEEDS-USER) and, for STALE, the specific factual update.
*Scale tactic.* For a large open-task set, dispatch read-only investigation sub-agents over batches of tasks (parallel-safe per =subagents.md= — independent read-only domains). Each returns a per-task bucket + suggested update. *Never* let sub-agents write to =todo.org= concurrently — apply all edits serially in the main thread (concurrent writes to one file race and lose work).
diff --git a/todo.org b/todo.org
index 01d00c9..61be603 100644
--- a/todo.org
+++ b/todo.org
@@ -402,8 +402,8 @@ Codex re-read the revised [[file:docs/specs/2026-07-01-docs-lifecycle-spec.org][
*** 2026-07-01 Wed @ 23:34:15 -0400 Decomposed into build tasks; spec flipped READY → DOING
spec-response Phase 6 run: this parent now carries the =:SPEC_ID:= binding (the spec's status-heading UUID), the phase tasks below track the build, and the spec's status heading is DOING. Completeness pass done: all ten acceptance criteria have homes across the phase tasks; vNext (org-agenda view) was already filed as the [#D] task below.
-*** TODO Phase 1 — docs-lifecycle rule + spec-workflow updates :solo:
-Write claude-rules/docs-lifecycle.md (the generalized shape). Update, canonical-side: spec-create (emit into docs/specs/, two-sequence keyword header + status heading + :ID: in the template, DRAFT stamped at authoring), spec-review (compatibility rule — legacy locations accepted until :LAST_SPEC_SORT: stamped, then docs/specs/ hardens; DRAFT→READY flip = keyword + history + mirror), spec-response (owns READY→DOING at Phase 6; stamps :SPEC_ID: on the build parent; always emits the final flip-to-IMPLEMENTED task), task-audit (reconcile bullet: :SPEC_ID: query flags a DOING spec whose bound parent is closed/archived/missing). Verify: workflow-integrity bats + sync-check clean + make test.
+*** 2026-07-01 Wed @ 23:39:10 -0400 Phase 1 landed — docs-lifecycle rule + four spec-workflow updates
+claude-rules/docs-lifecycle.md written and linked machine-wide (make install). Canonical-side updates: spec-create Phase 5 + template (docs/specs/ location, two-sequence keyword header, DRAFT status heading with :ID:, transition mechanics), spec-review (location expectation with the legacy compatibility rule keyed on :LAST_SPEC_SORT:, plus the DRAFT→READY flip — and the demote-back-to-DRAFT path a failed re-review takes), spec-response Phase 6 (owns READY→DOING, stamps :SPEC_ID: on the build parent, always emits the flip-to-IMPLEMENTED task), task-audit Phase B (the :SPEC_ID: reconcile query, checking the parent's keyword rather than counting children). Mirror synced; make test green end to end.
*** TODO Phase 2 — spec-sort helper + bats suite :solo:
Build claude-templates/.ai/scripts/spec-sort per the spec's retrofit contract: classify (Decisions AND Implementation phases), evidence-based confirm gate, plan + validate before first write, move + rename to -spec.org + status heading + :ID:, relink file: links per the rewritten-roots/report-only contract, clean-worktree preflight (--allow-dirty override), named recovery on mid-apply failure (incl. deleting created untracked copies), residue-grep exit gate, :LAST_SPEC_SORT: stamp. Bats in claude-templates/.ai/scripts/tests/ covering classification, confirm gate, plan validation, move+rename, relink, preflight, forced-failure recovery output, idempotence, marker stamp. Verify: make test green, sync-check clean.