diff --git a/document-release/SKILL.md b/document-release/SKILL.md
index 64561b0ca..6a25bbe82 100644
--- a/document-release/SKILL.md
+++ b/document-release/SKILL.md
@@ -780,6 +780,17 @@ subjective decisions.
---
+## Section index — Read each section when its situation applies
+
+This skill is a decision-tree skeleton. The steps below point to on-demand
+sections. Read a section in full before doing its step; do not work from memory.
+
+| When | Read this section |
+|------|-------------------|
+| auditing each doc file and applying updates, polishing CHANGELOG voice, checking cross-doc consistency, cleaning up TODOS, the VERSION bump, and committing (Steps 2-9, after the coverage map in Step 1.5) | `sections/release-body.md` |
+
+---
+
## Step 1: Pre-flight & Diff Analysis
1. Check the current branch. If on the base branch, **abort**: "You're on the base branch. Run from a feature branch."
@@ -856,364 +867,8 @@ When significant gaps are found, suggest running `/document-generate` to fill th
---
-## Step 2: Per-File Documentation Audit
-
-Read each documentation file and cross-reference it against the diff. Use these generic heuristics
-(adapt to whatever project you're in — these are not gstack-specific):
-
-**README.md:**
-- Does it describe all features and capabilities visible in the diff?
-- Are install/setup instructions consistent with the changes?
-- Are examples, demos, and usage descriptions still valid?
-- Are troubleshooting steps still accurate?
-
-**ARCHITECTURE.md:**
-- Do ASCII diagrams and component descriptions match the current code?
-- Are design decisions and "why" explanations still accurate?
-- Be conservative — only update things clearly contradicted by the diff. Architecture docs
- describe things unlikely to change frequently.
-
-**CONTRIBUTING.md — New contributor smoke test:**
-- Walk through the setup instructions as if you are a brand new contributor.
-- Are the listed commands accurate? Would each step succeed?
-- Do test tier descriptions match the current test infrastructure?
-- Are workflow descriptions (dev setup, operational learnings, etc.) current?
-- Flag anything that would fail or confuse a first-time contributor.
-
-**CLAUDE.md / project instructions:**
-- Does the project structure section match the actual file tree?
-- Are listed commands and scripts accurate?
-- Do build/test instructions match what's in package.json (or equivalent)?
-
-**Any other .md files:**
-- Read the file, determine its purpose and audience.
-- Cross-reference against the diff to check if it contradicts anything the file says.
-
-For each file, classify needed updates as:
-
-- **Auto-update** — Factual corrections clearly warranted by the diff: adding an item to a
- table, updating a file path, fixing a count, updating a project structure tree.
-- **Ask user** — Narrative changes, section removal, security model changes, large rewrites
- (more than ~10 lines in one section), ambiguous relevance, adding entirely new sections.
-
----
-
-## Step 3: Apply Auto-Updates
-
-Make all clear, factual updates directly using the Edit tool.
-
-For each file modified, output a one-line summary describing **what specifically changed** — not
-just "Updated README.md" but "README.md: added /new-skill to skills table, updated skill count
-from 9 to 10."
-
-**Never auto-update:**
-- README introduction or project positioning
-- ARCHITECTURE philosophy or design rationale
-- Security model descriptions
-- Do not remove entire sections from any document
-
----
-
-## Step 4: Ask About Risky/Questionable Changes
-
-For each risky or questionable update identified in Step 2, use AskUserQuestion with:
-- Context: project name, branch, which doc file, what we're reviewing
-- The specific documentation decision
-- `RECOMMENDATION: Choose [X] because [one-line reason]`
-- Options including C) Skip — leave as-is
-
-Apply approved changes immediately after each answer.
-
----
-
-## Step 5: CHANGELOG Voice Polish
-
-**CRITICAL — NEVER CLOBBER CHANGELOG ENTRIES.**
-
-This step polishes voice. It does NOT rewrite, replace, or regenerate CHANGELOG content.
-
-A real incident occurred where an agent replaced existing CHANGELOG entries when it should have
-preserved them. This skill must NEVER do that.
-
-**Rules:**
-1. Read the entire CHANGELOG.md first. Understand what is already there.
-2. Only modify wording within existing entries. Never delete, reorder, or replace entries.
-3. Never regenerate a CHANGELOG entry from scratch. The entry was written by `/ship` from the
- actual diff and commit history. It is the source of truth. You are polishing prose, not
- rewriting history.
-4. If an entry looks wrong or incomplete, use AskUserQuestion — do NOT silently fix it.
-5. Use Edit tool with exact `old_string` matches — never use Write to overwrite CHANGELOG.md.
-
-**If CHANGELOG was not modified in this branch:** skip this step.
-
-**If CHANGELOG was modified in this branch**, review the entry for voice:
-
-- **Sell test (Diataxis rubric):** Score each CHANGELOG entry 0-3:
- - **1 point** — answers "What changed?" (reference: names the feature/fix)
- - **1 point** — answers "Why should I care?" (explanation: user impact, pain removed)
- - **1 point** — answers "How do I use it?" (how-to: command, flag, or link to docs)
- - Entries scoring <2 need a rewrite. Entries scoring 3 are gold.
-- Lead with what the user can now **do** — not implementation details.
-- "You can now..." not "Refactored the..."
-- Flag and rewrite any entry that reads like a commit message.
-- Internal/contributor changes belong in a separate "### For contributors" subsection.
-- Auto-fix minor voice adjustments. Use AskUserQuestion if a rewrite would alter meaning.
-
----
-
-## Step 6: Cross-Doc Consistency & Discoverability Check
-
-After auditing each file individually, do a cross-doc consistency pass:
-
-1. Does the README's feature/capability list match what CLAUDE.md (or project instructions) describes?
-2. Does ARCHITECTURE's component list match CONTRIBUTING's project structure description?
-3. Does CHANGELOG's latest version match the VERSION file?
-4. **Discoverability:** Is every documentation file reachable from README.md or CLAUDE.md? If
- ARCHITECTURE.md exists but neither README nor CLAUDE.md links to it, flag it. Every doc
- should be discoverable from one of the two entry-point files.
-5. Flag any contradictions between documents. Auto-fix clear factual inconsistencies (e.g., a
- version mismatch). Use AskUserQuestion for narrative contradictions.
-
----
-
-## Step 7: TODOS.md Cleanup
-
-This is a second pass that complements `/ship`'s Step 5.5. Read `review/TODOS-format.md` (if
-available) for the canonical TODO item format.
-
-If TODOS.md does not exist, skip this step.
-
-1. **Completed items not yet marked:** Cross-reference the diff against open TODO items. If a
- TODO is clearly completed by the changes in this branch, move it to the Completed section
- with `**Completed:** vX.Y.Z.W (YYYY-MM-DD)`. Be conservative — only mark items with clear
- evidence in the diff.
-
-2. **Items needing description updates:** If a TODO references files or components that were
- significantly changed, its description may be stale. Use AskUserQuestion to confirm whether
- the TODO should be updated, completed, or left as-is.
-
-3. **New deferred work:** Check the diff for `TODO`, `FIXME`, `HACK`, and `XXX` comments. For
- each one that represents meaningful deferred work (not a trivial inline note), use
- AskUserQuestion to ask whether it should be captured in TODOS.md.
-
----
-
-## Step 8: VERSION Bump Question
-
-**CRITICAL — NEVER BUMP VERSION WITHOUT ASKING.**
-
-1. **If VERSION does not exist:** Skip silently.
-
-2. Check if VERSION was already modified on this branch:
-
-```bash
-git diff ...HEAD -- VERSION
-```
-
-3. **If VERSION was NOT bumped:** Use AskUserQuestion:
- - RECOMMENDATION: Choose C (Skip) because docs-only changes rarely warrant a version bump
- - A) Bump PATCH (X.Y.Z+1) — if doc changes ship alongside code changes
- - B) Bump MINOR (X.Y+1.0) — if this is a significant standalone release
- - C) Skip — no version bump needed
-
-4. **If VERSION was already bumped:** Do NOT skip silently. Instead, check whether the bump
- still covers the full scope of changes on this branch:
-
- a. Read the CHANGELOG entry for the current VERSION. What features does it describe?
- b. Read the full diff (`git diff ...HEAD --stat` and `git diff ...HEAD --name-only`).
- Are there significant changes (new features, new skills, new commands, major refactors)
- that are NOT mentioned in the CHANGELOG entry for the current version?
- c. **If the CHANGELOG entry covers everything:** Skip — output "VERSION: Already bumped to
- vX.Y.Z, covers all changes."
- d. **If there are significant uncovered changes:** Use AskUserQuestion explaining what the
- current version covers vs what's new, and ask:
- - RECOMMENDATION: Choose A because the new changes warrant their own version
- - A) Bump to next patch (X.Y.Z+1) — give the new changes their own version
- - B) Keep current version — add new changes to the existing CHANGELOG entry
- - C) Skip — leave version as-is, handle later
-
- The key insight: a VERSION bump set for "feature A" should not silently absorb "feature B"
- if feature B is substantial enough to deserve its own version entry.
-
----
-
-## Step 9: Commit & Output
-
-**Empty check first:** Run `git status` (never use `-uall`). If no documentation files were
-modified by any previous step, output "All documentation is up to date." and exit without
-committing.
-
-**Commit:**
-
-1. Stage modified documentation files by name (never `git add -A` or `git add .`).
-2. Create a single commit:
-
-```bash
-git commit -m "$(cat <<'EOF'
-docs: update project documentation for vX.Y.Z.W
-
-Co-Authored-By: Claude Opus 4.7
-EOF
-)"
-```
-
-3. Push to the current branch:
-
-```bash
-git push
-```
-
-**PR/MR body update (idempotent, race-safe):**
-
-1. Read the existing PR/MR body into a PID-unique tempfile (use the platform detected in Step 0):
-
-**If GitHub:**
-```bash
-gh pr view --json body -q .body > /tmp/gstack-pr-body-$$.md
-```
-
-**If GitLab:**
-```bash
-glab mr view -F json 2>/dev/null | python3 -c "import sys,json; print(json.load(sys.stdin).get('description',''))" > /tmp/gstack-pr-body-$$.md
-```
-
-2. If the tempfile already contains a `## Documentation` section, replace that section with the
- updated content. If it does not contain one, append a `## Documentation` section at the end.
-
-3. The Documentation section should include:
-
- a. **Doc diff preview** — for each file modified, describe what specifically changed (e.g.,
- "README.md: added /document-release to skills table, updated skill count from 9 to 10").
-
- b. **Documentation debt** — if the coverage map from Step 1.5 found gaps, append a
- `### Documentation Debt` subsection listing:
- - Critical gaps: new public surface with zero documentation coverage
- - Common gaps: features with reference-only coverage (no how-to or tutorial)
- - Stale diagrams: architecture diagrams with entity names that drifted from the code
- - Each item should include a one-line description of what's missing and which Diataxis
- quadrant would fill it (e.g., "⚠️ `/new-skill` — has reference in AGENTS.md but no
- how-to example in README")
-
- If there are any documentation debt items, suggest adding a `docs-debt` label to the PR.
-
-4. Redaction scan-at-sink, then write the updated body back. The body is already
- in a temp file (`/tmp/gstack-pr-body-$$.md`); scan THAT file before editing so
- the bytes scanned are the bytes sent:
-
-```bash
-REDACT_VIS=$(~/.claude/skills/gstack/bin/gstack-config get redact_repo_visibility 2>/dev/null)
-[ -z "$REDACT_VIS" ] && REDACT_VIS=$(gh repo view --json visibility -q .visibility 2>/dev/null | tr 'A-Z' 'a-z')
-~/.claude/skills/gstack/bin/gstack-redact --from-file /tmp/gstack-pr-body-$$.md --repo-visibility "${REDACT_VIS:-unknown}" --json
-# exit 3 (HIGH) → do NOT edit, rotate+redact; exit 2 (MEDIUM) → confirm per finding.
-```
-
-**If GitHub:**
-```bash
-gh pr edit --body-file /tmp/gstack-pr-body-$$.md
-```
-
-**If GitLab:**
-Read the contents of `/tmp/gstack-pr-body-$$.md` using the Read tool, then pass it to `glab mr update` using a heredoc to avoid shell metacharacter issues:
-```bash
-glab mr update -d "$(cat <<'MRBODY'
-
-MRBODY
-)"
-```
-
-5. Clean up the tempfile:
-
-```bash
-rm -f /tmp/gstack-pr-body-$$.md
-```
-
-6. If `gh pr view` / `glab mr view` fails (no PR/MR exists): skip with message "No PR/MR found — skipping body update."
-7. If `gh pr edit` / `glab mr update` fails: warn "Could not update PR/MR body — documentation changes are in the
- commit." and continue.
-
-**PR/MR title sync (idempotent, always-on):**
-
-PR titles must always start with `v` — same rule as `/ship`. If Step 8 bumped VERSION after `/ship` had already created the PR, the title is now stale. This sub-step fixes it.
-
-1. Read the current VERSION:
-
-```bash
-V=$(cat VERSION 2>/dev/null | tr -d '[:space:]')
-```
-
-If `VERSION` does not exist or is empty, skip this sub-step entirely.
-
-2. Read the current PR/MR title:
-
-**If GitHub:**
-```bash
-CURRENT_TITLE=$(gh pr view --json title -q .title 2>/dev/null || true)
-```
-
-**If GitLab:**
-```bash
-CURRENT_TITLE=$(glab mr view -F json 2>/dev/null | jq -r .title 2>/dev/null || true)
-```
-
-If `CURRENT_TITLE` is empty (no open PR/MR), skip with message "No PR/MR found — skipping title sync."
-
-3. Compute the corrected title using the shared helper (single source of truth — same one `/ship` uses):
-
-```bash
-NEW_TITLE=$(~/.claude/skills/gstack/bin/gstack-pr-title-rewrite.sh "$V" "$CURRENT_TITLE")
-```
-
-The helper handles three cases: title already correct (no-op), title has a different `v` prefix (replace it), or title has no version prefix (prepend one).
-
-4. If `NEW_TITLE` differs from `CURRENT_TITLE`, update it:
-
-**If GitHub:**
-```bash
-gh pr edit --title "$NEW_TITLE"
-```
-
-**If GitLab:**
-```bash
-glab mr update -t "$NEW_TITLE"
-```
-
-5. If the edit command fails: warn "Could not update PR/MR title — documentation changes are still in the commit." and continue. Do not block on title sync failure.
-
-**Structured doc health summary (final output):**
-
-Output a scannable summary showing every documentation file's status:
-
-```
-Documentation health:
- README.md [status] ([details])
- ARCHITECTURE.md [status] ([details])
- CONTRIBUTING.md [status] ([details])
- CHANGELOG.md [status] ([details])
- TODOS.md [status] ([details])
- VERSION [status] ([details])
-```
-
-Where status is one of:
-- Updated — with description of what changed
-- Current — no changes needed
-- Voice polished — wording adjusted
-- Not bumped — user chose to skip
-- Already bumped — version was set by /ship
-- Skipped — file does not exist
-
-If the coverage map from Step 1.5 identified any gaps, append:
-
-```
-Documentation coverage:
- [entity] [reference] [how-to] [tutorial] [explanation]
- /new-skill ✅ ❌ ❌ ❌
- --new-flag ✅ ✅ ❌ ❌
-
-Diagram drift:
- ARCHITECTURE.md: "FooProcessor" renamed to "BarProcessor" in code — diagram may be stale
-```
-
-If all coverage is complete and no diagrams drifted, output: "Coverage: all shipped features have adequate documentation."
+> **STOP.** Before auditing each doc file and applying updates, polishing CHANGELOG voice, checking cross-doc consistency, cleaning up TODOS, the VERSION bump, and committing (Steps 2-9, after the coverage map in Step 1.5), Read `~/.claude/skills/gstack/document-release/sections/release-body.md` and execute it
+> in full. Do not work from memory — that section is the source of truth for this step.
---
diff --git a/document-release/SKILL.md.tmpl b/document-release/SKILL.md.tmpl
index 7367cbf4e..7621cb312 100644
--- a/document-release/SKILL.md.tmpl
+++ b/document-release/SKILL.md.tmpl
@@ -59,6 +59,10 @@ subjective decisions.
---
+{{SECTION_INDEX:document-release}}
+
+---
+
## Step 1: Pre-flight & Diff Analysis
1. Check the current branch. If on the base branch, **abort**: "You're on the base branch. Run from a feature branch."
@@ -135,364 +139,7 @@ When significant gaps are found, suggest running `/document-generate` to fill th
---
-## Step 2: Per-File Documentation Audit
-
-Read each documentation file and cross-reference it against the diff. Use these generic heuristics
-(adapt to whatever project you're in — these are not gstack-specific):
-
-**README.md:**
-- Does it describe all features and capabilities visible in the diff?
-- Are install/setup instructions consistent with the changes?
-- Are examples, demos, and usage descriptions still valid?
-- Are troubleshooting steps still accurate?
-
-**ARCHITECTURE.md:**
-- Do ASCII diagrams and component descriptions match the current code?
-- Are design decisions and "why" explanations still accurate?
-- Be conservative — only update things clearly contradicted by the diff. Architecture docs
- describe things unlikely to change frequently.
-
-**CONTRIBUTING.md — New contributor smoke test:**
-- Walk through the setup instructions as if you are a brand new contributor.
-- Are the listed commands accurate? Would each step succeed?
-- Do test tier descriptions match the current test infrastructure?
-- Are workflow descriptions (dev setup, operational learnings, etc.) current?
-- Flag anything that would fail or confuse a first-time contributor.
-
-**CLAUDE.md / project instructions:**
-- Does the project structure section match the actual file tree?
-- Are listed commands and scripts accurate?
-- Do build/test instructions match what's in package.json (or equivalent)?
-
-**Any other .md files:**
-- Read the file, determine its purpose and audience.
-- Cross-reference against the diff to check if it contradicts anything the file says.
-
-For each file, classify needed updates as:
-
-- **Auto-update** — Factual corrections clearly warranted by the diff: adding an item to a
- table, updating a file path, fixing a count, updating a project structure tree.
-- **Ask user** — Narrative changes, section removal, security model changes, large rewrites
- (more than ~10 lines in one section), ambiguous relevance, adding entirely new sections.
-
----
-
-## Step 3: Apply Auto-Updates
-
-Make all clear, factual updates directly using the Edit tool.
-
-For each file modified, output a one-line summary describing **what specifically changed** — not
-just "Updated README.md" but "README.md: added /new-skill to skills table, updated skill count
-from 9 to 10."
-
-**Never auto-update:**
-- README introduction or project positioning
-- ARCHITECTURE philosophy or design rationale
-- Security model descriptions
-- Do not remove entire sections from any document
-
----
-
-## Step 4: Ask About Risky/Questionable Changes
-
-For each risky or questionable update identified in Step 2, use AskUserQuestion with:
-- Context: project name, branch, which doc file, what we're reviewing
-- The specific documentation decision
-- `RECOMMENDATION: Choose [X] because [one-line reason]`
-- Options including C) Skip — leave as-is
-
-Apply approved changes immediately after each answer.
-
----
-
-## Step 5: CHANGELOG Voice Polish
-
-**CRITICAL — NEVER CLOBBER CHANGELOG ENTRIES.**
-
-This step polishes voice. It does NOT rewrite, replace, or regenerate CHANGELOG content.
-
-A real incident occurred where an agent replaced existing CHANGELOG entries when it should have
-preserved them. This skill must NEVER do that.
-
-**Rules:**
-1. Read the entire CHANGELOG.md first. Understand what is already there.
-2. Only modify wording within existing entries. Never delete, reorder, or replace entries.
-3. Never regenerate a CHANGELOG entry from scratch. The entry was written by `/ship` from the
- actual diff and commit history. It is the source of truth. You are polishing prose, not
- rewriting history.
-4. If an entry looks wrong or incomplete, use AskUserQuestion — do NOT silently fix it.
-5. Use Edit tool with exact `old_string` matches — never use Write to overwrite CHANGELOG.md.
-
-**If CHANGELOG was not modified in this branch:** skip this step.
-
-**If CHANGELOG was modified in this branch**, review the entry for voice:
-
-- **Sell test (Diataxis rubric):** Score each CHANGELOG entry 0-3:
- - **1 point** — answers "What changed?" (reference: names the feature/fix)
- - **1 point** — answers "Why should I care?" (explanation: user impact, pain removed)
- - **1 point** — answers "How do I use it?" (how-to: command, flag, or link to docs)
- - Entries scoring <2 need a rewrite. Entries scoring 3 are gold.
-- Lead with what the user can now **do** — not implementation details.
-- "You can now..." not "Refactored the..."
-- Flag and rewrite any entry that reads like a commit message.
-- Internal/contributor changes belong in a separate "### For contributors" subsection.
-- Auto-fix minor voice adjustments. Use AskUserQuestion if a rewrite would alter meaning.
-
----
-
-## Step 6: Cross-Doc Consistency & Discoverability Check
-
-After auditing each file individually, do a cross-doc consistency pass:
-
-1. Does the README's feature/capability list match what CLAUDE.md (or project instructions) describes?
-2. Does ARCHITECTURE's component list match CONTRIBUTING's project structure description?
-3. Does CHANGELOG's latest version match the VERSION file?
-4. **Discoverability:** Is every documentation file reachable from README.md or CLAUDE.md? If
- ARCHITECTURE.md exists but neither README nor CLAUDE.md links to it, flag it. Every doc
- should be discoverable from one of the two entry-point files.
-5. Flag any contradictions between documents. Auto-fix clear factual inconsistencies (e.g., a
- version mismatch). Use AskUserQuestion for narrative contradictions.
-
----
-
-## Step 7: TODOS.md Cleanup
-
-This is a second pass that complements `/ship`'s Step 5.5. Read `review/TODOS-format.md` (if
-available) for the canonical TODO item format.
-
-If TODOS.md does not exist, skip this step.
-
-1. **Completed items not yet marked:** Cross-reference the diff against open TODO items. If a
- TODO is clearly completed by the changes in this branch, move it to the Completed section
- with `**Completed:** vX.Y.Z.W (YYYY-MM-DD)`. Be conservative — only mark items with clear
- evidence in the diff.
-
-2. **Items needing description updates:** If a TODO references files or components that were
- significantly changed, its description may be stale. Use AskUserQuestion to confirm whether
- the TODO should be updated, completed, or left as-is.
-
-3. **New deferred work:** Check the diff for `TODO`, `FIXME`, `HACK`, and `XXX` comments. For
- each one that represents meaningful deferred work (not a trivial inline note), use
- AskUserQuestion to ask whether it should be captured in TODOS.md.
-
----
-
-## Step 8: VERSION Bump Question
-
-**CRITICAL — NEVER BUMP VERSION WITHOUT ASKING.**
-
-1. **If VERSION does not exist:** Skip silently.
-
-2. Check if VERSION was already modified on this branch:
-
-```bash
-git diff ...HEAD -- VERSION
-```
-
-3. **If VERSION was NOT bumped:** Use AskUserQuestion:
- - RECOMMENDATION: Choose C (Skip) because docs-only changes rarely warrant a version bump
- - A) Bump PATCH (X.Y.Z+1) — if doc changes ship alongside code changes
- - B) Bump MINOR (X.Y+1.0) — if this is a significant standalone release
- - C) Skip — no version bump needed
-
-4. **If VERSION was already bumped:** Do NOT skip silently. Instead, check whether the bump
- still covers the full scope of changes on this branch:
-
- a. Read the CHANGELOG entry for the current VERSION. What features does it describe?
- b. Read the full diff (`git diff ...HEAD --stat` and `git diff ...HEAD --name-only`).
- Are there significant changes (new features, new skills, new commands, major refactors)
- that are NOT mentioned in the CHANGELOG entry for the current version?
- c. **If the CHANGELOG entry covers everything:** Skip — output "VERSION: Already bumped to
- vX.Y.Z, covers all changes."
- d. **If there are significant uncovered changes:** Use AskUserQuestion explaining what the
- current version covers vs what's new, and ask:
- - RECOMMENDATION: Choose A because the new changes warrant their own version
- - A) Bump to next patch (X.Y.Z+1) — give the new changes their own version
- - B) Keep current version — add new changes to the existing CHANGELOG entry
- - C) Skip — leave version as-is, handle later
-
- The key insight: a VERSION bump set for "feature A" should not silently absorb "feature B"
- if feature B is substantial enough to deserve its own version entry.
-
----
-
-## Step 9: Commit & Output
-
-**Empty check first:** Run `git status` (never use `-uall`). If no documentation files were
-modified by any previous step, output "All documentation is up to date." and exit without
-committing.
-
-**Commit:**
-
-1. Stage modified documentation files by name (never `git add -A` or `git add .`).
-2. Create a single commit:
-
-```bash
-git commit -m "$(cat <<'EOF'
-docs: update project documentation for vX.Y.Z.W
-
-{{CO_AUTHOR_TRAILER}}
-EOF
-)"
-```
-
-3. Push to the current branch:
-
-```bash
-git push
-```
-
-**PR/MR body update (idempotent, race-safe):**
-
-1. Read the existing PR/MR body into a PID-unique tempfile (use the platform detected in Step 0):
-
-**If GitHub:**
-```bash
-gh pr view --json body -q .body > /tmp/gstack-pr-body-$$.md
-```
-
-**If GitLab:**
-```bash
-glab mr view -F json 2>/dev/null | python3 -c "import sys,json; print(json.load(sys.stdin).get('description',''))" > /tmp/gstack-pr-body-$$.md
-```
-
-2. If the tempfile already contains a `## Documentation` section, replace that section with the
- updated content. If it does not contain one, append a `## Documentation` section at the end.
-
-3. The Documentation section should include:
-
- a. **Doc diff preview** — for each file modified, describe what specifically changed (e.g.,
- "README.md: added /document-release to skills table, updated skill count from 9 to 10").
-
- b. **Documentation debt** — if the coverage map from Step 1.5 found gaps, append a
- `### Documentation Debt` subsection listing:
- - Critical gaps: new public surface with zero documentation coverage
- - Common gaps: features with reference-only coverage (no how-to or tutorial)
- - Stale diagrams: architecture diagrams with entity names that drifted from the code
- - Each item should include a one-line description of what's missing and which Diataxis
- quadrant would fill it (e.g., "⚠️ `/new-skill` — has reference in AGENTS.md but no
- how-to example in README")
-
- If there are any documentation debt items, suggest adding a `docs-debt` label to the PR.
-
-4. Redaction scan-at-sink, then write the updated body back. The body is already
- in a temp file (`/tmp/gstack-pr-body-$$.md`); scan THAT file before editing so
- the bytes scanned are the bytes sent:
-
-```bash
-REDACT_VIS=$(~/.claude/skills/gstack/bin/gstack-config get redact_repo_visibility 2>/dev/null)
-[ -z "$REDACT_VIS" ] && REDACT_VIS=$(gh repo view --json visibility -q .visibility 2>/dev/null | tr 'A-Z' 'a-z')
-~/.claude/skills/gstack/bin/gstack-redact --from-file /tmp/gstack-pr-body-$$.md --repo-visibility "${REDACT_VIS:-unknown}" --json
-# exit 3 (HIGH) → do NOT edit, rotate+redact; exit 2 (MEDIUM) → confirm per finding.
-```
-
-**If GitHub:**
-```bash
-gh pr edit --body-file /tmp/gstack-pr-body-$$.md
-```
-
-**If GitLab:**
-Read the contents of `/tmp/gstack-pr-body-$$.md` using the Read tool, then pass it to `glab mr update` using a heredoc to avoid shell metacharacter issues:
-```bash
-glab mr update -d "$(cat <<'MRBODY'
-
-MRBODY
-)"
-```
-
-5. Clean up the tempfile:
-
-```bash
-rm -f /tmp/gstack-pr-body-$$.md
-```
-
-6. If `gh pr view` / `glab mr view` fails (no PR/MR exists): skip with message "No PR/MR found — skipping body update."
-7. If `gh pr edit` / `glab mr update` fails: warn "Could not update PR/MR body — documentation changes are in the
- commit." and continue.
-
-**PR/MR title sync (idempotent, always-on):**
-
-PR titles must always start with `v` — same rule as `/ship`. If Step 8 bumped VERSION after `/ship` had already created the PR, the title is now stale. This sub-step fixes it.
-
-1. Read the current VERSION:
-
-```bash
-V=$(cat VERSION 2>/dev/null | tr -d '[:space:]')
-```
-
-If `VERSION` does not exist or is empty, skip this sub-step entirely.
-
-2. Read the current PR/MR title:
-
-**If GitHub:**
-```bash
-CURRENT_TITLE=$(gh pr view --json title -q .title 2>/dev/null || true)
-```
-
-**If GitLab:**
-```bash
-CURRENT_TITLE=$(glab mr view -F json 2>/dev/null | jq -r .title 2>/dev/null || true)
-```
-
-If `CURRENT_TITLE` is empty (no open PR/MR), skip with message "No PR/MR found — skipping title sync."
-
-3. Compute the corrected title using the shared helper (single source of truth — same one `/ship` uses):
-
-```bash
-NEW_TITLE=$(~/.claude/skills/gstack/bin/gstack-pr-title-rewrite.sh "$V" "$CURRENT_TITLE")
-```
-
-The helper handles three cases: title already correct (no-op), title has a different `v` prefix (replace it), or title has no version prefix (prepend one).
-
-4. If `NEW_TITLE` differs from `CURRENT_TITLE`, update it:
-
-**If GitHub:**
-```bash
-gh pr edit --title "$NEW_TITLE"
-```
-
-**If GitLab:**
-```bash
-glab mr update -t "$NEW_TITLE"
-```
-
-5. If the edit command fails: warn "Could not update PR/MR title — documentation changes are still in the commit." and continue. Do not block on title sync failure.
-
-**Structured doc health summary (final output):**
-
-Output a scannable summary showing every documentation file's status:
-
-```
-Documentation health:
- README.md [status] ([details])
- ARCHITECTURE.md [status] ([details])
- CONTRIBUTING.md [status] ([details])
- CHANGELOG.md [status] ([details])
- TODOS.md [status] ([details])
- VERSION [status] ([details])
-```
-
-Where status is one of:
-- Updated — with description of what changed
-- Current — no changes needed
-- Voice polished — wording adjusted
-- Not bumped — user chose to skip
-- Already bumped — version was set by /ship
-- Skipped — file does not exist
-
-If the coverage map from Step 1.5 identified any gaps, append:
-
-```
-Documentation coverage:
- [entity] [reference] [how-to] [tutorial] [explanation]
- /new-skill ✅ ❌ ❌ ❌
- --new-flag ✅ ✅ ❌ ❌
-
-Diagram drift:
- ARCHITECTURE.md: "FooProcessor" renamed to "BarProcessor" in code — diagram may be stale
-```
-
-If all coverage is complete and no diagrams drifted, output: "Coverage: all shipped features have adequate documentation."
+{{SECTION:release-body}}
---
diff --git a/document-release/sections/manifest.json b/document-release/sections/manifest.json
new file mode 100644
index 000000000..05d2c6c2b
--- /dev/null
+++ b/document-release/sections/manifest.json
@@ -0,0 +1,14 @@
+{
+ "$schema": "https://gstack.dev/schemas/section-manifest.json",
+ "skill": "document-release",
+ "version": 1,
+ "note": "PASSIVE registry (v2 plan T9 / CM2). id/file/title/trigger text ONLY. The skeleton's decision-tree prose decides WHEN to read. No machine predicate here.",
+ "sections": [
+ {
+ "id": "release-body",
+ "file": "release-body.md",
+ "title": "Per-file audit, auto-updates, risky-change asks, CHANGELOG voice polish, cross-doc consistency, TODOS cleanup, VERSION bump, commit + PR body (Steps 2-9)",
+ "trigger": "auditing each doc file and applying updates, polishing CHANGELOG voice, checking cross-doc consistency, cleaning up TODOS, the VERSION bump, and committing (Steps 2-9, after the coverage map in Step 1.5)"
+ }
+ ]
+}
diff --git a/document-release/sections/release-body.md b/document-release/sections/release-body.md
new file mode 100644
index 000000000..f391eb8a3
--- /dev/null
+++ b/document-release/sections/release-body.md
@@ -0,0 +1,360 @@
+
+
+## Step 2: Per-File Documentation Audit
+
+Read each documentation file and cross-reference it against the diff. Use these generic heuristics
+(adapt to whatever project you're in — these are not gstack-specific):
+
+**README.md:**
+- Does it describe all features and capabilities visible in the diff?
+- Are install/setup instructions consistent with the changes?
+- Are examples, demos, and usage descriptions still valid?
+- Are troubleshooting steps still accurate?
+
+**ARCHITECTURE.md:**
+- Do ASCII diagrams and component descriptions match the current code?
+- Are design decisions and "why" explanations still accurate?
+- Be conservative — only update things clearly contradicted by the diff. Architecture docs
+ describe things unlikely to change frequently.
+
+**CONTRIBUTING.md — New contributor smoke test:**
+- Walk through the setup instructions as if you are a brand new contributor.
+- Are the listed commands accurate? Would each step succeed?
+- Do test tier descriptions match the current test infrastructure?
+- Are workflow descriptions (dev setup, operational learnings, etc.) current?
+- Flag anything that would fail or confuse a first-time contributor.
+
+**CLAUDE.md / project instructions:**
+- Does the project structure section match the actual file tree?
+- Are listed commands and scripts accurate?
+- Do build/test instructions match what's in package.json (or equivalent)?
+
+**Any other .md files:**
+- Read the file, determine its purpose and audience.
+- Cross-reference against the diff to check if it contradicts anything the file says.
+
+For each file, classify needed updates as:
+
+- **Auto-update** — Factual corrections clearly warranted by the diff: adding an item to a
+ table, updating a file path, fixing a count, updating a project structure tree.
+- **Ask user** — Narrative changes, section removal, security model changes, large rewrites
+ (more than ~10 lines in one section), ambiguous relevance, adding entirely new sections.
+
+---
+
+## Step 3: Apply Auto-Updates
+
+Make all clear, factual updates directly using the Edit tool.
+
+For each file modified, output a one-line summary describing **what specifically changed** — not
+just "Updated README.md" but "README.md: added /new-skill to skills table, updated skill count
+from 9 to 10."
+
+**Never auto-update:**
+- README introduction or project positioning
+- ARCHITECTURE philosophy or design rationale
+- Security model descriptions
+- Do not remove entire sections from any document
+
+---
+
+## Step 4: Ask About Risky/Questionable Changes
+
+For each risky or questionable update identified in Step 2, use AskUserQuestion with:
+- Context: project name, branch, which doc file, what we're reviewing
+- The specific documentation decision
+- `RECOMMENDATION: Choose [X] because [one-line reason]`
+- Options including C) Skip — leave as-is
+
+Apply approved changes immediately after each answer.
+
+---
+
+## Step 5: CHANGELOG Voice Polish
+
+**CRITICAL — NEVER CLOBBER CHANGELOG ENTRIES.**
+
+This step polishes voice. It does NOT rewrite, replace, or regenerate CHANGELOG content.
+
+A real incident occurred where an agent replaced existing CHANGELOG entries when it should have
+preserved them. This skill must NEVER do that.
+
+**Rules:**
+1. Read the entire CHANGELOG.md first. Understand what is already there.
+2. Only modify wording within existing entries. Never delete, reorder, or replace entries.
+3. Never regenerate a CHANGELOG entry from scratch. The entry was written by `/ship` from the
+ actual diff and commit history. It is the source of truth. You are polishing prose, not
+ rewriting history.
+4. If an entry looks wrong or incomplete, use AskUserQuestion — do NOT silently fix it.
+5. Use Edit tool with exact `old_string` matches — never use Write to overwrite CHANGELOG.md.
+
+**If CHANGELOG was not modified in this branch:** skip this step.
+
+**If CHANGELOG was modified in this branch**, review the entry for voice:
+
+- **Sell test (Diataxis rubric):** Score each CHANGELOG entry 0-3:
+ - **1 point** — answers "What changed?" (reference: names the feature/fix)
+ - **1 point** — answers "Why should I care?" (explanation: user impact, pain removed)
+ - **1 point** — answers "How do I use it?" (how-to: command, flag, or link to docs)
+ - Entries scoring <2 need a rewrite. Entries scoring 3 are gold.
+- Lead with what the user can now **do** — not implementation details.
+- "You can now..." not "Refactored the..."
+- Flag and rewrite any entry that reads like a commit message.
+- Internal/contributor changes belong in a separate "### For contributors" subsection.
+- Auto-fix minor voice adjustments. Use AskUserQuestion if a rewrite would alter meaning.
+
+---
+
+## Step 6: Cross-Doc Consistency & Discoverability Check
+
+After auditing each file individually, do a cross-doc consistency pass:
+
+1. Does the README's feature/capability list match what CLAUDE.md (or project instructions) describes?
+2. Does ARCHITECTURE's component list match CONTRIBUTING's project structure description?
+3. Does CHANGELOG's latest version match the VERSION file?
+4. **Discoverability:** Is every documentation file reachable from README.md or CLAUDE.md? If
+ ARCHITECTURE.md exists but neither README nor CLAUDE.md links to it, flag it. Every doc
+ should be discoverable from one of the two entry-point files.
+5. Flag any contradictions between documents. Auto-fix clear factual inconsistencies (e.g., a
+ version mismatch). Use AskUserQuestion for narrative contradictions.
+
+---
+
+## Step 7: TODOS.md Cleanup
+
+This is a second pass that complements `/ship`'s Step 5.5. Read `review/TODOS-format.md` (if
+available) for the canonical TODO item format.
+
+If TODOS.md does not exist, skip this step.
+
+1. **Completed items not yet marked:** Cross-reference the diff against open TODO items. If a
+ TODO is clearly completed by the changes in this branch, move it to the Completed section
+ with `**Completed:** vX.Y.Z.W (YYYY-MM-DD)`. Be conservative — only mark items with clear
+ evidence in the diff.
+
+2. **Items needing description updates:** If a TODO references files or components that were
+ significantly changed, its description may be stale. Use AskUserQuestion to confirm whether
+ the TODO should be updated, completed, or left as-is.
+
+3. **New deferred work:** Check the diff for `TODO`, `FIXME`, `HACK`, and `XXX` comments. For
+ each one that represents meaningful deferred work (not a trivial inline note), use
+ AskUserQuestion to ask whether it should be captured in TODOS.md.
+
+---
+
+## Step 8: VERSION Bump Question
+
+**CRITICAL — NEVER BUMP VERSION WITHOUT ASKING.**
+
+1. **If VERSION does not exist:** Skip silently.
+
+2. Check if VERSION was already modified on this branch:
+
+```bash
+git diff ...HEAD -- VERSION
+```
+
+3. **If VERSION was NOT bumped:** Use AskUserQuestion:
+ - RECOMMENDATION: Choose C (Skip) because docs-only changes rarely warrant a version bump
+ - A) Bump PATCH (X.Y.Z+1) — if doc changes ship alongside code changes
+ - B) Bump MINOR (X.Y+1.0) — if this is a significant standalone release
+ - C) Skip — no version bump needed
+
+4. **If VERSION was already bumped:** Do NOT skip silently. Instead, check whether the bump
+ still covers the full scope of changes on this branch:
+
+ a. Read the CHANGELOG entry for the current VERSION. What features does it describe?
+ b. Read the full diff (`git diff ...HEAD --stat` and `git diff ...HEAD --name-only`).
+ Are there significant changes (new features, new skills, new commands, major refactors)
+ that are NOT mentioned in the CHANGELOG entry for the current version?
+ c. **If the CHANGELOG entry covers everything:** Skip — output "VERSION: Already bumped to
+ vX.Y.Z, covers all changes."
+ d. **If there are significant uncovered changes:** Use AskUserQuestion explaining what the
+ current version covers vs what's new, and ask:
+ - RECOMMENDATION: Choose A because the new changes warrant their own version
+ - A) Bump to next patch (X.Y.Z+1) — give the new changes their own version
+ - B) Keep current version — add new changes to the existing CHANGELOG entry
+ - C) Skip — leave version as-is, handle later
+
+ The key insight: a VERSION bump set for "feature A" should not silently absorb "feature B"
+ if feature B is substantial enough to deserve its own version entry.
+
+---
+
+## Step 9: Commit & Output
+
+**Empty check first:** Run `git status` (never use `-uall`). If no documentation files were
+modified by any previous step, output "All documentation is up to date." and exit without
+committing.
+
+**Commit:**
+
+1. Stage modified documentation files by name (never `git add -A` or `git add .`).
+2. Create a single commit:
+
+```bash
+git commit -m "$(cat <<'EOF'
+docs: update project documentation for vX.Y.Z.W
+
+Co-Authored-By: Claude Opus 4.7
+EOF
+)"
+```
+
+3. Push to the current branch:
+
+```bash
+git push
+```
+
+**PR/MR body update (idempotent, race-safe):**
+
+1. Read the existing PR/MR body into a PID-unique tempfile (use the platform detected in Step 0):
+
+**If GitHub:**
+```bash
+gh pr view --json body -q .body > /tmp/gstack-pr-body-$$.md
+```
+
+**If GitLab:**
+```bash
+glab mr view -F json 2>/dev/null | python3 -c "import sys,json; print(json.load(sys.stdin).get('description',''))" > /tmp/gstack-pr-body-$$.md
+```
+
+2. If the tempfile already contains a `## Documentation` section, replace that section with the
+ updated content. If it does not contain one, append a `## Documentation` section at the end.
+
+3. The Documentation section should include:
+
+ a. **Doc diff preview** — for each file modified, describe what specifically changed (e.g.,
+ "README.md: added /document-release to skills table, updated skill count from 9 to 10").
+
+ b. **Documentation debt** — if the coverage map from Step 1.5 found gaps, append a
+ `### Documentation Debt` subsection listing:
+ - Critical gaps: new public surface with zero documentation coverage
+ - Common gaps: features with reference-only coverage (no how-to or tutorial)
+ - Stale diagrams: architecture diagrams with entity names that drifted from the code
+ - Each item should include a one-line description of what's missing and which Diataxis
+ quadrant would fill it (e.g., "⚠️ `/new-skill` — has reference in AGENTS.md but no
+ how-to example in README")
+
+ If there are any documentation debt items, suggest adding a `docs-debt` label to the PR.
+
+4. Redaction scan-at-sink, then write the updated body back. The body is already
+ in a temp file (`/tmp/gstack-pr-body-$$.md`); scan THAT file before editing so
+ the bytes scanned are the bytes sent:
+
+```bash
+REDACT_VIS=$(~/.claude/skills/gstack/bin/gstack-config get redact_repo_visibility 2>/dev/null)
+[ -z "$REDACT_VIS" ] && REDACT_VIS=$(gh repo view --json visibility -q .visibility 2>/dev/null | tr 'A-Z' 'a-z')
+~/.claude/skills/gstack/bin/gstack-redact --from-file /tmp/gstack-pr-body-$$.md --repo-visibility "${REDACT_VIS:-unknown}" --json
+# exit 3 (HIGH) → do NOT edit, rotate+redact; exit 2 (MEDIUM) → confirm per finding.
+```
+
+**If GitHub:**
+```bash
+gh pr edit --body-file /tmp/gstack-pr-body-$$.md
+```
+
+**If GitLab:**
+Read the contents of `/tmp/gstack-pr-body-$$.md` using the Read tool, then pass it to `glab mr update` using a heredoc to avoid shell metacharacter issues:
+```bash
+glab mr update -d "$(cat <<'MRBODY'
+
+MRBODY
+)"
+```
+
+5. Clean up the tempfile:
+
+```bash
+rm -f /tmp/gstack-pr-body-$$.md
+```
+
+6. If `gh pr view` / `glab mr view` fails (no PR/MR exists): skip with message "No PR/MR found — skipping body update."
+7. If `gh pr edit` / `glab mr update` fails: warn "Could not update PR/MR body — documentation changes are in the
+ commit." and continue.
+
+**PR/MR title sync (idempotent, always-on):**
+
+PR titles must always start with `v` — same rule as `/ship`. If Step 8 bumped VERSION after `/ship` had already created the PR, the title is now stale. This sub-step fixes it.
+
+1. Read the current VERSION:
+
+```bash
+V=$(cat VERSION 2>/dev/null | tr -d '[:space:]')
+```
+
+If `VERSION` does not exist or is empty, skip this sub-step entirely.
+
+2. Read the current PR/MR title:
+
+**If GitHub:**
+```bash
+CURRENT_TITLE=$(gh pr view --json title -q .title 2>/dev/null || true)
+```
+
+**If GitLab:**
+```bash
+CURRENT_TITLE=$(glab mr view -F json 2>/dev/null | jq -r .title 2>/dev/null || true)
+```
+
+If `CURRENT_TITLE` is empty (no open PR/MR), skip with message "No PR/MR found — skipping title sync."
+
+3. Compute the corrected title using the shared helper (single source of truth — same one `/ship` uses):
+
+```bash
+NEW_TITLE=$(~/.claude/skills/gstack/bin/gstack-pr-title-rewrite.sh "$V" "$CURRENT_TITLE")
+```
+
+The helper handles three cases: title already correct (no-op), title has a different `v` prefix (replace it), or title has no version prefix (prepend one).
+
+4. If `NEW_TITLE` differs from `CURRENT_TITLE`, update it:
+
+**If GitHub:**
+```bash
+gh pr edit --title "$NEW_TITLE"
+```
+
+**If GitLab:**
+```bash
+glab mr update -t "$NEW_TITLE"
+```
+
+5. If the edit command fails: warn "Could not update PR/MR title — documentation changes are still in the commit." and continue. Do not block on title sync failure.
+
+**Structured doc health summary (final output):**
+
+Output a scannable summary showing every documentation file's status:
+
+```
+Documentation health:
+ README.md [status] ([details])
+ ARCHITECTURE.md [status] ([details])
+ CONTRIBUTING.md [status] ([details])
+ CHANGELOG.md [status] ([details])
+ TODOS.md [status] ([details])
+ VERSION [status] ([details])
+```
+
+Where status is one of:
+- Updated — with description of what changed
+- Current — no changes needed
+- Voice polished — wording adjusted
+- Not bumped — user chose to skip
+- Already bumped — version was set by /ship
+- Skipped — file does not exist
+
+If the coverage map from Step 1.5 identified any gaps, append:
+
+```
+Documentation coverage:
+ [entity] [reference] [how-to] [tutorial] [explanation]
+ /new-skill ✅ ❌ ❌ ❌
+ --new-flag ✅ ✅ ❌ ❌
+
+Diagram drift:
+ ARCHITECTURE.md: "FooProcessor" renamed to "BarProcessor" in code — diagram may be stale
+```
+
+If all coverage is complete and no diagrams drifted, output: "Coverage: all shipped features have adequate documentation."
diff --git a/document-release/sections/release-body.md.tmpl b/document-release/sections/release-body.md.tmpl
new file mode 100644
index 000000000..ea5a54524
--- /dev/null
+++ b/document-release/sections/release-body.md.tmpl
@@ -0,0 +1,358 @@
+## Step 2: Per-File Documentation Audit
+
+Read each documentation file and cross-reference it against the diff. Use these generic heuristics
+(adapt to whatever project you're in — these are not gstack-specific):
+
+**README.md:**
+- Does it describe all features and capabilities visible in the diff?
+- Are install/setup instructions consistent with the changes?
+- Are examples, demos, and usage descriptions still valid?
+- Are troubleshooting steps still accurate?
+
+**ARCHITECTURE.md:**
+- Do ASCII diagrams and component descriptions match the current code?
+- Are design decisions and "why" explanations still accurate?
+- Be conservative — only update things clearly contradicted by the diff. Architecture docs
+ describe things unlikely to change frequently.
+
+**CONTRIBUTING.md — New contributor smoke test:**
+- Walk through the setup instructions as if you are a brand new contributor.
+- Are the listed commands accurate? Would each step succeed?
+- Do test tier descriptions match the current test infrastructure?
+- Are workflow descriptions (dev setup, operational learnings, etc.) current?
+- Flag anything that would fail or confuse a first-time contributor.
+
+**CLAUDE.md / project instructions:**
+- Does the project structure section match the actual file tree?
+- Are listed commands and scripts accurate?
+- Do build/test instructions match what's in package.json (or equivalent)?
+
+**Any other .md files:**
+- Read the file, determine its purpose and audience.
+- Cross-reference against the diff to check if it contradicts anything the file says.
+
+For each file, classify needed updates as:
+
+- **Auto-update** — Factual corrections clearly warranted by the diff: adding an item to a
+ table, updating a file path, fixing a count, updating a project structure tree.
+- **Ask user** — Narrative changes, section removal, security model changes, large rewrites
+ (more than ~10 lines in one section), ambiguous relevance, adding entirely new sections.
+
+---
+
+## Step 3: Apply Auto-Updates
+
+Make all clear, factual updates directly using the Edit tool.
+
+For each file modified, output a one-line summary describing **what specifically changed** — not
+just "Updated README.md" but "README.md: added /new-skill to skills table, updated skill count
+from 9 to 10."
+
+**Never auto-update:**
+- README introduction or project positioning
+- ARCHITECTURE philosophy or design rationale
+- Security model descriptions
+- Do not remove entire sections from any document
+
+---
+
+## Step 4: Ask About Risky/Questionable Changes
+
+For each risky or questionable update identified in Step 2, use AskUserQuestion with:
+- Context: project name, branch, which doc file, what we're reviewing
+- The specific documentation decision
+- `RECOMMENDATION: Choose [X] because [one-line reason]`
+- Options including C) Skip — leave as-is
+
+Apply approved changes immediately after each answer.
+
+---
+
+## Step 5: CHANGELOG Voice Polish
+
+**CRITICAL — NEVER CLOBBER CHANGELOG ENTRIES.**
+
+This step polishes voice. It does NOT rewrite, replace, or regenerate CHANGELOG content.
+
+A real incident occurred where an agent replaced existing CHANGELOG entries when it should have
+preserved them. This skill must NEVER do that.
+
+**Rules:**
+1. Read the entire CHANGELOG.md first. Understand what is already there.
+2. Only modify wording within existing entries. Never delete, reorder, or replace entries.
+3. Never regenerate a CHANGELOG entry from scratch. The entry was written by `/ship` from the
+ actual diff and commit history. It is the source of truth. You are polishing prose, not
+ rewriting history.
+4. If an entry looks wrong or incomplete, use AskUserQuestion — do NOT silently fix it.
+5. Use Edit tool with exact `old_string` matches — never use Write to overwrite CHANGELOG.md.
+
+**If CHANGELOG was not modified in this branch:** skip this step.
+
+**If CHANGELOG was modified in this branch**, review the entry for voice:
+
+- **Sell test (Diataxis rubric):** Score each CHANGELOG entry 0-3:
+ - **1 point** — answers "What changed?" (reference: names the feature/fix)
+ - **1 point** — answers "Why should I care?" (explanation: user impact, pain removed)
+ - **1 point** — answers "How do I use it?" (how-to: command, flag, or link to docs)
+ - Entries scoring <2 need a rewrite. Entries scoring 3 are gold.
+- Lead with what the user can now **do** — not implementation details.
+- "You can now..." not "Refactored the..."
+- Flag and rewrite any entry that reads like a commit message.
+- Internal/contributor changes belong in a separate "### For contributors" subsection.
+- Auto-fix minor voice adjustments. Use AskUserQuestion if a rewrite would alter meaning.
+
+---
+
+## Step 6: Cross-Doc Consistency & Discoverability Check
+
+After auditing each file individually, do a cross-doc consistency pass:
+
+1. Does the README's feature/capability list match what CLAUDE.md (or project instructions) describes?
+2. Does ARCHITECTURE's component list match CONTRIBUTING's project structure description?
+3. Does CHANGELOG's latest version match the VERSION file?
+4. **Discoverability:** Is every documentation file reachable from README.md or CLAUDE.md? If
+ ARCHITECTURE.md exists but neither README nor CLAUDE.md links to it, flag it. Every doc
+ should be discoverable from one of the two entry-point files.
+5. Flag any contradictions between documents. Auto-fix clear factual inconsistencies (e.g., a
+ version mismatch). Use AskUserQuestion for narrative contradictions.
+
+---
+
+## Step 7: TODOS.md Cleanup
+
+This is a second pass that complements `/ship`'s Step 5.5. Read `review/TODOS-format.md` (if
+available) for the canonical TODO item format.
+
+If TODOS.md does not exist, skip this step.
+
+1. **Completed items not yet marked:** Cross-reference the diff against open TODO items. If a
+ TODO is clearly completed by the changes in this branch, move it to the Completed section
+ with `**Completed:** vX.Y.Z.W (YYYY-MM-DD)`. Be conservative — only mark items with clear
+ evidence in the diff.
+
+2. **Items needing description updates:** If a TODO references files or components that were
+ significantly changed, its description may be stale. Use AskUserQuestion to confirm whether
+ the TODO should be updated, completed, or left as-is.
+
+3. **New deferred work:** Check the diff for `TODO`, `FIXME`, `HACK`, and `XXX` comments. For
+ each one that represents meaningful deferred work (not a trivial inline note), use
+ AskUserQuestion to ask whether it should be captured in TODOS.md.
+
+---
+
+## Step 8: VERSION Bump Question
+
+**CRITICAL — NEVER BUMP VERSION WITHOUT ASKING.**
+
+1. **If VERSION does not exist:** Skip silently.
+
+2. Check if VERSION was already modified on this branch:
+
+```bash
+git diff ...HEAD -- VERSION
+```
+
+3. **If VERSION was NOT bumped:** Use AskUserQuestion:
+ - RECOMMENDATION: Choose C (Skip) because docs-only changes rarely warrant a version bump
+ - A) Bump PATCH (X.Y.Z+1) — if doc changes ship alongside code changes
+ - B) Bump MINOR (X.Y+1.0) — if this is a significant standalone release
+ - C) Skip — no version bump needed
+
+4. **If VERSION was already bumped:** Do NOT skip silently. Instead, check whether the bump
+ still covers the full scope of changes on this branch:
+
+ a. Read the CHANGELOG entry for the current VERSION. What features does it describe?
+ b. Read the full diff (`git diff ...HEAD --stat` and `git diff ...HEAD --name-only`).
+ Are there significant changes (new features, new skills, new commands, major refactors)
+ that are NOT mentioned in the CHANGELOG entry for the current version?
+ c. **If the CHANGELOG entry covers everything:** Skip — output "VERSION: Already bumped to
+ vX.Y.Z, covers all changes."
+ d. **If there are significant uncovered changes:** Use AskUserQuestion explaining what the
+ current version covers vs what's new, and ask:
+ - RECOMMENDATION: Choose A because the new changes warrant their own version
+ - A) Bump to next patch (X.Y.Z+1) — give the new changes their own version
+ - B) Keep current version — add new changes to the existing CHANGELOG entry
+ - C) Skip — leave version as-is, handle later
+
+ The key insight: a VERSION bump set for "feature A" should not silently absorb "feature B"
+ if feature B is substantial enough to deserve its own version entry.
+
+---
+
+## Step 9: Commit & Output
+
+**Empty check first:** Run `git status` (never use `-uall`). If no documentation files were
+modified by any previous step, output "All documentation is up to date." and exit without
+committing.
+
+**Commit:**
+
+1. Stage modified documentation files by name (never `git add -A` or `git add .`).
+2. Create a single commit:
+
+```bash
+git commit -m "$(cat <<'EOF'
+docs: update project documentation for vX.Y.Z.W
+
+{{CO_AUTHOR_TRAILER}}
+EOF
+)"
+```
+
+3. Push to the current branch:
+
+```bash
+git push
+```
+
+**PR/MR body update (idempotent, race-safe):**
+
+1. Read the existing PR/MR body into a PID-unique tempfile (use the platform detected in Step 0):
+
+**If GitHub:**
+```bash
+gh pr view --json body -q .body > /tmp/gstack-pr-body-$$.md
+```
+
+**If GitLab:**
+```bash
+glab mr view -F json 2>/dev/null | python3 -c "import sys,json; print(json.load(sys.stdin).get('description',''))" > /tmp/gstack-pr-body-$$.md
+```
+
+2. If the tempfile already contains a `## Documentation` section, replace that section with the
+ updated content. If it does not contain one, append a `## Documentation` section at the end.
+
+3. The Documentation section should include:
+
+ a. **Doc diff preview** — for each file modified, describe what specifically changed (e.g.,
+ "README.md: added /document-release to skills table, updated skill count from 9 to 10").
+
+ b. **Documentation debt** — if the coverage map from Step 1.5 found gaps, append a
+ `### Documentation Debt` subsection listing:
+ - Critical gaps: new public surface with zero documentation coverage
+ - Common gaps: features with reference-only coverage (no how-to or tutorial)
+ - Stale diagrams: architecture diagrams with entity names that drifted from the code
+ - Each item should include a one-line description of what's missing and which Diataxis
+ quadrant would fill it (e.g., "⚠️ `/new-skill` — has reference in AGENTS.md but no
+ how-to example in README")
+
+ If there are any documentation debt items, suggest adding a `docs-debt` label to the PR.
+
+4. Redaction scan-at-sink, then write the updated body back. The body is already
+ in a temp file (`/tmp/gstack-pr-body-$$.md`); scan THAT file before editing so
+ the bytes scanned are the bytes sent:
+
+```bash
+REDACT_VIS=$(~/.claude/skills/gstack/bin/gstack-config get redact_repo_visibility 2>/dev/null)
+[ -z "$REDACT_VIS" ] && REDACT_VIS=$(gh repo view --json visibility -q .visibility 2>/dev/null | tr 'A-Z' 'a-z')
+~/.claude/skills/gstack/bin/gstack-redact --from-file /tmp/gstack-pr-body-$$.md --repo-visibility "${REDACT_VIS:-unknown}" --json
+# exit 3 (HIGH) → do NOT edit, rotate+redact; exit 2 (MEDIUM) → confirm per finding.
+```
+
+**If GitHub:**
+```bash
+gh pr edit --body-file /tmp/gstack-pr-body-$$.md
+```
+
+**If GitLab:**
+Read the contents of `/tmp/gstack-pr-body-$$.md` using the Read tool, then pass it to `glab mr update` using a heredoc to avoid shell metacharacter issues:
+```bash
+glab mr update -d "$(cat <<'MRBODY'
+
+MRBODY
+)"
+```
+
+5. Clean up the tempfile:
+
+```bash
+rm -f /tmp/gstack-pr-body-$$.md
+```
+
+6. If `gh pr view` / `glab mr view` fails (no PR/MR exists): skip with message "No PR/MR found — skipping body update."
+7. If `gh pr edit` / `glab mr update` fails: warn "Could not update PR/MR body — documentation changes are in the
+ commit." and continue.
+
+**PR/MR title sync (idempotent, always-on):**
+
+PR titles must always start with `v` — same rule as `/ship`. If Step 8 bumped VERSION after `/ship` had already created the PR, the title is now stale. This sub-step fixes it.
+
+1. Read the current VERSION:
+
+```bash
+V=$(cat VERSION 2>/dev/null | tr -d '[:space:]')
+```
+
+If `VERSION` does not exist or is empty, skip this sub-step entirely.
+
+2. Read the current PR/MR title:
+
+**If GitHub:**
+```bash
+CURRENT_TITLE=$(gh pr view --json title -q .title 2>/dev/null || true)
+```
+
+**If GitLab:**
+```bash
+CURRENT_TITLE=$(glab mr view -F json 2>/dev/null | jq -r .title 2>/dev/null || true)
+```
+
+If `CURRENT_TITLE` is empty (no open PR/MR), skip with message "No PR/MR found — skipping title sync."
+
+3. Compute the corrected title using the shared helper (single source of truth — same one `/ship` uses):
+
+```bash
+NEW_TITLE=$(~/.claude/skills/gstack/bin/gstack-pr-title-rewrite.sh "$V" "$CURRENT_TITLE")
+```
+
+The helper handles three cases: title already correct (no-op), title has a different `v` prefix (replace it), or title has no version prefix (prepend one).
+
+4. If `NEW_TITLE` differs from `CURRENT_TITLE`, update it:
+
+**If GitHub:**
+```bash
+gh pr edit --title "$NEW_TITLE"
+```
+
+**If GitLab:**
+```bash
+glab mr update -t "$NEW_TITLE"
+```
+
+5. If the edit command fails: warn "Could not update PR/MR title — documentation changes are still in the commit." and continue. Do not block on title sync failure.
+
+**Structured doc health summary (final output):**
+
+Output a scannable summary showing every documentation file's status:
+
+```
+Documentation health:
+ README.md [status] ([details])
+ ARCHITECTURE.md [status] ([details])
+ CONTRIBUTING.md [status] ([details])
+ CHANGELOG.md [status] ([details])
+ TODOS.md [status] ([details])
+ VERSION [status] ([details])
+```
+
+Where status is one of:
+- Updated — with description of what changed
+- Current — no changes needed
+- Voice polished — wording adjusted
+- Not bumped — user chose to skip
+- Already bumped — version was set by /ship
+- Skipped — file does not exist
+
+If the coverage map from Step 1.5 identified any gaps, append:
+
+```
+Documentation coverage:
+ [entity] [reference] [how-to] [tutorial] [explanation]
+ /new-skill ✅ ❌ ❌ ❌
+ --new-flag ✅ ✅ ❌ ❌
+
+Diagram drift:
+ ARCHITECTURE.md: "FooProcessor" renamed to "BarProcessor" in code — diagram may be stale
+```
+
+If all coverage is complete and no diagrams drifted, output: "Coverage: all shipped features have adequate documentation."
diff --git a/test/helpers/carve-guards.ts b/test/helpers/carve-guards.ts
index 8dfd04a04..6b3d1d898 100644
--- a/test/helpers/carve-guards.ts
+++ b/test/helpers/carve-guards.ts
@@ -192,6 +192,23 @@ export const CARVE_GUARDS: Record = {
minUnionBytes: 70_000,
mustContain: ['design doc', 'problem statement'],
},
+ 'document-release': {
+ skill: 'document-release',
+ expectedSections: ['release-body.md'],
+ requiredReads: ['release-body.md'],
+ scenario:
+ 'A PR has shipped a new CLI flag and touched README.md and CHANGELOG.md. Skip the git pre-flight shell commands (assume the diff adds --new-flag and updates those two docs). Run the documentation workflow: build the coverage map, then audit the docs, apply updates, and polish the CHANGELOG voice. Produce the documentation health summary.',
+ staticInvariants: {
+ mustStayInSkeleton: ['## Step 1: Pre-flight', '## Step 1.5: Coverage Map'],
+ mustMoveToSection: ['## Step 2: Per-File Documentation Audit', '## Step 5: CHANGELOG Voice Polish'],
+ // Operational skill (no plan-mode review gate).
+ gateAfterStop: undefined,
+ },
+ behavioral: 'prompt',
+ maxSkeletonBytes: 50_000,
+ minUnionBytes: 55_000,
+ mustContain: ['CHANGELOG', 'Diataxis', 'coverage'],
+ },
};
/** Sorted carved-skill names. Consumers derive their lists from this — no parallel lists. */