Skip to content

Commit 3800e42

Browse files
claude[bot]claude
andauthored
fix(scripts,runtime): the code-helper stamp shape reaches the object-literal position (#13477)
* wip: objlithelper shape + discharge list * feat(scripts): widen the code-helper shape to the object-literal stamp position * docs(changeset): record the object-literal code-helper position widening --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 4ca7ccf commit 3800e42

3 files changed

Lines changed: 1215 additions & 192 deletions

File tree

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
---
2+
"@objectstack/runtime": patch
3+
---
4+
5+
fix(scripts,runtime): the code-helper stamp shape reaches the OBJECT-LITERAL position (#13233)
6+
7+
`check:dispatcher-error-vocabulary`'s `codehelper` shape was anchored on an
8+
assignment — `.code = ident` — so the equally ordinary helper that builds an
9+
object literal was invisible to it:
10+
11+
```ts
12+
function postureError(code: string, message: string) {
13+
return { severity: 'error', code, message }; // <- nothing matched
14+
}
15+
```
16+
17+
No pattern in that gate or in `check:error-code-casing` fired there. `objlit`
18+
needs a quote, `objlitconst` needs a SCREAMING_SNAKE identifier (the
19+
conventional parameter name is `code`), `objlittemplate` needs backticks. So
20+
there was no site **and** no unresolved entry — the one way the gate's own
21+
"reported, never dropped" bound can fail without anything saying so. The new
22+
`objlithelper` shape closes it, guarded structurally twice over: the innermost
23+
enclosing bracket at the `code` token must be a `{` (which is what separates an
24+
object literal from the argument list `f(a, code, b)` and the array
25+
`[a, code]`), and the identifier must be a parameter of the enclosing
26+
declaration. Together with the class-method declaration form, the live instance
27+
that motivated the enquiry — `Parser#error` in `@objectstack/sdui-parser` — is
28+
now reached.
29+
30+
Measured on `packages/**` non-test source, through the gate's own derivation
31+
rather than a separate instrument: **13 helpers · 117 newly reached in-file call
32+
sites · 29 new verdict rows · 5 helpers that reduce to nothing · 0 unregistered
33+
wire codes hiding**. All 29 rows are one genre — ADR-0114 D2 `FieldErrorCode`
34+
members stamped by four validation helpers whose `code` parameter is *typed* to
35+
that closed enum, landing at `ApiError.details.fields[].code` and never at
36+
`error.code` (ADR-0112 D6). They are declared `foreign-vocabulary`.
37+
38+
`@objectstack/runtime` carries the declaration half. `UNREGISTERED_CODE_SITES`
39+
gains those 29 rows, and a second declared list `UNRESOLVED_CODE_HELPERS`
40+
classifies the five helpers the scan can see but cannot read. That list is the
41+
answer to the blocker this change had to clear: an `unresolved` entry is pushed
42+
unconditionally and no row discharged it, so every one of the five would have
43+
been a **red gate with no verdict available**. A `reason: 'helper'` entry is now
44+
dischargeable by a row carrying a door, a verdict and its evidence, reconciled
45+
in both directions like any site row. The restriction is the argument: every
46+
other unresolved reason names a remedy the author can carry out ("resolve the
47+
constant", "spell it `const`"), and a row there would buy an exemption from
48+
work that is possible — a helper whose callers live in another package, pass a
49+
vocabulary declared out of the gate's population, or pass a genuine runtime
50+
value has no such remedy.
51+
52+
Internal to the package (`dispatcher-error-vocabulary.ts` is not re-exported
53+
from the package index), so no published surface changes and no runtime
54+
behaviour moves — the gate's population does.
55+
56+
⚠️ Recorded rather than smoothed over: this position's precision is measurably
57+
lower than the assignment position's. `.code = ident` needs a property named
58+
`code` on a value being mutated; `{ code }` is how any record carries any field
59+
called `code`. Two of the thirteen helpers reached carry no error code at all —
60+
an SMS one-time password and a YAML fence body — and no sibling-key test
61+
separates them (the obvious candidate, requiring a `message` sibling, drops 25
62+
of the 29 rows with them). Both are classified rather than filtered out.

0 commit comments

Comments
 (0)