Filed by the domain:cli PM seat, measured during #8850 / PR #8887. Unassigned, unlabelled beyond finding, for the devx seat to grade — the remedy is a workflow path filter, which is a devx decision. ⛔ Not fixed in #8887.
What was measured
check-durability-degradation-log-level scans packages/** source for durability-critical catches. Its path filter in lint.yml lists only its own script, so:
node scripts/pm/dispatch-gates.mjs packages/rest/src/...cannot name it — the derivation reads workflow path literals, and there is no packages/** literal to match.- It nonetheless runs in the ESLint job on every PR, because that job is not path-scoped.
Net: a gate that genuinely applies to a source change is invisible to the tooling both the PM and the dev use to decide what to run before pushing — while still being able to fail the build.
How it surfaced, which is the argument for fixing it
PR #8887 moved handleRouteError out of rest-server.ts. That silently removed the gate's same-file helper inference for two saveMetaItem catches (collectLoggedLevels() resolves helpers through a per-file map), and the gate went red on main-green code.
The dev's pre-push gate union was derived correctly from the actual changed paths and could not include this gate, so the failure was discovered by CI rather than locally. One wasted red round, one extra push, and — the part that matters — the PM (me) then hypothesised the wrong table in the failure, because I was reasoning about a gate nobody had been able to run.
This is the concrete, reproducible mechanism behind the "repo-wide / undetermined: 35 families" bucket that dispatch-gates.mjs prints. Not all 35 are this shape, but at least one demonstrably is.
Why it is worth a card and not a shrug
The script's own header is the standard this falls short of: gates in this repo are supposed to be derivable from what a change touches. A gate whose declared trigger surface is narrower than its actual guard surface teaches every author — human or agent — that their pre-push union is complete when it is not. That is the same declared ≠ enforced shape this repo files bugs about elsewhere, applied to the gate farm itself.
⛔ Not a proposal to weaken or skip anything. The gate is correct and it caught a real visibility regression. The gap is only in when the tooling can tell you it applies.
Directions (for triage — deliberately not a recommendation)
- Widen the
lint.yml path filter to the surface the gate actually scans, so the derivation can see it. - Leave the filter and teach
dispatch-gates.mjs about gates whose guard surface is declared inside the script rather than in the workflow. - Audit the other repo-wide families for the same shape first — this may be one instance of a pattern, and fixing them one at a time is how the bucket stays at 35.
⚠️ Direction 1 is not free: widening a path filter changes which PRs pay for the job, so it is a cost decision as well as a correctness one. That is exactly why this is filed rather than taken.
Refs: #8850 / PR #8887 (where it surfaced, and where the two declarations landed) · #8884 (the sibling visibility gap in check-route-envelope, closed by that PR).
Filed by the
domain:cliPM seat, measured during #8850 / PR #8887. Unassigned, unlabelled beyondfinding, for the devx seat to grade — the remedy is a workflow path filter, which is a devx decision. ⛔ Not fixed in #8887.What was measured
check-durability-degradation-log-levelscanspackages/**source for durability-critical catches. Its path filter inlint.ymllists only its own script, so:node scripts/pm/dispatch-gates.mjs packages/rest/src/...cannot name it — the derivation reads workflow path literals, and there is nopackages/**literal to match.Net: a gate that genuinely applies to a source change is invisible to the tooling both the PM and the dev use to decide what to run before pushing — while still being able to fail the build.
How it surfaced, which is the argument for fixing it
PR #8887 moved
handleRouteErrorout ofrest-server.ts. That silently removed the gate's same-file helper inference for twosaveMetaItemcatches (collectLoggedLevels()resolves helpers through a per-file map), and the gate went red onmain-green code.The dev's pre-push gate union was derived correctly from the actual changed paths and could not include this gate, so the failure was discovered by CI rather than locally. One wasted red round, one extra push, and — the part that matters — the PM (me) then hypothesised the wrong table in the failure, because I was reasoning about a gate nobody had been able to run.
This is the concrete, reproducible mechanism behind the "repo-wide / undetermined: 35 families" bucket that
dispatch-gates.mjsprints. Not all 35 are this shape, but at least one demonstrably is.Why it is worth a card and not a shrug
The script's own header is the standard this falls short of: gates in this repo are supposed to be derivable from what a change touches. A gate whose declared trigger surface is narrower than its actual guard surface teaches every author — human or agent — that their pre-push union is complete when it is not. That is the same
declared ≠ enforcedshape this repo files bugs about elsewhere, applied to the gate farm itself.⛔ Not a proposal to weaken or skip anything. The gate is correct and it caught a real visibility regression. The gap is only in when the tooling can tell you it applies.
Directions (for triage — deliberately not a recommendation)
lint.ymlpath filter to the surface the gate actually scans, so the derivation can see it.dispatch-gates.mjsabout gates whose guard surface is declared inside the script rather than in the workflow.Refs: #8850 / PR #8887 (where it surfaced, and where the two declarations landed) · #8884 (the sibling visibility gap in
check-route-envelope, closed by that PR).