Skip to content

Commit 6cd6c13

Browse files
committed
fix(pm): the exclusion vocabulary recognises DEFERRED, so a deferred table stops reading as a scan surface
`EXCLUSION_DECL_NAME` listed no `DEFERRED`, and `check-issue-citations.mjs` declares its exclusion table as `DEFERRED_SURFACES` / `DEFERRED_GLOBS` and applies it as an exclusion — `surfaceFor` opens by returning `null` for every deferred glob. So the derivation read that exclusion table as a watch surface and told a `.changeset/**` path it triggers a gate that looks at nothing there. One `DEFERRED` branch in the predicate. The measured census in the docblock is re-measured in the same stroke, by the method it now spells out, and the per-word tally, the moved-hint table and the cost split are rewritten from that reading rather than carried forward. One self-test case joins the named-spelling cases beside it. Claude-Session: https://claude.ai/code/session_01W5y9kRg1YtYaMQYExVLRc2 Co-authored-by: Claude <noreply@anthropic.com>
1 parent 7ec8534 commit 6cd6c13

1 file changed

Lines changed: 64 additions & 38 deletions

File tree

‎scripts/pm/dispatch-gates.mjs‎

Lines changed: 64 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5886,57 +5886,81 @@ export function packageRootAnchoredHint(hint, base, tree, files) {
58865886
*
58875887
* ## The census, measured on this tree
58885888
*
5889-
* 3,513 top-level VALUE declarations over the 230 tracked JS/TS files under
5890-
* `scripts/`. 64 identifiers match the predicate; 58 carry at least one string
5891-
* literal; the whole set moves 14 hints, across 6 files:
5892-
*
5893-
* scripts/check-doc-authoring.mjs SKIP_PATHS, SKIP_FILES,
5889+
* Re-measured with the `DEFERRED` arm in place, on objectstack-ai/objectstack
5890+
* `7ec8534127`. The METHOD, which this block used to leave implicit: run
5891+
* `topLevelDecls` over every tracked JS/TS file under `scripts/`, keep the
5892+
* non-callable declarations, test each name against the predicate, and price
5893+
* the arm by diffing `extractWatchHints` against a build of this module whose
5894+
* predicate matches nothing. Attribution is the regex engine's own — leftmost
5895+
* position first, then alternation order.
5896+
*
5897+
* 4,697 top-level VALUE declarations over the 287 tracked JS/TS files under
5898+
* `scripts/`. 75 identifiers match the predicate; 66 carry at least one string
5899+
* literal; the whole set moves 24 hints, across 8 files:
5900+
*
5901+
* scripts/check-issue-citations.mjs DEFERRED_SURFACES 8
5902+
* scripts/check-doc-authoring.mjs SKIP_DIRS, SKIP_PATHS, SKIP_FILES,
58945903
* PACKAGES_PROSE_EXCLUDED 6
58955904
* scripts/check-refd-timer-probe.mjs EXCLUDED_DIRS 4
5896-
* scripts/check-corpus-claim-drift.mjs SKIP_SUBTREES 1
5897-
* scripts/check-role-word.mjs SKIP_SUBTREES 1
5905+
* scripts/pm/measurement-claim-triage.mjs EXCLUDED, SKIP_DIRS 2
5906+
* scripts/check-corpus-claim-drift.mjs SKIP_DIRS, SKIP_SUBTREES 1
5907+
* scripts/check-role-word.mjs SKIP_DIRS, SKIP_SUBTREES 1
58985908
* scripts/check-keyed-text-bounds.mjs SKIP_DIRS 1
5899-
* scripts/pm/check-half-states.mjs H36_SHARED_PREFIX_NOISE 1
5909+
* scripts/pm/check-half-states.mjs H36_SHARED_PATH_NOISE,
5910+
* H36_SHARED_PREFIX_NOISE 1
59005911
*
59015912
* Each was read against the gate that declares it, and each is an exclusion in
59025913
* that gate's own words: "whole subtrees skipped by path", "generated
59035914
* subtrees, excluded by PATH under ROOTS", "generated from spec/frontmatter —
59045915
* not hand-authored, don't police", "directories `git ls-files` can still name
5905-
* that hold no authored source", and — for `PACKAGES_PROSE_EXCLUDED`, the one
5906-
* that is a bare string rather than a list — the `continue` in the gate's own
5907-
* `descend` that skips it.
5908-
*
5909-
* ## What the 14 cost, which is not 14
5910-
*
5911-
* EIGHT of them change no derivation at all, because the gate ALSO declares the
5912-
* containing root as an inclusion population and `hintCovers` still reaches the
5913-
* path through that. Measured per hint, probing under each dropped hint against
5914-
* the surviving set: all six of check-doc-authoring's (`.claude/**`, `docs/**`,
5915-
* `content/**` and `packages/**` are its `ROOT_WATCH_HINTS`) and both
5916-
* `content/docs/references` (covered by `content/docs`). That gate's own
5917-
* self-test already said so from the other side — every `SKIP_PATHS` entry must
5918-
* sit UNDER a declared root — so the exclusion hints were pure duplication.
5919-
*
5920-
* SIX really leave a derivation, and every one of them is a lead that was
5916+
* that hold no authored source", "deliberately OUT, each with the reading that
5917+
* put it out", and — for `PACKAGES_PROSE_EXCLUDED`, the one that is a bare
5918+
* string rather than a list — the `continue` in the gate's own `descend` that
5919+
* skips it.
5920+
*
5921+
* ## What the 24 cost, which is not 24
5922+
*
5923+
* THIRTEEN of them change no derivation at all, because the gate ALSO declares
5924+
* the containing root as an inclusion population and `hintCovers` still reaches
5925+
* the path through that. Measured per hint, probing under each dropped hint
5926+
* against the surviving set: all six of check-doc-authoring's (`.claude/**`,
5927+
* `docs/**`, `content/**` and `packages/**` are its `ROOT_WATCH_HINTS`), both
5928+
* `content/docs/references` (covered by `content/docs`), and the five test
5929+
* globs of the deferred table (covered by check-issue-citations' own
5930+
* `packages/**`). That gate's own self-test already said so from the other
5931+
* side — every `SKIP_PATHS` entry must sit UNDER a declared root — so those
5932+
* exclusion hints were pure duplication.
5933+
*
5934+
* ELEVEN really leave a derivation, and every one of them is a lead that was
59215935
* false: `node_modules`, `dist`, `coverage` and `.turbo` off
5922-
* check-refd-timer-probe's skip set, and `.changeset` twice — off
5936+
* check-refd-timer-probe's skip set; `.changeset` twice — off
59235937
* check-keyed-text-bounds' `SKIP_DIRS` and off the noise floor the card was
5924-
* filed on. The changeset pair is what a dev actually saw: a card that has not
5925-
* written its changeset yet is told which families it will owe once it does,
5926-
* and that projection carried FOUR fabricated rows, 16 -> 12 — including
5938+
* filed on; the two gate paths measurement-claim-triage declares it skips; and
5939+
* `scripts/**`, `docs/adr/**` and `.changeset/**` off `DEFERRED_SURFACES`,
5940+
* which is what the `DEFERRED` arm retired. The changeset pair is what a dev
5941+
* actually saw when #15753 was filed: a card that has not written its
5942+
* changeset yet is told which families it will owe once it does, and that
5943+
* projection carried FOUR fabricated rows, 16 -> 12 — including
59275944
* `check-half-states.mjs --format=markdown --provenance="$PROVENANCE"`, the
59285945
* networked half-state-patrol sweep, advertised to every card in the tree as a
5929-
* gate its changeset would trigger.
5946+
* gate its changeset would trigger. The deferred table is that same reading
5947+
* one gate over, and it is why this arm exists: `surfaceFor` opens by
5948+
* returning `null` for every deferred glob, so `check:issue-citations` was
5949+
* offered to a changeset path as a gate it triggers while the gate looks at
5950+
* nothing there.
59305951
*
59315952
* ## The predicate: what the census kept, and what it retired
59325953
*
59335954
* `DENY`/`DENIED` was measured and REMOVED. It matched exactly one declaration
59345955
* on this tree and that one is a false positive — an HTTP fixture, not an
59355956
* exclusion list — and "deny" in this tree names AUTHORIZATION vocabulary
5936-
* (`DENY_CODE`), never a path skip list. Matches for the surviving
5937-
* alternatives, first-match attribution: SKIP 47, EXCLUDED 9, NOISE 2,
5938-
* SKIPPED 2, EXCLUSION 2, EXCLUSIONS 1, EXCLUDES 1, and EXCLUDE / IGNORE /
5939-
* IGNORED 0. The three zero-scoring arms are kept deliberately and the reason is
5957+
* (`DENY_CODE`), never a path skip list. `DEFERRED` was measured and ADDED: it
5958+
* matches two declarations on this tree, `DEFERRED_SURFACES` and
5959+
* `DEFERRED_GLOBS` in `check-issue-citations.mjs`, and both are that gate's
5960+
* own exclusion table. Matches for the surviving alternatives, first-match
5961+
* attribution: SKIP 54, EXCLUDED 10, EXCLUSION 4, NOISE 2, SKIPPED 2,
5962+
* DEFERRED 2, EXCLUSIONS 1, and EXCLUDE / EXCLUDES / IGNORE / IGNORED 0. The
5963+
* four zero-scoring arms are kept deliberately and the reason is
59405964
* the direction this predicate fails in: over-matching DROPS a hint (a missing
59415965
* lead — one card, one CI round), while under-matching KEEPS a wrong one (a
59425966
* fabricated lead pasted into every dispatch prompt whose surface brushes it).
@@ -5959,14 +5983,16 @@ export function packageRootAnchoredHint(hint, base, tree, files) {
59595983
* is not reached — `check-test-completeness.mjs` has the one instance on this
59605984
* tree, and it costs nothing today because every literal in it is a bare
59615985
* directory word the admission rule already refuses. camelCase spellings are
5962-
* not reached either: the anchor is the SCREAMING_SNAKE segment, and the four
5963-
* camelCase near-misses on this tree (`scripts/docs-audit/affected-docs.mjs`)
5964-
* are counters and note strings, not populations. Both are the direction that
5986+
* not reached either: the anchor is the SCREAMING_SNAKE segment, and the seven
5987+
* camelCase near-misses on this tree (five in
5988+
* `scripts/docs-audit/affected-docs.mjs`, one in
5989+
* `scripts/check-type-check-coverage.mjs`, one here) are counters, note strings
5990+
* and memo caches, not populations. Both are the direction that
59655991
* drops LESS, which is the direction a widening of this rule may not silently
59665992
* take.
59675993
*/
59685994
const EXCLUSION_DECL_NAME =
5969-
/(?:^|_)(?:NOISE|SKIP|SKIPPED|EXCLUDE|EXCLUDED|EXCLUDES|EXCLUSION|EXCLUSIONS|IGNORE|IGNORED)(?:_|$)/;
5995+
/(?:^|_)(?:NOISE|SKIP|SKIPPED|DEFERRED|EXCLUDE|EXCLUDED|EXCLUDES|EXCLUSION|EXCLUSIONS|IGNORE|IGNORED)(?:_|$)/;
59705996

59715997
/** `topLevelDecls` classifies self-tests for its OTHER caller; this one has no stake in it. */
59725998
const NO_SELF_TEST_STARTS = new Set();
@@ -17145,7 +17171,7 @@ function selfTest() {
1714517171
t('and a declaration AFTER it is unaffected — the span closes where the statement does', multilineHints.includes('packages/core/src'));
1714617172
// The named spellings, one case each, so a narrowing of the predicate is
1714717173
// visible here rather than only in the live census.
17148-
for (const word of ['SKIP', 'EXCLUDE', 'EXCLUDED', 'EXCLUSIONS', 'IGNORE']) {
17174+
for (const word of ['SKIP', 'EXCLUDE', 'EXCLUDED', 'EXCLUSIONS', 'IGNORE', 'DEFERRED']) {
1714917175
const named = `const ${word}_PATHS = ['packages/skipped/src'];`;
1715017176
t(`\`${word}\` names an exclusion too — the predicate is the convention, not one constant`, !extractWatchHints(named).includes('packages/skipped/src'));
1715117177
}

0 commit comments

Comments
 (0)