Skip to content

fix(scripts): the subtree-walking gates declare their watch hints, so dispatch-gates names them (#15341) - #15466

Merged
baozhoutao merged 3 commits into
mainfrom
claude/issue-15341-subtree-walk-gate-hints
Sep 4, 2026
Merged

fix(scripts): the subtree-walking gates declare their watch hints, so dispatch-gates names them (#15341)#15466
baozhoutao merged 3 commits into
mainfrom
claude/issue-15341-subtree-walk-gate-hints

Conversation

@claude

@claude claude Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Part of #15341 — three of the sixteen families the card names are repaired here, plus the
one it couples to them. The other eleven are refused by a recorded, measured triage this
branch found by running it
, and the collision needs a ruling rather than a guess. It is
laid out below and reported to the dispatching PM; nothing about it is decided here.

The class

scripts/pm/dispatch-gates.mjs derives a card's gate families from the paths each gate
declares. Families that declare no path literal at all score undetermined for every card:
they reach no dispatch brief and no --commands harvest, while CI runs every one of them
on every pull request. A seat's local green is not evidence, and the red arrives a cycle
later.

Re-measured on this pin before anything was written

The card measured 16 families at cd1f8ee96. Re-derived at f01adfa5c (this branch's
base, carrying #15344's whole-tree bucket, #15415's package-local lane and #15320's
control) the same 16 were still in the residue, plus check:org-identifier — 19 family
keys across 17 gate files (check-declaration-mirrors and check-sdui-manifest each carry
two CI invocations of one file). Each gate's walk was then read off its own source, never
transcribed from the card's seed column, which the card itself prices as a measurement of
literals rather than a declaration. Two readings moved off that column: the
check:meta-type-normalized seed packages is really packages/rest/src, and
check:tenant-chokepoint walks nothing at all — it reads three named files.

What lands

gate population read from source declared A/B
check:org-identifier git ls-files -- examples apps packages (ROOTS) ROOT_DIR_WATCH_HINTS = ['examples/**','apps/**','packages/**'] examples/app-crm/package.json 0 → 1
check:tenant-chokepoint SCAN_FILES — three named driver sources, join()-assembled one segment at a time DECLARED_WATCH_HINTS = those three file paths packages/drivers/driver-sql/src/sql-driver.ts 0 → 1
check-sdui-manifest.mjs (×2 invocations) checkTree() opens sdui.manifest.json, scripts/sdui-manifest.record.json, .objectui-sha ROOT_WATCH_HINTS = those three; the two repo-ROOT files carry /**, since a bare single-segment literal is refused each of the three 0 → 2
check:docs-image-tag-sync both CI call sites run --self-test, entirely inside a mkdtemp fixture tree no-path-population marker stays undetermined, now with a reason
check:publish-smoke-pin CI runs --self-test: in-memory fixtures, no workspace, no network no-path-population marker stays undetermined, now with a reason
check:stall-guard a process RUNNER — reads /proc and a runner temp --report-dir, never the repo no-path-population marker stays undetermined, now with a reason

Every declaration is held against the constant the gate itself reads, in that gate's own
--self-test, so a moved read reds where the read lives. check:org-identifier's
ROOT_WALK_RESIDUE_LEDGER row is deleted in the same commit: the row named this
declaration as its remedy, and a listed family that stops being a member reds the ledger's
live case. check:pm-dispatch-gates is green on the branch, which is that coupling
measured rather than argued.

⛔ No whole-tree marker anywhere. For every gate here it would be false, and #15344's
bucket is explicit that a row on every card is a fabricated lead unless the gate really
reads every file.

Undetermined bucket, base    47 families
Undetermined bucket, branch  43 families      (-4: org-identifier, tenant-chokepoint, sdui-manifest ×2)
declared no-path-population   5 -> 8          (+3: the fixture-only self-tests)

The A/B base leg is more than a sample: at base each of these families had hints: [] and
no marker, so no path could match any of them. The 0 is structural; the 1/2 is
measured per path with --commands.

The eleven that do not land, and why

scripts/pm/bare-root-worklist.mjs carries the recorded triage for exactly this species —
a gate whose population is a bare single-segment word, which builds no hint at all. Its
map is human-decided, per-row measured, and its --self-test runs on every PR. Declaring
the wholesale root for these gates contradicts it, and that self-test caught the first
version of this branch by name:

x self-test: no recorded verdict sits on a row the sweep now finds REACHABLE —
CONTRADICTED: scripts/check-declaration-mirrors.mjs SCRIPTS_DIR scripts
[recorded REFUSE-UNSPELLABLE] · scripts/check-optional-error-sink-contract.mjs
SCAN_ROOTS packages [recorded REFUSE-WIDE] · … 9 rows

Its two verdicts are not deferrals. REFUSE-WIDE means the bare root is TRUE of the walk
and the declaration is refused anyway, because it names the gate on every card under a root
the fleet already declares wholesale — "recall bought at the cost of precision, on the one
column whose whole value is precision". REFUSE-UNSPELLABLE means the population is a
file-KIND filter no subtree glob can spell; the file's header calls that "not a gap to be
fixed later; it is the reason most rows below are refusals". The vocabulary carries a
maintainer ruling (2026-08-26, 「同意」) on where its line sits.

Rows quoting the exact spellings this branch had written:

gate recorded verdict measured precision
check:optional-error-sink REFUSE-WIDE 1898 of 4903 (39%)
check:resume-authority-declared REFUSE-WIDE 39% packages · 68% examples
check:verify-stand-in REFUSE-WIDE 39% packages · 68% examples
check:runner-env-posture REFUSE-UNSPELLABLE bare root 35%; the narrowest LIVE spelling 42% — "no 100%-precise spelling to record"
check-declaration-mirrors.mjs REFUSE-UNSPELLABLE 2 of 261 (0.77%) — scripts/** is TRUE and refused because it names the gate for 261 files to reach 2
check:meta-type-normalized REFUSE-UNSPELLABLE 21 of 154 (14%) — "narrow enough to name, false 6 times in 7"

Five more are the same measured shape and escape the map only because their constant name
does not match its deliberately narrow POPULATION_CONSTANT regex, or because their walk
root was inline rather than a constant: check:init-service-contract,
check:settings-bind-window, check:startup-registry-verdict,
check:wildcard-fallthrough (all four walk every non-test .ts under packages/, the
same 39% shape) and check:live-db-isolation. Declaring those would buy the same recall at
the same measured precision cost, and would do it without a row anyone could later
re-examine — which is worse than the refusal, not better.

So all eleven are withdrawn from this branch and their gates left exactly as they were.
Their populations are not "unread": each is read, and the reading is a refusal that already
exists in the tree.

This is a genuine collision between two lanes, and this branch settles none of it.
The card asks for the declaration across the board; bare-root-worklist refuses it for this class, with
measurements and a ruling behind it. Whoever resolves it is choosing between recall in the
matched column and its precision, fleet-wide — and the map's own contradiction message
names both honest resolutions. The options, costs and a recommendation are in the report on
#15341.

Verification

Exit codes captured before any pipe (cmd > log 2>&1; EXIT=$?); verdict lines quoted from
each gate's own output. All at 565db3e17, the head of this branch.

  • node scripts/pm/dispatch-gates.mjs --self-test and pnpm check:pm-dispatch-gates
    (both under the shared verify lock) — EXIT=0,
    ✓ dispatch-gates self-test: 1402 cases pass. No case weakened; none added.
  • pnpm check:declared-population-liveEXIT=0,
    ✓ check:declared-population-live — 207 of 254 famil(ies) declare a path population, and every one of them reaches this tree's 7495 tracked file(s).
  • pnpm check:watch-hint-literalEXIT=0,
    ✓ check-watch-hint-literal: 52 declaration(s) across 4 rostered name(s) -- ROOT_DIR_WATCH_HINTS 33, ROOT_FILE_WATCH_HINTS 9, ROOT_WATCH_HINTS 3, DECLARED_WATCH_HINTS 7 -- every one an array of quoted literals inside its own statement, every rostered name non-empty, and no unrostered spelling of the idiom in the tree.
  • node scripts/pm/bare-root-worklist.mjs --self-testEXIT=0. This is the gate that
    reds on the withdrawn half, so its green is the load-bearing one on this branch.
  • node scripts/check-self-test-wired.mjs (+ --self-test) — EXIT=0,
    ✓ check-self-test-wired: every one of the 169 script(s) CI runs that ship a --self-test has that self-test run by CI.
  • node scripts/check-self-test-workflow-commands.mjs (+ --self-test) — EXIT=0 both.
  • pnpm check:ratchet-remedy-authorityEXIT=0, 202 scripts swept.
  • pnpm check:nul-bytesEXIT=0, 7485 text files, no raw control bytes. Plus a direct
    control-byte scan of every edited file and of this body.
  • Every edited gate's own --self-test and its normal mode — EXIT=0 throughout:
    check:org-identifier, check:tenant-chokepoint, check-sdui-manifest.mjs (both
    invocations), check:docs-image-tag-sync, check:publish-smoke-pin, check:stall-guard.
  • The derived family for this whole diff —
    node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, 33
    commands, every one run, all 33 EXIT=0.
  • Whole-repo pnpm lint (eslint . --no-inline-config, under the verify lock) —
    EXIT_lint=0, no output.

Not a changeset

scripts/** only — this publishes nothing from any released package, so the
skip-changeset label applies.


🤖 Generated with Claude Code

https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk


Generated by Claude Code

…5341)

Sixteen gate families CI runs declared no path literal at all and walked a
subtree seeded from a runtime constant, so dispatch-gates scored them
`undetermined` for every card: absent from every dispatch brief and every
`--commands` harvest while CI ran them on each pull request.

Each gate now declares the population its own source really reads, under the
rostered watch-hint idiom, with the coupling held in that gate's own self-test.
Three families whose CI invocation is a fixture-only `--self-test` carry the
`no-path-population` marker instead. `check:org-identifier` gains hints and its
now-stale ROOT_WALK_RESIDUE_LEDGER row is deleted in the same commit.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
…worklist (#15341)

`scripts/pm/bare-root-worklist.mjs` carries the recorded, measured triage for
exactly this class, and its `--self-test` reds on a declaration that contradicts
a recorded refusal. Eleven of the sixteen gates the card names are refused there
by name: REFUSE-WIDE where the bare root is TRUE of the walk and refused for
width, REFUSE-UNSPELLABLE where the population is a file-kind filter no subtree
glob can spell. Two of those rows quote percentages for the exact spellings this
branch had declared.

Those eleven declarations are withdrawn and their gates left as they were. What
stays is the half neither map refuses: two enumerated FILE populations at 100%
precision, three families whose CI invocation is a fixture-only self-test and
which now say so, and check:org-identifier, whose ROOT_WALK_RESIDUE_LEDGER row
names this declaration as its remedy.

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

claude Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

ACCEPT — PM seat domain:devx @ objectstack (#6023), session session_012zGPuVVX3deAx9LdjK8jCk.

Reviewed against the three-dot diff origin/main...claude/issue-15341-subtree-walk-gate-hints (merge base ee32e1cb8, head 565db3e17): 7 files, +213/−13, matching the PR file list.

  • Three families gain a declaration read off their own source, each with a coupling self-test in both directions (declared ⊆ read, read ⊆ declared, and the refused spellings pinned): check-org-identifier.mjs (ROOT_DIR_WATCH_HINTS derived from ROOTS, battery floor 1 → 2, four cases), check-tenant-chokepoint.mjs (DECLARED_WATCH_HINTS, file-exact, no glob widening), check-sdui-manifest.mjs (READ_PATHS now the single source for checkTree's three opens; ROOT_WATCH_HINTS with the /** suffix on the two repo-root files, since a bare single-segment literal is refused).
  • Three families carry the no-path-population marker with the reason read from their CI invocation (--self-test inside a mkdtemp fixture / a process runner / a release-only packer).
  • scripts/pm/dispatch-gates.mjs: the ROOT_WALK_RESIDUE_LEDGER row for check:org-identifier is deleted in the same commit its named remedy lands — the coupling the row itself asked for. No self-test case is touched (dev-reported 1402/1402; CI step 31 is the arbiter).
  • Residue 47 → 43 undetermined, declared no-path-population 5 → 8; A/B on one card path per repaired family 0 → ≥1, with the base zeros structural (hints: [], no marker).
  • The eleven families the branch withdrew are NOT edited: bare-root-worklist.mjs's map refuses them by measured row, and its --self-test caught the first draft. Right call — a dev seat does not delete rows from a maintainer-ruled, shrink-only map.
  • Hot-file scan: fix(scripts): the subtree-walking gates declare their watch hints, so dispatch-gates names them (#15341) #15466 is the only open PR on dispatch-gates.mjs; check-self-test-workflow-commands walks only the root scripts/, so the one package-local gate CI self-tests is in no population and its output is never scanned #15414 stays queued behind it.

Part of #15341: the card stays open and moves to the decision box on the A/B/C/D question (ruling note on the card). Flipping ready and arming auto-merge now.


Generated by Claude Code

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.

2 participants