Uh oh!
There was an error while loading. Please reload this page.
ci(lint): scan instruction surfaces for stale required-context names, budgeted for in-flight renames - #9504
Merged
Conversation
…9491) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XqDQYVU5smx29ts9pAErja
os-steve
marked this pull request as ready for review
August 18, 2026 06:23
Uh oh!
There was an error while loading. Please reload this page.
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
This was referenced Aug 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes#9491
What this adds
scripts/check-required-contexts.mjsalready pins the workflowname:literals that branch protection matches check-runs by. This PR extends the same file to the instruction surfaces — the files that state the required set as operative prose and tell a review seat which check-runs to confirm before flipping a PR ready / arming auto-merge / enqueuing. The card's measurement: replacing the job name in the review checklist withNonexistent Job Nameleft the file's whole derived gate union green.Two mechanisms, both registry-driven, both pure-function judged so the self-test exercises the real decision:
RETIRED_CONTEXT_NAMES). A rename PR must add a row recording the old literal, what replaced it, and the occurrence counts of the sites stale at that moment. Above budget is red (a dead name written fresh); at or below budget is green with a printed notice. Budgets only ratchet down. A row whose budgets are trimmed away becomes a standing ban on the dead name.mustNameinINSTRUCTION_SURFACES). The two surfaces that state the required set —AGENTS.mdand the pm-dispatch review checklist — must contain each blocking context literal: the current name, or a ledgered former name while its rename is in flight (renameInFlight: true).The scan set was derived, not assumed: every
*.mdunderAGENTS.md,CLAUDE.md,.claude/anddocs/naming any registered context, case-sensitive, with a positive control run on the zero hits. That adds three scan-only surfaces beyond the card's two:.claude/skills/spec-property-retirement/SKILL.md,docs/launch-readiness.md,docs/releases-maintenance.md. Deliberately excluded:docs/adr/**and package CHANGELOGs (point-in-time records a rename must not retro-edit — scanning them would demand exactly that), plus this script and the workflows themselves (the ledger and the pinned half; old names live there as history by design).The actual design problem: satisfiable at every intermediate state
A rename cannot land atomically: the Settings entry is maintainer-only, and the instruction files are split across seat tiers (
.claude/skills/pm-dispatch/**is a maintainer-merge surface a dev seat may not edit — the reason the checklist half of the #9325 rename is its own card, #9420). Today'smainis that intermediate state: the registry saysLint & Repo Gates, the checklist still saysESLint, and the fix (PR #9490) is open. The card's literal direction 2 goes red at rest on today'smainand blocks every PR in the repo, including the fix itself.What I chose, and why:
ESLintas a historical mention ("改名前的 PR 仍列旧名"). A ban would go red the moment the fix merges. The budget for the checklist is 1 across both states on purpose.renameInFlightgrace on the naming requirement. During the window, the old literal satisfiesmustName. Flipping it off later is self-ordering: the flip PR is red while any required-set surface still leans on the grace, so it cannot merge before the instruction fixes do — it never races them.staleSitesis red per site with the real count. Both directions are pinned in the self-test.scripts/. (b) The grace means a ledgered former name satisfiesmustNameuntil the flip — bounded by the budget half, and closed by the follow-up filed below. (c) A time-based grace was rejected outright: it turns red at rest on a date with no causing PR.Direction 2 vs direction 1, tested rather than inherited
Recognition of a "required-context-shaped literal" in bilingual prose is not reliably buildable without markers in the instruction files — which are exactly the files split across seat tiers. So recognition here is lexicon-only (registry + ledger), which is blind to a never-existed name written fresh. That case is covered from the other side:
mustNameis direction 1 reduced to identifier presence — rewording-tolerant (any sentence shape passes as long as the literal appears; the name is a contract identifier, not prose) — and it reds when garbage replaces a real name, because the file then no longer contains the required literal under any recognised spelling. The self-test ablates the guard and shows the vacuous file passes without it: the guard is load-bearing, not decorative. Residuals recorded, not implied covered: paraphrase drift (e.g. "Lint & Type Check" indocs/launch-readiness.md) is invisible to both halves; after a shortening rename (new name a substring of the old), an old-literal mention would satisfy the new name's presence check by substring — the budget half still bounds staleness there.Compatibility with the in-flight fix PR, in both merge orders
ESLint— green, with the flip-to-false notice. The self-test pins that exact post-fix line shape green.Verification
Self-test grew 55 → 85 assertions; both directions pinned for every new behaviour (stale-beyond-budget red / rewording-with-current-names green; vacuous red / guard-ablated green; window green / flip-early red; ledgered rename green / un-ledgered red; hygiene reds for malformed ledger shapes; #4690 never-read reds; wiring assertions that
main()actually runs the surface scan).Reverse verification by ablation at the shipped level, from a committed state, direction predicted before each leg (this gate runs from source —
scripts/*.mjs, no dist build involved, so no dist preflight applies; the pre-change control was copied fromorigin/mainintoscripts/so its own root resolution held):ESLintmention to the checklist (count 2, budget 1)ESLintreplaced withNonexistent Job Nameorigin/mainMutations restored via
git checkoutagainst the committed branch;git status --porcelainandgit diff HEADboth empty afterwards; self-test re-run green.Derived gate union (
node scripts/pm/dispatch-gates.mjs scripts/check-required-contexts.mjs→pnpm check:required-contexts, plus the any-editcheck:nul-bytes), run after the final commit at HEAD661d90c85: both green — 85 assertions, 9 contexts pinned, 5 surfaces scanned, 1 in-budget notice for the live intermediate state.Tests/tooling only (
scripts/— not a published package): no changeset;skip-changesetlabel applied per this repo's mechanism.Out of scope, follow-up filed
Post-transition ledger housekeeping (flip
renameInFlightoff once the checklist half lands; re-check the budget) is filed as its own card, blocked by #9420. #9420 and #9490 are not addressed here and remain open; #9421 and #9325 landed the workflow + registry half and are untouched.Generated by Claude Code
Generated by Claude Code