Skip to content

Commit d57333b

Browse files
claude[bot]claude
andauthored
tooling(required-contexts): scan the PM readings ledger for the six required names (#15727)
The seat's readings ledger restates the six required check-run names as the operative per-repo set it reads before a PR may be enqueued, and no gate saw that copy: renaming a job reddens the pin on AGENTS.md and on the review checklist, so the rename PR is forced to fix those two, while the ledger keeps the dead name — in the one place consulted at the moment of the decision. The RETIRED_CONTEXT_NAMES standing ban did not reach it either. Enrol it as an INSTRUCTION_SURFACES entry with mustName for all six, the same treatment review-checklist.md already gets; both halves arrive through that one entry. Measured on a throwaway copy of the ledger: renaming one of the six reds the gate on the ledger's entry with exactly one problem, and the pre-change gate is green on the identical mutation while scanning five surfaces instead of six. The scan set's derivation was re-run with the same query: the ledger is the only *.md in that population naming a registered context that was not enrolled, and references/true-green.md names none, so it stays out. Claude-Session: https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox Co-authored-by: Claude <noreply@anthropic.com>
1 parent ae7b7f1 commit d57333b

1 file changed

Lines changed: 59 additions & 3 deletions

File tree

scripts/check-required-contexts.mjs

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ const SELF_TEST_BATTERIES = Object.freeze({
221221
'(10) a `carries` string that embeds a step count': 3,
222222
'missing input is a failure, never a pass (#4690)': 6,
223223
'the `on:` key under both YAML schemas': 3,
224-
'instruction surfaces (#9491): the stale-name scan': 28,
224+
'instruction surfaces (#9491): the stale-name scan': 31,
225225
'the dispatch-gates declaration (#9979)': 6,
226226
'the wiring: this gate must actually run on every PR': 28,
227227
'the live mode stays OFF the required path': 3,
@@ -500,6 +500,12 @@ export const REQUIRED_CONTEXTS = [
500500
* them would demand exactly that), and this script + `.github/workflows/**`
501501
* (the ledger and the pinned half themselves — old names live here as
502502
* history by design).
503+
*
504+
* Re-derived 2026-09-05 with the same query: the pm-dispatch readings ledger
505+
* names all six and nothing pinned it, so it joins the set; every other `*.md`
506+
* in that population was already enrolled, and `references/true-green.md`
507+
* names no registered context at all, so it stays out — a surface enters this
508+
* set by naming one, never by sitting next to one that does.
503509
*/
504510
export const INSTRUCTION_SURFACES = [
505511
{
@@ -526,6 +532,19 @@ export const INSTRUCTION_SURFACES = [
526532
file: '.claude/skills/pm-dispatch/references/review-checklist.md',
527533
mustName: ['Lint & Repo Gates', 'TypeScript Type Check'],
528534
},
535+
{
536+
// The seat's readings ledger states the required set it reads before a PR
537+
// may be enqueued, so it states the required set ⇒ mustName, all six.
538+
file: '.claude/skills/pm-dispatch/references/platform-readings.md',
539+
mustName: [
540+
'Lint & Repo Gates',
541+
'TypeScript Type Check',
542+
'Test Core',
543+
'Dogfood Regression Gate',
544+
'Build Core',
545+
'Temporal Conformance (live PG + MySQL)',
546+
],
547+
},
529548
{
530549
// Names the typecheck context as the job two generated-artifact gates run
531550
// in — operative, but does not state the required set ⇒ scan-only.
@@ -542,8 +561,8 @@ export const INSTRUCTION_SURFACES = [
542561
* (#9979, applying #9964's pattern).
543562
*
544563
* That tool derives a card's gate list from the path literals in each gate's
545-
* own source, and "looks like a path" there means "carries a separator". Four
546-
* of the five surfaces have one; `AGENTS.md` does not, because a repo-root FILE
564+
* own source, and "looks like a path" there means "carries a separator". Five
565+
* of the six surfaces have one; `AGENTS.md` does not, because a repo-root FILE
547566
* has no separator to be found by — so an AGENTS.md card derived this gate not
548567
* at all, while that surface is the one carrying `mustName` for all six
549568
* required contexts (widened 2→6 by the #9677 ruling). Editing the merge-queue
@@ -2216,6 +2235,43 @@ async function selfTest() {
22162235
'an empty scan set ⇒ red, never a silent tick (#4690)',
22172236
);
22182237

2238+
// The readings ledger, the copy a seat consults at the moment it decides
2239+
// whether a PR may be enqueued: enrolled, and carrying every required
2240+
// context rather than a subset.
2241+
const LEDGER_SURFACE = '.claude/skills/pm-dispatch/references/platform-readings.md';
2242+
const ledgerEntry = INSTRUCTION_SURFACES.find((s) => s.file === LEDGER_SURFACE);
2243+
assert(
2244+
ledgerEntry !== undefined &&
2245+
ledgerEntry.mustName.length === REQUIRED_CONTEXTS.length &&
2246+
REQUIRED_CONTEXTS.every((e) => ledgerEntry.mustName.includes(e.context)),
2247+
`the readings ledger is a scanned surface naming all ${REQUIRED_CONTEXTS.length} required contexts — got ${JSON.stringify(ledgerEntry)}`,
2248+
);
2249+
// A rename reaches it. Read from the file as it ships, with ONE of the six
2250+
// replaced by a name that never existed: the baseline above is green, so
2251+
// the literal is present and this substitution cannot be a no-op.
2252+
const ledgerRenamed = judgeSurfaces({
2253+
files: surfaceMap({
2254+
[LEDGER_SURFACE]: surfaceSources[LEDGER_SURFACE].replaceAll('Dogfood Regression Gate', 'Nonexistent Job Name'),
2255+
}),
2256+
});
2257+
assert(
2258+
ledgerRenamed.problems.some(
2259+
(p) => p.includes(LEDGER_SURFACE) && p.includes("'Dogfood Regression Gate'") && p.includes('no longer names'),
2260+
),
2261+
'renaming a required context in the readings ledger ⇒ red on the ledger, naming the dropped literal',
2262+
);
2263+
// …and the standing ban arrives with the same entry: a retired name written
2264+
// fresh into the ledger is red on its budget of zero, as on the checklist.
2265+
const ledgerStale = judgeSurfaces({
2266+
files: surfaceMap({ [LEDGER_SURFACE]: surfaceSources[LEDGER_SURFACE] + '\n- 入队前亲核 ESLint job 是否已绿\n' }),
2267+
});
2268+
assert(
2269+
ledgerStale.problems.some(
2270+
(p) => p.includes(LEDGER_SURFACE) && p.includes("retired required context 'ESLint'") && p.includes('budgeted: 0'),
2271+
),
2272+
'a retired name written fresh into the readings ledger ⇒ red (the standing ban reaches it through the same entry)',
2273+
);
2274+
22192275
// ── the dispatch-gates declaration (#9979) ───────────────────────────────
22202276
//
22212277
// Enforcement cannot hold any of these: the declaration is read by another

0 commit comments

Comments
 (0)