From d0c92d0e21dd8698bfc772903bcc42252a70d1ee Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Wed, 1 Jul 2026 23:39:46 -0400 Subject: feat(docs-lifecycle): add the lifecycle rule and wire the spec workflows Phase 1 of the docs-lifecycle build. claude-rules/docs-lifecycle.md captures the shape: formal-vs-notes location split (docs/specs/ vs docs/design/), an authoritative org-keyword status heading with dated history and an :ID: UUID, the two-sequence keyword header that keeps decision cookies computing, named owners for every transition, and the one-grep status board. The four workflows each take their piece: spec-create emits into docs/specs/ and stamps DRAFT in the template; spec-review checks location (legacy spots stay reviewable until :LAST_SPEC_SORT: is stamped) and owns the DRAFT-to-READY flip plus the demote path; spec-response owns READY-to-DOING at decomposition, stamps :SPEC_ID: on the build parent, and always emits the flip-to-IMPLEMENTED task; task-audit reconciles DOING specs against their bound parent's keyword. --- claude-templates/.ai/workflows/spec-create.org | 14 +++++++++++--- claude-templates/.ai/workflows/spec-response.org | 6 ++++-- claude-templates/.ai/workflows/spec-review.org | 7 +++++++ claude-templates/.ai/workflows/task-audit.org | 2 ++ 4 files changed, 24 insertions(+), 5 deletions(-) (limited to 'claude-templates') 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/-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--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: — Spec ,#+AUTHOR: ,#+DATE: -,#+TODO: TODO | DONE SUPERSEDED CANCELLED +,#+TODO: TODO | DONE +,#+TODO: DRAFT READY DOING | IMPLEMENTED SUPERSEDED CANCELLED + +,* DRAFT +:PROPERTIES: +:ID: +:END: +- — 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). -- cgit v1.2.3