Skip to content

feat(governance): govern the published skills/ catalog under the ADR maintainer approval gate - #9511

Merged
os-steve merged 1 commit into
mainfrom
claude/issue-9404-govern-published-skills
Aug 18, 2026
Merged

feat(governance): govern the published skills/ catalog under the ADR maintainer approval gate#9511
os-steve merged 1 commit into
mainfrom
claude/issue-9404-govern-published-skills

Conversation

@os-steve

Copy link
Copy Markdown
Collaborator

Fixes#9404

What

The published skills/** catalog joins the ADR maintainer approval gate as its third governed surface, alongside docs/adr/** and .claude/skills/** — implementing the maintainer's 2026-08-18 ruling on #9404 (option A, verbatim 「同意」). All three of the pm-dispatch ACCEPT fork's human-merge prefixes are now machine-enforced by the same required check.

One file changed: scripts/check-adr-merge-approval.mjs (its self-test lives inside it, behind --self-test).

How

  • GOVERNED_SURFACES takes a third row (id: 'published-skill', prefix skills/) with its own rule wording: it cites the finding: the published skills/ catalog is human-merge by convention but is not gated — two of the pm-dispatch fork's three prefixes are enforced #9404 ruling, the outward-propagation rationale, and the accepted cost (~148 commits/month ≈ 5 extra human merges/day) — never another surface's rule.
  • New exported PUBLISHED_SKILL_PATH_PREFIX and publishedSkillFilesIn() helper, matching the existing per-surface pattern.
  • Header prose updated everywhere it stated the exclusion out loud: the surface list, the GUARANTEED table, the decision rule, the "Only ... are governed" sentence — and the "Deliberately NOT widened" paragraph now points at a new "The published catalog surface (skills/**), added 2026-08-18" section instead of stating a gap that no longer exists.

Self-test (96 → 108 assertions)

  • The card-named assertion the-published-skills-catalog-is-NOT-governed is kept as a case, inverted: the-published-skills-catalog-IS-governed pins the same fixture on the opposite verdict, and pins that ONLY the published surface claims it (no double-catch by the internal prefix).
  • New prefix-anchoring pins: .claude/skills/** does not double-match; packages/spec/skills/x.md, skillsets/overview.md, skills.md do not match — the trailing slash is load-bearing, as for the other two prefixes.
  • The third path class replays the same behaviours as the other two: unreviewed → red; approved + disarmed → green; the [governance] The ADR gate blocks the merge but not the ARMING of auto-merge — an AI seat armed it on a live docs/adr/** PR today, which would have made the maintainer's approval the merge trigger #8012 emptiness proof (identical reviews, only the arming bit differs, opposite verdicts); mixed diff gate-scoped in full.
  • Distinct-wording assertions extended three-way: each surface's red cites its own rule and none of the others'; the mixed red carries every rule its diff touches. ((skills/**) is asserted in its parenthesised spelling because .claude/skills/** contains skills/** as a substring.)
  • The zero-lookup clean path still short-circuits: the clean fixture (which held skills/objectstack-ui/SKILL.md until this change made it governed) is proven on near-neighbours alone, with both lazy thunks still throwing on invocation.

Verification at a679947

  • node scripts/check-adr-merge-approval.mjs --self-test → 108 assertions, green (origin/main baseline: 96).
  • Gate mode on this branch's own diff → clean pass: "No files under docs/adr/** / .claude/skills/** / skills/** ... zero API lookups on the clean path".
  • Reverse-verified by ablation from the committed state: deleting the third GOVERNED_SURFACES row turned 18 of 108 assertions red (the inversion anchor, table order, the whole published path class, and the wording pins), including the emptiness proof reporting armed=true, disarmed=true — the exact pre-finding: the published skills/ catalog is human-merge by convention but is not gated — two of the pm-dispatch fork's three prefixes are enforced #9404 state. Restored and confirmed byte-identical (git hash-object matches the committed blob).
  • check:nul-bytes OK (6136 files scanned); eslint exit 0 on the changed file.

Blast radius, measured

  • The new prefix matches exactly the 50 tracked files under skills/ — zero near-misses in the tree, and no other skills/ directory exists anywhere (nested or root-adjacent).
  • Re-measured at branch point (14 open PRs enumerated): 0 open PRs touch skills/**, 0 hold the gate script — landing this flips no in-flight PR into maintainer-merge.
  • No workflow change needed: adr-merge-approval.yml deliberately carries no path filter, so the widened predicate is live the moment this lands.

Not in this PR


Generated by Claude Code

…ner approval gate (#9404)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XqDQYVU5smx29ts9pAErja
@os-steveos-steve added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 18, 2026 — with Claude
@os-steve
os-steve marked this pull request as ready for review August 18, 2026 06:23
@os-steve
os-steve requested a review from hotlong as a code ownerAugust 18, 2026 06:23
@os-steve
os-steve added this pull request to the merge queueAug 18, 2026
Merged via the queue into main with commit d2258f6Aug 18, 2026
24 checks passed
@os-steve
os-steve deleted the claude/issue-9404-govern-published-skills branch August 18, 2026 06:45
os-zhuang pushed a commit that referenced this pull request Aug 18, 2026
 instruction scan gains the retirement ledger row
The modify/delete conflict on scripts/check-adr-merge-approval.mjs
resolves as deletion: #9511 widened the per-PR gate's predicate to the
published skills/ catalog under the pre-retirement regime, and that
semantic content survives in the audit's GOVERNED_SURFACES (skills/**
was already governed there by the 2026-08-18 unified definition). The
#9504 instruction-surface scan lands intact; per its append-only ledger
contract this merge adds the 'ADR maintainer approval' retirement row
(replacedBy: null) in the same PR that removes the registry entry.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rn7aaamsR99FXRqLcpL99q
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/mskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

finding: the published skills/ catalog is human-merge by convention but is not gated — two of the pm-dispatch fork's three prefixes are enforced

2 participants

@os-steve@claude