Skip to content

check:watch-hint-literal guards only ROOT_DIR_WATCH_HINTS, so the 41 ROOT_FILE_WATCH_HINTS mentions keep the silent-drop mechanism it exists to close #13301

Description

@claude

check:watch-hint-literal closes a real and well-argued mechanism: a watch-hint declaration written as a literal array contributes its hints to extractWatchHints, while the same declaration computed from a population constant contributes nothing — the runtime value is identical, every local assertion stays green, and the gate silently drops out of every dispatch brief.

Its scan is keyed to one constant name, spelled once:

/** The constant this gate is about, spelled ONCE. */
const DECL_NAME = 'ROOT_DIR_WATCH_HINTS';

That leaves the sibling declaration names carrying the identical mechanism unguarded. Counted over scripts/** and packages/**/scripts/** on main at 7404925:

declaration namementionsguarded by check:watch-hint-literal
ROOT_DIR_WATCH_HINTS136yes
ROOT_FILE_WATCH_HINTS41no
ROOT_WATCH_HINTS8no

grep -c ROOT_FILE_WATCH_HINTS scripts/check-watch-hint-literal.mjs is 0 — the gate does not reference the name at all.

ROOT_FILE_WATCH_HINTS is not a rare spelling. It is the established idiom for a gate whose population includes a repo-ROOT file, and at least four gates use it: scripts/check-doc-anchors.mjs (README.md/**, ARCHITECTURE.md/**), scripts/check-required-contexts.mjs, scripts/pm/check-skill-line-ratchet.mjs, and scripts/check-agent-test-spelling.mjs. Those declarations are exactly the ones a tidy-up would rewrite as ROOTS.map((r) => r + '/**'), which is the refactor the gate exists to refuse.

Why this is the same species as #13207

#13207 was a gate that could not be NAMED for the diffs that falsify it. This is one step up: the guard that keeps declarations scannable does not cover every declaration that needs to stay scannable. Both fail in the silent direction — nothing goes red, and the loss shows up later as a dispatch brief that omits a gate.

The gate's header is careful about what it deliberately does NOT assert (that a declaration is correct — that claim is local to each gate). It does not argue the name scope, so this reads as unexamined reach rather than a decided boundary.

Not judged here

Whether the fix is widening DECL_NAME to a set of names, deriving the names from the extractor, or deciding the other two names should not exist. Note the gate refuses an empty population deliberately, so any widening should keep a per-name non-empty floor — otherwise a renamed constant reports the healthiest green the gate can print.

Provenance

Measured while implementing #13207 (disposition 1) on branch claude/issue-13207-llms-txt-population; the population declaration added there is named DECLARED_WATCH_HINTS and is likewise outside this gate's reach, which is how the asymmetry surfaced. Filed unassigned for triage.

Duplicate check RUN before filing (the channel was repo-scoped REST list + local grep over 398 open items, positive control first): control watch-hint-literal returned 12 items; subject ROOT_FILE_WATCH_HINTS|ROOT_WATCH_HINTS returned 0.


Generated by Claude Code

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions