aboutsummaryrefslogtreecommitdiff
path: root/claude-rules/docs-lifecycle.md
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-07-01 23:39:46 -0400
committerCraig Jennings <c@cjennings.net>2026-07-01 23:39:46 -0400
commitd0c92d0e21dd8698bfc772903bcc42252a70d1ee (patch)
tree4dd4d1e2f7a68289fb248301b07ef68db22ac913 /claude-rules/docs-lifecycle.md
parent328ca18a15c4dd14cc4898b483cc6b2681dbf7eb (diff)
downloadrulesets-d0c92d0e21dd8698bfc772903bcc42252a70d1ee.tar.gz
rulesets-d0c92d0e21dd8698bfc772903bcc42252a70d1ee.zip
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.
Diffstat (limited to 'claude-rules/docs-lifecycle.md')
-rw-r--r--claude-rules/docs-lifecycle.md75
1 files changed, 75 insertions, 0 deletions
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.