Repository navigation
Carry overrideNotice on a dispatch envelope at the seam, not on ActionDef (#5611) - #5644
Merged
Merged
Conversation
… inventory `overrideNotice` was produced, read, and declared nowhere. `DeclaredActionsBar` composes the dispatch as `any` and hands it over through a `dispatch as ActionDef` cast; `useConsoleActionRuntime`'s param-collection handler took `action?: any`. The key therefore crossed the entire producer/reader seam without one declaration, and `warnOnUnknownActionKeys` told the author, in dev, that a key "no reader recognizes" was present — on every privileged-override dispatch, about a key two files read. Same shape objectstack#4075 step 3 promoted `description` out of, and for the stated reason: authorable-or-host-composed, forwarded, read, and undeclared. Declaring it widens nothing — the key is already accepted at runtime through that cast; this only makes the type layer say so. Steps 1 and 2 move together because `actionKeys.pin.test.ts` re-derives `ACTION_DEF_KEYS` from the interface's AST: either half alone turns the pin red. Documented at the declaration as objectui dialect with no spec counterpart, and in a stronger sense than `description` — that key at least derives from `@object-ui/types`' renderer view, while this one is not authorable metadata at all. Hand-typed `string` precisely because there is no spec field to derive FROM. objectui#5178's ruling that it must NOT be folded into `description` is restated at the declaration, since that is what makes a separate key correct rather than redundant. Co-authored-by: Claude <noreply@anthropic.com>
… any` to `ActionDef` The payoff of the declaration in the previous commit, and the half objectui#4282 measured and backed out rather than casting to compile. With `overrideNotice` declared, the annotation is a one-token change on each handler — `ActionDef` was already imported by both files, so no new import and no barrel export. This is what makes the compiler cover these two files at all. Every other read in both handlers (`objectName`, `params`, `name`, `label`, `description`) was already a declared field; `overrideNotice` was the only key holding the `any` in place. Line numbers re-derived on the current tip rather than taken from the card: `useConsoleActionRuntime.tsx:196` and `RecordDetailView.tsx:500`, both unmoved. The rejected alternative stays rejected: casting the `overrideNotice` read at its use site would have swapped a visible `any` for an invisible cast and re-hidden the undeclared key. Co-authored-by: Claude <noreply@anthropic.com>
… narrowing Co-authored-by: Claude <noreply@anthropic.com>
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
… the seam
Reworks this branch to the ruled narrow-B shape (maintainer ruling 2026-08-22).
`packages/core` returns to base: the published `ActionDef` stays closed and
`ACTION_DEF_KEYS` gains nothing, because `overrideNotice` is the first action key
no author supplies — declaring it on the authored-metadata mirror would make an
unenforced key legally writable in metadata.
Instead the key is declared at the dispatch seam, in the one package where its
producer (`DeclaredActionsBar`) and its reader (`useConsoleActionRuntime`) both
live: `ConsoleActionDispatch = ActionDef & { overrideNotice?: string }`.
- `DeclaredActionsBar` composes the dispatch AS that type; the
`dispatch as ActionDef` cast is gone and `execute(dispatch)` needs none.
- Both param-collection handlers narrow off `action?: any` to the envelope,
which is what puts those functions under the compiler at all.
- A compiler-driven pin compiles the same seven cases against BOTH types and
asserts the delta between them is exactly `overrideNotice` — so dropping the
key from the envelope and declaring it on `ActionDef` each turn it red.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012u2pRjcqAYtoEjgr3wwhnK
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
overrideNotice on ActionDef, then narrow both param handlers' action?: anyoverrideNotice on a dispatch envelope at the seam, not on ActionDef (#5611)
…ops crying wolf `ActionRunner.execute` classifies the object it was HANDED, and a console host hands it a DISPATCH rather than a stored metadata row. Every list feeding `KNOWN_ACTION_KEYS` restated an AUTHORED surface, so `overrideNotice` — composed by `DeclaredActionsBar` on the privileged-override branch and read by both param-collection handlers — was reported as a key "no reader recognizes", with a prescription to promote it to an explicit field on `ActionDef`. That is the one shape the 2026-08-22 ruling forbids for this key, so acting on the diagnostic walked an author into a rejected design as well as a red pin. The path it fires on is the branch that finalises an approval over approvers who have not acted. Adds `HOST_DISPATCH_ACTION_KEYS` (sole member `overrideNotice`) and unions it into `KNOWN_ACTION_KEYS` as its fourth input — the first that is not an authored-surface restatement. Documented at the declaration in the style of the in-file precedent `HOST_STASHED_PARAM_KEYS`, which models the same category one level down, inside `params`. The authored surface does not move, and the pins say so by name: `overrideNotice` is not declared on `ActionDef`, not in `ACTION_DEF_KEYS`, not in `SPEC_ACTION_KEYS`, asserted off the interface's own AST. The new list's contents are pinned exactly, because the set is the ruling's scope and a second member must not be able to arrive quietly. The declaration's docblock says outright that it claims no derivation from `@objectstack/spec`. A first draft called the other three lists "mirrors" of the surfaces they restate, and `check:spec-symbols` read that as a spec-alignment claim standing behind this symbol with nothing under it — the gate is right, so the wording states the negative instead of implying the positive. Measured on the exact dispatch the bar composes: `KNOWN_ACTION_KEYS.has` false to true, unknown `['overrideNotice']` to `[]`, warn count 1 to 0, the key set grown by exactly one member with none removed, and a real typo riding the same dispatch still warned about — naming `targt` alone. Part of #5611
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
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 free
to 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.
Part of #5611
Reworked to the ruled narrow-B shape (maintainer ruling 2026-08-22), then completed with item 4 under the Option-A ruling of 2026-08-22 ~17:26Z.
overrideNoticeis carried on a host-composed envelope type at the dispatch seam, and the dev-mode warning that called it unknown now knows about it. The publishedActionDefstill declares nothing new andACTION_DEF_KEYSstill gains nothing — that prohibition is untouched; what item 4 adds topackages/coreis a separate host-dispatch key list, detailed in its own section at the bottom. The earlier+32/+6onActionRunner.ts/actionKeys.tsare gone; the mechanical proof that they are gone is the byte-identicaldistbelow.The ruled shape, item by item
@object-ui/app-shellConsoleActionDispatch—src/consoleActionDispatch.tsdispatch as ActionDefcastDeclaredActionsBar.tsx— the dispatch is composed AS the envelope,execute(dispatch)needs no castuseConsoleActionRuntime.tsxandRecordDetailView.tsxwarnOnUnknownActionKeysfalse flagHOST_DISPATCH_ACTION_KEYSinpackages/core/src/actions/actionKeys.ts, unioned intoKNOWN_ACTION_KEYS, pinned. Warn count 1 → 0. See the item-4 section at the bottomAll four items are now complete and verified. Item 4 was escalated as a ruling-level question, ruled Option A, and implemented in a second round; the escalation section below is kept as the record of how that decision was reached, and the section at the bottom is what actually landed.
1. The envelope
packages/app-shell/src/consoleActionDispatch.ts(new):Why that home. It belongs to neither the producer nor the reader — it is the contract between them — so it sits at the package root beside the other package-wide contracts (
types.ts,urlParams.ts,runtime-config.ts) rather than insideviews/orhooks/. It is deliberately not re-exported fromsrc/index.ts:@object-ui/app-shell'sexportsmap has exactly one entry pointing atdist/index.d.ts, so keeping the type off the barrel means this card adds no published surface in any package.@object-ui/core's surface does not move either (byte-identical, below), so the authored-metadata surface is exactly as strict as it was onmain— writingoverrideNoticein anActionDefliteral is still a compile error.The docblock carries the ruling's own grounds, so the next reader finds the reasoning rather than re-deriving it.
2 + 3. The cast is gone, and both handlers come off
anyBefore, the key crossed the whole seam undeclared:
const dispatch: any = …→execute(dispatch as ActionDef)on one side,action?: anyon the other. Producer and reader could disagree in silence — and no existing test could see it, because each side's suite spells the key itself (DeclaredActionsBar.overrideAffordance.test.tsxreadsdispatch.overrideNoticeoff its own spy;useConsoleActionRuntime.overrideNotice.test.tsxhands in a literal). Rename it on one side and the notice stops appearing, all green.RecordDetailView's handler does not read the key. It still takes the envelope, per the ruling — so the two handlers on this seam cannot drift from each other, and a reader added there later has a declaration instead of a reach for a cast. There is no sequencing cost: #5610 landed 2026-08-21T18:37:09Z, so the deadtitlelimb is already gone from that handler and this file's change is the single annotation.4. The
warnOnUnknownActionKeysfalse flag — the escalation (historical; RULED and implemented, see the bottom)The defect is real and reproduced at base (built
@object-ui/coreatf1c27f037, driving the exact dispatchDeclaredActionsBarcomposes on the override branch):The ruling asks for a seam-level known-key, not an
ACTION_DEF_KEYSentry. There is no mechanism for one today, and the fences on this rework forbid creating it. Enumerated mechanically rather than asserted:packages/core/src/actions/ActionRunner.ts:919, first statement ofexecute(). No host code stands between the producer and it.KNOWN_ACTION_KEYStakes no seam contribution —actionKeys.ts:297builds it once at module scope from three core-owned lists (ACTION_DEF_KEYS,SPEC_ACTION_KEYS,NAVIGATION_ALIAS_KEYS), andclassifyActionKeys:313is its only reader. Grepping@object-ui/core/srcfor a registration API (register*,addKnownKey, anything naming the set) returns those two lines and nothing else.ActionRunner's host-facing configuration surface is ten members —setConfirmHandler,setToastHandler,setModalHandler,setNavigationHandler,setParamCollectionHandler,setResultDialogHandler,registerHandler,unregisterHandler,registerScript,unregisterScript. None touches the key set.So any fix is one of: (a) a fourth, host-dispatch key list in
packages/core/src/actions/actionKeys.tsunioned intoKNOWN_ACTION_KEYS(not anACTION_DEF_KEYSentry, not a declaration onActionDef— there is in-file precedent inHOST_STASHED_PARAM_KEYS, which already names host-stashed keys and citesDeclaredActionsBarby name); (b) a core registration API the seam calls at module init, which is the literal "seam-level" reading but adds mutable global state and an init-order hazard; (c) mutating the exportedReadonlySetfrom app-shell through anas Set<string>cast — which would reintroduce exactly the invisible cast this card exists to delete, so it is listed only to be rejected; (d) defer to a follow-up card.All of (a)–(c) touch
packages/core, which this rework is fenced against. Recommendation is (a), but that is a decision, not a dev call — see the report on #5611.Two things worth stating about the cost of leaving it: the dev-console lie continues on every privileged-override dispatch, and its prescription now points at a shape the ruling forbids ("promote the key to an explicit field on
ActionDef"). #5642 covers the message's own wrongness and stays open, unassigned.Reverse verification — two legs, opposite directions, each measured failing
The fix is a type, so the gauge has to be the compiler.
src/__tests__/consoleActionDispatch.pin.test.ts(new) compiles the same seven cases against bothConsoleActionDispatchandActionDef— same harness aspackages/core/src/actions/__tests__/actionKeys.types.test.ts— and asserts the delta between the two columns is exactlyoverrideNotice. Green: 16 passed (16).overrideNotice?: string;fromconsoleActionDispatch.tsgit diff --numstat=0 1type-checkexit 2overrideNotice?: string;onActionDefinActionRunner.tsgit diff --numstat=1 0overrideNoticerows and the delta rowLeg 1's
tscoutput is the more interesting half, because it is four diagnostics where #4282 and this card both measured three:The fourth is the producer, and it exists only because the cast is gone. Under
dispatch as ActionDefthat file was invisible to the compiler; removing the cast is what put it under one. That is the card's own thesis, measured.Leg 2 doubles as the harness's resolution proof. Core's
distwas deliberately not rebuilt for it, and the control printed0occurrences ofoverrideNoticeindist/actions/ActionRunner.d.tsbefore and after the mutation — so a harness readingdistwould have stayed green. It went red, which is how the file'spaths-based source resolution is demonstrated rather than claimed. (The harness also throws loudly on any diagnostic landing in its own import header, so an unresolvable import can never be read as "the compiler accepted everything".)Both legs restore under
trap … EXIT INT TERM. After each, the tree was verified byte-identical toeb3ccfd77—git status --porcelainempty andgit diff --stat HEADempty. The restore is written asgit checkout SHA -- PATHthengit reset -q HEAD -- PATHthengit checkout -- PATH, because the first form stages the base content and a bare follow-upgit checkout -- PATHwould otherwise restore from the index rather than from the commit.packages/coreis byte-identical to base — the mechanical proof of the ruling's first clauseTwo independent clean builds: one from this branch, one from a worktree checked out at the pinned base
f1c27f037that never contained the diff.tscis composite and skips emit whentsconfig.tsbuildinfosurvives — it lives outsidedist/, so both were cleared and the count is printed as a control (0after clean,1regenerated, so emit really ran).f1c27f037worktree)eb3ccfd77)dist/index.d.tssha256f6494f80…f6494f80…dist/actions/ActionRunner.d.tssha25681a74ca5…81a74ca5…dist/tree sha2568bd78cc9…8bd78cc9…Compared by hash, not byte count.
81a74ca5…is the same figure this PR's previous round independently recorded for its base leg, so the head build now reproduces base exactly.git diff --stat BASE HEAD -- packages/coreis also empty, which is the same fact from the source side.dist/index.d.tsis the file that matters for reachability —ActionDefreaches the published entry throughexport *, so a grep of the barrel for its name means nothing and only the hash answers. It does not move.Scope proof for the declared test narrowing
pnpm testis the repo-wide farm CI owns. The narrowing here is not a judgement call — it is measured: this diff changes no executable JavaScript anywhere in@object-ui/app-shell.Two clean builds of the package, one with the diff and one with it reverted in place:
.jsfiles: 432 (head) vs 431 (base); the only set difference is the new./consoleActionDispatch.js, a type-only module.useConsoleActionRuntime.js,DeclaredActionsBar.js,RecordDetailView.js.//comment lines (removeCommentsis not set anywhere in the tsconfig chain, so comments survive emit). Non-comment deltas: 0.ascasts and type annotations are erased, soexecute(dispatch as ActionDef)andexecute(dispatch)emit identically. With zero executable change, no pre-existing runtime test in this repo can change verdict because of this diff, which is what makes the suite selection below a superset rather than a sample.Verification
All at final commit
eb3ccfd77, union re-run after the last commit, working tree clean.@object-ui/app-shell—type-checkexit 0 with both tsc projects run (tsc --noEmit && tsc -p tsconfig.test.json; the&&short-circuits, so exit 0 is the only reading that proves the test project ran).vitest run --maxWorkers=2over the new pin, bothDeclaredActionsBarsuites, all ofhooks/__tests__/, and all 14RecordDetailView.*suites → Test Files 43 passed (43) / Tests 421 passed (421).@object-ui/corecontrol —vitest run packages/core/src/actions/→ Test Files 23 passed (23) / Tests 407 passed (407), includingactionKeys.pin.test.tsandactionDef-closed-surface.test.ts. Green because core is at base.pnpm --filter @object-ui/app-shell test跑的是 @object-ui/console 的 22 个文件,app-shell 自己的 276 个一个没跑,却报绿 #3378 guard.$?(exit captured before any pipe):check-control-bytes—OK (scanned 4693 tracked text file(s); skipped 85 binary)check-action-forward-parity—5 surfaces checked against 39 runtime-read keys from 4 consumers; 19 justified omissions, 7 known gaps(owed sets unchanged — this card adds no action key to any surface)check-package-self-import—No package names itself inside its own src/.check-phantom-dependencies—Every in-scope import is declared by the package that publishes it.check-node-esm-load --specifiers-only—no un-ledgered package emits an extensionless relative specifiercheck-type-check-coverage—45/46 via type-check … test type-check coverage: 41/41check-lint-coverage—46/46 packages linted, 0 with outstanding errors (0 total)check-changeset-presence/-no-major/-fixed— all ✅pnpm --filter @object-ui/app-shell lint→✖ 2546 problems (0 errors, 2546 warnings), exit 0. That is the whole of the only package this diff touches, not a file subset; type-aware linting is not enabled anywhere in the config (noprojectService, noparserOptions.project, norecommendedTypeChecked), so no rule reads cross-file type information and this diff cannot move an untouched package's verdict. On the changed files, counted from--format json: 5 files, 0 errors, 164 warnings, and the two new files contribute 0. Measured against the same three files at base: 167 → 164 warnings,no-explicit-any142 → 139 — the narrowing removes threeanys and adds none.Changeset
.changeset/console-action-dispatch-envelope-5611.md, empty frontmatter. The previous round's changeset described a declaration on a published interface and is deleted. Nothing here is user-visible:@object-ui/coreis byte-identical, the envelope is not exported from app-shell's barrel, and the emitted JavaScript is comment-only different.check-changeset-presence.mjsis the authority and agrees:If item 4 lands later and the dev-console warning actually stops, that is the user-visible half and earns a real bump then.
Out of scope
#5642 stays open and unassigned — the same warning's message states a fact objectstack#4075 step 3 retired and points the author at the wrong file. It is a different defect class (shipped prose vs. a missing declaration) and is not folded in here. Its second half now matters more, not less: the prescription it ships ("promote the key to an explicit field on
ActionDef") is the shape this card's ruling forbids.Item 4 — RULED and implemented:
HOST_DISPATCH_ACTION_KEYSin core (Option A)Maintainer ruling, 2026-08-22 ~17:26Z on #5611: Option A — a host-dispatch key list in
packages/core/src/actions/actionKeys.ts, unioned intoKNOWN_ACTION_KEYS, pinned. The seat'sown "
packages/coremust not be touched" fence is explicitly lifted by that ruling; the twoprohibitions the earlier ruling set are preserved verbatim and are quoted here because they
are the constraint the implementation had to satisfy, not decoration:
> ⛔ 不声明到
ActionDef,⛔ 不进ACTION_DEF_KEYS(AST 派生 pin 不动)——授权面严格度与今天逐字节相同。Both hold.
ActionDefgains nothing,ACTION_DEF_KEYSgains nothing, and the AST-derived pinactionKeys.pin.test.tsre-derives that list from the interface unchanged. WritingoverrideNoticein anActionDefliteral is still a compile error.What landed
packages/core/src/actions/actionKeys.ts:unioned into
KNOWN_ACTION_KEYSas its fourth input, alongsideACTION_DEF_KEYS,SPEC_ACTION_KEYSandNAVIGATION_ALIAS_KEYS— and the first input that is not a restatementof an authored surface.
classifyActionKeysremains its only reader; nothing else moved.The docblock is written in the style of the in-file precedent
HOST_STASHED_PARAM_KEYS, whichmodels the same category one level down (host-composed keys inside
params) and likewise citesDeclaredActionsBarby name. It records the producer (views/DeclaredActionsBar.tsx, thecan_act:false && can_override:truebranch) and both readers(
hooks/useConsoleActionRuntime.tsx,views/RecordDetailView.tsx), and states the admissiontest for anything added later: composed by a host in code, never read back out of stored
metadata, read by the runtime.
The false flag is dead — measured, not asserted
Both legs drive the exact dispatch object literal
DeclaredActionsBarcomposes on theoverride branch, through
classifyActionKeys/warnOnUnknownActionKeysloaded from source.KNOWN_ACTION_KEYS.has('overrideNotice')falsetrueclassifyActionKeys(dispatch).unknown["overrideNotice"][]targt)overrideNoticeandtargttargtaloneThe "before" line is the same figure the escalation round recorded, reproduced at branch head:
That prescription is the shape the ruling forbids for this key, which is why the diagnostic was
worse than noise.
No other key's classification moved, and that is a set measurement rather than a spot check.
Importing the base file and the head file into one process and differencing the two sets:
Pins
Four new assertions in
packages/core/src/actions/__tests__/actionKeys.pin.test.ts(13 → 17tests):
HOST_DISPATCH_ACTION_KEYSexact contents['overrideNotice']—toEqualon the wholearray, not
toContain. The set is the ruling's scope, and the risk this list carries isgrowth: a key in it is a key the warning stops asking about, so a silent second member must
be a red test that names it.
KNOWN_ACTION_KEYS.has('overrideNotice') === true.declaredOnActionDef: false, inActionDefKeys: false, inSpecActionKeys: false. Re-declaring the key onActionDef"for consistency" fails here by name.
same dispatch still produces exactly one — naming
targtand notoverrideNotice. Withoutthe second half, stubbing
classifyActionKeysto return nothing would pass the first.Ablation — one leg, from the committed state
Mutation:
['overrideNotice'] as const→[] as const. Proven on disk by anchored occurrencecount, because an editor's exit code is not evidence a replacement landed:
Result:
Tests 4 failed | 13 passed (17)— all four new pins red and named(
expected [] to deeply equal [ 'overrideNotice' ],expected false to be true,expected "warn" to not be called at all, but actually been called 1 times,expected '[ActionRunner] action "approval_rejec…' not to contain 'overrideNotice'), and thenode repro's warn count back to 1 with the false message restored. The third pin — the
authored surface staying closed — stayed green, which is correct: that half must not depend
on the list, and an ablation that reddened it would mean the two halves were entangled.
packages/core'sdistwas deliberately not rebuilt for this leg. The harness resolves@object-ui/corethroughpaths→packages/core/src(roottsconfig.json, and the same aliasin
vitest.config.mts), so a dist-reading harness would have stayed green; going red is thedemonstration of source resolution rather than a claim of it.
Restored under
trap … EXIT INT TERM. Tree verified byte-identical afterwards:git status --porcelainempty,git diff --stat HEADempty, and the file's blob hash equal to the committedone (
75fae1e6…).A gate the dispatch list did not name, and my own diff tripped it
check:spec-symbols(check-spec-symbol-derivation.mjs) went red on the first draft of thenew docblock: it read the word "mirrors", written about the other three lists, as a
spec-alignment claim standing behind
HOST_DISPATCH_ACTION_KEYSwith nothing under it.The gate is right, and its own third prescription applies — "delete the sentence, because it is
not true here". This list derives from nothing in
@objectstack/specand must not, so thewording now states that negative outright instead of implying a positive. Re-run: exit 0,
spec alignment claims: 2 declared deliberate copies, 18 unbacked claims in 5 packages(thepre-existing ledger; this symbol is not among them). Recorded rather than quietly fixed, because
the gate that catches you is worth more than the list you were handed.
Changeset — core's published surface moves this time
HOST_DISPATCH_ACTION_KEYSreaches@object-ui/core's package entry (actions/index.ts→src/index.ts, bothexport *), verified by importing the built package entry rather thanthe source:
["overrideNotice"],KNOWN_ACTION_KEYS.has('overrideNotice') true, set size 65.So
.changeset/host-dispatch-action-keys-5611.mddeclares a realpatchon@object-ui/core.The items-1–3 changeset kept its empty frontmatter but lost one sentence that item 4 made false —
it claimed
@object-ui/corewas untouched. It now names the second changeset instead. Both arecounted by the gate:
7 source file(s) of 2 released package(s) changed, and this change declares 2 changeset(s).Verification — union re-run AFTER the final commit
eeaa7eb, tree cleanEvery exit captured before any pipe; each verdict below is the gate's own printed line.
@object-ui/core—vitest run packages/core/→ Test Files 93 passed (93) / Tests 1950passed (1950), including
actionKeys.pin.test.ts,actionDef-closed-surface.test.tsandactionKeys.types.test.ts.@object-ui/app-shell— the whole package ran green at the pre-amend tree: Test Files 489passed (489) / Tests 4809 passed | 1 skipped (4810). The only delta between that tree and
eeaa7ebis the docblock reword above — non-comment changed lines: 0, confined to one coresource file — and at
eeaa7ebthe three suites that actually spell this key re-ran green:consoleActionDispatch.pin.test.ts,DeclaredActionsBar.overrideAffordance.test.tsx,useConsoleActionRuntime.overrideNotice.test.tsx→ 3 passed / 38 passed. Declared as anarrowing rather than presented as a full re-run.
tsc --noEmit && tsc -p tsconfig.test.json, exit 0 each,with the script name echoed so a zero-match
--filtercannot read as green. The dependencyclosure was built first (
pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' build, exit 0).pnpm --filter @object-ui/app-shell test跑的是 @object-ui/console 的 22 个文件,app-shell 自己的 276 个一个没跑,却报绿 #3378 guard.check:spec-symbols✅ ·check-control-bytesOK (scanned 4694 tracked text file(s); skipped 85 binary)·check-action-forward-parity5 surfaces checked against 39 runtime-read keys from 4 consumers; 19 justified omissions, 7 known gaps(unchanged — this card adds noaction key to any renderer surface) ·
check-package-self-importNo package names itself inside its own src/.·check-phantom-dependenciesEvery in-scope import is declared by the package that publishes it.·check-node-esm-load --specifiers-onlyno un-ledgered package emits an extensionless relative specifier·check-type-check-coverage45/46 via type-check … test type-check coverage: 41/41·check-lint-coverage46/46 packages linted, 0 with outstanding errors (0 total)·check-changeset-presence/-no-major/-fixed✅. Also sweptand green:
check:published-dist,check:i18n-keys,check:i18n-drift,check:i18n-dead-keys,check:skills-paths,check:eager-closure.eslint --format json packages/core, population chosen by eslint's own config, not byme: 185 files, 0 errors, 513 warnings; the two changed files contribute 0 errors, 0
warnings. Type-aware linting is not enabled anywhere in
eslint.config.js(grep forprojectService/parserOptions/TypeCheckedexits 1, captured before any pipe), so norule reads cross-file type information and this diff cannot move an untouched package's verdict.
The repo-wide
eslint .farm is CI's run and is not claimed here.Items 1–3 generated by Claude Code
Item 4 generated by Claude Code
Generated by Claude Code