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 cannot name check:type-check-debt for a scripts/** card — the root package's tsc scope is defined by EXCLUSION, so no path literal will ever describe it #9873
Filed by the dev seat working #9851 (PR #9853), which paid for it with a CI round-trip. ⛔ Unassigned, unlabeled, for triage to level and route. ⛔ Not fixed here: #9851's scope is a benchmark and a reconciliation, and this is PM tooling in scripts/pm/.
What happened
PR #9853 adds exactly one file, scripts/bench/runtime-publish-gate.bench.mts. The dispatching instruction is to derive the verification union with node scripts/pm/dispatch-gates.mjs, which was done, at the final head, with no hand-fed paths. It named two gates:
Both were run and both were green. CI then failed TypeScript Type Check:
check-type-check-coverage --re-measure: 1 ledger entr(ies) drifted upward
• @objectstack/spec-monorepo: DEBT records 80 raw tsc error(s),
`tsc --noEmit` now reports 99 (+19).
All 19 came from the one new file — process and console are absent because the root tsconfig carries lib: ['ES2020'] and no types. Reproduced locally, fixed by declaring the two globals ambiently (narrowed to the members called, the same shape as the ambient process in examples/app-showcase/objectstack.config.ts), and the ledger is back at exactly 80. No baseline was raised.
⭐ Why this is a DISTINCT defect from #9721 and #9700 — and why their proposed fix would not catch it
This matters more than the instance, so taking it first.
#9721's gate (check:slot-lookup) is absent from the deriver entirely — grep -c slot returns 0. #9700's is present but its source names only its own baseline artifact, so it scores silent for every card. Both are cases of the deriver cannot name this gate for any path.
check:type-check-debt is neither. It is discovered, and it does name paths:
It names the gate's own scripts plus the ledgered package names. That is a real and mostly-correct population: for the 12 non-root ledger entries, editing a file in one of those packages is nameable.
⚠️The root entry is the hole.@objectstack/spec-monorepo — the root workspace package, which #4311's audit deliberately counted like any other — has its tsc program defined in tsconfig.json by exclusion:
There is no positive path literal anywhere that says "the root program is everything else", because that is not how the config expresses it. So scripts/** — and any other top-level TypeScript — sits squarely inside a ledgered package's tsc scope while being unnameable by any source-literal derivation, in principle rather than by omission.
⇒ #9721's recommended self-test would pass on this gate and still miss this case. Its proposed invariant is "every pnpm check:* invoked by lint.yml is nameable by the deriver for at least one path". check:type-check-debt is nameable for at least one path (twelve packages' worth), so the assertion is satisfied and the root-scope hole survives it. Worth knowing before that fix is scoped, since it is the one currently on the table.
Scope of the hole
Any card that adds or edits TypeScript outside packages/, apps/ and examples/ can move the root ledger entry, and the deriver will report check:type-check-debt as not implicated. That includes scripts/** — 25+ .mts/.ts files today, and the natural home for exactly the tooling, benchmarks and one-off checkers that get written under dispatch.
⚠️ The failure mode is asymmetric in the expensive direction. The gate is a shrink-only ratchet, so the author's remedy is to fix the errors — but a dev who does not know to run it discovers the drift only in CI, and the tempting repair at that point (raising the entry) is the one the gate's own text calls maintainer-only and explicitly not a co-equal option. Not knowing to run the gate is what puts a dev in front of that choice.
Candidate fixes (leads, not decisions)
A CHANGE_KIND_GATES-style convention entry: "edits a .ts / .mts / .cts file that is neither under packages/, apps/ nor examples/" fires check:type-check-debt. Mechanical, cheap, and mirrors the root tsconfig's own exclusion list rather than duplicating a path guess.
⭐ Better, and closes the class: derive each ledgered package's population from its tsconfig's real program rather than from path literals in the gate's source — for the root, that is the complement of its exclude array. The information is already on disk and already authoritative; nothing needs to be kept in sync by hand.
Whichever route, the deriver's --self-test will need a case pinning it, and the entry's why text should say the thing that made this one expensive: scripts/** is inside the ROOT package's type-check scope, and the repair is to make the new file typecheck, never to raise the ledger.
Not claimed
⛔ No defect in check-type-check-coverage.mjs. It worked exactly as designed, caught a real regression, refused to measure on an unbuilt closure, and its failure text names the correct remedy first and marks the wrong one maintainer-only. The failure is that nobody could know to run it before pushing.
Refs: #9721 · #9700 · #8632 (the convention-entry precedent) · #9851 / PR #9853 (the card that paid for this) · #4311 (the coverage ledger) · #5278 (the ratchet is shrink-only)
Filed by the dev seat working #9851 (PR #9853), which paid for it with a CI round-trip. ⛔ Unassigned, unlabeled, for triage to level and route. ⛔ Not fixed here: #9851's scope is a benchmark and a reconciliation, and this is PM tooling in
scripts/pm/.What happened
PR #9853 adds exactly one file,
scripts/bench/runtime-publish-gate.bench.mts. The dispatching instruction is to derive the verification union withnode scripts/pm/dispatch-gates.mjs, which was done, at the final head, with no hand-fed paths. It named two gates:Both were run and both were green. CI then failed
TypeScript Type Check:All 19 came from the one new file —
processandconsoleare absent because the root tsconfig carrieslib: ['ES2020']and notypes. Reproduced locally, fixed by declaring the two globals ambiently (narrowed to the members called, the same shape as the ambientprocessinexamples/app-showcase/objectstack.config.ts), and the ledger is back at exactly 80. No baseline was raised.⭐ Why this is a DISTINCT defect from #9721 and #9700 — and why their proposed fix would not catch it
This matters more than the instance, so taking it first.
#9721's gate (
check:slot-lookup) is absent from the deriver entirely —grep -c slotreturns 0. #9700's is present but its source names only its own baseline artifact, so it scoressilentfor every card. Both are cases of the deriver cannot name this gate for any path.check:type-check-debtis neither. It is discovered, and it does name paths:It names the gate's own scripts plus the ledgered package names. That is a real and mostly-correct population: for the 12 non-root ledger entries, editing a file in one of those packages is nameable.
@objectstack/spec-monorepo— the root workspace package, which #4311's audit deliberately counted like any other — has its tsc program defined intsconfig.jsonby exclusion:There is no positive path literal anywhere that says "the root program is everything else", because that is not how the config expresses it. So
scripts/**— and any other top-level TypeScript — sits squarely inside a ledgered package's tsc scope while being unnameable by any source-literal derivation, in principle rather than by omission.⇒ #9721's recommended self-test would pass on this gate and still miss this case. Its proposed invariant is "every
pnpm check:*invoked bylint.ymlis nameable by the deriver for at least one path".check:type-check-debtis nameable for at least one path (twelve packages' worth), so the assertion is satisfied and the root-scope hole survives it. Worth knowing before that fix is scoped, since it is the one currently on the table.Scope of the hole
Any card that adds or edits TypeScript outside
packages/,apps/andexamples/can move the root ledger entry, and the deriver will reportcheck:type-check-debtas not implicated. That includesscripts/**— 25+.mts/.tsfiles today, and the natural home for exactly the tooling, benchmarks and one-off checkers that get written under dispatch.Candidate fixes (leads, not decisions)
CHANGE_KIND_GATES-style convention entry: "edits a.ts/.mts/.ctsfile that is neither underpackages/,apps/norexamples/" firescheck:type-check-debt. Mechanical, cheap, and mirrors the root tsconfig's own exclusion list rather than duplicating a path guess.excludearray. The information is already on disk and already authoritative; nothing needs to be kept in sync by hand.scripts/pm/dispatch-gates.mjsdoes not knowcheck:slot-lookupexists, so no dev brief ever derives it — it cost a p0 a CI round-trip today #9721 audit lands first, widen its invariant from "nameable for at least one path" to something that can see this: a gate whose population is a tsc program should be checked against that program, not against string literals.Whichever route, the deriver's
--self-testwill need a case pinning it, and the entry'swhytext should say the thing that made this one expensive:scripts/**is inside the ROOT package's type-check scope, and the repair is to make the new file typecheck, never to raise the ledger.Not claimed
check-type-check-coverage.mjs. It worked exactly as designed, caught a real regression, refused to measure on an unbuilt closure, and its failure text names the correct remedy first and marks the wrong one maintainer-only. The failure is that nobody could know to run it before pushing.scripts/pm/dispatch-gates.mjsdoes not knowcheck:slot-lookupexists, so no dev brief ever derives it — it cost a p0 a CI round-trip today #9721's audit.Refs: #9721 · #9700 · #8632 (the convention-entry precedent) · #9851 / PR #9853 (the card that paid for this) · #4311 (the coverage ledger) · #5278 (the ratchet is shrink-only)