Skip to content

docs: rename docs/ root files to lower-kebab-case and gate the rule - #4097

Open
kyle-sexton wants to merge 18 commits into
mainfrom
claude/docs-naming-consistency-cr6ys6
Open

docs: rename docs/ root files to lower-kebab-case and gate the rule#4097
kyle-sexton wants to merge 18 commits into
mainfrom
claude/docs-naming-consistency-cr6ys6

Conversation

@kyle-sexton

@kyle-sexton kyle-sexton commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

No related issue: the rename was requested directly by the maintainer; the one follow-up (an ADR-number uniqueness gate) is filed as #4109 and linked under Related.

Summary

Rename the 13 UPPERCASE-KEBAB markdown files at the docs/ root (PLUGIN-PHILOSOPHY.md, MIGRATION-PLAYBOOK.md, GLOSSARY.md, CATALOG.md, and nine more) to lower-kebab-case, repoint every live reference, and add the rule, the CI gate, and the ADR that keep the tree consistent. The 13 were the only files in a 193-file tree that broke the rule every other naming surface in this repository already states (plugin names, skill leaf names, ecosystem ids, topic slugs); Google, GitLab, and Microsoft Learn style guides all mandate lowercase-with-hyphens for doc filenames, and the conventional uppercase exceptions (README.md, CHANGELOG.md, INDEX.md, code files) stay as they are.

Two of the 13 (plugin-philosophy.md, migration-playbook.md) are a raw-URL interface under ADR 0018, so this is a hard cutover with no tombstones (a case-colliding pair corrupts every Windows and macOS checkout) carried by a patch bump on every plugin whose body cites them.

Fix

