Skip to content

tooling(pm): stop reading a gate's exclusion constant as a watch hint - #15801

Merged
os-steve merged 3 commits into
mainfrom
claude/issue-15753-noise-floor-is-not-a-watch-hint
Sep 5, 2026
Merged

os-steve merged 3 commits into
mainfrom
claude/issue-15753-noise-floor-is-not-a-watch-hint

Conversation

@claude

@claude claude Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Fixes #15753

extractWatchHints scans a gate's whole module body for path-shaped string
literals, so a path declared inside that gate's own exclusion constant was
admitted as a surface the gate watches. The card's own sentence — the one
triage marked as the whole value of the card and asked to travel into the PR
unchanged — is carried here as it stands, in both the wordings it stands in:

What is worth fixing is the CLASS -- an exclusion list read as an inclusion
surface -- because the size of the mistake is set by the spelling that happens
to be in the constant, not by anything anyone chose.

⇒ 值得修的是类别,不是今天的代价:一份排除清单被读成一个包含面,而错误的规模由常量里碰巧写着的那个拼法决定,而不是由任何人的选择决定。

The fix

One file, scripts/pm/dispatch-gates.mjs. A literal whose offset falls inside a
top-level value declaration whose identifier carries NOISE / SKIP /
EXCLUDE / IGNORE (segment-anchored) is skipped at admission. The exclusion is
read from the scanned gate's own declaration, never from a list kept here:

Spans, not lines: a noise floor is usually written multi-line, and a per-line
check would admit every entry but the first.

One correction to the card's framing, verified rather than assumed: the
"precedent" it points at is not one. pnpm-lock.yaml — the other spelling in the
same noise floor — was never extracted because it fails looksPathy (no
separator, not one of the four dotted names), which is an incidental refusal
rather than noise awareness. After this change both spellings of that floor are
refused for the SAME declared reason, which is what makes the pair symmetric for
the first time.

