Skip to content

feat(dx): enforce documentation upkeep in /create-issue and /work skills - #1769

Draft
norbert-kulus-blockydevs wants to merge 3 commits into
mainfrom
1768-enforce-docs-upkeep-skills
Draft

feat(dx): enforce documentation upkeep in /create-issue and /work skills#1769
norbert-kulus-blockydevs wants to merge 3 commits into
mainfrom
1768-enforce-docs-upkeep-skills

Conversation

@norbert-kulus-blockydevs

@norbert-kulus-blockydevs norbert-kulus-blockydevs commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Adds a documentation-upkeep step to the two fast-path workflow skills (/create-issue, /work) so reference docs stop drifting out of sync with the code. This is a self-attested convention in the AI instructions, not a hard CI gate (per request).
  • Coverage is four levels, not just the central reference docs: central docs/*.md, package-local docs (integration READMEs + their docs/, apps/web/README.md, root README.md, in-tree notes), ADRs, and stale why comments in the code.
  • /ship (the third PR-producing skill) is aligned to the same standard so it isn't a silent bypass.

Changes

  • .claude/commands/create-issue.md
    • Step 2 now diagnoses documentation impact from the code it reads.
    • New ## Docs impact section in the issue format (central docs + package-local docs + ADR) - a pointer /work consumes, not an edit.
    • New acceptance criterion for documentation upkeep.
    • Step 5: assign the issue to the requesting user via the MCP update_issue tool (no gh CLI). The in-progress label is intentionally not applied here - /work applies it (Phase 1.5) when work actually starts.
  • .claude/commands/work.md
    • New Phase 4.5 - Documentation between Implement and Review & Ship: starts from the issue's ## Docs impact, runs a classifier across four levels, edits what applies in each doc's existing style, and produces an explicit doc-impact statement.
    • Phase 5 PR body must now carry a ## Docs section.
  • .claude/commands/ship.md
    • Phase 4 now mirrors /work Phase 4.5 (four levels + doc-impact statement); PR template gains a ## Docs section.

Scope note

Step 5 of /create-issue also sets issue self-assignment and defers the in-progress label to /work Phase 1.5. That is a workflow/policy tweak adjacent to - but distinct from - the documentation-upkeep goal of this PR; called out here so it can be reviewed on its own terms.

Test plan

Docs

None - this change edits the workflow skills themselves. It introduces no port, capability, cross-context edge, schema change, or FE pattern, so no central docs/*.md, package-local doc, or ADR is affected, and no in-code why comment is contradicted. The edited files are the process definition, not documentation of the system.

Closes #1768

🤖 Generated with Claude Code

Add a mandatory documentation step to the two fast-path workflow skills so
reference docs, package-local docs, ADRs, and stale why-comments stop drifting
out of sync with the code.

/create-issue: diagnose doc impact in Step 2, emit a `## Docs impact` section
(central docs + package-local docs + ADR) in the issue format, add a docs
acceptance criterion, and add Step 5 to self-assign the requesting user. The
in-progress label is intentionally NOT applied at issue-creation time - it
marks active work and is applied by /work when implementation starts.

/work: add a mandatory Phase 4.5 - Documentation between Implement and
Review & Ship that classifies impact across four levels, edits what applies,
and carries a `## Docs` statement into the PR body. Add a behavior rule
forbidding a silent skip.

Closes #1768

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: norbert-kulus-blockydevs <norbert.kulus@blockydevs.com>
@norbert-kulus-blockydevs
norbert-kulus-blockydevs force-pushed the 1768-enforce-docs-upkeep-skills branch from a55dde1 to 5fb06b8 Compare July 22, 2026 14:21

@norbert-kulus-blockydevs norbert-kulus-blockydevs left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review — enforce documentation upkeep in /create-issue and /work skills

Reviewed across three lenses (skill-instruction correctness, contributor/DX experience, domain-documentation-taxonomy consistency). This is a well-targeted DX change: the three-level doc classifier (central docs/ → package-local → ADR → in-code comments) is grounded in the repo's real layout — every one of the ~11 central docs and the package-local example paths it references actually exists — routes each change kind to the right doc, and ships a sensible None — <reason> escape hatch so trivial fixes don't force stale-doc churn. Verdict: Approve with changes — no blockers; two cross-file inconsistencies worth reconciling before merge, the rest polish.

🟡 IMPORTANT — --assignee @me (gh CLI) contradicts work.md's "gh CLI is not installed"

Flagged independently by two lenses. create-issue.md:54 Step 5 instructs --assignee @me, which is gh CLI syntax, but its sibling work.md:25 states "All GitHub operations use the MCP GitHub tools (gh CLI is not installed)" and does everything via MCP (add_issue_comment, issue_write, get_label). Within one skill suite the two files now disagree on whether gh even exists — whoever runs /create-issue will reach for a tool the sibling skill says isn't there. Reconcile onto one GitHub tooling path (name the MCP update_issue/equivalent, or make it tool-neutral: "assign it to the requesting user").

🟡 IMPORTANT — ship.md left divergent, providing a silent bypass of the new enforcement

/ship (.claude/commands/ship.md) is a third PR-producing skill that also branches, commits Closes #N, and opens the PR — but its Phase 4 — Documentation (ship.md:73-83) is the old, thinner version: only 5 central docs, no package-local/ADR/in-code-comment levels, no mandatory doc-impact statement, and its PR template (ship.md:87-116) has ## Summary/## Changes/## Test plan/## Tech review but no ## Docs section. So an author who runs /ship instead of /work silently escapes the "mandatory, do-not-skip" gate this PR adds — the suite now carries two contradictory doc-upkeep standards. Arguably outside the PR's literal "in /create-issue and /work" scope, but it directly undercuts the stated goal of enforcing upkeep. Either update ship.md Phase 4 + PR template to match (or have it defer to work.md Phase 4.5), or explicitly scope it out in the PR body.

🟢 SUGGESTION items (non-blocking)

  • "Enforce"/"mandatory" is self-attested, not enforced — there's no lint/CI check for the ## Docs PR section (grep of scripts/ and .github/ finds none); the None — <reason> escape is trivially satisfiable and the assistant both writes and judges its own statement. Reasonable for a prompt-based skill, but the word "enforce" oversells a soft convention. If a hard gate is wanted, a CI check asserting the PR body contains a ## Docs section is the way; otherwise consider softening the wording.
  • Promote the anti-padding guardrail — the strong "must produce a statement / a silent skip is a defect" framing, combined with an assistant's compliance bias, can nudge toward padding docs to look compliant. The mitigations are already written in ("Update intent and current state, not a changelog of your diff. Do not add docs for things already covered") but buried in step 3 — promote that line directly under the Phase 4.5 heading so "don't over-document" is as prominent as "don't skip."
  • lessons.md route omits its own graduate-don't-duplicate rule — a change that alters a naming convention hits both engineering-standards.md and lessons.md, and the classifier gives no precedence hint, leaving a narrow path to write an architectural rule into the regression ledger. One clause ("record empirical gotchas here; if it's an actual rule, put it in the canonical doc and leave only a pointer") closes it — matches lessons.md's own preamble.
  • Classifier is duplicated across create-issue.md (issue-time "Docs impact" prose) and work.md (Phase 4.5 table) with slightly different phrasings (e.g. capabilities.md described differently in each) — they agree today but will drift; consider pointing both at the canonical CLAUDE.md reference-doc table as the single source.
  • capabilities.md's "authoritative full inventory" status isn't surfaced — the classifier pairs port/capability changes with "architecture-overview.md (+ capabilities.md)" but a contributor may update the curated highlight and skip the code-synced full list; a half-line ("capabilities.md is the authoritative full list — always update it; architecture-overview is a curated subset") prevents it going stale.
  • Scope creep in the PR body — Step 5 also adds self-assignment + in-progress-label timing, unrelated to doc upkeep; a one-line note in the PR body makes that policy change reviewable on its own terms.
  • Near-identical artifact names — the issue's ## Docs impact (prediction) vs the PR's ## Docs (outcome) are deliberately different, and work.md correctly calls the issue section "the hypothesis, not the final answer," but a one-line "the PR ## Docs is the realized version of the issue's ## Docs impact" removes any conflation.
  • Vague lint-rerun hedge — work.md:160's "re-run lint if any doc has a linked invariant (rare)" has no concrete referent today (check:invariants targets code, not docs); drop it or make it concrete.

What's solid

  • All references are grounded — every central doc, the ADR README, and the package-local examples (ksef FA3 notes, setup-guide, root README) verified to exist; the (#NNN) annotation guidance matches the actual convention in architecture-overview.md.
  • Taxonomy-faithful routing — ADR "when to write / skip" mirrors adrs/README.md verbatim (no ADR spam), the three-level model maps cleanly onto the repo's docs-live-close-to-code layout, and the in-code-comment clause stays within CLAUDE.md's "keep why comments truthful, never add what comments" rule.
  • Proportionate friction — the None — <reason> escape on both the issue side and the /work side means a trivial fix costs two one-line statements, not a doc-editing detour; the /create-issue → /work diagnose-then-verify handoff reduces rediscovery rather than duplicating effort.
  • Good cross-file coherence on the in-progress label — create-issue.md:58 correctly defers label application to work.md Phase 1.5, exactly where it lives.

…soften enforce framing

Address the consolidated review on PR #1769:
- create-issue.md: drop `gh` CLI `--assignee @me` (contradicted work.md's
  "gh CLI not installed"); route issue create/assign through MCP tools.
- ship.md: replace the thinner Phase 4 doc step with the /work Phase 4.5
  standard (three levels + doc-impact statement) and add a `## Docs`
  section to its PR template, closing the silent-bypass path.
- work.md: soften "mandatory/enforce" to an honest self-attested
  convention with a CI-check follow-up note; promote the anti-padding
  guardrail under the Phase 4.5 heading.
- Both skills: point the doc classifier at the canonical CLAUDE.md
  Reference Documentation table as single source; note capabilities.md
  is the authoritative full inventory; add the lessons.md
  graduate-don't-duplicate clause; clarify `## Docs impact` (prediction)
  vs `## Docs` (realized); drop the vague lint-rerun hedge.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: norbert-kulus-blockydevs <norbert.kulus@blockydevs.com>
@norbert-kulus-blockydevs

Copy link
Copy Markdown
Collaborator Author

Review findings addressed

Thanks for the thorough three-lens review. All items addressed in 15f0b0e9. Finding by finding:

IMPORTANT

1. --assignee @me (gh CLI) contradicted work.md's "gh CLI is not installed".
Fixed in create-issue.md Step 5. It now creates the issue via the MCP GitHub tools and assigns via the MCP update_issue tool, with an explicit "do not use gh CLI syntax such as --assignee @me" note. The whole suite is now on one GitHub tooling path (MCP), matching work.md:25.

2. ship.md left divergent (silent bypass of the new gate).
Addressed in scope, not scoped out. ship.md Phase 4 no longer carries the old thinner 5-doc list; it now mirrors /work Phase 4.5 verbatim in substance - the same four levels (central docs incl. capabilities.md, package-local docs, ADRs, stale why comments), the don't-over-document rule, and the explicit doc-impact statement - and points to /work Phase 4.5 as the source of the full classifier so the two stay in sync. Its PR template gains a ## Docs section. An author running /ship can no longer escape the convention.

SUGGESTION

3. "Enforce"/"mandatory" oversells a self-attested convention.
Chose to soften the framing (there is no CI gate, so honesty over false assurance). work.md Phase 4.5 heading is now "Documentation (required step)"; a blockquote states plainly it is a self-attested convention with no CI check today and names a lint/CI check asserting the ## Docs section as a sensible follow-up. The "never skip" behavior rule is reworded to note a justified None - <reason> satisfies it.

4. Promote the anti-padding guardrail.
Done. The "Don't over-document" guidance is now a bolded paragraph directly under the Phase 4.5 heading (as prominent as "don't skip"), explicitly stating that padding docs to look compliant is as much a defect as skipping. The step-3 mention is trimmed to a back-reference.

5. lessons.md graduate-don't-duplicate clause.
Added to the classifier in both work.md (table row) and create-issue.md: record empirical gotchas in lessons.md, but if it is actually an architectural rule, put it in the canonical doc and leave only a pointer - matching lessons.md's own preamble.

6. Classifier duplicated across the two skills (drift risk).
Both classifiers now point at the Reference Documentation table in CLAUDE.md as the single source of truth for topic-to-doc routing, with the local tables labelled as convenience mirrors ("if the two diverge, CLAUDE.md wins"). Future routing edits happen in one place.

7. capabilities.md authoritative-full-list status not surfaced.
Both skills now state capabilities.md is the authoritative code-synced full inventory and architecture-overview.md only a curated subset, with "always update capabilities.md for a capability change". The work.md table row leads with capabilities.md.

8. Scope creep (self-assignment + in-progress-label timing).
Added a ## Scope note to the PR body flagging that policy tweak as adjacent to but distinct from the doc-upkeep goal, so it is reviewable on its own terms.

9. Near-identical ## Docs impact vs ## Docs names.
Both skills now spell out the relationship: the issue's ## Docs impact is the prediction/hypothesis, the PR's ## Docs is the realized/confirmed outcome - deliberately named differently.

10. Vague lint-rerun hedge (work.md:160).
Dropped the "re-run lint if any doc has a linked invariant (rare)" hedge (no concrete referent - check:invariants targets code, not docs). Replaced with: no quality-gate rerun for prose-only doc edits; re-run the relevant scoped check only if a script/config was edited alongside.

No quality gate was run: the change is markdown/skill files only, no script or config touched.

@norbert-kulus-blockydevs

Copy link
Copy Markdown
Collaborator Author

/pr-review - post-fix verification pass

Re-reviewed the PR in its current state (head 15f0b0e9, includes the round of fixes applied in response to the prior three-lens review). This is an independent pass, not a rubber stamp of the "addressed" comment - each claimed fix was checked against the actual current diff, and the file was read end-to-end (not just the diff hunks) to catch anything the hunk-level view would hide.

Verification of the 10 previously-claimed fixes

All 10 items from the prior review comment are genuinely fixed in the current diff:

  1. --assignee @me (gh CLI) - fixed. create-issue.md Step 5 now creates via MCP and assigns via MCP update_issue, with an explicit "do not use gh CLI" note. Confirmed no leftover gh /gh CLI usage anywhere in the three files except that one cautionary mention.
  2. ship.md silent bypass - fixed. Phase 4 now mirrors /work Phase 4.5's four levels and carries a ## Docs PR-template section.
  3. "Enforce"/"mandatory" softened - fixed. Phase 4.5 heading + blockquote now correctly frame this as a self-attested convention with no CI gate.
  4. Anti-padding guardrail promoted - fixed, now a bolded paragraph right under the Phase 4.5 heading.
  5. lessons.md graduate-don't-duplicate clause - fixed, present in both classifiers and verified to match lessons.md's own preamble ("When a lesson hardens into a rule, graduate it...").
  6. Single source of truth via CLAUDE.md table - present in both classifiers, but see IMPORTANT Epic: Integrations & Setup #1 below - this fix introduces a new problem.
  7. capabilities.md authority surfaced - fixed in both skills, but see IMPORTANT Epic: Integrations & Setup #1 below.
  8. Scope-creep note - fixed, ## Scope note present in the PR body.
  9. ## Docs impact vs ## Docs naming distinction - fixed, spelled out in both skills.
  10. Vague lint-rerun hedge dropped - fixed, replaced with a concrete "prose-only edits need no rerun" statement.

New/independent findings

[IMPORTANT] - .claude/commands/work.md (Phase 4.5 table + intro), .claude/commands/create-issue.md (## Docs impact section)

Both new classifier tables state: "The canonical routing map ... is the Reference Documentation table in CLAUDE.md ... if the two ever appear to diverge, CLAUDE.md wins." But CLAUDE.md's Reference Documentation table has no row for docs/capabilities.md at all - only architecture-overview.md, engineering-standards.md, testing-guide.md, code-review-guide.md, migrations.md, frontend-architecture.md, frontend-ui-style-guide.md, implementation-plan-generator-guide.md, lessons.md. Both new sections simultaneously declare capabilities.md "authoritative" and "always update," and declare CLAUDE.md the tie-breaking single source of truth for the same routing map - but CLAUDE.md doesn't know capabilities.md exists. Per the PR's own rule, this is a real divergence, and CLAUDE.md "wins," which would silently drop the capabilities.md requirement the fix round worked hard to add (items #6/#7 above). Fix: add a docs/capabilities.md row to CLAUDE.md's Reference Documentation table (e.g. "Full sub-capability inventory | docs/capabilities.md") in this same PR - otherwise the "single source of truth" claim is false on day one.

[IMPORTANT] - .claude/commands/work.md:28,40,183 (pre-existing, not touched by this diff, but directly on-theme)

Phase 1.5 (untouched by this PR) references issue_read, issue_write, and get_label as MCP GitHub tools. None of these exist in the current GitHub MCP toolset - the real tools are get_issue, update_issue, add_issue_comment, create_issue, list_issues, etc. (verified against the live tool registry; no mcp__github__issue_read/issue_write/get_label exist). create-issue.md's new Step 5 (this PR) correctly names update_issue right next to it, and the PR description explicitly claims "The whole suite is now on one GitHub tooling path (MCP)" - but that claim is false as long as work.md's claim-lock (Phase 1.5) and claim-release (Phase 5 step 7) still reference nonexistent tool names. Since this PR's stated purpose (per the fix commit) was reconciling GitHub tooling across the skill suite, and it touches work.md in this exact area (Phase 5 step 5, immediately above step 7's issue_write), it's a low-cost, high-value fix to land in the same PR: swap issue_read -> get_issue, issue_write -> update_issue, and drop/replace get_label (no such tool exists either - a label check would go through search_issues/direct read of the issue's labels via get_issue, or simply be dropped as unverifiable via MCP). Not a hard blocker since it's pre-existing content, but it directly undercuts a claim this very PR makes.

[SUGGESTION] - docs/engineering-standards.md § "Pull Requests"

This PR makes the ## Docs section a required PR-body element (self-attested convention) for both /work and /ship. engineering-standards.md's own "Pull Requests" section (PR description should include "What changed and why / How to test / Related issues / Screenshots") isn't updated to mention the new ## Docs section, even though this is exactly the kind of "new convention" the PR's own classifier table would route to engineering-standards.md. Minor - the convention lives correctly in the skill files - but leaving the human-facing standards doc silent on it means a non-AI contributor following engineering-standards.md alone wouldn't know the convention exists.

[SUGGESTION] - .claude/commands/work.md Phase 1.5, step 1

search_pull_requests (referenced alongside list_pull_requests) also doesn't appear in the current GitHub MCP tool registry. Same root cause as the IMPORTANT finding above - bundling a fix would be efficient since it's the same neighborhood.

Documentation-taxonomy alignment (this PR's own subject matter)

  • The three-level classifier (central docs / package-local docs / ADRs) plus in-code comments is a faithful mirror of CLAUDE.md's own doc-routing intent and of docs/architecture/adrs/README.md's ADR-vs-not guidance (both cross-checked directly against source - the "add or supersede an ADR... skip for local refactors" language matches the ADR README's own criteria almost verbatim).
  • The lessons.md "graduate, don't duplicate" clause matches that file's real preamble (checked verbatim).
  • No stale references, broken relative paths, or dead anchors found elsewhere in the three touched files.

Merge readiness

Approve with changes.

The prior review's 10 findings are genuinely resolved. However, this fix round introduced one new, self-inflicted inconsistency (the capabilities.md / CLAUDE.md divergence) that undermines the exact "single source of truth" guarantee the round was trying to establish, and it left one real (if pre-existing) tool-naming gap unaddressed in the same file it was already editing for GitHub-tooling consistency. Both are cheap, mechanical fixes - not a design problem.

Priority fixes (if any)

  1. Add a docs/capabilities.md row to CLAUDE.md's Reference Documentation table so the "if they diverge, CLAUDE.md wins" rule doesn't silently drop the capabilities.md requirement this PR just added.
  2. Swap the nonexistent issue_read / issue_write / get_label (and search_pull_requests) tool references in work.md Phase 1.5 / Phase 5 for the real MCP tool names (get_issue, update_issue, etc.), matching the naming already fixed in create-issue.md Step 5.
  3. (Optional) Add a one-line pointer in docs/engineering-standards.md § Pull Requests noting the ## Docs section convention.

…ool names

Close the self-contradiction introduced by the docs-upkeep classifier: add a
docs/capabilities.md row to CLAUDE.md's Reference Documentation table so the
"CLAUDE.md is the single source of truth" rule no longer silently drops the
capabilities.md requirement the classifier declares authoritative.

Swap the nonexistent GitHub MCP tool references in work.md Phase 1.5 / Phase 5
(issue_read, issue_write, get_label, search_pull_requests) for the real tools
(get_issue, update_issue, list_pull_requests), matching create-issue.md Step 5.

Document the new ## Docs PR-body section convention in engineering-standards.md
§ Pull Requests so non-AI contributors see it too.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: norbert-kulus-blockydevs <norbert.kulus@blockydevs.com>
@norbert-kulus-blockydevs

Copy link
Copy Markdown
Collaborator Author

Post-fix findings addressed

All findings from the post-fix verification pass are addressed in eb1b3acb. Finding by finding:

IMPORTANT - capabilities.md / CLAUDE.md divergence

Added a docs/capabilities.md row to CLAUDE.md's Reference Documentation table (Full sub-capability inventory (code-synced) | docs/capabilities.md). CLAUDE.md now knows the file exists, so the classifier's "if they diverge, CLAUDE.md wins" rule no longer silently drops the capabilities.md requirement. The single-source-of-truth claim is now true.

IMPORTANT - nonexistent MCP tool names in work.md

Verified the real GitHub MCP toolset before renaming (get_issue, update_issue, add_issue_comment, create_issue, list_issues, list_pull_requests exist; issue_read, issue_write, get_label, search_pull_requests do not). Swapped in work.md:

  • Phase 1.5 step 1: issue_read -> get_issue.
  • Phase 1.5 step 3: get_label (no such tool) replaced with reading the issue's current labels via get_issue; issue_write -> update_issue.
  • Phase 5 step 7: issue_write -> update_issue.

work.md is now consistent with create-issue.md Step 5's update_issue naming, so the "whole suite on one GitHub tooling path" claim holds.

SUGGESTION - search_pull_requests in Phase 1.5 step 1

Dropped. The line now references only list_pull_requests (plus the git log origin/main --grep fallback that was already there).

SUGGESTION - engineering-standards.md § Pull Requests

Added a one-line bullet to the PR-description list noting the new ## Docs section convention (path -> what changed, or None - <reason>) that /work and /ship require, so a non-AI contributor following the standards doc alone sees it.

Note on adjacent stale references (not addressed - out of scope)

refine-product.md and pre-implement.md also reference issue_read / issue_write. Left untouched: they are not part of this PR's diff, were not flagged by the review, and refine-product.md targets a different repo (SilkSoftwareHouse/openlinker). Worth a separate cleanup, but folding them into this PR would widen its scope beyond the doc-upkeep-skills subject.

Markdown/skill files only - no quality gate run. Commit eb1b3acb, GPG-signed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[TASK] DX — enforce documentation upkeep in /create-issue and /work skills

1 participant