Four Tidy-First commits plus a base merge, each green on its own sanity block:

  1. bdb8eb14 Rename. git mv the 13 files and repoint the runtime consumers (generate-catalog.mjs, generate-cheatsheet.mjs, validate-plugin-contracts.mjs, cheatsheet-config.mjs, overlap.py and its test, the docs-only allowlist and its proof, docs/native-surfaces/records.json).
  2. 14126266 Reference sweep and bumps. Scripted basename and bare-stem maps applied by a three-way boundary: current surfaces change in every form (the six absolute GitHub URLs, 54 plugin setup skills, .claude/rules, README.md, docs/conventions/**, and the lockstep pair plugins/skill-quality/scripts/check-skill.sh + evals.json); docs/adr, docs/specs, docs/upstream change in links and backtick paths only; plugin CHANGELOG.md released entries stay untouched except one real link (below). Every plugin with a body edit (56) takes a patch bump with a ## [x.y.z] / ### Changed entry. docs/architecture/landscape.json edges regenerated through reference-edges.sh; docs/catalog.md and docs/skill-cheat-sheet.md regenerated.
  3. 6de5b0fc Gate. scripts/check-docs-naming.sh --check (basename regex, three exemption classes, case-collision rule) with a test-first .test.sh (10 cases), .claude/rules/docs-naming.md (paths: docs/**), the AGENTS.md row, and the lint job step pair (id: docs_naming, advisory, fed to the aggregator).
  4. ecc33889 ADR 0033 records the rule, the exemptions, the hard cutover and why, the three-way historical-record boundary, the enforcement pair, and the duplicates-stay stance for ADR numbers; the rule file links it.
  5. b5481c31, 82899c3a, and 71754f56 merge origin/main (nine commits across three syncs), 8a259be4 and ccb23908 bring the checker onto the check-script contract, ad5c1165 closes Phase 5 in the plan, ae07c1ce prunes the slice. Every plugin bumped on both sides resolves to main's version plus one patch with this branch's entry above main's: miro and skill-quality on the second sync, and on the third sync (main's fix(playbooks,skills): keep first and second person out of description prose across 36 skills #4108 bumped 24 plugins) the 18 that overlap this branch's set, so for example claude-ops lands at 0.54.2 and source-control at 0.55.77.

Stray commit, disclosed: f9fce8c9 (subject case, author test <t@t.test>) adds only the then-untracked scripts/check-docs-naming.test.sh. It was made by that suite itself on its first red run: its discover-mode case ran git -C "$repo" after a failed fixture build left $repo empty, so the fixture commit landed in this checkout. The guard is fixed on the branch, the commit is byte-identical to what the next commit adds, and it disappears under the repository's squash merge; rewriting three merge commits above it to drop it was judged riskier than disclosing it.

Declared released-entry edit, per the changelog-parity discipline: the one markdown link inside plugins/visualization/CHANGELOG.md's ## [0.3.2] entry now points at docs/plugin-philosophy.md; the plugin's new ## [0.6.2] entry names the correction.

Pre-prune head (the last commit carrying the contract slice docs/topics/docs-naming-consistency/): ad5c1165f17ca5948a5d4ac219d5032790ef1f9d. The final commit removes the slice, so contract-slice-diff goes green on this head and the plan is preserved below.

docs/topics/docs-naming-consistency/PLAN.md (Brief + five-phase plan, as of the pre-prune head)

docs-naming-consistency

Brief

Scope-change note, 2026-09-11: the accepted answer to Q8 (two compatibility tombstones at the
old uppercase paths) was found infeasible at plan review. A tombstone would share a tree with its
lowercase twin, and on case-insensitive filesystems "checking out both files will result in the
second one overwriting the first one" (Microsoft Learn, Azure Repos case sensitivity, fetched
2026-09-11); this repository runs two windows-2025 CI jobs. Q12 in the interview register
reopens the decision. The Brief below is written for the recommended answer (hard cutover, no
tombstones, norm-conformant plugin bumps) and is revised if the user picks otherwise.

TLDR

  • Rename the 13 UPPERCASE-KEBAB .md files at the docs/ root to lower-kebab-case with git mv,
    and update every live reference (links, backtick paths, bare stems, runtime constants) to the
    new names.
  • No tombstones: the six absolute GitHub URLs in plugin bodies are repointed in the same PR, and
    every plugin whose body the sweep edits gets a patch bump and a changelog entry, which is what
    delivers the corrected citations to installed copies.
  • Add enforcement: a deterministic scripts/check-docs-naming.sh (+ .test.sh, CI-wired,
    affected-tests mapped) that also refuses any two docs/ paths differing only by case, and a
    path-scoped .claude/rules/docs-naming.md for docs/**.
  • Record the rule as the next free ADR number; file one follow-up issue for an ADR-number
    uniqueness gate.
  • Everything else (in-file formatting, the reusable skill, ADR renumbering) is out of this PR.

Goal

Every file under docs/ follows one naming rule a reader can state in a sentence: lower-kebab-case
for markdown and data files, with the conventional exceptions (README.md, CHANGELOG.md,
INDEX.md, code files in their ecosystem's casing, and the branch-only contract slice), so that
the 13 root files stop being the only outliers, nothing that points at them breaks, and the drift
cannot silently recur.

Constraints

  • Filenames only. In-file formatting (headings, frontmatter) is deferred to a later pass.
  • git mv per file, history-preserving; no content edit to docs/PLUGIN-ARTIFACT-PROTOCOL.md
    (six plugins/*/reference/artifact-protocol.md copies must stay byte-identical to it).
  • Runtime consumers move in the same commit: scripts/generate-cheatsheet.mjs,
    scripts/generate-catalog.mjs, scripts/validate-plugin-contracts.mjs,
    plugins/claude-ops/skills/audit-native-overlap/scripts/overlap.py and test_overlap.py,
    scripts/check-docs-only.test.sh, scripts/generate-cheatsheet.test.sh,
    scripts/docs-only-paths.txt.
  • Reference-update boundary (three-way). Tier 1, current surfaces (skill bodies, agents, READMEs,
    rules, scripts, prompts, .github, docs/ outside adr/, specs/, upstream/): every form,
    bare stems included. Tier 2, docs/adr/**, docs/specs/**, docs/upstream/**: markdown links
    and backtick paths only, narrative untouched. Tier 3, plugin CHANGELOG.md released entries:
    untouched except the one markdown link in plugins/visualization/CHANGELOG.md, declared in the
    PR body and in that plugin's new release entry.
  • Every plugin whose body the sweep edits gets a patch bump in .claude-plugin/plugin.json and a
    ## [x.y.z] / ### Changed entry, the shape 12 of the last 12 body-editing commits used.
  • The 15 GLOSSARY.md mentions under plugins/education/** and
    plugins/domain-driven-design/** name a learner-workspace file and are excluded from the sweep.
  • No file may be added whose path differs from another tracked path only by case.
  • Checker exemptions: README.md, CHANGELOG.md, INDEX.md, the contract slice
    (docs/topics/**), and code files by extension (.py, .sh, .mjs, .js, .ps1).
  • House style: no em dashes in any new rule, script comment, ADR, or skill prose; skill bodies
    state the current rule, never the incident.
  • Draft PR first; Conventional Commits title; PR body with ## Summary, ## Fix,
    ## Verification, ## Related, a No linked issue line, the PLAN.md in a <details> block,
    and the pre-prune commit SHA.
  • Validation: scripts/affected-tests.sh --run must select and pass every mapped suite; a changed
    file mapping to zero suites is an error.

Acceptance criteria

  • git ls-files docs/ | grep -E '/[^/]*[A-Z][^/]*$' | grep -vE '/(README|CHANGELOG|INDEX)\.md$' | grep -v '^docs/topics/' returns empty.
  • scripts/check-docs-naming.sh --check exits 0 on the renamed tree and exits non-zero when a
    fixture adds docs/NEW-FILE.md or a case-colliding pair; its .test.sh proves both, and
    scripts/affected-tests.sh --explain scripts/check-docs-naming.sh selects that test.
  • An offline relative-link resolver over every tracked .md reports 0 missing targets, and
    ! git grep -qE '(main|blob/main)/docs/[A-Z][A-Z-]*\.md' holds (no absolute URL names an
    uppercase root file).
  • node scripts/generate-catalog.mjs, node scripts/generate-cheatsheet.mjs --check,
    node scripts/validate-plugin-contracts.mjs, the overlap.py tests, and
    scripts/check-changed-skills.sh origin/main all pass.
  • The new ADR exists at the next free number, follows the observed ADR shape, and cites the checker
    and the rule file; .claude/rules/docs-naming.md exists with paths: ["docs/**"] and a matching
    row in the AGENTS.md rules table.
  • Every plugin with a body edit on this branch has a manifest version strictly greater than on
    origin/main and a new ## [<v>] entry (scripts/check-changelog-parity.sh --check-bump origin/main).
  • IF any reference to an old uppercase name survives in a Tier 1 surface (link, backtick path,
    bare stem, runtime constant), THEN the anchored git grep sanity check or an affected test fails
    before the PR leaves draft.

Captured assumptions

  • No .claude/topic-docs.yaml exists, so the documented defaults apply; this PR does not add a
    concern file. Revisit if a later PR binds one.
  • No other repository links to the 13 files by absolute URL. GitHub code search was unavailable
    from this session. Revisit if a 404 report arrives; the remedy is a follow-up that repoints it.
  • Users on installed plugin copies older than this PR's bumps fetch a 404 for the two raw doctrine
    URLs until they update; this is the repository's declared posture for a rename ("a clean breaking
    change carried by a version bump and a changelog note").
  • acceptance_criteria_format resolved to free-text (default; no convention-home region).
  • The unwanted-behaviour criterion above covers the coverage prompt; no state-driven case applies.

Out-of-scope

  • In-file formatting consistency across docs/ (headings, frontmatter shape).
  • Renaming README.md / CHANGELOG.md / INDEX.md or any code file.
  • Renumbering the duplicate ADRs 0018, 0025, 0028 (they stay; a follow-up issue asks for a
    uniqueness gate).
  • The reusable naming-consistency skill (separate PR, second in sequence).
  • Rewriting plugin CHANGELOG.md released entries beyond the one visualization link.
  • Shortening the four over-cap skill descriptions the sweep touches; they are recorded in
    scripts/skill-description-cap-baseline.txt and WARN, not FAIL.

Deferred questions

  • None. Every asked question resolved to an answer in the register; Q12 is a reopened question
    awaiting the user, not a deferral.

Plan

Goal

What: rename the 13 UPPERCASE-KEBAB root files under docs/ to lower-kebab-case, repoint
every live reference, bump every plugin the sweep edits, and add the rule, the gate, and the ADR
that stop the drift recurring.
Why: the 13 are the only files in a 193-file tree that break the rule every other naming
surface in this repository already states, and nothing today prevents the 14th.

Standards grounding

No standards index exists (.claude/standards.yaml and docs/standards/ absent; rung 6 of the
ladder, nothing persisted). The plan is grounded in the repository's own convention surfaces
read this session:

Surface Sections cited Layer provenance
docs/adr/0018-treat-the-plugin-as-the-encapsulation-boundary-for-skill-citation.md plugin bodies cite docs/ by absolute URL, so a rename is an interface change team
docs/MIGRATION-PLAYBOOK.md lines 483-490 a rename is a clean breaking change carried by a version bump and a changelog note; the plugin cache is version-keyed team
docs/PLUGIN-PHILOSOPHY.md lines 512-519 silent shims forbidden team
scripts/check-changelog-parity.sh header released-entry body edits need a PR-body declaration and a release entry team
scripts/check-changed-skills.sh and scripts/skill-description-cap-baseline.txt every touched SKILL.md is linted; recorded cap breaches WARN team
scripts/check-fixture-git-isolation.sh, scripts/test-git-helpers.sh a fixture-building test clears inherited git env team
scripts/check-stale-base-overlap.sh a PR from a stale base fails on overlapping paths team
.claude/rules/skill-bodies-state-current-rules.md skill bodies state the rule, never the incident team (ambient)
.claude/rules/vendor-docs-are-not-style.md no em dashes in rules, skills, READMEs, AGENTS.md team (ambient)
.claude/rules/pr-body-contract.md draft PR, Conventional Commits title, four sections team (ambient)
plugins/architecture/skills/record-decision/SKILL.md Gotchas never renumber duplicate ADRs; pick highest plus one team
docs/conventions/topic-docs/README.md lines 656-670 INDEX.md reserved; PLAN.md pasted in the PR body; pre-prune SHA named; slice pruned before merge team

Phase 1: Rename the 13 and move the runtime consumers [DONE]

One structural commit. Every git mv and every hardcoded path constant moves together so no
intermediate state has a generator reading a missing file.

File moves (all git mv docs/<OLD>.md docs/<new>.md):

  • CATALOG-TAXONOMY.md -> catalog-taxonomy.md
  • CATALOG.md -> catalog.md
  • CI-RUNNER-ROUTING.md -> ci-runner-routing.md
  • CLOUD-FLEET-SETUP.md -> cloud-fleet-setup.md
  • CLOUD-SESSIONS.md -> cloud-sessions.md
  • FINDING-YOUR-UNKNOWNS.md -> finding-your-unknowns.md
  • GLOSSARY.md -> glossary.md
  • MIGRATION-PLAYBOOK.md -> migration-playbook.md
  • NATIVE-SURFACES.md -> native-surfaces.md
  • OFFICIAL-DOCS.md -> official-docs.md
  • PLUGIN-ARTIFACT-PROTOCOL.md -> plugin-artifact-protocol.md (no content edit)
  • PLUGIN-PHILOSOPHY.md -> plugin-philosophy.md
  • SKILL-CHEAT-SHEET.md -> skill-cheat-sheet.md

Runtime consumers (path constants, fixtures, allowlist proof):

File Action Rationale
[x] scripts/generate-cheatsheet.mjs MODIFY OUTPUT_PATH and the header comment
[x] scripts/generate-catalog.mjs MODIFY outputPath, taxonomyPath, error text, header comment
[x] scripts/validate-plugin-contracts.mjs MODIFY canonical artifact-protocol path, comments, and the two bare stems at lines 101 and 187
[x] scripts/cheatsheet-config.mjs MODIFY header comment
[x] plugins/claude-ops/skills/audit-native-overlap/scripts/overlap.py MODIFY default --view path and help text
[x] plugins/claude-ops/skills/audit-native-overlap/scripts/test_overlap.py MODIFY fixture path mirrors the default
[x] scripts/check-docs-only.test.sh MODIFY fixture files and assertions
[x] scripts/generate-cheatsheet.test.sh MODIFY fixture tree paths
[x] scripts/docs-only-paths.txt MODIFY the inertness-proof comment
[x] docs/native-surfaces/records.json MODIFY the store's own note field
[x] plugins/*/reference/artifact-protocol.md (six) KEEP byte-identical to the canonical; no content change