The census, measured over scripts/**

3,513 top-level value declarations across the 230 tracked JS/TS files under
scripts/. 64 identifiers match the predicate, 58 carry at least one string
literal, and the whole set moves 14 hints across 6 files:

gate declaration hints dropped
check-doc-authoring.mjs SKIP_PATHS, SKIP_FILES, PACKAGES_PROSE_EXCLUDED 6
check-refd-timer-probe.mjs EXCLUDED_DIRS 4
check-corpus-claim-drift.mjs SKIP_SUBTREES 1
check-role-word.mjs SKIP_SUBTREES 1
check-keyed-text-bounds.mjs SKIP_DIRS 1
check-half-states.mjs H36_SHARED_PREFIX_NOISE 1

Each was read against the gate that declares it, and each is an exclusion in
that gate's own words ("whole subtrees skipped by path", "generated subtrees,
excluded by PATH under ROOTS", "directories git ls-files can still name that
hold no authored source", and — for the one that is a bare string rather than a
list — the continue in the gate's own descend that skips it).

8 of the 14 change no derivation at all: the gate also declares the
containing root as an inclusion population, so hintCovers still reaches the
path through that (measured per hint by probing under each dropped hint against
the surviving set). check-doc-authoring's own self-test already said so from
the other side — every SKIP_PATHS entry must sit under a declared root.

6 really leave a derivation, and every one was a false lead. The user-visible
half is the changeset pair. A card that has not written its changeset yet is told
which families it will owe once it does, and that projection carried four
fabricated rows, 16 -> 12
— including
check-half-states.mjs --format=markdown --provenance="$PROVENANCE", the
networked half-state-patrol sweep, advertised to every card in the tree as a gate
its changeset would trigger.

The predicate was narrowed by the census. DENY/DENIED matched exactly one
declaration and that one is a false positive (an HTTP fixture, not an exclusion
list); "deny" in this tree names authorization vocabulary, never a path skip
list, so that arm was removed. One false positive survives and costs nothing:
SHOW_EXCLUDED in scripts/objectui-range.mjs is a CLI flag, and its only
literal is '--all', refused by the flag rule regardless. No matched identifier
turned out to be an inclusion list — the reading that would narrow the
predicate further; check-watch-hint-literal.mjs's roster of the inclusion idiom
shares no word with it.

Blind spots are stated in the docblock rather than left to be discovered: only
top-level declarations (one function-local instance on this tree, costing
nothing today) and only SCREAMING_SNAKE segments. Both drop less, which is the
direction this extractor errs in everywhere.

Two consequences that are not cosmetic, and are not hidden

Removing the false hint exposed two things it had been masking. Neither is
papered over:

  1. check:pm-half-states joins ROOT_WALK_RESIDUE_LEDGER. It sweeps the
    repo root, declares neither marker, and was "derivable by path" only through
    the bogus .changeset hint. Its new row says what it reads instead: lint.yml
    runs the self-test half and never the sweep, and the git ls-files oracle
    belongs to the networked patrol no lint job schedules. The ablation below
    shows the row is measuring something — it reds in the opposite direction
    ("listed but no longer a member") when the fix is reverted.
  2. Two self-test blocks ([finding] dispatch-gates --ran has an explained bucket for CI-measured and pending families but not for the value-bearing class, so a recorded one reads as extra #15115, [finding] dispatch-gates offers check-adr-0087-registration --self-test as the runnable member and files the REAL check as NOT RUNNABLE LOCALLY — but the script's own usage line defaults --base to origin/main #15441) were probing with a changeset path
    because that is what reached a value-bearing family — through this very
    defect. The probe card now names the gate script too, every original
    assertion is unchanged, and a new case pins the removal itself: a changeset
    path alone reaches no value-bearing family any more.
    The derivation this
    change removes is recorded as an assertion rather than lost with the probe.

A third case, check-doc-authoring's bounded over-claim, was restated rather
than deleted: docs/** still claims the exempt docs/plans, but that is now the
declaration's over-claim alone instead of being doubled by the skip list.

Verification

  • dispatch-gates.mjs --self-test: 1478 -> 1493 cases, 0 failures (the
    brief's 1445 was stale; 1478 is the count at 66e68adc6, re-measured).
  • Red first, then green, then ablation. Reverting only the one-line skip, on a
    throwaway worktree at this head — mutation confirmed on disk by blob hash
    before and after, never by the editor's exit code — reds 11 of 1493: the
    fixture case, the multi-line case, all five named-spelling cases, the live
    case, the doc-authoring provenance case, the ledger membership case (in the
    opposite direction: "listed but no longer a member", which is what makes the
    new row a measurement rather than a placeholder) and the changeset control.
    Every positive control stays green through the ablation, which is what makes
    the negatives a measurement. Restored and the worktree removed, with
    git diff HEAD empty and the marker gone.
  • Live: dispatch-gates.mjs .changeset/foo.md --repo objectstack-ai/objectstack
    derives no check:pm-half-states; the same tool on
    scripts/pm/check-half-states.mjs still does, via gate script.
  • Gate family derived with --commands --repo objectstack-ai/objectstack on the
    final file list — 28 commands — and run in full at this head: 28 pass, 0 fail at a7ddb020ac.
    --ran reconciles clean: "28 derived famil(ies) accounted for — 28 run,
    0 NOT-MEASURED", exit 0. Whole-repo pnpm lint through
    scripts/pm/os-verify-lock.sh (slot issue-15753): eslint . --no-inline-config over the whole repo, exit 0, no output. Every exit
    code captured by redirect, never read through a pipe.
  • Cost: one scanSource per declaring file. Measured --commands over this
    file, two runs each: 17.2s baseline, 19.2s unconditional, 18.1s with the
    declaration prefilter that ships — about 5%, paid only by the ~50 files that
    carry an exclusion constant.

skip-changeset: scripts/pm/ publishes nothing from any released package.

Generated by Claude Code


Generated by Claude Code

extractWatchHints scans a gate's whole module body, so a path declared
inside that gate's own exclusion list was admitted as a surface the gate
watches -- the exact inverse of the declaration. A literal whose offset
falls inside a top-level value declaration named for exclusion (NOISE /
SKIP / EXCLUDE / IGNORE, segment-anchored) is now skipped at admission,
read from the scanned gate's own declaration rather than from any list
kept here.

Census over scripts/**: 64 of 3,513 top-level value declarations match;
14 hints move across 6 files; 8 of those change no derivation because
the gate also declares the containing root. The 6 that do were all false
leads, and the pending-changeset projection every card without a
changeset carries drops from 16 families to 12.

Two consequences are recorded rather than hidden: check:pm-half-states
joins ROOT_WALK_RESIDUE_LEDGER (it was placed by path only through the
bogus hint), and the two self-test blocks that probed with a changeset
path now name the gate script too, with the removal itself pinned.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox
@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 5, 2026
@github-actions github-actions Bot added the size/m label Sep 5, 2026

os-steve commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

ACCEPT — in-seat review of PR #15801, head a7ddb020a (skills seat, 2026-09-05T09:0xZ).

Implemented-by: claude/issue-15753-noise-floor-is-not-a-watch-hint (os-dev subagent)
Reviewed-by: session_019RfFHiRCSs3JXLK4cwcfox (skills seat)

Verified in a detached compare worktree at the PR head, three-dot against origin/main, not from the report: one file, scripts/pm/dispatch-gates.mjs, +266 / −14. extractWatchHints now skips a literal whose offset falls inside a top-level, non-callable value declaration of the scanned source whose identifier carries NOISE / SKIP / EXCLUDE / IGNORE on a segment boundary — spans from the file's own topLevelDecls, so a multi-line list is covered whole, with a declaration prefilter so sources without such a name pay nothing. No copy of any noise list is added, no comment-marker convention (the masked body blanks comments; declaration text survives), no new gate file, check-half-states.mjs untouched. The docblock carries the census as ruled: 3,513 top-level value declarations over 230 tracked files, 64 matched, 14 hints moved across 6 files, 8 of them changing no derivation and the 6 that do all false leads; DENY measured and removed because its one match was authorization vocabulary, not a skip list. Seat runs on this head: dispatch-gates.mjs .changeset/foo.md derives no check:pm-half-states while dispatch-gates.mjs scripts/pm/check-half-states.mjs still does through the gate-script path; extractWatchHints(check-half-states.mjs) = the repo slug, the gate's own path and the owner/name placeholder — .changeset gone; governed exit 0. The seat's --self-test run in the compare worktree hit its 280 s cap with every printed case green and no verdict line, so it is recorded as NOT MEASURED to completion locally; the evidence is the dev's 1493 cases pass (1478 on main — the brief's 1445 was stale, corrected by the dev) and CI on a7ddb020a: 34 check runs, 23 success, 11 skipped, none failing, Lint & Repo Gates among the successes. Two consequences are stated rather than hidden: check:pm-half-states joins ROOT_WALK_RESIDUE_LEDGER with its reason (it was placeable by path only through the bogus hint), and the self-test blocks that probed with a changeset path now name the gate script too, with the removal pinned as its own case. The pending-changeset projection every changeset-less card carries drops from 16 families to 12. Triage's ⭐ sentence is in the PR body verbatim, in both the card's English and triage's Chinese. No model names in the diff or the PR body; Fixes #15753 first line; skip-changeset with the size label intact. The doubled attribution footer on the PR body is the platform's own append and is left alone.

The dev's evidence beyond the seat's runs: red first on 66e68adc6 (the fixture and the live gate both yielded .changeset), the ablation reverting only the one-line skip on a throwaway worktree reds 11 of 1493 with every positive control green and the restore proven by git diff HEAD empty; 28 derived families all exit 0 through the lock and reconciled 28 of 28; whole-repo lint through the lock; the prefilter measured (17.2 s → 18.1 s on --commands over this file).

Landing regime: pure code ⇒ ready + auto-merge in this same act (the queue's SQUASH governs whatever method the tool reports); Fixes #15753 closes the card on merge.


Generated by Claude Code

@os-steve
os-steve marked this pull request as ready for review September 5, 2026 09:01
@os-steve
os-steve added this pull request to the merge queue Sep 5, 2026

os-steve commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

Measurement follow-up to the ACCEPT above (skills seat, 2026-09-05T09:1xZ): the seat's own node scripts/pm/dispatch-gates.mjs --self-test on head a7ddb020a, re-run without the 280 s cap in the detached compare worktree, completed at 09:11Z with ✓ dispatch-gates self-test: 1493 cases pass. and exit 0 (about ten minutes wall-clock). The NOT MEASURED reading in the verdict is therefore replaced by a measured one; the verdict itself is unchanged.


Generated by Claude Code

Merged via the queue into main with commit 2de7e53 Sep 5, 2026
36 checks passed
@os-steve
os-steve deleted the claude/issue-15753-noise-floor-is-not-a-watch-hint branch September 5, 2026 09:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

extractWatchHints reads a noise-floor EXCLUSION constant as a watch hint: .changeset derives check:pm-half-states onto every changeset-adding card

2 participants