Repository navigation
Commit d328698
fix(types,core): one authority for ActionContext (objectui#6349, batch 4) (#12041)
Refs #6349 (batch 4)
Clause-②: yes
Batch 4 of the one-authority burn-down: the three `core` and `types`
rows of `KNOWN_COLLISIONS` (`ActionContext`, `ActionResult`,
`ComponentMeta`). **All three rows converge here.** `ActionContext`
converged in the first round. `ActionResult` and `ComponentMeta` were
stop-and-report in the first round (measured below). The seat's claim
amendment `6077155250` answered them (ActionResult **A1**, ComponentMeta
**A**), and the second round converged both (the dev's addendum
`6077857371`; summary in the next section). Types only: the emitted
JavaScript of both packages is byte-identical to the base.
Notation: REC means `Record` keyed by `string` with `any` values.
Generic arguments are spelled in words because GitHub strips
angle-bracket spans from bodies.
## Round 2: the amendment, converged (head `7fc6d14e`)
- **Ledger:** `KNOWN_COLLISIONS` had 28 rows at base and has 25 at head.
The gate is 11 of 11.
- Stale legs on `ActionResult` and `ComponentMeta` read `no longer
collides at:`, naming both files.
- Fresh legs on `ActionResult`, `ComponentMeta` and the moved
`UndoableOperation` read `a NEW colliding name`.
- **`ActionResult` (A1):** `@object-ui/types` is the one declaration.
- It gains the runner's `reload`, `redirect`, `modal`, `silent` and
`undo`, and its unread `refresh` is retired.
- `UndoableOperation` moves into `ui-action.ts` and is published from
the types entry. It needs no core-only type.
- core's `ActionRunner.ts` re-exports `ActionResult`, and
`UndoManager.ts` imports and re-exports `UndoableOperation`.
- **`ComponentMeta` (A):** core's derived declaration is renamed
`RegistryComponentMeta`, and core's `ComponentMeta` re-exports types'.
- `register`, `registerLazy`, `getMeta` and the registry's internal
readers use the new name, and `PluginScopeImpl.ts` imports it.
- The derivation pin is re-aimed, and it gains a pin that core's
`ComponentMeta` is the canonical one.
- The three `ComponentMeta['labelling']` readers (fields `index.tsx`,
app-shell `widgets.tsx`, `DashboardWidgetInspector.tsx`) read
`RegistryComponentMeta['labelling']`.
- **Published surface, one program per tree:**
- core's `ActionResult` and `UndoableOperation` keep identical members.
- core's `ComponentMeta` loses exactly `deprecated`, `labelling`,
`namespace`, `skipFallback` and `tier`, and core's
`RegistryComponentMeta` equals the old one.
- types' `ActionResult` gains five members and loses `refresh`.
- Exported names only grow: core 512 → 513 (`RegistryComponentMeta`),
types 710 → 711 (`UndoableOperation`).
- Emitted JS is byte-identical for types, fields and app-shell. In core
it differs in one JSDoc line in `registry/Registry.js`, with a code-only
diff of 0.
- **Consumer impact:** 15 of 15 type-checks exit 0: 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. They cover every package that names these
types or drives an `ActionRunner`.
- **Suites:**
- types + core + the gate: 566 files and 14,054 tests passed;
- fields: 242 files and 3,956 tests passed;
- app-shell, narrowed to the 37 files that import the two changed
modules: 550 tests passed. Its emitted JS is unchanged, and CI runs the
full suite.
- **Changesets:** `minor` on types, core, fields and app-shell, each
with a breaking-change note. ⛔ No `major`.
## `ActionContext`: converged on `@object-ui/types`
| member | `core` (`ActionRunner.ts`, before) | `types` (`ui-action.ts`,
before) | the one declaration (after) |
| :-- | :-- | :-- | :-- |
| `data` | optional REC | none (index signature, so `any`) | **optional
REC** (core's member moves down) |
| `record` | optional `any` | optional REC | optional REC |
| `selectedRecords` | optional REC array | same | same |
| `pageVariables` | optional REC | same | same |
| `user` | optional `any` | optional REC | optional REC |
| index signature | string key to `any` | same | same |
- **One concept, drifted copies.** Both are the runner's execution data
bag. `@object-ui/types` is the dependency-legal authority: it has no
`@object-ui/*` dependency, and `core` depends on it. `ActionRunner.ts`
now RE-EXPORTS it (`export type { ActionContext } from
'@object-ui/types'`), and its row leaves the ledger.
- **`data` moved down** because the runner reads it: as the fallback
record id in `executeForm`, and as the API request body in
`buildApiRequestBody`. **`record` / `user` keep the narrower REC**,
because every package below compiles against it.
- **Consumers, enumerated before reshaping.** Name importers: 33 import
sites of `ActionContext` point at `@object-ui/core` and 7 point at
`ActionRunner` relatively, against 2 of the `@object-ui/types` copy (its
barrel, and one `action-group-retired` lit control). Implicit users
drive an `ActionRunner` without naming the type. `pnpm --filter PKG
type-check` is green on 15 packages against the converged shape, with
`types` and `core` dist 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 zero `error TS` lines, and each run
echoed its script name. The same set was exit 0 at base.
### Published surface, read off the BUILT entry declarations
- An acceptance probe compiled against each tree's `dist/index.d.ts`,
with predictions written first. All matched.
- **Identity** of core's and types' `ActionContext`: base `TS2322` (two
types), head clean (one type).
- **Narrowings, on base and head:**
- core's `record` given a string: base clean, head `TS2322`.
- core's `user` given a string: base clean, head `TS2322`.
- types' `data` given a string: base clean, head `TS2322`.
- **Controls:**
- An object-shaped context compiles on both trees.
- The negative control (`selectedRecords` given a string) is `TS2322` on
both trees, at the same columns.
- **Exported name sets are unchanged.** Enumerated through the type
checker over `dist/index.d.ts`: core 512 = 512 and types 710 = 710, with
zero diff lines.
- **Emitted JS is byte-identical**: core 107 of 107 files and types 74
of 74.
- **Declaration diffs:**
- core: exactly `actions/ActionRunner.d.ts`.
- types: `ui-action.d.ts` (+311 tokens, 0 removed: the docblock and
`data`).
- types: 15 `zod/*.d.ts` files 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.
- **Grade:** `minor` for both packages, because a member type narrows on
each (objectui never declares `major`). The breaking semantics are
written into both changesets.
## `ActionResult`: round 1's stop, answered A1 by amendment `6077155250`
(the measurement that led there)
| member | `core` | `types` |
| :-- | :-- | :-- |
| `success`, `data`, `error`, `close` | yes | yes |
| `reload` | yes | no |
| `redirect` | optional `string` | no |
| `modal` | optional `any` | no |
| `silent` | yes | no |
| `undo` | optional `UndoableOperation` (declared in core's
`UndoManager.ts`) | no |
| `refresh` | no | yes (in-repo readers and writers found: none) |
One 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
HEAD` empty):
- **R1, a re-point at today's `types` shape.** `core` `tsc --noEmit`
exits 2 with 20 errors, every one on a core-only member: `redirect` ×7,
`reload` ×7, `undo` ×4, `modal` ×1, `silent` ×1.
- **R2, a widened authority.** `types` gains `reload` / `redirect` /
`modal` / `silent`, plus `undo` typed `unknown`, the most `types` can
say without reaching core. The `types` and `core` dist were rebuilt
inside the trap, and the probe marker read 1 in `types/dist`. The core
build itself fails. The `tsconfig.test.json` legs read: core src 1
error, core tests 17, app-shell tests 9. **All 27 are reads of `undo` as
an `UndoableOperation`**: the runner's
`globalUndoManager.push(result.undo)`, plus tests reading `undoData` /
`redoData` / `objectName`. The restore leg rebuilt and read the marker
at 0.
So the one blocker is that `UndoableOperation` lives in `core`.
Converging means declaring it in `@object-ui/types`, which is a new
published name, and having `UndoManager.ts` re-export it. Both are
outside this claim, so the row stays in the ledger.
## `ComponentMeta`: round 1's stop, answered A by amendment `6077155250`
(the measurement that led there)
`core`'s is `CanonicalComponentMeta & 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, with `core` dist rebuilt inside
the trap (marker present) and rebuilt again on restore (marker 0). It
renamed core's declaration to `RegistryComponentMeta` and re-pointed
`@object-ui/core`'s `ComponentMeta` at `types`. The breaks, all outside
this claim's files:
- fields `src/index.tsx`: 1, `TS2339` on `ComponentMeta['labelling']`;
- app-shell `widgets.tsx` and `DashboardWidgetInspector.tsx`: 2, the
same read;
- core `component-meta-derives-from-canonical.test.ts`: 8, the
derivation pin;
- sdui-parser, plugin-dashboard, plugin-report and plugin-timeline: 0.
`@object-ui/core`'s published `ComponentMeta` would 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)
- **The gate is green**
(`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.
- **Gate non-vacuity**, mutations proven and restored by state:
- Stale leg: re-adding the `ActionContext` row reads `1 failed | 10
passed` with `ActionContext — no longer collides at:` naming both files.
- Fresh leg: re-declaring it in `ActionRunner.ts` reads `ActionContext —
a NEW colliding name` with both sites.
- The first stale attempt was refused by `ablation-replace` (its
replacement contained its own anchor), so it ran nothing. It was redone
with a non-overlapping anchor.
- **The moved pin.** `actionKeys.pin.test.ts` now reads
`ActionContext`'s index signature off `ui-action.ts`. Ablating the
signature there reads `ActionContext: false` (red), and the restore is
proven.
- **Root-form vitest on `packages/types/` + `packages/core/` + the
gate**, run at `84f668973`: 565 of 566 files. The one failure was the
pin above, which read the runner module; it was repaired in `9495823c2`.
At `9495823c2`, the three changed or affected test files read 32 of 32.
- **`type-check` (hyphenated, script echoed):** types and core are exit
0. Core's `tsconfig.test.json` is exit 0 at `9495823c2`, and
`--listFiles` includes the pin file. `type-check:scripts` is exit 0 and
covers the ledger file.
- **Other gates:** `eslint` on 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.
- **Declared narrowings:**
- The verify lock was held by other worktrees for most of an hour
(repeated queue-timeouts). The final-commit runs of the core test
type-check, `type-check:scripts` and the three test files therefore ran
outside the lock, on a shared box.
- The full `types` + `core` suite was not re-run at `9495823c2`. The
only delta since `84f668973` is the one test file, which was run alone.
- Downstream type-check covers 15 of the 38 packages that depend on
`core`: the name importers plus every package that drives an
`ActionRunner`. CI runs the rest.
- **Eager first-load bytes:** not affected, because no emitted JS moved.
## Acceptance notes
- `types`' `ActionResult.refresh` has no in-repo reader or writer: the
runner reads `reload`. A handler typed against the `types` copy that
sets `refresh` is ignored at runtime. This belongs to the `ActionResult`
decision above, not to this PR.
- `ActionExecutor` (in `ui-action.ts`) has no implementer and no
importer outside its own barrel. It is an observation only.
Session: `https://claude.ai/code/session_01CGZy1BGCjdN5cXqL9cnvB8`
---
_Generated by [Claude
Code](https://claude.ai/code/session_01CGZy1BGCjdN5cXqL9cnvB8)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent d99b731 commit d328698
17 files changed
Lines changed: 316 additions & 118 deletions
File tree
- .changeset
- packages
- app-shell/src/views/metadata-admin
- inspectors
- core/src
- actions
- __tests__
- registry
- __tests__
- fields/src
- types/src
- scripts/__tests__
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
Lines changed: 4 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
31 | 31 | | |
32 | 32 | | |
33 | 33 | | |
34 | | - | |
| 34 | + | |
35 | 35 | | |
36 | 36 | | |
37 | 37 | | |
| |||
590 | 590 | | |
591 | 591 | | |
592 | 592 | | |
593 | | - | |
| 593 | + | |
594 | 594 | | |
595 | 595 | | |
596 | 596 | | |
| |||
606 | 606 | | |
607 | 607 | | |
608 | 608 | | |
609 | | - | |
| 609 | + | |
610 | 610 | | |
611 | 611 | | |
612 | 612 | | |
613 | 613 | | |
614 | 614 | | |
615 | 615 | | |
616 | 616 | | |
617 | | - | |
| 617 | + | |
618 | 618 | | |
619 | 619 | | |
620 | 620 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
44 | | - | |
| 44 | + | |
45 | 45 | | |
46 | 46 | | |
47 | 47 | | |
| |||
3059 | 3059 | | |
3060 | 3060 | | |
3061 | 3061 | | |
3062 | | - | |
| 3062 | + | |
3063 | 3063 | | |
3064 | 3064 | | |
3065 | 3065 | | |
| |||
3074 | 3074 | | |
3075 | 3075 | | |
3076 | 3076 | | |
3077 | | - | |
| 3077 | + | |
3078 | 3078 | | |
3079 | 3079 | | |
3080 | 3080 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
24 | | - | |
| 24 | + | |
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
28 | | - | |
| 28 | + | |
29 | 29 | | |
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
33 | | - | |
34 | | - | |
35 | | - | |
36 | | - | |
37 | | - | |
38 | | - | |
39 | | - | |
40 | | - | |
41 | | - | |
42 | | - | |
43 | | - | |
44 | | - | |
45 | | - | |
46 | | - | |
47 | | - | |
48 | | - | |
49 | | - | |
50 | | - | |
51 | | - | |
52 | | - | |
53 | | - | |
54 | | - | |
55 | | - | |
56 | | - | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
57 | 44 | | |
58 | | - | |
59 | | - | |
60 | | - | |
61 | | - | |
62 | | - | |
63 | | - | |
64 | | - | |
65 | | - | |
66 | | - | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
67 | 61 | | |
68 | 62 | | |
69 | 63 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
17 | | - | |
18 | | - | |
19 | | - | |
20 | | - | |
21 | | - | |
22 | | - | |
23 | | - | |
24 | | - | |
25 | | - | |
26 | | - | |
27 | | - | |
28 | | - | |
29 | | - | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
30 | 26 | | |
31 | 27 | | |
32 | 28 | | |
| |||
Lines changed: 19 additions & 7 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
37 | 37 | | |
38 | 38 | | |
39 | 39 | | |
40 | | - | |
41 | | - | |
42 | | - | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
43 | 55 | | |
44 | 56 | | |
45 | 57 | | |
46 | | - | |
| 58 | + | |
47 | 59 | | |
48 | 60 | | |
49 | 61 | | |
| |||
55 | 67 | | |
56 | 68 | | |
57 | 69 | | |
58 | | - | |
59 | | - | |
| 70 | + | |
| 71 | + | |
60 | 72 | | |
61 | 73 | | |
62 | 74 | | |
| |||
107 | 119 | | |
108 | 120 | | |
109 | 121 | | |
110 | | - | |
| 122 | + | |
111 | 123 | | |
112 | 124 | | |
113 | 125 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
24 | | - | |
| 24 | + | |
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
| |||
0 commit comments