Sanity Check:

  • git ls-files docs/ | grep -E '/[^/]*[A-Z][^/]*$' | grep -vE '/(README|CHANGELOG|INDEX)\.md$' | grep -v '^docs/topics/' returns empty
  • git ls-files | tr 'A-Z' 'a-z' | sort | uniq -d returns empty
  • node scripts/generate-catalog.mjs && git diff --quiet docs/catalog.md exits 0
  • node scripts/generate-cheatsheet.mjs --check exits 0
  • node scripts/validate-plugin-contracts.mjs exits 0
  • bash scripts/check-docs-only.test.sh && bash scripts/generate-cheatsheet.test.sh && bash scripts/validate-plugin-contracts.test.sh exit 0
  • bash plugins/claude-ops/skills/audit-native-overlap/scripts/overlap.test.sh exits 0

Phase 2: Reference sweep by the three-way boundary, with plugin bumps [DONE]

Scripted, not hand-edited. Two maps applied with sed over the file set each tier allows: the
13-row basename map (<OLD>.md -> <new>.md) and the 11-row bare-stem map (PLUGIN-PHILOSOPHY
-> plugin-philosophy, applied only to Tier 1 and only where the stem is not followed by .md).
Then a deliberate pass over the sites the maps cannot judge.

Tier 1, current surfaces, every form: every tracked file EXCEPT plugins/*/CHANGELOG.md,
docs/adr/**, docs/specs/**, docs/upstream/**, plugins/education/**,
plugins/domain-driven-design/**, .work/**, docs/topics/**. Includes the six absolute GitHub
URLs, .claude/rules/catalog-taxonomy.md, .claude/rules/ruff-pin.md, README.md,
.github/recurring-schedule.json, .claude/cloud-bootstrap.sh, .github/workflows/ci.yml
comments, prompts/cloud-bootstrap-rollout.md, scripts/skill-portability-tokens.txt, every
plugin setup SKILL.md citing docs/PLUGIN-PHILOSOPHY.md, and docs/conventions/**.

Lockstep edit: plugins/skill-quality/scripts/check-skill.sh (four bare stems, two in
user-visible WARN text) and plugins/skill-quality/skills/check/evals/evals.json line 104, which
quotes that WARN text verbatim; both change in the same commit.

Tier 2, docs/adr/**, docs/specs/**, docs/upstream/**: markdown links and backtick paths
only (the basename map); bare stems and narrative untouched.

Tier 3, plugin CHANGELOG.md released entries: untouched, except
plugins/visualization/CHANGELOG.md line 212 (the one real markdown link), fixed under the same
patch bump every other touched plugin gets, with the correction named in the new release entry.

Plugin bumps (scripted): for each plugin with a non-CHANGELOG file edited on this branch
(54 today; recomputed from git diff --name-only origin/main), bump the patch component of
plugins/<p>/.claude-plugin/plugin.json and prepend a ## [<v>] section with one ### Changed
bullet ("Cite the marketplace docs/ doctrine files by their lower-kebab names"). The visualization
entry additionally names the released-entry link correction.

Deliberate pass (from the exploration's bare-name table, plus the 27 bare-stem hits): confirm
each hit names the docs file and not a same-named file elsewhere; the GLOSSARY.md learner
workspace is the known false positive and is excluded by path.

Sanity Check:

  • An offline relative-link resolver over every tracked .md (scratch script; resolves each
    ](relative/path.md) against the file's directory) reports 0 missing targets
  • ! git grep -qE '(CATALOG-TAXONOMY|CATALOG|CI-RUNNER-ROUTING|CLOUD-FLEET-SETUP|CLOUD-SESSIONS|FINDING-YOUR-UNKNOWNS|GLOSSARY|MIGRATION-PLAYBOOK|NATIVE-SURFACES|OFFICIAL-DOCS|PLUGIN-ARTIFACT-PROTOCOL|PLUGIN-PHILOSOPHY|SKILL-CHEAT-SHEET)\.md' -- ':!plugins/*/CHANGELOG.md' ':!docs/adr' ':!docs/specs' ':!docs/upstream' ':!plugins/education' ':!plugins/domain-driven-design' ':!docs/topics' holds
  • ! git grep -qE '\b(PLUGIN-PHILOSOPHY|MIGRATION-PLAYBOOK|OFFICIAL-DOCS|CATALOG-TAXONOMY|SKILL-CHEAT-SHEET|CLOUD-SESSIONS|CLOUD-FLEET-SETUP|FINDING-YOUR-UNKNOWNS|NATIVE-SURFACES|CI-RUNNER-ROUTING|PLUGIN-ARTIFACT-PROTOCOL)\b' -- ':!plugins/*/CHANGELOG.md' ':!docs/adr' ':!docs/specs' ':!docs/upstream' ':!docs/topics' holds
  • ! git grep -qE '(main|blob/main)/docs/[A-Z][A-Z-]*\.md' holds
  • scripts/check-changelog-parity.sh --check-bump origin/main && scripts/check-changelog-parity.sh --check && scripts/check-changelog-parity.sh --check-order exit 0
  • scripts/check-changed-skills.sh origin/main exits 0
  • scripts/check-purged-em-dashes.sh exits 0

