From 9659596bc13e40b41ba2846d84f629f1c758e3c2 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 7 Sep 2026 05:28:43 +0000 Subject: [PATCH 1/4] test(vi-mock): inherit the real @object-ui/fields surface in 8 vi.mock factories Every one of the eight frozen factories hand-listed one or two of the barrel's 140 exports, so the next export any module in the file's import graph reads at module scope would resolve to `undefined` against the stand-in and the file would die during collection. Each now spreads the real module first; the hand-written doubles stay as the overrides, which is the behaviour those tests assert. No assertion moved. All ten call sites on this specifier (the eight converted plus the two that already inherited) run 58 tests green in both states. Part of objectui#6892 (slice 13). Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr --- .../src/views/metadata-admin/AccessExplainPanel.test.tsx | 3 ++- .../AssignedUsersSection.contractEnvelope-5945.test.tsx | 3 ++- .../src/views/metadata-admin/AssignedUsersSection.test.tsx | 3 ++- .../metadata-admin/PermissionMatrixEditor.basics.test.tsx | 3 ++- .../PermissionMatrixEditor.bulkMergeKeys.test.tsx | 3 ++- .../PermissionMatrixEditor.retiredLifecycleKeys.test.tsx | 3 ++- .../inspectors/FlowReferenceField.lookup.test.tsx | 3 ++- .../inspectors/FlowReferenceField.membershipTier.test.tsx | 3 ++- 8 files changed, 16 insertions(+), 8 deletions(-) diff --git a/packages/app-shell/src/views/metadata-admin/AccessExplainPanel.test.tsx b/packages/app-shell/src/views/metadata-admin/AccessExplainPanel.test.tsx index 93e5786e81..46e10a7d12 100644 --- a/packages/app-shell/src/views/metadata-admin/AccessExplainPanel.test.tsx +++ b/packages/app-shell/src/views/metadata-admin/AccessExplainPanel.test.tsx @@ -32,7 +32,8 @@ vi.mock('./useMetadata', () => ({ })); // The user picker has its own coverage; a stub keeps this suite focused on // the explain round-trip. -vi.mock('@object-ui/fields', () => ({ +vi.mock('@object-ui/fields', async (importOriginal) => ({ + ...(await importOriginal()), RecordPickerDialog: () => null, })); diff --git a/packages/app-shell/src/views/metadata-admin/AssignedUsersSection.contractEnvelope-5945.test.tsx b/packages/app-shell/src/views/metadata-admin/AssignedUsersSection.contractEnvelope-5945.test.tsx index f031b6d9bc..159fe7528f 100644 --- a/packages/app-shell/src/views/metadata-admin/AssignedUsersSection.contractEnvelope-5945.test.tsx +++ b/packages/app-shell/src/views/metadata-admin/AssignedUsersSection.contractEnvelope-5945.test.tsx @@ -34,7 +34,8 @@ import { AssignedUsersSection } from './AssignedUsersSection'; // `@object-ui/react` is imported transitively for more than `useAdapter` (the // related-count store subscribes to `subscribeDataChanges` at module scope), and // a wholesale `vi.mock` of it starves that import. -vi.mock('@object-ui/fields', () => ({ +vi.mock('@object-ui/fields', async (importOriginal) => ({ + ...(await importOriginal()), RecordPickerDialog: () => null, })); diff --git a/packages/app-shell/src/views/metadata-admin/AssignedUsersSection.test.tsx b/packages/app-shell/src/views/metadata-admin/AssignedUsersSection.test.tsx index 21f6f86bb2..0eba147355 100644 --- a/packages/app-shell/src/views/metadata-admin/AssignedUsersSection.test.tsx +++ b/packages/app-shell/src/views/metadata-admin/AssignedUsersSection.test.tsx @@ -15,7 +15,8 @@ vi.mock('@object-ui/react', async (importOriginal) => ({ ...(await importOriginal>()), useAdapter: () => mockAdapter, })); -vi.mock('@object-ui/fields', () => ({ +vi.mock('@object-ui/fields', async (importOriginal) => ({ + ...(await importOriginal()), RecordPickerDialog: () => null, })); diff --git a/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.basics.test.tsx b/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.basics.test.tsx index 78873e3996..a163daa36d 100644 --- a/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.basics.test.tsx +++ b/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.basics.test.tsx @@ -36,7 +36,8 @@ vi.mock('./useMetadata', () => ({ vi.mock('./AssignedUsersSection', () => ({ AssignedUsersSection: () => null })); // Stub the capability picker so the B1 collapse logic is isolated from the // live sys_capability registry read. -vi.mock('@object-ui/fields', () => ({ +vi.mock('@object-ui/fields', async (importOriginal) => ({ + ...(await importOriginal()), CapabilityMultiSelectField: () =>
, parseCapabilityNames: (v: unknown) => (typeof v === 'string' ? JSON.parse(v) : []), })); diff --git a/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.bulkMergeKeys.test.tsx b/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.bulkMergeKeys.test.tsx index 92ae5e7475..62dd6ca901 100644 --- a/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.bulkMergeKeys.test.tsx +++ b/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.bulkMergeKeys.test.tsx @@ -89,7 +89,8 @@ vi.mock('./useMetadata', () => ({ }), })); vi.mock('./AssignedUsersSection', () => ({ AssignedUsersSection: () => null })); -vi.mock('@object-ui/fields', () => ({ +vi.mock('@object-ui/fields', async (importOriginal) => ({ + ...(await importOriginal()), CapabilityMultiSelectField: () =>
, parseCapabilityNames: (v: unknown) => (typeof v === 'string' ? JSON.parse(v) : []), })); diff --git a/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.retiredLifecycleKeys.test.tsx b/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.retiredLifecycleKeys.test.tsx index 6641764b0a..6e04a2ca9d 100644 --- a/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.retiredLifecycleKeys.test.tsx +++ b/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.retiredLifecycleKeys.test.tsx @@ -67,7 +67,8 @@ vi.mock('./useMetadata', () => ({ }), })); vi.mock('./AssignedUsersSection', () => ({ AssignedUsersSection: () => null })); -vi.mock('@object-ui/fields', () => ({ +vi.mock('@object-ui/fields', async (importOriginal) => ({ + ...(await importOriginal()), CapabilityMultiSelectField: () =>
, parseCapabilityNames: (v: unknown) => (typeof v === 'string' ? JSON.parse(v) : []), })); diff --git a/packages/app-shell/src/views/metadata-admin/inspectors/FlowReferenceField.lookup.test.tsx b/packages/app-shell/src/views/metadata-admin/inspectors/FlowReferenceField.lookup.test.tsx index b7265b3e9a..8f64afe1e6 100644 --- a/packages/app-shell/src/views/metadata-admin/inspectors/FlowReferenceField.lookup.test.tsx +++ b/packages/app-shell/src/views/metadata-admin/inspectors/FlowReferenceField.lookup.test.tsx @@ -50,7 +50,8 @@ vi.mock('@object-ui/react', async (importOriginal) => ({ // @object-ui/components wires this at module scope (related-count-store). subscribeDataChanges: () => () => {}, })); -vi.mock('@object-ui/fields', () => ({ +vi.mock('@object-ui/fields', async (importOriginal) => ({ + ...(await importOriginal()), LookupField: (props: { field?: { reference_to?: string; idField?: string; multiple?: boolean } }) => (
({ // @object-ui/components wires this at module scope (related-count-store). subscribeDataChanges: () => () => {}, })); -vi.mock('@object-ui/fields', () => ({ +vi.mock('@object-ui/fields', async (importOriginal) => ({ + ...(await importOriginal()), LookupField: () =>
, })); vi.mock('../useMetadata', () => ({ From 720103e0e9aa97bc4603e82bfb708e9237ebcf68 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 7 Sep 2026 05:32:44 +0000 Subject: [PATCH 2/4] test(vi-mock): cover @object-ui/fields in check-vi-mock-inherit The sweep in the previous commit took this specifier to zero frozen, so it joins COVERED_SPECIFIERS -- the grow-only list whose documented widening precondition is a sweep, not a judgement. Seventeen members become eighteen and the gate reads 623 of 623 inheriting. The header gains the slice-13 record in the shape slices 5 to 12 used: the graph walk and its import-time effect classification, the two projects the sites run in and why they answer the cost question in opposite ways, the neighbour reading, and the refreshed remaining population -- which is now one specifier, the parked @object-ui/app-shell. Part of objectui#6892 (slice 13). Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr --- scripts/check-vi-mock-inherit.mjs | 95 +++++++++++++++++++++++++++++-- 1 file changed, 90 insertions(+), 5 deletions(-) diff --git a/scripts/check-vi-mock-inherit.mjs b/scripts/check-vi-mock-inherit.mjs index b3ae8fd274..a76093d691 100644 --- a/scripts/check-vi-mock-inherit.mjs +++ b/scripts/check-vi-mock-inherit.mjs @@ -82,7 +82,7 @@ * - **Workspace specifiers not in `COVERED_SPECIFIERS`.** See below. * * `COVERED_SPECIFIERS` holds the workspace packages whose frozen sites have - * actually been SWEPT to zero. Today that is seventeen, and each joined by sweep + * actually been SWEPT to zero. Today that is eighteen, and each joined by sweep * rather than by judgement. Running this file's classifier over all 1,499 * `vi.mock` call sites in the tree at `9ce20233f`: * @@ -733,10 +733,94 @@ * specifier exists anywhere in the tree, so slice 11's deferred-cost class * could not fire and no module-scope import was owed in any file. * - * The remaining 31 stay on objectui#6892: `@object-ui/app-shell` (23, ALL - * frozen, PARKED under objectui#8173 -- objectui#6892 and the closed - * objectui#6580 point opposite ways on that one specifier and a seat does not - * decide it) and `@object-ui/fields` (8 of 10). + * `@object-ui/fields` joined as objectui#6892's THIRTEENTH slice, re-derived on + * `340489334` by the same `scan()` method, the constant below again never + * widened-and-reverted: + * + * @object-ui/fields 10 judged, 2 inheriting, 8 frozen -> 0 + * + * with the population moving 31 -> 23 frozen over 660 judged and no site moving + * the other way -- a diff of the two per-specifier tables with the + * `@object-ui/fields` row removed is EMPTY. All 8 frozen sites sit under + * `packages/app-shell/src/views` (one in `metadata-admin`'s panel suite, three + * across its `AssignedUsersSection` and `AccessExplainPanel` specs, three in + * its `PermissionMatrixEditor` family and two under `inspectors`) and all 8 are + * ONE syntactic shape -- the zero-parameter object-literal arrow -- carrying + * THREE double families: a null-rendering `RecordPickerDialog` in three files, + * a `CapabilityMultiSelectField` JSX probe paired with a `parseCapabilityNames` + * function double in three, and a `LookupField` JSX probe in two. Each + * hand-listed one or two of the barrel's 140 exports. + * + * STEP 0 was taken again rather than inherited: 504 modules and 5,455 + * module-scope statements reached from `packages/fields/src/index.tsx` over + * nine workspace packages (`components` 205, `core` 95, `fields` 77, `react` + * 64, `i18n` 27, `types` 17, `sdui-parser` 8, `data-objectstack` 6, + * `providers` 5). NOT inert, and the slice proceeded on the CLASS of the + * effect: 112 module-scope `ComponentRegistry.register(...)` calls, ZERO of + * them bare -- `ui` 90, `element` 10, `page` 7, `action` 5, with the + * `page.tsx` renderer's five rows carrying `ui` through the spread `pageMeta` + * constant, so the deprecation `console.warn` in `register()` cannot fire. The + * barrel's OWN module-scope effects are the benign `packages/fields` class + * slice 7 measured, confirmed rather than inherited: five `registerFieldRenderer` + * map writes, one `setCellRendererResolver` assignment and `registerAllFields()`, + * which loops the widget map into `ComponentRegistry.register` under the `field` + * namespace wrapping a `React.lazy` loader -- so registering a widget does not + * LOAD it. Beyond registration the graph holds only allocation: 171 + * `React.forwardRef`, 81 `new Set`, 30 `createContext`, 14 `Object.freeze`, 13 + * `new Map`, 13 `cva`, 11 `createSafeTranslation`, four `Symbol.for` and one + * `subscribeDataChanges` (a `Set.add` into a module-level listener set). An AST + * walk that STOPS at every function-like boundary reports ZERO timers, globals, + * storage, `fetch` and connections at import time; 98 bare side-effect imports + * (the `@object-ui/components` renderer cascade) and one CSS import, inert + * because the root config declares no `css` option. Empirically, importing the + * real barrel under the light `dom` project exports 140 names, moves + * `ComponentRegistry.getAllTypes()` from 0 to 370 keys and emits ZERO + * `console.warn` and ZERO `console.error`. + * + * ⭐ This slice's sites span TWO projects and the two answer the cost question + * in OPPOSITE ways, so taking only one would have been useless. Eight run in + * the light `dom` project, where the isolated cold import costs a median 5.8s; + * the other two are in `heavyDomTests` and run in `dom-heavy`, whose setup + * ALREADY imports this very barrel at module scope -- there the isolated + * "cold" import measures 0 ms and leaves the registry unmoved at 391 keys, + * because the module is resident before any test file is transformed. That is + * the strongest form of the free confirmation this worklist has had for a + * specifier: for two of the eight, inheriting cannot cost anything at all. + * Statically the eight already hold 352 to 422 of the barrel's 504 modules, so + * inheriting adds 82 to 152; measured in the files that pay it the marginal is + * -0.29s (the `dom-heavy` one), +0.05s and +0.94s, and the ten files as ONE + * invocation, taken as an interleaved A/B against the committed tree, read + * +0.50s and +0.65s on a ~25.4s aggregate -- about 2%, inside the noise band + * and nowhere near objectui#6580's STOP band, with 58/58 green in every state. + * + * ⚠️ Slice 11's deferred-cost class was checked and is ABSENT for this + * specifier: the only `import('@object-ui/fields')` anywhere in the tree is a + * TYPE position (`typeof import(...)`) inside an already-inheriting factory, so + * no consuming module reaches this barrel through `React.lazy`. The two + * module-scope `React.lazy` calls the graph does contain are INSIDE the package + * and load package-local widget modules, which the real barrel resolves itself; + * neither defers anything across a converted file's assertion window. No + * module-scope import repair was owed, and none was made. + * + * The neighbour reading found ZERO repairs owed and said so in advance from the + * walk. Across the ten files there is not ONE third-party factory -- so the + * frozen `lucide-react` neighbour that killed 15 files in slice 6 cannot exist + * here, even though this barrel's graph reads `lucide-react` 76 times and + * reaches `sonner`. Every workspace neighbour already inherits (four + * `@object-ui/react` sites, one `@object-ui/auth`), and two of the four + * `@object-ui/react` ones already provide `subscribeDataChanges` explicitly -- + * the one binding this graph reads from that specifier at module scope, which + * is slice 12's sharpened rule satisfied before the fact rather than by luck. + * The remaining nine neighbours are local whole-module replacements, out of + * scope by construction and safe by REACH: this barrel's graph reaches nothing + * under `packages/app-shell`. No file among the ten mocks `@object-ui/app-shell`, + * so the parked specifier stays parked. + * + * The remaining 23 stay on objectui#6892, and they are now ONE specifier: + * `@object-ui/app-shell` (23, ALL frozen, PARKED under objectui#8173 -- + * objectui#6892 and the closed objectui#6580 point opposite ways on that one + * specifier and a seat does not decide it). Every other workspace specifier any + * `vi.mock` call site in this tree names is covered and reads zero frozen. * * **The precondition for widening is a sweep, not a judgement.** Convert a * specifier's frozen factories to the inheriting form, confirm this gate reads @@ -838,6 +922,7 @@ export const COVERED_SPECIFIERS = Object.freeze([ '@object-ui/plugin-chatbot', '@object-ui/plugin-designer', '@object-ui/plugin-list', + '@object-ui/fields', ]); /** Files the walk reads at all. */ From 36e0a954846b33969e105ed1f9613199e72a158c Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 7 Sep 2026 05:33:04 +0000 Subject: [PATCH 3/4] chore(changeset): declare slice 13 as releasing nothing Eight test files under a published package changed, so check-changeset-presence demands a declaration. It is test-only, hence the empty frontmatter. Part of objectui#6892 (slice 13). Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr --- .changeset/vi-mock-inherit-slice13-fields.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/vi-mock-inherit-slice13-fields.md diff --git a/.changeset/vi-mock-inherit-slice13-fields.md b/.changeset/vi-mock-inherit-slice13-fields.md new file mode 100644 index 0000000000..590c936ec6 --- /dev/null +++ b/.changeset/vi-mock-inherit-slice13-fields.md @@ -0,0 +1,6 @@ +--- +--- + +Test-only change: eight `vi.mock` factories in `@object-ui/app-shell` now inherit +the real `@object-ui/fields` export surface instead of freezing it, and the +`check-vi-mock-inherit` gate covers that specifier. No published behaviour changes. From c389601b23d7eb8d13ebd747959baeef8b3f2778 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 7 Sep 2026 06:18:07 +0000 Subject: [PATCH 4/4] docs(vi-mock): correct the slice-13 record's per-directory breakdown The clause counted the AccessExplainPanel spec twice, so the eight frozen sites read as nine. All eight sit under one directory; the breakdown now says so and adds to eight. Part of objectui#6892 (slice 13). Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr --- scripts/check-vi-mock-inherit.mjs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/check-vi-mock-inherit.mjs b/scripts/check-vi-mock-inherit.mjs index a76093d691..c1645ff41d 100644 --- a/scripts/check-vi-mock-inherit.mjs +++ b/scripts/check-vi-mock-inherit.mjs @@ -742,9 +742,9 @@ * with the population moving 31 -> 23 frozen over 660 judged and no site moving * the other way -- a diff of the two per-specifier tables with the * `@object-ui/fields` row removed is EMPTY. All 8 frozen sites sit under - * `packages/app-shell/src/views` (one in `metadata-admin`'s panel suite, three - * across its `AssignedUsersSection` and `AccessExplainPanel` specs, three in - * its `PermissionMatrixEditor` family and two under `inspectors`) and all 8 are + * `packages/app-shell/src/views/metadata-admin` -- three across the + * `AccessExplainPanel` and `AssignedUsersSection` specs, three in the + * `PermissionMatrixEditor` family and two under `inspectors` -- and all 8 are * ONE syntactic shape -- the zero-parameter object-literal arrow -- carrying * THREE double families: a null-rendering `RecordPickerDialog` in three files, * a `CapabilityMultiSelectField` JSX probe paired with a `parseCapabilityNames`