Found while wiring #8162 (PR #8477), measured rather than reasoned. Observation class, precision papercut — the tool's verdicts are unaffected, only its leads. Unassigned; grading is the triage seat's call.
The observation
extractWatchHints in scripts/pm/dispatch-gates.mjs scans a check script's source for quoted path-ish spans and treats each as a path that gate operates on. The scan does not distinguish
- a literal the gate really reads at runtime, from
- a self-test fixture string, from
- a path named in a comment — the regex accepts backticks, so every backticked path in a header is a hint too.
A gate whose source contains a fixture path is then printed in the Local gates for this card block — the MATCHED column, which the script's own header reserves for high-signal answers ("22 leads is the same as none") — for cards that have nothing to do with it.
Measured on main at 03b5f81, today
Coverage-capable hints per script (i.e. after hintCovers drops the too-generic ones):
| script |
hints |
notable entries |
scripts/pm/dispatch-gates.mjs |
45 |
2 real, 43 self-test fixtures — packages/spec/src, packages/objectql, packages/plugins, packages/drivers, .claude/agents |
scripts/check-adr-0087-registration.mjs |
33 |
packages/runtime, packages/spec — from changeset fixtures |
scripts/check-empty-changeset.mjs |
35 |
skills/demo/SKILL.md, src/app.ts, a dozen .changeset/*.md fixture names |
scripts/pm/check-skill-id-lint.mjs |
2 |
both real (this is what a clean one looks like) |
End to end, with dispatch-gates.mjs itself wired as a gate (the naive wiring PR #8477 measured and then rejected):
- pnpm check:pm-dispatch-gates [lint.yml] matched via packages/spec/src/data/filter.zod.ts ⇢ 'packages/spec/src'
The comment half is measured too: the first draft of scripts/pm/check-dispatch-gates.mjs explained the pollution with each path in backticks, and that header alone produced ten hints — reproducing, from the file documenting the problem, the exact false leads it was written to avoid.
Why it is worth a card and not a shrug
The error is one-directional in the expensive direction. A missing lead costs one CI round on one card; a fabricated lead is pasted into every dispatch prompt whose file surface brushes a fixture path, and the dev who runs it cannot tell it from a real one. The precision of the matched column is the whole product here — the "repo-wide / undetermined" bucket already exists for gates the derivation cannot place, and it is the honest home for these.
PR #8477 does not fix this. It sidesteps it for one gate by giving check:pm-dispatch-gates its own thin gate file whose only literal is the tool it runs, which is a local shape, not a remedy for the population above.
Directions (not a recommendation — grading is triage's)
- Stop scanning at the self-test boundary — most of these scripts put their self-test last; hints taken only from the module body would drop nearly all the false ones. Needs a boundary that is mechanically detectable, not a comment convention.
- Skip comment spans (and backticks inside them). Cheap, partial — it fixes the header half and none of the fixture half.
- Rank rather than filter — keep fixture-derived hints but print them in a weaker bucket than a literal the gate reads. Preserves recall, admits the tool cannot tell the two apart.
- Do nothing. The output is advisory and the PM's judgment call already sits on top of it.
Whichever direction is taken, the change is to extractWatchHints and its self-test only, and it should be measured by re-deriving the four scripts above rather than by reasoning about the regex.
Related
Generated by Claude Code
Found while wiring #8162 (PR #8477), measured rather than reasoned. Observation class, precision papercut — the tool's verdicts are unaffected, only its leads. Unassigned; grading is the triage seat's call.
The observation
extractWatchHintsinscripts/pm/dispatch-gates.mjsscans a check script's source for quoted path-ish spans and treats each as a path that gate operates on. The scan does not distinguishA gate whose source contains a fixture path is then printed in the
Local gates for this cardblock — the MATCHED column, which the script's own header reserves for high-signal answers ("22 leads is the same as none") — for cards that have nothing to do with it.Measured on
mainat 03b5f81, todayCoverage-capable hints per script (i.e. after
hintCoversdrops the too-generic ones):scripts/pm/dispatch-gates.mjspackages/spec/src,packages/objectql,packages/plugins,packages/drivers,.claude/agentsscripts/check-adr-0087-registration.mjspackages/runtime,packages/spec— from changeset fixturesscripts/check-empty-changeset.mjsskills/demo/SKILL.md,src/app.ts, a dozen.changeset/*.mdfixture namesscripts/pm/check-skill-id-lint.mjsEnd to end, with
dispatch-gates.mjsitself wired as a gate (the naive wiring PR #8477 measured and then rejected):The comment half is measured too: the first draft of
scripts/pm/check-dispatch-gates.mjsexplained the pollution with each path in backticks, and that header alone produced ten hints — reproducing, from the file documenting the problem, the exact false leads it was written to avoid.Why it is worth a card and not a shrug
The error is one-directional in the expensive direction. A missing lead costs one CI round on one card; a fabricated lead is pasted into every dispatch prompt whose file surface brushes a fixture path, and the dev who runs it cannot tell it from a real one. The precision of the matched column is the whole product here — the "repo-wide / undetermined" bucket already exists for gates the derivation cannot place, and it is the honest home for these.
PR #8477 does not fix this. It sidesteps it for one gate by giving
check:pm-dispatch-gatesits own thin gate file whose only literal is the tool it runs, which is a local shape, not a remedy for the population above.Directions (not a recommendation — grading is triage's)
Whichever direction is taken, the change is to
extractWatchHintsand its self-test only, and it should be measured by re-deriving the four scripts above rather than by reasoning about the regex.Related
dispatch-gates.mjshas 28 self-test cases and no CI job runs any of them #8162 / PR test(pm): run the dispatch-gates self-test in CI and anchor its convention-gate pins #8477 — where this surfaced; that PR's wiring made the tool a gate and the pollution visible.Generated by Claude Code