Repository navigation
fix(types,core): one authority for ActionContext (objectui#6349, batch 4) - #12041
Conversation
…h 4) @object-ui/types' ui-action module is the one declaration of ActionContext; @object-ui/core's ActionRunner module re-exports it instead of declaring a second copy. The copies had drifted on three members: `data` existed only on the runner's copy (now declared on the authority), and `record` / `user` were `any` there and `Record<string, any>` here (the narrower spelling stays). The row leaves KNOWN_COLLISIONS in the same change. Claude-Session: https://claude.ai/code/session_01CGZy1BGCjdN5cXqL9cnvB8 Co-authored-by: Claude <noreply@anthropic.com>
…jectui#6349, batch 4) Claude-Session: https://claude.ai/code/session_01CGZy1BGCjdN5cXqL9cnvB8 Co-authored-by: Claude <noreply@anthropic.com>
…ion (objectui#6349, batch 4) The pin that keeps ActionContext an open data bag (and ActionDef closed) read both interfaces off ActionRunner.ts by AST. ActionContext is now declared once, in @object-ui/types' ui-action.ts, and re-exported by the runner module, so the ActionContext half reads the authority. A missing interface still throws rather than reading as "no index signature". Claude-Session: https://claude.ai/code/session_01CGZy1BGCjdN5cXqL9cnvB8 Co-authored-by: Claude <noreply@anthropic.com>
✅ 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
|
…jectui#6349, batch 4) Claim amendment 6077155250 (ActionResult A1, ComponentMeta A). ActionResult: @object-ui/types' ui-action module is the one declaration. It takes the runner's members (reload, redirect, modal, silent, undo); its unread `refresh` member is retired. UndoableOperation, which types `undo`, moves down beside it and is published from the types entry; core's UndoManager and ActionRunner modules re-export both. ComponentMeta: the two declarations meant different things, so the registry's derived type is renamed RegistryComponentMeta (register, registerLazy, getMeta and the registry's internal readers use it), and @object-ui/core's ComponentMeta re-exports @object-ui/types' one. PluginScopeImpl, the registry pins, and the three `ComponentMeta['labelling']` readers in fields and app-shell move to the new name. Both rows leave KNOWN_COLLISIONS in the same change. Claude-Session: https://claude.ai/code/session_01CGZy1BGCjdN5cXqL9cnvB8 Co-authored-by: Claude <noreply@anthropic.com>
✅ 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
|
…ds and app-shell (objectui#6349) Claude-Session: https://claude.ai/code/session_01CGZy1BGCjdN5cXqL9cnvB8 Co-authored-by: Claude <noreply@anthropic.com>
✅ 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
|
Contract reviewServed-tier: Inputs, and nothing else: card #6349 (body and all 14 comments, the batch 4 claim ① Derived judgmentsEvery public-surface and accept-set change the diff implies, each named right or wrong:
Exported name sets only grow (core + ② Semver level
③ Boundary flagsDev report
Dev addendum
Other facts on the card, recorded so the seat need not re-derive them:
Implemented-by: VERDICT: PASS |
Refs #6349 (batch 4)
Clause-②: yes
Batch 4 of the one-authority burn-down: the three
coreandtypesrows ofKNOWN_COLLISIONS(ActionContext,ActionResult,ComponentMeta). All three rows converge here.ActionContextconverged in the first round.ActionResultandComponentMetawere stop-and-report in the first round (measured below). The seat's claim amendment6077155250answered them (ActionResult A1, ComponentMeta A), and the second round converged both (the dev's addendum6077857371; summary in the next section). Types only: the emitted JavaScript of both packages is byte-identical to the base.Notation: REC means
Recordkeyed bystringwithanyvalues. Generic arguments are spelled in words because GitHub strips angle-bracket spans from bodies.Round 2: the amendment, converged (head
7fc6d14e)KNOWN_COLLISIONShad 28 rows at base and has 25 at head. The gate is 11 of 11.ActionResultandComponentMetareadno longer collides at:, naming both files.ActionResult,ComponentMetaand the movedUndoableOperationreada NEW colliding name.ActionResult(A1):@object-ui/typesis the one declaration.reload,redirect,modal,silentandundo, and its unreadrefreshis retired.UndoableOperationmoves intoui-action.tsand is published from the types entry. It needs no core-only type.ActionRunner.tsre-exportsActionResult, andUndoManager.tsimports and re-exportsUndoableOperation.ComponentMeta(A): core's derived declaration is renamedRegistryComponentMeta, and core'sComponentMetare-exports types'.register,registerLazy,getMetaand the registry's internal readers use the new name, andPluginScopeImpl.tsimports it.ComponentMetais the canonical one.ComponentMeta['labelling']readers (fieldsindex.tsx, app-shellwidgets.tsx,DashboardWidgetInspector.tsx) readRegistryComponentMeta['labelling'].ActionResultandUndoableOperationkeep identical members.ComponentMetaloses exactlydeprecated,labelling,namespace,skipFallbackandtier, and core'sRegistryComponentMetaequals the old one.ActionResultgains five members and losesrefresh.RegistryComponentMeta), types 710 → 711 (UndoableOperation).registry/Registry.js, with a code-only diff of 0.ActionRunner.minoron types, core, fields and app-shell, each with a breaking-change note. ⛔ Nomajor.ActionContext: converged on@object-ui/typescore(ActionRunner.ts, before)types(ui-action.ts, before)dataany)recordanyselectedRecordspageVariablesuseranyany@object-ui/typesis the dependency-legal authority: it has no@object-ui/*dependency, andcoredepends on it.ActionRunner.tsnow RE-EXPORTS it (export type { ActionContext } from '@object-ui/types'), and its row leaves the ledger.datamoved down because the runner reads it: as the fallback record id inexecuteForm, and as the API request body inbuildApiRequestBody.record/userkeep the narrower REC, because every package below compiles against it.ActionContextpoint at@object-ui/coreand 7 point atActionRunnerrelatively, against 2 of the@object-ui/typescopy (its barrel, and oneaction-group-retiredlit control). Implicit users drive anActionRunnerwithout naming the type.pnpm --filter PKG type-checkis green on 15 packages against the converged shape, withtypesandcoredist rebuilt first: types, core, react, sdui-parser, fields, plugin-dashboard, plugin-report, plugin-timeline, components, app-shell, plugin-grid, plugin-detail, plugin-view, plugin-designer and console. All 15 read exit 0 with zeroerror TSlines, and each run echoed its script name. The same set was exit 0 at base.Published surface, read off the BUILT entry declarations
dist/index.d.ts, with predictions written first. All matched.ActionContext: baseTS2322(two types), head clean (one type).recordgiven a string: base clean, headTS2322.usergiven a string: base clean, headTS2322.datagiven a string: base clean, headTS2322.selectedRecordsgiven a string) isTS2322on both trees, at the same columns.dist/index.d.ts: core 512 = 512 and types 710 = 710, with zero diff lines.actions/ActionRunner.d.ts.ui-action.d.ts(+311 tokens, 0 removed: the docblock anddata).zod/*.d.tsfiles read different, but every one is token-multiset-equal. That is literal-union member ORDER between a cached base build and a fresh head build, not content.minorfor both packages, because a member type narrows on each (objectui never declaresmajor). The breaking semantics are written into both changesets.ActionResult: round 1's stop, answered A1 by amendment6077155250(the measurement that led there)coretypessuccess,data,error,closereloadredirectstringmodalanysilentundoUndoableOperation(declared in core'sUndoManager.ts)refreshOne concept, the result of executing an action, but the only legal direction cannot carry
undo. Two probes, both run with the mutation proven on disk and restored under a trap (blob equal to HEAD,git diff HEADempty):typesshape.coretsc --noEmitexits 2 with 20 errors, every one on a core-only member:redirect×7,reload×7,undo×4,modal×1,silent×1.typesgainsreload/redirect/modal/silent, plusundotypedunknown, the mosttypescan say without reaching core. Thetypesandcoredist were rebuilt inside the trap, and the probe marker read 1 intypes/dist. The core build itself fails. Thetsconfig.test.jsonlegs read: core src 1 error, core tests 17, app-shell tests 9. All 27 are reads ofundoas anUndoableOperation: the runner'sglobalUndoManager.push(result.undo), plus tests readingundoData/redoData/objectName. The restore leg rebuilt and read the marker at 0.So the one blocker is that
UndoableOperationlives incore. Converging means declaring it in@object-ui/types, which is a new published name, and havingUndoManager.tsre-export it. Both are outside this claim, so the row stays in the ledger.ComponentMeta: round 1's stop, answered A by amendment6077155250(the measurement that led there)core's isCanonicalComponentMeta & RegistryComponentMetaExtras:types' declaration plus five registry-only keys (tier,namespace,skipFallback,labelling,deprecated). That is a different, narrower meaning, registration metadata, so the card's remedy is the rename branch. A rename probe was run, withcoredist rebuilt inside the trap (marker present) and rebuilt again on restore (marker 0). It renamed core's declaration toRegistryComponentMetaand re-pointed@object-ui/core'sComponentMetaattypes. The breaks, all outside this claim's files:src/index.tsx: 1,TS2339onComponentMeta['labelling'];widgets.tsxandDashboardWidgetInspector.tsx: 2, the same read;component-meta-derives-from-canonical.test.ts: 8, the derivation pin;@object-ui/core's publishedComponentMetawould lose five keys, which is a reshaped published name. The row stays in the ledger.Verification, round 1 (commit
9495823c2; round 2's readings are above)scripts/__tests__/one-authority-per-exported-name-6273.test.ts, 11 of 11). Its ledger had 28 rows at base and 27 after round 1, and has 25 at head after round 2. The re-derivation instrument is the test itself.ActionContextrow reads1 failed | 10 passedwithActionContext — no longer collides at:naming both files.ActionRunner.tsreadsActionContext — a NEW colliding namewith both sites.ablation-replace(its replacement contained its own anchor), so it ran nothing. It was redone with a non-overlapping anchor.actionKeys.pin.test.tsnow readsActionContext's index signature offui-action.ts. Ablating the signature there readsActionContext: false(red), and the restore is proven.packages/types/+packages/core/+ the gate, run at84f668973: 565 of 566 files. The one failure was the pin above, which read the runner module; it was repaired in9495823c2. At9495823c2, the three changed or affected test files read 32 of 32.type-check(hyphenated, script echoed): types and core are exit 0. Core'stsconfig.test.jsonis exit 0 at9495823c2, and--listFilesincludes the pin file.type-check:scriptsis exit 0 and covers the ledger file.eslinton the 4 touched files has 0 errors (22 warnings, 27 at base).check:control-bytes,check:test-path-roots,check:changeset-claims,check:pending-changeset-literals,check:new-line-citations, changeset presence and no-major are all exit 0. The governed-queue guard reads NOT GOVERNED.type-check:scriptsand the three test files therefore ran outside the lock, on a shared box.types+coresuite was not re-run at9495823c2. The only delta since84f668973is the one test file, which was run alone.core: the name importers plus every package that drives anActionRunner. CI runs the rest.Acceptance notes
types'ActionResult.refreshhas no in-repo reader or writer: the runner readsreload. A handler typed against thetypescopy that setsrefreshis ignored at runtime. This belongs to theActionResultdecision above, not to this PR.ActionExecutor(inui-action.ts) has no implementer and no importer outside its own barrel. It is an observation only.Session:
https://claude.ai/code/session_01CGZy1BGCjdN5cXqL9cnvB8Generated by Claude Code