Phase 2 evidence notes: the link resolver reports 0 targets newly missing against origin/main
(the 31 pre-existing misses are example paths and placeholders in specs, changelogs, and skill
context files, identical on both trees); the URL check's one hit is a README.md fixture inside
scripts/check-skill-portability.test.sh, which is in the exempt set. docs/architecture/landscape.json
was regenerated through reference-edges.sh (edge counts unchanged; six files samples re-sorted)
and render-landscape.sh produced byte-identical landscape.md and portfolio.md.

Phase 3: Checker, rule file, CI wiring [DONE]

Checker (CREATE):

  • scripts/check-docs-naming.sh: --check mode; walks git ls-files docs/; passes a
    basename when it matches ^[a-z0-9]+([.-][a-z0-9]+)*\.[a-z0-9.]+$, or is README.md /
    CHANGELOG.md / INDEX.md, or the path is under docs/topics/, or the extension is a
    code extension (py sh mjs js ps1); additionally fails when any two tracked paths under
    docs/ differ only by case; prints one path: reason line per offender; exit 1 on any
    offender; header comment states the rule and its reason
  • scripts/check-docs-naming.test.sh: black-box, mktemp fixture tree with a throwaway git
    repo built through scripts/test-git-helpers.sh (or unset GIT_DIR GIT_WORK_TREE GIT_CONFIG)
    so scripts/check-fixture-git-isolation.sh --check passes; no ok "skip" line; asserts
    pass on a clean tree, fail on docs/NEW-FILE.md, pass on docs/x/README.md, pass on
    docs/topics/t/PLAN.md, pass on docs/a/b_c.py, pass on docs/a/v1.2.schema.json, fail
    on docs/Foo.md beside docs/foo.md

Rule file and index (CREATE / MODIFY):

  • .claude/rules/docs-naming.md: paths: ["docs/**"]; states the rule, the exemptions, that
    scripts/check-docs-naming.sh --check is the gate (path rules load on read, not on file
    creation), and links the ADR from Phase 4; no em dash
  • AGENTS.md: one new row in the "Conventions that load on demand" table

CI and validation wiring (MODIFY):

  • .github/workflows/ci.yml lint job: "Run docs-naming tests" (bash scripts/check-docs-naming.test.sh,
    gated on run_shell) then "Check docs/ filenames are lower-kebab" with id: docs_naming
    and continue-on-error: true, beside the skill-leaf-names pair; a
    docs-naming=${{ steps.docs_naming.outcome }} line in the outcome block that
    scripts/aggregate-hygiene-results.sh consumes
  • scripts/affected-tests.sh --explain scripts/check-docs-naming.sh .claude/rules/docs-naming.md .github/workflows/ci.yml returns no UNMAPPED

Sanity Check:

  • scripts/check-docs-naming.sh --check exits 0 on the working tree
  • bash scripts/check-docs-naming.test.sh exits 0 and prints one ok line per case above
  • shellcheck scripts/check-docs-naming.sh scripts/check-docs-naming.test.sh && shfmt -d scripts/check-docs-naming.sh scripts/check-docs-naming.test.sh exit 0
  • scripts/check-fixture-git-isolation.sh --check && scripts/check-silent-skips.sh exit 0
  • actionlint .github/workflows/ci.yml exits 0
  • grep -c 'docs-naming' AGENTS.md returns 1 and grep -c '^paths:' .claude/rules/docs-naming.md returns 1
  • ! grep -rqP '\xE2\x80\x94' .claude/rules/docs-naming.md scripts/check-docs-naming.sh scripts/check-docs-naming.test.sh holds (no em dash in any new file)

Phase 4: ADR at the next free number [DONE]

  • Compute the number as highest existing plus one at write time (0033 as of this revision;
    ·r·echeck after the Phase 5 base sync) and write
    docs/adr/<NNNN>-name-docs-files-lower-kebab-case-with-conventional-exceptions.md through
    /architecture:record-decision in the observed shape: the rule and its exemptions; hard
    cutover with no tombstones and why (case collision on case-insensitive checkouts); the
    three-way historical-record boundary; the duplicates-stay stance for ADR numbers; the checker
    and rule file as the enforcement pair; Consequences name the 404 window for stale installed
    plugin copies and the stale-path-verify hook's advisory notices on future edits citing a
    retired path
  • .claude/rules/docs-naming.md links the ADR

