Uh oh!
There was an error while loading. Please reload this page.
fix(tooling): the error-vocabulary resolver reduces a code held in a ternary or a literal chain (#9568) - #9622
Merged
Conversation
…ternary or a literal chain (#9568) Co-Authored-By: Claude <noreply@anthropic.com>
…olve-ternary-literal-codes
os-zhuang
marked this pull request as ready for review
August 18, 2026 13:32
os-zhuang
enabled auto-merge
August 18, 2026 13:32
Uh oh!
There was an error while loading. Please reload this page.
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#9568
Verified at
3c91ed447(the branch head this description reports on — every count below was re-taken on that tree after theorigin/mainmerge).What changed
check:dispatcher-error-vocabularycould not reduce a code held in a local ternary of string literals.resolveConstantreduced exactly one spelling,const NAME = 'LITERAL', so the live 403 inpackages/metadata-protocol/src/sys-metadata-repository.ts:1265contributed nothing:The resolver is now value-SET valued end to end.
resolveConstantreturns an array, and a newliteralCodeValuesreducer handles a quoted literal, a ternary of reducible branches (nested; the condition is never evaluated), a||/??chain whose every operand reduces, and either wearing parentheses oras const. An identifier limb is handed back to the resolver, so a ternary of two named constants reduces too. Every constant-resolving shape routes through it, soclassconst,objlitconst,assignconstand a helper's argument all gained the same reduction from one change.Two properties are deliberate and pinned by the self-test:
asSemanticCode(a) ?? asSemanticCode(b)(packages/client) reduces to nothing rather than to its literal half. Harvesting the literal limbs of a partly-runtime expression reports a code the program may never stamp while staying silent about the limb it cannot see, which is wrong in both directions at once.nulland are reported, the same rule the workspace half already applied across a package.The one wiring change outside the resolver:
codehelper(the.code = identposition) used to drop the identifier when it was not a parameter of the enclosing declaration. It now offers it toresolveConstantfirst and reports what reduces, underassignconst— the same shape name that position already uses for its constant indirection. An identifier that does not reduce keeps its old treatment exactly: no site, no unresolved finding. That is the header's runtime-value bound, not a silencing.The widening matches: predicted, then observed
A resolver that matches nothing looks exactly like a resolver that passes, so this is measured by name against
origin/main's script, not by an exit code.Resolver level, on the real file (
packages/metadata-protocol/src/sys-metadata-repository.ts:1265):Gate level, repo-wide, registry neutralized. Both trees scan the identical 1840 sources (this diff touches no scanned file);
deriveSiteswas run with an empty registered set so the measurement shows what the RESOLVER reaches rather than what the ledger filters:Exactly +2, both by name, nothing lost and no new unresolved finding. The newly-resolvable set repo-wide is the named specimen and nothing else.
The card's registration premise is falsified, and it changes the outcome
The card states the two codes are unregistered and "both codes stay invisible". They are registered:
NOT_CREATABLEandNOT_OVERRIDABLEsit inERROR_CODE_LEDGER(packages/spec/src/api/error-code-ledger.zod.ts:387-388), added by445ae4debon 2026-08-16, two days before the card was filed. The card's control ("the same probe findsPERMISSION_DENIEDin the union") proved the probe reads the union; it did not test these two.So the gate as CI runs it reports the same 18 sites, all classified, 2 awaiting a ledger entry before and after this change. That is the gate's declared bound working, not blindness: it reports only codes the registered vocabulary does not contain, and these two are in it. The reduction is real and proven above; what it resolves is already registered.
Consequences, stated rather than left to be inferred:
packages/runtime/src/dispatcher-error-vocabulary.tsis untouched. Nothing was classified silently and nothing was filed, because the widened scan surfaced nothing to classify or file.Self-test
--self-testgoes from 81 to 102 assertions (8 shapes unchanged). The new block pins the specimen shape, the reduction in the other constant positions, chains, nesting, a ternary of named constants, a ternary handed to a helper, both splitters' silent hazards (a comparison operator read as a bracket;?./??read as the conditional), and the all-or-nothing bound in both directions.Ablation, predicted before running:
splitTernaryreturnsnull(reduction reverted)codehelperfallback wiring removedassignconst's own regex through a SCREAMING_SNAKE constantRestored from the commit after each leg;
git statusclean, self-test back to 102.Gates
Local, at
3c91ed447:scripts/pm/dispatch-gates.mjsre-derived on the merged ref matches one family for this surface,check:dispatcher-error-vocabulary. The newcheck:single-claim-pathsdeclares only.objectui-sha, which this diff does not touch. CI job names are the authority; the PM reads them.No changeset: the diff is
scripts/only. It publishes nothing, soskip-changesetcarries the reason.Not weakened: no ignore or allowlist entry, no narrowed pattern, no ratchet number moved. The resolver only gets stricter (it now refuses to guess between two declarations) and only gains reach.
Generated by Claude Code
Generated by Claude Code