Skip to content

docs(tooling): record the fifth casing-gate recognizer, and who owns a runtime-limbed chain - #10898

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-10762-delegation-map-fallback-spelling
Aug 21, 2026
Merged

docs(tooling): record the fifth casing-gate recognizer, and who owns a runtime-limbed chain#10898
os-zhuang merged 1 commit into
mainfrom
claude/issue-10762-delegation-map-fallback-spelling

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes#10762. Verified at 278c9c6856; base origin/main = 9faa9bc51d.

One file, comment-only: scripts/check-dispatcher-error-vocabulary.mjs. No changeset — CI-internal gate tooling, publishes nothing (skip-changeset, by pr-automation.yml's own prescription: "this PR edits a CI-internal script" is the textbook case).

The card's falsification test, run first and last

The card's acceptance criterion is that nothing moves. Captured before the edit and again after, redirect-then-capture so no pipe eats the exit code:

$ node scripts/check-dispatcher-error-vocabulary.mjs --self-test EXIT=0
check-dispatcher-error-vocabulary --self-test: 8 shapes + 102 assertions OK (vocabulary + #9098 door typing)
$ node scripts/check-dispatcher-error-vocabulary.mjs EXIT=0
check-dispatcher-error-vocabulary: OK — 21 unregistered code-stamping site(s), all classified; 1 awaiting a ledger entry (#8846).
scope: 1883 non-test source files under packages/; 291 registered codes (241 ledger + 50 standard); 21 unregistered code-stamping site(s) found; 21 classified.

diff of the captured before/after files is empty for both — not "the same numbers", byte-identical output. No self-test case moved, so the delegation is what the comments claim.

Comment-only proven two ways rather than asserted: no added or removed line in the diff is a non-comment line, and the file's non-comment byte stream is md5-identical to HEAD (2e9cfa29e4d03764361b277839eff427 both sides).

The enumerations were TWO, not three

The card says three. Swept for them rather than trusting the count — QUOTED, code === 'x', code?: 'x', .code = 'x', and every delegat/owns mention in the file. There are exactly two verbatim enumerations of that gate's recognizers:

linesite
90–92the header's [#9460] declared bound
802–804the jsdoc on keep() — the card calls it isMine; the function is named keep

Both now carry the fifth. Nothing else in the file enumerates the recognizer set: the neighbouring delegation notes (628, 1323) speak about anchoring on the token code and stay accurate after #10760, since the new pattern anchors on the token too.

The fifth spelling, in the owning gate's words

Read off check-error-code-casing.mjs rather than from the card, per the card's own instruction that the owning gate is the truth:

// [#10658] the OUR-DEFAULT slot of a fallback chain:// code: parsed?.code || 'verify_domain_failed'// err.code = e?.code ?? 'lookup_failed'{name: 'fallback',re: /(?:\bcode\s*\??\s*:|\.code\s*=(?!=))\s*(?['"`])[\w$.?!()[\]|&\s]{0,80}?(?:\|\||\?\?)\s*'([a-z][a-z0-9_]*)'/g}

So it is written into both enumerations as code: parsed?.code || 'x' / .code = e?.code ?? 'x' — both positions and both operators, which the card's one-form paraphrase (code: parsed?.code || 'x') leaves half-stated.

One discrepancy with the card, resolved in the gates' favour

The card asks for a clause saying a runtime-limbed chain "reduces to nothing here and is therefore delegated, not dropped — owned by check:error-code-casing rather than by nobody". Measured against both gates' own exported entry points (findViolations, deriveSites), that is true at one position and false at the other, so writing it unqualified would install into the delegation map the exact "two gates, each assuming the other" error the map exists to prevent:

shapethis gatecheck:error-code-casing
stamp site { code: p?.code || 'stamp_lower_failed' }no site1 (fallback)
stamp site err.code = p?.code || 'stamp_lower_failed'no site1 (fallback)
local init const code = p?.code || 'local_lower_failed'no site, no unresolved0
control — local init const code = flag ? 'TERN_A' : 'TERN_B'2 sites (assignconst)n/a

The control row is what makes the zeros readable rather than a broken probe: this gate does reduce and report a local initializer when every limb is a literal (#9568), and rows 1–2 are the matching live control on the casing side.

Two facts follow, and the clause now states both:

  • At the stamp site there is no reduction at all.objlit/assign need the quote immediately, so this gate never had a shape there — nothing was "reduced to nothing". Since fix(tooling): check-error-code-casing — reach our default through an ||/?? fallback chain, and stop printing an unqualified clean sweep #10760 that literal is read by the casing gate, so the shape is genuinely delegated. This is the position the two live SSO codes in register-sso-provider.ts occupy (checked on disk: { code: parsed?.code || 'request_domain_verification_failed', … }, no local, no resolveConstant), so the card's exemplar belongs to this row, not to the all-or-nothing rule it is filed under.
  • In a local's initializer it is owned by nobody. The all-or-nothing rule declines it here — correctly, and this PR does not touch that, per the card — and the casing gate's fallback pattern anchors on code:/code?:/.code =, so const code = is out of its reach too. A typed local does not escape either: const code: string = puts an = in the gap class, which the class refuses.

The second row is a behaviour question in a different gate, so it is not addressed here: filed unassigned as #10897, with the measurements above and a tree sweep putting its live extent at 0 (1885 non-test files under packages/, comments masked with the gates' own maskComments). Like this card, it understates coverage and has no victim today.

The edit, proven on disk

Anchored marker counts, each asserted to hit exactly once before writing (the script aborts on any other count rather than making a partial write) and re-counted after:

markerbeforeafter
header enumeration anchor10 (replaced)
keep() enumeration anchor10 (replaced)
[#10760] code: parsed?.code || 'x'02
[#10762] WHO owns a runtime-limbed chain01
the #9568 ALL-OR-NOTHING line (must survive)11

Gates

node scripts/pm/dispatch-gates.mjs with no paths, at 278c9c6856, clean tree — it derived the change set from the merge base as 1 path and named six families. All six run green:

gateverdict lineexit
check:dispatcher-error-vocabulary8 shapes + 102 assertions OK · OK — 21 unregistered code-stamping site(s), all classified0
check:cross-package-test-inputsAll 104 self-test cases passed. · OK: 13 package(s) read outside themselves, all declared0
check:entry-guard129 scripts/ file(s) — every entry guard goes through invoked-as.mjs; 87 export bindings, 77 of them inert on import0
check:parse-guardself-test + sweep clean0
check:nul-bytesOK (scanned 6298 text file(s) -- … no raw ASCII control bytes)0
check-ci-filter-parity.mjsOK: all 82 declared cross-package glob(s) (71 unique) are covered0

Declared narrowing, so the report is not read as more than it is: no pnpm install was run in this worktree. Both gates this card concerns import only node builtins plus two local .mjs, so they need none. The one derived family that does need a dependency (check-ci-filter-parity wants yaml) was run against a single temporary symlink to an already-resolved yaml@2.9.0, removed immediately after; a broken link would have errored loudly rather than passing quietly, so its green is a real run.

Generated by Claude Code


Generated by Claude Code

… runtime-limbed chain
`scripts/check-dispatcher-error-vocabulary.mjs` documents its delegation
contract with `check:error-code-casing` by enumerating that gate's
recognizers. PR #10760 added a fifth — the OUR-DEFAULT slot of a `||`/`??`
fallback chain — and the enumerations were left short by one.
Comment-only. Both enumerations now carry the fifth spelling as the owning
gate spells it, and the #9568 ALL-OR-NOTHING bound now records who owns a
runtime-limbed chain, split by position because the two answers differ:
delegated to `check:error-code-casing` at the stamp site, owned by nobody in
a local's initializer (filed as #10897).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_c970724d-303c-5614-9d20-a3f92205cfad
@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 21, 2026 16:32
@os-zhuang
os-zhuang added this pull request to the merge queueAug 21, 2026
Merged via the queue into main with commit 409077eAug 21, 2026
32 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-10762-delegation-map-fallback-spelling branch August 21, 2026 16:47
@github-actions

Copy link
Copy Markdown
Contributor

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

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

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

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

    ✗ Build failed in 4.71s
    

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

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

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

历史信号:

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

分诊清单:

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

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

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@os-zhuang@claude