Sanity Check:

  • ls docs/adr/ | grep -oE '^[0-9]{4}' | sort | uniq -d | grep -vE '^(0018|0025|0028)$' returns empty (the new number is unique)
  • grep -c '^- Status: accepted' docs/adr/<NNNN>-*.md returns 1
  • scripts/check-docs-naming.sh --check still exits 0

Phase 5: Sync, validate, publish, close out [DONE]

  • Phase-entry: git fetch origin main && git merge --no-edit origin/main; re-run the
    Phase 2 sed maps and every Phase 1 to 4 sanity check on the merged tree; re-check the ADR
    number against origin/main; scripts/check-stale-base-overlap.sh --check origin/main exits 0
  • scripts/affected-tests.sh --run exits 0 with every changed file mapped
  • markdownlint-cli2 over changed markdown, typos, editorconfig-checker, shellcheck, shfmt -d, actionlint all exit 0
  • Commits in Tidy-First order: (A) Phase 1, (B) Phase 2 sweep + bumps, (C) Phase 3, (D) Phase 4; each green on its own sanity block; PLAN.md phase tags advance in the same commits
  • PR body: PLAN.md inside a <details> block, the pre-prune commit SHA, the visualization
    released-entry correction declared, ## Verification filled with the commands and exit codes
  • Phase-entry check for the follow-up issue: gh issue list --state all --search 'ADR number uniqueness in:title'; if a match exists comment on it, else create "Add an ADR-number uniqueness gate (existing duplicates 0018/0025/0028 stay)" citing the new ADR; record the number under ## Related
  • Close-out: git rm -r docs/topics/docs-naming-consistency/ in a final commit; flip the PR to ready

Sanity Check:

  • scripts/check-contract-slice-prune.sh --check-diff origin/main exits 0 on the final head
  • PR body contains all four section headings, a No linked issue line, a <details> block, and a 40-hex pre-prune SHA
  • The follow-up issue number is recorded in the PR body's ## Related

Phase 5 evidence notes: the merge is b5481c31 (claude-ops and miro, bumped on both sides, resolve to main plus one patch); scripts/affected-tests.sh --run on the merged tree passes every selected shell suite except the two process-budget cases in plugins/claude-ops/skills/plugins/scripts/cache-content-check.test.sh, which fail identically on a clean origin/main checkout in this container and belong to a skill this branch never touched; the run also caught that scripts/check-script-contract.test.sh registers every check-*.sh, fixed in ccb23908. The follow-up issue is #4109. The three sanity boxes above are verified in the close-out turn: the PR body is updated before the prune commit, and the prune check runs on the pruned head right after.

Alternatives considered

Alternative Why rejected Switch condition
Tombstones at the old uppercase paths Case-only path pairs cannot coexist on macOS or Windows checkouts (Microsoft Learn); two windows-2025 CI jobs A tombstone mechanism that does not require the old path (none exists for raw URLs)
Keep the two URL-targeted files uppercase, rename 11 Leaves the two most-cited doctrine files as the outliers and defers the identical decision; no measurable trigger for "cached copies aged out" The user prefers a two-step rollout
Rename README/CHANGELOG too 463 references, changelog-parity gate, ~155 absolute URLs; every fetched style guide exempts them A style guide the org adopts mandates lowercase README
Edit plugin bodies without bumps Contradicts 12/12 recent commits; installed copies never receive the corrected citations The marketplace starts refreshing installed copies on content hash
Rewrite all plugin CHANGELOG released entries 55 non-link mentions; each edit needs a declaration A link checker starts flagging backtick paths
Rule file only, no script Rules load on read, never on file creation; the drift happened ungated The harness gains a create-time rule trigger
ls-lint or remark-lint as the gate Adds a dependency for a 60-line bash check the repo's siblings already pattern; research on both is MEDIUM (single-pool) The repo adopts either tool for another reason
Renumber duplicate ADRs here record-decision Gotchas: never renumber The ADR convention changes
Shorten the four over-cap descriptions here They are recorded in the cap baseline and WARN; shortening is a semantic edit to trigger surfaces The baseline file is retired

Test strategy

Test boundaries (the public interfaces the tests drive):

  • scripts/check-docs-naming.sh --check (newly introduced): black-box .test.sh with a mktemp
    fixture repo; Red first (the failing NEW-FILE.md and case-collision cases before the script),
    then Green, then the exemption cases
  • scripts/generate-cheatsheet.mjs --check, scripts/generate-catalog.mjs,
    scripts/validate-plugin-contracts.mjs (existing): their .test.sh suites, fixtures updated
  • overlap.py defaults (existing): test_overlap.py fixture path updated
  • Every touched SKILL.md (existing gate): scripts/check-changed-skills.sh origin/main
  • Reference integrity (no existing boundary): a scratch offline link resolver before and after the
    sweep; the weekly link-check.yml lane is the durable backstop
  • No regression test for the rename itself beyond the generators: a rename has no behavior; the
    sanity greps are the assertions

Risks and mitigations

Risk Likelihood Impact Mitigation
A bare-stem mention in a skill body is missed or over-rewritten Med Low the bare-stem map is Tier 1 only; the deliberate pass; the anchored sanity greps
An external repo links to one of the 13 by absolute URL Low Low (one 404) captured assumption; a follow-up repoints it
A user on a stale installed plugin copy fetches a 404 Med Low the declared posture; the bumps deliver the fix on update; ADR Consequences say so
A concurrent plugin bump on main collides with one of the 54 Med Low --check-bump VERSION COLLISION fails loudly; Phase 5 re-sync and rebump
The sweep touches a file main also changed (stale-base gate) High Low Phase 5 phase-entry merge and re-run
The checker false-positives on a legal future name Low Med (advisory red) regex allows dots inside the stem; v1.2.schema.json test case; continue-on-error
The contract-slice prune drops the plan a reviewer wanted Med Low PLAN.md in the PR body plus the pre-prune SHA

Execution shape

Fully sequential: Phase 1 -> 2 -> 3 -> 4 -> 5. Phase 2 needs Phase 1's paths; Phase 3's checker
runs over the renamed tree; Phase 4's ADR is linked from Phase 3; Phase 5 re-syncs and validates
the whole. The sweep and the bumps are scripts, not volume hand-editing.

Phase Surface Basis
1 main-session thirteen git mv plus path constants; one commit
2 main-session two scripted sed maps, a scripted bump loop, and a judgment pass over bare-stem hits
3 main-session new script authored test-first; CI wiring
4 main-session ADR prose; house style
5 main-session sync, validation, commits, PR body, issue, prune

