You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
finding: dispatch-gates never names check:slot-lookup — the #8632 convention entry stops one gate short, and a source-file card can only learn about the ratchet from CI #9700
Found while implementing #9391, and it cost that p0 a CI round-trip: the guard added five service lookups typed getService with an any type argument, pnpm check:slot-lookup failed in Lint & Repo Gates, and the gate had appeared nowhere in the union the dispatching seat derived for the card.
What was measured
node scripts/pm/dispatch-gates.mjs --residue <changed paths> classifies the gate like this:
Those are the only two paths its source names, so for any card that edits source rather than the baseline JSON, the derivation scores it silent — the residue summary's own weakest verdict, and explicitly not a clearance:
A silent verdict is this derivation's weakest claim, not a clearance: a gate that computes its own population and names only its baseline artifact scores silent for every card in the tree.
That sentence describes this gate exactly. check-slot-lookup-ratchet.mjs lints packages/**/*.{ts,tsx,mts,cts} itself, so its real population is "most of the repo" and no path literal in its source will ever say so.
Why this is a gap and not just the deriver being honest
The deriver already has the channel for this class — CHANGE_KIND_GATES in scripts/pm/dispatch-gates.mjs — and two of check:slot-lookup's structural siblings are wired into it. Compare their residue lines:
#8632 is the precedent and its title states the principle: a gate being a PM judgement call rather than a convention entry is the defect, when a mechanical trigger for it exists. One exists here too. The three gates differ only in which files they walk — and check:slot-lookup's are source files, which is why the test-file convention that catches the other two does not catch it.
The consequence is the one the ratchet was built to prevent, displaced one level up. Its own header says ESLint ignores cannot express a ratchet because "an ignored file is ignored completely, so NEW erasures added to a listed file ride the existing entry in total silence". The ratchet closes that for the code. But if the gate is never named in a dispatch, the author does not run it, pnpm lint passes (the file is grandfathered, so ESLint says nothing), and the first signal is a red CI job — which for a priority:p0 security fix is the expensive place to find out.
What a fix would look like (a lead, not a decision)
Add a CHANGE_KIND_GATES entry for check:slot-lookup. The trigger has two candidate spellings and the narrower one looks clearly better:
broad — "edits a .ts/.tsx/.mts/.cts file under packages/". Mechanical and complete, but fires on very nearly every card, which is the cost the residue's silent/undetermined split exists to keep down.
narrow, recommended — "edits a file under packages/ that contains a service lookup". The rule's own trigger vocabulary is a three-name list in eslint.config.mjs (SLOT_LOOKUPS: resolveService, getService, getRequestKernelService), so a matches predicate can grep the changed files for those names — cheap, no type information, and it reads the same list the rule does rather than a copy. It would have fired on The datasource-admin HTTP family is reachable unauthenticated, read and write — mounts outside the enforceAuth seam #9391's diff and stays quiet for cards that touch no lookup.
Either way the entry needs the why text every other entry carries, and it should say the two things that made this one expensive: pnpm lint passing proves nothing for a grandfathered file, and the repair is to type the lookup, never to --update the baseline upward.
Note for whoever picks this up: the deriver's --self-test pins the convention section by name (it asserts the section "names all five convention gates"), so an added entry needs that assertion updated in the same edit.
Scope note
Filed rather than fixed: #9391 is a priority:p0 security card whose scope is ruled to the authentication guard, and this is PM tooling in scripts/pm/. The immediate ratchet failure was repaired in that PR by typing the five new lookups against their slots' contracts (IAuthService, IDataEngine); the file's two pre-existing grandfathered sites were left at their recorded count.
Backlinks: #8632 (the same defect for check:engine-double-contract, closed — the precedent), #9391 (the card that paid for this), #9320 and #8551 (other derivation gaps in the same script). Unassigned and unqueued, for the triage seat to level and route.
Found while implementing #9391, and it cost that p0 a CI round-trip: the guard added five service lookups typed
getServicewith ananytype argument,pnpm check:slot-lookupfailed inLint & Repo Gates, and the gate had appeared nowhere in the union the dispatching seat derived for the card.What was measured
node scripts/pm/dispatch-gates.mjs --residue <changed paths>classifies the gate like this:Those are the only two paths its source names, so for any card that edits source rather than the baseline JSON, the derivation scores it
silent— the residue summary's own weakest verdict, and explicitly not a clearance:That sentence describes this gate exactly.
check-slot-lookup-ratchet.mjslintspackages/**/*.{ts,tsx,mts,cts}itself, so its real population is "most of the repo" and no path literal in its source will ever say so.Why this is a gap and not just the deriver being honest
The deriver already has the channel for this class —
CHANGE_KIND_GATESinscripts/pm/dispatch-gates.mjs— and two ofcheck:slot-lookup's structural siblings are wired into it. Compare their residue lines:CHANGE_KIND_GATES?check:where-matchernames: ...baseline.json, origin/mainadds or edits a test filecheck:engine-double-contractcheck:slot-lookup#8632 is the precedent and its title states the principle: a gate being a PM judgement call rather than a convention entry is the defect, when a mechanical trigger for it exists. One exists here too. The three gates differ only in which files they walk — and
check:slot-lookup's are source files, which is why the test-file convention that catches the other two does not catch it.The consequence is the one the ratchet was built to prevent, displaced one level up. Its own header says ESLint
ignorescannot express a ratchet because "an ignored file is ignored completely, so NEW erasures added to a listed file ride the existing entry in total silence". The ratchet closes that for the code. But if the gate is never named in a dispatch, the author does not run it,pnpm lintpasses (the file is grandfathered, so ESLint says nothing), and the first signal is a red CI job — which for apriority:p0security fix is the expensive place to find out.What a fix would look like (a lead, not a decision)
Add a
CHANGE_KIND_GATESentry forcheck:slot-lookup. The trigger has two candidate spellings and the narrower one looks clearly better:.ts/.tsx/.mts/.ctsfile underpackages/". Mechanical and complete, but fires on very nearly every card, which is the cost the residue'ssilent/undeterminedsplit exists to keep down.packages/that contains a service lookup". The rule's own trigger vocabulary is a three-name list ineslint.config.mjs(SLOT_LOOKUPS:resolveService,getService,getRequestKernelService), so amatchespredicate can grep the changed files for those names — cheap, no type information, and it reads the same list the rule does rather than a copy. It would have fired on The datasource-admin HTTP family is reachable unauthenticated, read and write — mounts outside the enforceAuth seam #9391's diff and stays quiet for cards that touch no lookup.Either way the entry needs the
whytext every other entry carries, and it should say the two things that made this one expensive:pnpm lintpassing proves nothing for a grandfathered file, and the repair is to type the lookup, never to--updatethe baseline upward.Note for whoever picks this up: the deriver's
--self-testpins the convention section by name (it asserts the section "names all five convention gates"), so an added entry needs that assertion updated in the same edit.Scope note
Filed rather than fixed: #9391 is a
priority:p0security card whose scope is ruled to the authentication guard, and this is PM tooling inscripts/pm/. The immediate ratchet failure was repaired in that PR by typing the five new lookups against their slots' contracts (IAuthService,IDataEngine); the file's two pre-existing grandfathered sites were left at their recorded count.Backlinks: #8632 (the same defect for
check:engine-double-contract, closed — the precedent), #9391 (the card that paid for this), #9320 and #8551 (other derivation gaps in the same script). Unassigned and unqueued, for the triage seat to level and route.