Observed live on PR #11191 (packages/create-objectstack/src/starter-comments-self-contained.test.ts, three prose comments naming another gate in backticks). node scripts/pm/dispatch-gates.mjs (no paths — merge-base derived) reported a full gate union, all green, and none of it was check:cross-package-test-inputs. CI's Lint & Repo Gates job then failed on exactly that gate:
scripts/check-published-readme-links.mjs (named in packages/create-objectstack/src/starter-comments-self-contained.test.ts)
Widen the package's globs to cover them.
grep -i cross-package-test-inputs over a fresh dispatch-gates.mjs run (no args) for that diff produces zero lines — the gate is absent from the matched list, the convention-triggered list, and the unreachable-by-construction list. It only surfaces under --residue, in the silent/undetermined bucket, which the tool's own text says is "not known irrelevant" but reads, in practice, as safe to skip.
Root cause
check-cross-package-test-inputs.mjs's population is not a path set. Two independent things make a test file matter to it:
- a real escaping read/import (an actual cross-package dependency), or
- a prose mention — its flat literal collector (
repoRelativeLiterals) matches ANY backtick/quote-wrapped (packages|apps|examples|content|scripts|skills)/... string anywhere in the file's text, comments included, with no parsing.
Both are properties of a test file's content, not of which package owns it — the same shape #9955 documented for check:test-source-alias ("the trigger is a NEW cross-package import inside a test, which no path literal describes"). #9955 was fixed by PR #10540 declaring workspace-parent globs, but that fix was for a gate whose declared population is expressible as parent globs once every workspace member is listed. check-cross-package-test-inputs has no such fix available: a package with zero prior entries in its per-package ledger (like create-objectstack before this PR) contributes nothing for the tool to widen — there is no existing glob to have named it, because the trigger is "any test file's content changed," full stop.
dispatch-gates.mjs already has exactly this shape of trigger modeled — the 'adds or edits a test file' convention-trigger kind (CHANGE_KIND_GATES[0], scripts/pm/dispatch-gates.mjs:2157) — and it already carries five gates for the same reason (check:query-options-erasure, check:type-check-coverage, check:type-check-debt, check:engine-double-contract, check:where-matcher), each because it "walks every *.test.* file" or "*.test.ts file" for something a path literal cannot describe. check-cross-package-test-inputs is the same kind of whole-corpus, content-driven scan, runs in the same CI job (lint.yml's lint job, "Lint & Repo Gates"), and is conspicuously absent from that list with no rationale in the source excluding it — it appears to simply have been missed when the convention-trigger list was built.
Why this matters
This is not a false-positive-tolerance question — the gate itself was correct (my test file's comments genuinely did read as an undeclared escape to its literal collector). The gap is that a dev following the standard dispatch-gates.mjs + reported-green workflow has no local signal at all that this gate exists to fail, for any PR that merely edits or adds a test file anywhere in the repo — which is a very large fraction of PRs. The existing five-gate convention list exists precisely to cover this class of blind spot for its siblings; this gate rides the identical trigger and sits just outside it.
Suggested fix, not asserted as the only one
Add check:cross-package-test-inputs as a sixth entry under CHANGE_KIND_GATES[0] ('adds or edits a test file'), alongside its five current siblings — cheap (one more entry, no new derivation machinery) and consistent with how the other whole-corpus test-content scanners in the same CI job are already handled. Not measured here: whether any other currently-unlisted gate in lint.yml shares this same "scans every test file's content" shape and is missing from the same list for the same reason — worth a companion sweep if this fix lands.
Filed while working #10990/#11022 (PR #11191); not fixed there because widening dispatch-gates.mjs is unrelated to that PR's own scope.
Observed live on PR #11191 (
packages/create-objectstack/src/starter-comments-self-contained.test.ts, three prose comments naming another gate in backticks).node scripts/pm/dispatch-gates.mjs(no paths — merge-base derived) reported a full gate union, all green, and none of it wascheck:cross-package-test-inputs. CI'sLint & Repo Gatesjob then failed on exactly that gate:grep -i cross-package-test-inputsover a freshdispatch-gates.mjsrun (no args) for that diff produces zero lines — the gate is absent from the matched list, the convention-triggered list, and the unreachable-by-construction list. It only surfaces under--residue, in thesilent/undeterminedbucket, which the tool's own text says is "not known irrelevant" but reads, in practice, as safe to skip.Root cause
check-cross-package-test-inputs.mjs's population is not a path set. Two independent things make a test file matter to it:repoRelativeLiterals) matches ANY backtick/quote-wrapped(packages|apps|examples|content|scripts|skills)/...string anywhere in the file's text, comments included, with no parsing.Both are properties of a test file's content, not of which package owns it — the same shape #9955 documented for
check:test-source-alias("the trigger is a NEW cross-package import inside a test, which no path literal describes"). #9955 was fixed by PR #10540 declaring workspace-parent globs, but that fix was for a gate whose declared population is expressible as parent globs once every workspace member is listed.check-cross-package-test-inputshas no such fix available: a package with zero prior entries in its per-package ledger (likecreate-objectstackbefore this PR) contributes nothing for the tool to widen — there is no existing glob to have named it, because the trigger is "any test file's content changed," full stop.dispatch-gates.mjsalready has exactly this shape of trigger modeled — the'adds or edits a test file'convention-trigger kind (CHANGE_KIND_GATES[0],scripts/pm/dispatch-gates.mjs:2157) — and it already carries five gates for the same reason (check:query-options-erasure,check:type-check-coverage,check:type-check-debt,check:engine-double-contract,check:where-matcher), each because it "walks every*.test.*file" or "*.test.ts file" for something a path literal cannot describe.check-cross-package-test-inputsis the same kind of whole-corpus, content-driven scan, runs in the same CI job (lint.yml'slintjob, "Lint & Repo Gates"), and is conspicuously absent from that list with no rationale in the source excluding it — it appears to simply have been missed when the convention-trigger list was built.Why this matters
This is not a false-positive-tolerance question — the gate itself was correct (my test file's comments genuinely did read as an undeclared escape to its literal collector). The gap is that a dev following the standard
dispatch-gates.mjs+ reported-green workflow has no local signal at all that this gate exists to fail, for any PR that merely edits or adds a test file anywhere in the repo — which is a very large fraction of PRs. The existing five-gate convention list exists precisely to cover this class of blind spot for its siblings; this gate rides the identical trigger and sits just outside it.Suggested fix, not asserted as the only one
Add
check:cross-package-test-inputsas a sixth entry underCHANGE_KIND_GATES[0]('adds or edits a test file'), alongside its five current siblings — cheap (one more entry, no new derivation machinery) and consistent with how the other whole-corpus test-content scanners in the same CI job are already handled. Not measured here: whether any other currently-unlisted gate inlint.ymlshares this same "scans every test file's content" shape and is missing from the same list for the same reason — worth a companion sweep if this fix lands.Filed while working #10990/#11022 (PR #11191); not fixed there because widening
dispatch-gates.mjsis unrelated to that PR's own scope.