Open questions

  • Q12 (reopened Q8): hard cutover with bumps (recommended) or keep the two URL-targeted files
    uppercase. The plan is written for the recommendation.

Handoff to implementation

User-approval gates

  • Q12 resolution before Phase 1 starts. No other gates; no [FALLBACK] decisions.

Execution shape ([EXEC-SHAPE] tagged)

  • [EXEC-SHAPE] Sequential, all main-session (table above).
  • [EXEC-SHAPE] Bumps and the two sed maps are scripts run once, not hand edits; the scripts live in the session scratchpad, not the repo.
  • [EXEC-SHAPE] No exemptions registry file: with no tombstones the checker's exemptions are the fixed conventional set, hardcoded with their reasons; a registry is added when the first path-specific exemption is needed.
  • [EXEC-SHAPE] The CI step is continue-on-error: true with an aggregated outcome, matching every sibling check-*.sh step in the lint job.
  • [EXEC-SHAPE] The offline link resolver is a scratch script; the durable link lane is the existing weekly link-check.yml.
  • [EXEC-SHAPE] Commit boundaries follow Tidy First: rename, sweep and bumps, gate, ADR.

Mechanical work

  • Each phase's Sanity Check block is the verification checkpoint; a red check stops the phase.
  • If implementation diverges (a consumer the exploration missed, a generator that reads the old path indirectly), stop and re-plan via /planning:plan review.

Blast radius

HIGH by file count (roughly 165 files across 54 plugins and 20 convention READMEs, plus a CI
workflow, a rule file, two generators, and 54 manifest bumps), LOW by reversibility (every change
is a git revert away; no data, schema, or published API), and every consumer that could break is
covered by an existing CI gate. Triggers matched: "new conventions or enforcement mechanisms" and
"infrastructure changes", so the formal stress-test ran.

Stress-test summary

