Uh oh!
There was an error while loading. Please reload this page.
fix(devx): read the our-default slot in a code local's initializer too - #10914
Merged
Conversation
`check-error-code-casing`'s fifth recognizer (#10760) anchors on the POSITION token — `code:` / `code?:` / `.code =` — so it reaches an `||`/`??` fallback chain only where the chain sits AT the stamp site. The identical chain one indirection earlier, in a local's initializer, matched nothing: const code = parsed?.code || 'lower_thing'; // our authored default err.code = code; `const code =` is neither spelling, and a type annotation does not rescue it: `const code: string = …` does match `code:`, but then the gap has to cross an `=`, which that character class refuses on purpose. Nothing else saw it either. `check:dispatcher-error-vocabulary` reaches the local (`err.code = code` is its `codehelper`/`assignconst` shape) but its `resolveConstant` reduction is ALL-OR-NOTHING by design (#9568): one runtime limb reduces the whole chain to nothing, because half an expression's values is a finding wrong in both directions at once. That bound is deliberate and is untouched here — its verdict line is byte-identical before and after. So the literal half is this gate's, on exactly the reasoning #10760 published for the stamp site: the capture is still only ever a STRING LITERAL, and a literal in our source is by construction the default WE author. Where we write the chain does not change whose default it is; the asymmetry was an artifact of where the recognizer anchored, not a decision anyone took. Adds a sixth recognizer, `local-fallback`, with the annotation gap spelled `[^=;\n]` (the same spelling `classfield` uses in the sibling gate) and the fifth pattern's own gap class and tail verbatim. The delegation runs the OTHER way for an ALL-literal initializer — a bare literal, a ternary, a chain — which IS reducible and stays the dispatcher gate's site under `assignconst`, lowercase included; the quote refusal keeps this pattern off those, so one literal never gets two reporters. Also updates the three delegation enumerations in `check-dispatcher-error-vocabulary.mjs` that #10762 had just corrected: they recorded this position as owned by NOBODY and named #10897 as the open half. Comment-only there; 8 shapes + 102 assertions and the full-run verdict all unchanged. Fixes#10897 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_c970724d-303c-5614-9d20-a3f92205cfad
os-zhuang
marked this pull request as ready for review
August 22, 2026 03:56
Uh oh!
There was an error while loading. Please reload this page.
Contributor
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 32550887524 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes#10897
check-error-code-casing's fifth recognizer (#10760) anchors on the positiontoken —
code:/code?:/.code =— so it reaches an||/??fallbackchain only where the chain sits at the stamp site. The identical chain one
indirection earlier matched nothing:
A type annotation does not rescue it either:
const code: string = ...doesmatch
code:, but the gap then has to cross an=, which that character classrefuses on purpose (refusing
=is part of what stops a match leaping out ofone property's value into a neighbour's). Verified both, below.
The table, re-derived on today's
origin/main(58563be069)Driving both gates' own exported entry points (
findViolations,deriveSites).Every cell reproduces the card's measurement at
9faa9bc51d— nothing moved.check:dispatcher-error-vocabulary{ code: p?.code || 'stamp_lower_failed' }fallback)fallback)err.code = p?.code || 'stamp_lower_failed'fallback)fallback)const code = p?.code || 'local_lower_failed'local-fallback)const code: string = p?.code || 'typed_lower_failed'local-fallback)const code = p?.code || 'LOCAL_UPPER_FAILED'const code = flag ? 'TERN_A' : 'TERN_B'assignconst)const code = 'local_direct_failed'assignconst)const code = flag ? 'tern_lower_a' : 'tern_lower_b'assignconst)const code = 'chain_lower_a' || 'chain_lower_b'assignconst)The control row is what makes the zeros readable rather than a broken probe.
The last three rows are new here and they set the boundary in the other
direction: an all-literal initializer — a bare literal, a ternary, a chain —
IS reducible under #9568, so it stays the dispatcher gate's site under
assignconst, lowercase included. Only the runtime-limbed chain fellthrough both gates. The dispatcher column is identical in every row before and
after this PR.
The fix
A sixth recognizer,
local-fallback. The annotation gap is spelled[^=;\n]— the spelling
check-dispatcher-error-vocabulary's ownclassfieldalreadyuses for this job — and everything after the
=is the fifth pattern's gapclass and tail verbatim: same operand alphabet, same 80-char runaway bound, same
lowercase value space. The quote refusal (the lookahead plus a gap class that
admits no quote) keeps it off the head of an all-literal chain, so one literal
never gets two reporters.
The reasoning is #10760's own, applied one indirection earlier: the capture is
still only ever a string literal, and a literal in our source is by
construction the default we author — the operand ADR-0112 D1 governs. A vendor
code passing through is a runtime value with no literal to capture. Where we
write the chain does not change whose default it is.
The boundary that was NOT touched
check:dispatcher-error-vocabulary's silence on a runtime-limbed chain iscorrect and is untouched. Its ALL-OR-NOTHING reduction (#9568) is deliberate:
harvesting the literal half would report a code the program may never stamp
while staying silent about the limb it cannot see. Its verdict line is
byte-identical before and after:
The only edit in that file is comment-only: the three delegation
enumerations #10762 had just corrected recorded this position as owned by
NOBODY and named #10897 as the open half. Leaving them would have recreated the
exact drift #10762 closed. Named here rather than slipped in.
Blast radius across
packages/**— measured, with two positive controlsSwept 4393 non-
.d.ts.ts/.tsxfiles, comments masked with the gates' ownmaskComments:code-named local declaration at allSo the widened recognizer newly matches nothing in the tree — and that zero
comes from an instrument shown to produce 5 and 47. The 5 any-case matches, each
judged:
packages/formula/src/template-engine.ts:75|| 'USD'— a currency code, notan error code, and out of the value space regardless.
packages/metadata-fs/src/repository.ts:655?? 'UNKNOWN'— a Node errnofallback; SCREAMING, compliant.
packages/plugins/plugin-auth/src/admin-user-endpoints.ts:405andset-initial-password.ts:87?? 'INTERNAL_ERROR'— SCREAMING, registered.packages/rest/src/import-runner.ts:293?? 'IMPORT_ROW_FAILED'— SCREAMING,and that file is already in
EXEMPT_FILES(D6).Every one of them is a genuine authored default, and every one is compliant
today. The gate's real-tree verdict is byte-identical before and after:
no unlisted lowercase error codes in 4393 scanned file(s) (ADR-0112).Self-test: 29 recognizer cases to 46, both directions
New positives: untyped local, typed local,
let, fallback at the end of achain — plus both stamp-site spellings re-pinned as the pair halves that must
not regress. New negatives: a SCREAMING default; a vendor code with no literal;
codeName(a local whose name merely starts withcode); a neighbour's localfallback; the three all-literal shapes that stay the dispatcher gate's; a case
proving the annotation gap cannot leap into the next statement; and NOT_CODES,
D6 and
adr0112-ok:still winning through the new shape.Every case carries the error-shaped neighbour the filters require, negatives
included — a zero produced by a missing neighbour would test nothing about the
recognizer. Each negative was then checked as a live probe: flipping the single
property under test takes it 0 to 1, all ten of them.
Ablation — prediction written before the run
Both legs mutated on disk and proven by marker counts, never by an editing
tool's exit code; each restore leg proven by
git diff --quiet.Leg 1 — delete the
local-fallbackrecognizer. Markername: 'local-fallback'1 to 0. Predicted: self-test red, exit 1, exactly 4failures, the four positive local cases; stamp-site halves and all negatives
green. Observed: exactly that. The real tree stayed green under the
mutation — which is precisely why the real tree cannot be the control here and
the fixture self-test has to be.
Leg 2 — admit a quote to the
local-fallbackgap class only(
&\s]{0,80}?to&\s']{0,80}?, marker 1/0 to 0/1). Predicted: exit 1,exactly 1 failure — "an all-literal chain reduces too, and stays the dispatcher
gate's". Observed: exactly that, proving the delegation boundary is enforced
by the pattern and pinned by that case rather than merely asserted in a comment.
Restore after each:
git diff --quietclean, markers back to 1 and 1/0,self-test 46+4 green.
Gates run locally at
23e86a219bDerived with
node scripts/pm/dispatch-gates.mjsfrom the real merge-basechangeset (2 paths), not from a hand-written list — all 7 matched families:
Exit codes captured before any pipe; each verdict quoted is the gate's own
printed line.
Coordination
Checked immediately before pushing, against all 11 open PRs:
either file here — it edits
check-driver-conformance.mjs,check-skill-*.mjsandpm/bare-root-worklist.mjs. The warned-about overlapdid not materialise.
register-sso-provideremits two lowercase wire-visible error codes (request_domain_verification_failed,verify_domain_failed) — ADR-0112 violation invisible to the casing gate #10716 SSO rename) does touchscripts/check-error-code-casing.mjs, but a different region: it emptiesKNOWN_LOWERCASE_CODESand parameterisespartitionKnown, roughly 20 linesbelow where this PR's recognizer sits, and adds its self-test cases after this
PR's. No textual conflict, and no semantic one either — this recognizer adds
no registry entries (it matches 0 live sites), and after that rename the SSO
defaults are SCREAMING and out of this pattern's value space.
Changeset
skip-changeset: this PR touches only two CI-internal gate scripts andpublishes nothing, which
pr-automation.ymlcalls the textbook case for thelabel in its own words.
Refs #10762 (the delegation map) - #10658 / #10760 (the widening) - #9568 (the
ALL-OR-NOTHING reduction) - ADR-0112 D1
Generated by Claude Code
Generated by Claude Code