Skip to content

fix(devx): enumerate and triage the invisible half of the bare-root species - #10906

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-10840-invisible-bare-root-worklist
Aug 22, 2026
Merged

fix(devx): enumerate and triage the invisible half of the bare-root species#10906
os-zhuang merged 2 commits into
mainfrom
claude/issue-10840-invisible-bare-root-worklist

Conversation

@claude

@claudeclaudeBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Fixes#10840

Observation-class card, and the deliverable is the worklist and its triage — not 33 fixes. The card's own words: "What is missing is the worklist" and "this wants triage as a batch, not 33 self-dispatched one-liners."

Every number on the card was stale. Re-measured on this tree.

The card was measured on a7ea3289eb; scripts/pm/dispatch-gates.mjs has moved three times since (#10839, #10873, #10890).

card (a7ea3289eb)this tree
discovered families128131
restricted sweep (constant-name ON)34 triples / 33 undeclared33 triples / 32 undeclared
unrestricted sweep (constant-name OFF)73 pairs across 52 families72 pairs across 44 families

The counts held up; the family spread of the wide sweep did not (52 to 44). One methodological correction accounts for most of the drift, and it matters: invisibility is decided by the extractor itself, by putting each literal back through extractWatchHints alone in a module body and requiring it to build nothing — not by a hand-copied looksPathy. The dotted top-level roots (.claude, .changeset, .github) clear looksPathy on its second branch and were never in this species; a copied separator test sweeps them in and inflates both counts.

Non-vacuity check on the probe: it independently recovers all four landed precedents as already-covered — check:role-word skills (#10114), check:examples-live-imports examples (#10314), and check:doc-authoring / check:doc-formula-expressions (#10662 / #10687).

The triage split, measured

The card predicted the join(...)-path-component kind would dominate. That is true of the wide sweep and false of the restricted one — which is the empirical justification for the constant-name restriction the card was unsure about. Of the 32 undeclared triples, 29 name a root the gate really does walk; only 3 are literals that are merely path components.

But precision is not what decides the remedy. Two structural facts do, and between them they account for 30 of the 32 rows:

  • The instrument can only express a SUBTREE.collapseHint strips globs, so packages/spec/src/data/*-conformance.ts collapses to a path naming nothing. A gate whose population is a file-KIND or FILENAME filter has no honest declaration available — the only spellable claim is the whole subtree, false for most of what it would name. Measured examples: workspace manifests only, 73 of 4903 (1.5%); one named config per child dir, 3 of 238 (1.3%); test files only, 2510 of 4903 (51%).
  • A true declaration on a saturated root stops discriminating.packages/** is already declared wholesale by three families, scripts/** and skills/** by four each. check:error-code-casing really does read 4408 of 4903 files under packages (90%) — the declaration would be true, and would add one more identical line to every card in the repo, restating "run the farm" on the one column whose whole value is precision.

So the useful conclusion is not "here are 33 gates to fix". It is: the #10114/#10314 escape only works when the population is a subtree, and most of this species' populations are not. That is what stops this class being re-found one gate at a time.

Landed: 3 declarations, the only rows clearing precision ≥85% and blast radius ≤300 files

gatedeclaredprecisionvs. the bare root
check:driver-conformancepackages/drivers/**259/291 = 89%259/4903 = 5.3%, a 17× narrower subtree
check:skill-frame-syncskills/**48/50 = 96%
check:skill-compatibilityskills/**49/50 = 98%

Each pins the coupling in its own self-test, derived from the population constant rather than re-spelled, and each pins its refusals by name too — check:driver-conformance refuses both the bare root and CASE_SETS_DIR, check:skill-compatibility refuses all three PACKAGE_ROOTS, following #10314's shape of pinning the refusal so a later author meets an assertion instead of prose.

Verified end to end, both directions: a driver card now names check:driver-conformance and a packages/core card still does not; a skills card now names both skill gates and a packages/spec/src/data card names neither.

Nearest miss, recorded rather than taken: check:engine-double-contract examples at 199/238 = 84%.

The durable home: scripts/pm/bare-root-worklist.mjs

The card asked for the worklist "somewhere durable and re-derivable", and warned that a 73-row ledger would be "an allowlist nobody re-reads rather than a debt list". So the two halves are separated:

  • Derived at runtime from the derivation's own exported predicates — no family, root or word is listed in the file. --wide runs the unrestricted contrast sweep, kept runnable purely so the restriction is justified by measurement, and never triaged.
  • Recorded — one verdict per row (DECLARED-NARROWER / REFUSE-WIDE / REFUSE-UNSPELLABLE), each carrying its measured reason. The self-test pins the two halves together in both directions: a verdict cannot outlive its row (the shrink), and a new row cannot land unjudged. So it cannot rot into an unread allowlist — it fails when the tree moves.

No recognizer was added to dispatch-gates.mjs, per the card and the triage comment. Nothing in the derivation reads this file, and no verdict in it reaches a dispatch prompt. What runs per-PR is only its --self-test. hintCovers' :920 refusal is untouched; the +139084 measurement stands.

Verification

  • 18/18 derived gates green at 77d6bbbe38, including the brand-new check-step-collectors.mjs (fix(ci): collect every self-test verdict in a step, instead of masking after the first failure #10887) which parses the lint.yml block I edited. dispatch-gates --self-test: 506 cases pass.
  • Declared narrowing:check:type-check-debt was skipped locally — it requires a built workspace closure this container lacks. Proven environment-caused, not change-caused: red at the merge base with an identical message, and this change contains no TypeScript. CI builds the closure and runs it for real.
  • Three ablations, predictions written before each run, every mutation proven on disk by marker counts (an editing tool's exit code is not evidence) and every restore proven byte-identical by blob hash:
    • A — retarget the driver declaration to the bare root: gate self-test RED, and the derivation starts naming the gate for packages/core (the fabricated lead). Prediction deviation, recorded: I predicted 2 failing cases; 4 fired, because the bare root also swallows the case-sets path, so both refusal pins are more tightly coupled than expected.
    • B — rename one triage key: RED under STALE. Deviation: FRESH fired too, correctly — renaming a key orphans both a verdict and a row.
    • C — delete one triage entry: RED under FRESH, naming the row.
    • No rebuild leg applies: these are plain .mjs run directly by node, with no dist/ in the resolution path.

skip-changeset: tooling and workflow only, nothing published.


Generated by Claude Code

…pecies
A gate whose population literal carries no separator builds no watch hint at
all -- `looksPathy` drops it before `hintCovers` is consulted -- so it is
unnameable by any dispatch brief and leaves no residue saying so. That half is
invisible to the derivation AND to ESCAPABLE_LITERAL_LEDGER, which #10890's
comment says in the source and names #10840 for.
Adds scripts/pm/bare-root-worklist.mjs: the sweep, derived at runtime from the
derivation's own exported predicates, plus one recorded verdict per row. Its
self-test pins the triage to the tree in both directions -- a verdict cannot
outlive its row, and a new row cannot land unjudged -- and proves the
recogniser both speaks and discriminates.
Lands three per-gate declarations, the only rows clearing precision >= 85% and
blast radius <= 300 files:
check:driver-conformance packages/drivers/** 259/291 (89%)
check:skill-frame-sync skills/** 48/50 (96%)
check:skill-compatibility skills/** 49/50 (98%)
Each pins the coupling in its own self-test, derived from the population
constant rather than re-spelled, and pins its REFUSALS by name too.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DdCnBGcHeufjrq7drTD3wt
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 21, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review August 22, 2026 03:56
@os-zhuang
os-zhuang added this pull request to the merge queueAug 22, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 32550935031 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Console Pin Gate — 失败步骤: Build the Console SPA at the pinned objectui SHA

    ✗ Build failed in 5.03s
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

跨 PR 相同签名(24h,按失败测试文件聚合):

  • ⚠️本次没有可用的聚合签名(日志里没有能解析出测试文件名的 FAIL 行)—— 这不是「没有同签名的其他 PR」,是这一轮没测到。跨 PR 聚合本次不可用,请手工比对其他 PR 的同类评论。
  • ⚠️ 24h 评论账本没读完(超过 5 页仍未读到窗口尽头),所以上面的「不同 PR 数」是下界,不是全量。

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 77 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

Merged via the queue into main with commit f29e897Aug 22, 2026
32 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-10840-invisible-bare-root-worklist branch August 22, 2026 04:25
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cdsize/lskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] the INVISIBLE half of the bare-root species is ~33 gates, not 4 — a population literal with no separator never reaches the hint set at all

2 participants

@os-zhuang@claude