Fresh-context plan reviewer: 1 CRITICAL, 4 IMPORTANT, 4 SUGGESTION. Devil's-advocate: 1 CRITICAL,
1 HIGH, 2 MEDIUM, 4 LOW. All verified against the repository before this revision:

  • CRITICAL (both): tombstones would create case-colliding path pairs; confirmed by the Microsoft
    Learn primary and the two windows-2025 jobs. Fixed: no tombstones; Q12 reopened; the checker
    now refuses case collisions.
  • IMPORTANT: the URL-carrying plugins needed bumps for installed copies to receive the fix; the
    repo's norm is a bump on every body edit (12/12 recent commits). Fixed: scripted bumps for every
    touched plugin.
  • IMPORTANT: sanity greps were unanchored and would match 27 bare stems and 27 false-positive
    raw URLs. Fixed: .md-anchored and main/docs/[A-Z] patterns; bare stems handled by a Tier 1
    map with the check-skill.sh + evals.json lockstep edit.
  • IMPORTANT: the new test must satisfy the fixture-git-isolation and silent-skips gates. Fixed in
    Phase 3.
  • IMPORTANT: stale base and ADR number claimed on main. Fixed: branch merged with origin/main
    (stale-base gate exit 0); ADR number computed at write time; Phase 5 re-sync.
  • HIGH (devil's-advocate): four touched skills fail the description cap. Refuted: all four are in
    scripts/skill-description-cap-baseline.txt, so check-changed-skills.sh downgrades them to
    WARN; a sanity check runs that gate explicitly.
  • SUGGESTIONS adopted: ! git grep -q form; docs/upstream/** (and docs/specs/**) as Tier 2;
    em-dash grep over new files; pre-prune SHA in the PR body; stale-path-verify noted in the ADR.

Verification

On the merged head, all exit 0 unless noted:

  • scripts/affected-tests.sh --run: every changed file mapped; every selected shell suite passes except the two process budget cases in plugins/claude-ops/skills/plugins/scripts/cache-content-check.test.sh, which fail identically on a clean origin/main checkout in this container (the strace probe counts nothing here) and belong to a skill this PR does not touch; the 24 NOT RUN suites are the Python, Node, and PowerShell ecosystems the runner does not execute, left to their CI lanes; the run also caught that scripts/check-script-contract.test.sh registers every check-*.sh, fixed in ccb23908 (findings to stderr, exit 2 without git)
  • scripts/check-docs-naming.sh --check; bash scripts/check-docs-naming.test.sh (PASS=13 FAIL=0, after the two Codex findings: empty dot segments rejected, Bash 3.2-safe case fold)
  • node scripts/generate-catalog.mjs --check, node scripts/generate-cheatsheet.mjs --check, node scripts/validate-plugin-contracts.mjs
  • scripts/check-changelog-parity.sh --check-bump origin/main, --check, --check-order, --check-preserved origin/main
  • scripts/check-changed-skills.sh origin/main (69 skills, 0 failed); scripts/check-stale-base-overlap.sh --check origin/main
  • scripts/check-purged-em-dashes.sh; scripts/check-fixture-git-isolation.sh --check; scripts/check-silent-skips.sh; scripts/check-shell-portability.sh --paths over the new scripts; scripts/check-lane-coverage.sh --check; scripts/check-docs-only-gate.sh --check
  • shellcheck and shfmt -d over every changed .sh (the one shfmt diff, in .claude/cloud-bootstrap.sh, predates this branch and is identical on main); actionlint .github/workflows/ci.yml; markdownlint-cli2 over the 209 changed markdown files (0 issues); typos and editorconfig-checker over the changed files (the one typos hit, ANDed in ci.yml, predates this branch)
  • Residual sweep: ! git grep -qE '<the 13 old basenames>\.md' and the bare-stem form both hold outside the frozen trees; ! git grep -qE '(main|blob/main)/docs/[A-Z][A-Z-]*\.md' holds
  • Offline relative-link resolver over every tracked .md: 0 targets newly missing against origin/main (the 31 pre-existing misses are example paths and placeholders, identical on both trees)
  • scripts/check-contract-slice-prune.sh --check-diff origin/main exit 0 on the final head

Related

  • ADR 0033: docs/adr/0033-name-docs-files-lower-kebab-case-with-conventional-exceptions.md (added by this PR); ADR 0018 (the raw-URL citation interface the rename changes)
  • Follow-up: Add an ADR-number uniqueness gate (existing duplicates 0018/0025/0028 stay) #4109, an ADR-number uniqueness gate (existing duplicates 0018/0025/0028 stay)
  • Precedent: docs/conventions/consumer-config-layering/README.md (the repo's one prior docs rename)
  • A reusable naming-consistency skill is a separate PR

🤖 Generated with Claude Code

https://claude.ai/code/session_01CUVaZs5Qssq3xN2gGEHwer

Contract-slice artifacts for the docs/ filename rename: the interview
Brief (11 questions answered and validated by two fresh-context agents),
the design early-exit, and the draft five-phase plan pending stress-test
review. The slice is pruned before merge per the topic-docs convention.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CUVaZs5Qssq3xN2gGEHwer
Drop the case-variant tombstones (two paths differing only by case cannot
coexist on case-insensitive checkouts), add norm-conformant patch bumps for
every plugin the sweep edits, anchor the sanity greps, widen the historical
tier to docs/specs and docs/upstream, and add the fixture-isolation and
stale-base steps the reviewers surfaced. Q12 reopens the tombstone decision.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CUVaZs5Qssq3xN2gGEHwer
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CUVaZs5Qssq3xN2gGEHwer

Copy link
Copy Markdown
Contributor Author

CI status note (draft stage). The lint job is red on exactly one hygiene line, contract-slice-diff (scripts/check-contract-slice-prune.sh --check-diff); every other hygiene entry is success.

That gate fails because this branch carries the contract slice docs/topics/docs-naming-consistency/ (the locked Brief and the plan), which the topic-docs convention commits on the task branch and prunes in the final commit before merge. The gate's own output says as much: "committed on a task branch only, pruned before merge ... the deletion itself passes this gate."

So this is the designed mid-flight state, not a defect in the change. It turns green at close-out (Phase 5 of the plan), when the final commit removes the slice after the durable outcomes (the ADR and the follow-up issue) have graduated. Nothing to fix or re-run before then.


Generated by Claude Code

claude and others added 7 commits September 11, 2026 16:55
Structural commit: git mv each UPPERCASE-KEBAB file at the docs/ root to its
lower-kebab twin and move the path constants, fixtures, and allowlist proof
that read them at runtime (generate-cheatsheet, generate-catalog,
validate-plugin-contracts, cheatsheet-config, the claude-ops overlap script and
its test, check-docs-only and generate-cheatsheet fixtures, docs-only-paths,
the native-surfaces store note). No content edit to plugin-artifact-protocol.md,
so the six plugin copies stay byte-identical.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CUVaZs5Qssq3xN2gGEHwer
…the citing plugins

Phase 2 of docs/topics/docs-naming-consistency/PLAN.md. The 13 docs/ root files were
renamed in the previous commit; this commit moves every reference to them across the
three-way boundary the plan draws:

- Tier 1 (current surfaces, every form): the scripted basename map and bare-stem map over
  every tracked file outside the frozen trees, including the six absolute GitHub URLs, the
  two .claude/rules files, README.md, the plugin setup SKILL.md files, docs/conventions/**,
  and the lockstep pair plugins/skill-quality/scripts/check-skill.sh + evals.json (the WARN
  text and the eval that quotes it change together).
- Tier 2 (docs/adr, docs/specs, docs/upstream): markdown links and backtick paths only;
  narrative and bare stems left as written.
- Tier 3 (plugin CHANGELOG released entries): untouched, except the one real markdown link
  in plugins/visualization/CHANGELOG.md (0.3.2 entry), corrected under the plugin's new
  release entry, which names the correction.

Every plugin with a non-CHANGELOG edit on the branch (56) gets a patch bump in its
plugin.json and a `## [x.y.z]` / `### Changed` entry naming the repoint. docs/catalog.md
and docs/skill-cheat-sheet.md are regenerated. docs/architecture/landscape.json has its
edges regenerated through reference-edges.sh (counts unchanged; six `files` samples
re-sorted for the new lowercase paths); the rendered landscape.md and portfolio.md are
byte-identical.

Sanity: the three anchored `git grep` residual checks are clean, the offline link resolver
reports no target newly missing against origin/main, check-changelog-parity
--check-bump/--check/--check-order/--check-preserved exit 0, check-changed-skills exits 0,
check-purged-em-dashes exits 0, markdownlint over the 210 changed markdown files reports 0
issues, and validate-plugin-contracts, generate-catalog --check, and generate-cheatsheet
--check all pass.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CUVaZs5Qssq3xN2gGEHwer
Phase 3 of docs/topics/docs-naming-consistency/PLAN.md. The rename (Phase 1) and the
reference sweep (Phase 2) made the tree consistent; this commit keeps it that way.

- scripts/check-docs-naming.sh --check walks `git ls-files docs/` and fails any basename
  outside `^[a-z0-9]+([.-][a-z0-9]+)*\.[a-z0-9.]+$`, with README.md, CHANGELOG.md, INDEX.md,
  everything under docs/topics/, and code files (py sh mjs js ps1) exempt. Independently, it
  fails any two tracked paths under docs/ that differ only by case, because a case-insensitive
  checkout writes the second over the first. The header states the rule and its reason.
- scripts/check-docs-naming.test.sh, written first and observed red, builds a throwaway git
  repository through fixture-tree.sh and proves ten cases: a clean tree passes; NEW-FILE.md,
  snake_case.md, and Foo.md beside foo.md fail and are named; README/CHANGELOG/INDEX,
  docs/topics/, b_c.py, Run-Thing.ps1, and v1.2.schema.json pass; discover mode names the
  offender; an unknown flag exits 2.
- .claude/rules/docs-naming.md (paths: docs/**) states the rule, the exemptions, the
  hard-cutover consequence, and that the script is the gate, since a path-scoped rule loads on
  read and never on file creation. AGENTS.md gains the on-demand row.
- The lint job runs the suite (gated on run_shell) and then the check with id docs_naming and
  continue-on-error, beside the skill-leaf-names pair, and feeds docs-naming into the
  aggregator.

Sanity: suite 10/10, checker exits 0 on the tree, shellcheck and shfmt clean, no em dash,
check-fixture-git-isolation, check-silent-skips, check-shell-portability, actionlint,
check-lane-coverage, check-docs-only-gate, and markdownlint all pass; affected-tests --explain
maps the new script to its co-located suite.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CUVaZs5Qssq3xN2gGEHwer
Phase 4 of docs/topics/docs-naming-consistency/PLAN.md. ADR 0033 records the decision the
previous three commits carried out: every file under docs/ is lower-kebab-case, with
README.md, CHANGELOG.md, INDEX.md, docs/topics/, and code files by extension exempt; the
thirteen uppercase root files were renamed in one hard cutover with no tombstones, because a
case-colliding pair corrupts every case-insensitive checkout; the historical record was
repointed by tier; and scripts/check-docs-naming.sh with .claude/rules/docs-naming.md is the
enforcement pair. The Evidence section names the three style guides, the Azure Repos
case-sensitivity page, the repository's own bump-on-body-change norm, and the git mv behaviour
the plan rested on; the Consequences name the 404 window for stale installed plugin copies and
the stale-path-verify advisory on future edits.

The number is the next free one (0032 was the highest); the existing duplicates 0018, 0025,
and 0028 are left as they are, per the record-decision skill, and a uniqueness gate is a
separate follow-up. The rule file's placeholder line now links the ADR.

Sanity: the duplicate-number grep excluding the three known pairs is empty, the ADR carries
exactly one `- Status: accepted`, scripts/check-docs-naming.sh --check still exits 0, no em
dash, markdownlint clean, and the rule-file link resolves.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CUVaZs5Qssq3xN2gGEHwer
…nsistency-cr6ys6

# Conflicts:
#	plugins/claude-ops/.claude-plugin/plugin.json
#	plugins/claude-ops/CHANGELOG.md
#	plugins/miro/.claude-plugin/plugin.json
#	plugins/miro/CHANGELOG.md
…ailing example

The header cited a retired uppercase path as its example of a name the rule rejects,
which is exactly the string the branch's residual sweep greps for and the stale-path
hook flags on future edits. A made-up name shows the same shape without naming a path
that no longer exists.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CUVaZs5Qssq3xN2gGEHwer
scripts/check-script-contract.test.sh registers every scripts/check-*.sh and failed the
new checker as UNREGISTERED. Registering it exposed two contract gaps in the script
itself: findings went to stdout rather than stderr, and a missing git was swallowed by
the process substitution, so the checker would have printed the clean-run statement and
exited 0 without inspecting anything.

- The checker now exits 2 with a stderr diagnostic when git is absent or the cwd is not
  a repository, prints each offender on stderr, and keeps the clean-run statement on
  stdout, per README.md "The check-script contract".
- The contract suite carries the row (`git` prerequisite, `docs_naming` recipe) and the
  recipe seeds a one-file git fixture clean and with a mixed-case name; its violation
  needle is the finding text. The suite now covers 8 recipes and 32 cases.

Sanity: check-script-contract.test.sh 32/32, check-docs-naming.test.sh 10/10, the
checker exits 2 with git hidden from PATH, shellcheck and shfmt clean on both files.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CUVaZs5Qssq3xN2gGEHwer
Phase 5 of docs/topics/docs-naming-consistency/PLAN.md, ticked before the slice is
pruned so this commit is the pre-prune head the PR body cites.

origin/main (3b273a2, five commits) is merged; the two plugins bumped on both sides
resolve to main's version plus one patch. On the merged tree every Phase 1 to 4 sanity
block holds, scripts/affected-tests.sh --run passes every selected shell suite except the
two process-budget cases in claude-ops' cache-content-check suite (identical on a clean
origin/main checkout in this container, in a skill this branch does not touch), and the
linters, the stale-base gate, the four changelog-parity modes, and the changed-skills gate
all exit 0. Follow-up issue #4109 is filed for the ADR-number uniqueness gate.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CUVaZs5Qssq3xN2gGEHwer
The plan and its design-resolution record served their purpose on the branch; the PR body
carries PLAN.md verbatim inside a details block and names the pre-prune head (ad5c116), so
the slice leaves the tree before merge per the topic-docs convention.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CUVaZs5Qssq3xN2gGEHwer
@kyle-sexton
kyle-sexton marked this pull request as ready for review September 11, 2026 18:02
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 11, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-11T18:11:33.470667Z ae07c1c Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

…nsistency-cr6ys6

# Conflicts:
#	plugins/claude-ops/.claude-plugin/plugin.json
#	plugins/claude-ops/CHANGELOG.md
#	plugins/skill-quality/.claude-plugin/plugin.json
#	plugins/skill-quality/CHANGELOG.md
#	plugins/source-control/CHANGELOG.md
…nsistency-cr6ys6

# Conflicts:
#	plugins/bugs/CHANGELOG.md
#	plugins/claude-config/CHANGELOG.md
#	plugins/claude-ops/CHANGELOG.md
#	plugins/discipline/CHANGELOG.md
#	plugins/discovery/CHANGELOG.md
#	plugins/docs-hygiene/CHANGELOG.md
#	plugins/education/CHANGELOG.md
#	plugins/firecrawl/CHANGELOG.md
#	plugins/improvement/CHANGELOG.md
#	plugins/instruction-placement/CHANGELOG.md
#	plugins/kindle-dedrm/.claude-plugin/plugin.json
#	plugins/kindle-dedrm/CHANGELOG.md
#	plugins/mutation-testing/CHANGELOG.md
#	plugins/overengineering/CHANGELOG.md
#	plugins/playbooks/CHANGELOG.md
#	plugins/plugin-quality/CHANGELOG.md
#	plugins/session-flow/.claude-plugin/plugin.json
#	plugins/session-flow/CHANGELOG.md
#	plugins/songwriting/CHANGELOG.md
#	plugins/source-control/CHANGELOG.md

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ae07c1ceeb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/check-docs-naming.sh Outdated
Comment thread scripts/check-docs-naming.sh Outdated
…in check-docs-naming

Two review findings on the checker, both real:

- The extension part of the name rule was `\.[a-z0-9.]+$`, which accepted `foo..md`,
  `foo.md.`, and `foo...`. It is now `\.[a-z0-9]+$`; dotted stems such as
  `v1.2.schema.json` still pass through the stem group, and three negative cases join
  the suite (13 cases).
- The case-collision pass folded paths with `${path,,}`, a Bash 4 expansion that aborts
  with `bad substitution` on stock macOS Bash 3.2, the very checkouts the collision rule
  protects. The fold now goes through `tr '[:upper:]' '[:lower:]'`.

ADR 0033 states the tightened regex. The header comment names the new counter-examples.

Sanity: check-docs-naming.test.sh 13/13, check-script-contract.test.sh 32/32, the checker
exits 0 on the tree, shellcheck, shfmt, check-shell-portability, markdownlint clean, no em
dash.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CUVaZs5Qssq3xN2gGEHwer
…eckout

The discover-mode case in check-docs-naming.test.sh called mk_repo without checking its
result, so when the build failed the empty $repo turned `git -C "$repo"` into a command
against this checkout: that is how commit f9fce8c (subject "case", author "test") entered
the branch history with the then-untracked suite file. The case now runs its git commands
only when the build succeeded and the path is non-empty, and reports a build failure as a
failed case otherwise.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CUVaZs5Qssq3xN2gGEHwer
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants