diff --git a/.changeset/vi-mock-inherit-slice11-plugin-designer.md b/.changeset/vi-mock-inherit-slice11-plugin-designer.md
new file mode 100644
index 0000000000..cce2fcea0d
--- /dev/null
+++ b/.changeset/vi-mock-inherit-slice11-plugin-designer.md
@@ -0,0 +1,7 @@
+---
+---
+
+Test-only change: the ten `vi.mock('@object-ui/plugin-designer', ...)` factories in the
+`AppContent.*` sibling family now inherit the real module's export surface instead of
+freezing three of its 29 exports, and the specifier joins the covered set of
+`scripts/check-vi-mock-inherit.mjs`. No published behaviour changes.
diff --git a/apps/console/src/__tests__/AppContent.systemHubRoutes.test.tsx b/apps/console/src/__tests__/AppContent.systemHubRoutes.test.tsx
index a94d94d150..c7a2e9bbf8 100644
--- a/apps/console/src/__tests__/AppContent.systemHubRoutes.test.tsx
+++ b/apps/console/src/__tests__/AppContent.systemHubRoutes.test.tsx
@@ -107,7 +107,8 @@ vi.mock('../../../../packages/app-shell/src/console/marketplace/MarketplacePacka
MarketplacePackagePage: () =>
,
}));
-vi.mock('@object-ui/plugin-designer', () => ({
+vi.mock('@object-ui/plugin-designer', async (importOriginal) => ({
+ ...(await importOriginal()),
CreateAppPage: () => create app
,
EditAppPage: () => ,
DashboardDesignPage: () => ,
diff --git a/packages/app-shell/src/console/__tests__/AppContent.bootRedirectCoverage.test.tsx b/packages/app-shell/src/console/__tests__/AppContent.bootRedirectCoverage.test.tsx
index 9d07165133..3426082ebf 100644
--- a/packages/app-shell/src/console/__tests__/AppContent.bootRedirectCoverage.test.tsx
+++ b/packages/app-shell/src/console/__tests__/AppContent.bootRedirectCoverage.test.tsx
@@ -34,7 +34,8 @@ import React, { useLayoutEffect } from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import { MemoryRouter, Routes, Route, useLocation } from 'react-router-dom';
-vi.mock('@object-ui/plugin-designer', () => ({
+vi.mock('@object-ui/plugin-designer', async (importOriginal) => ({
+ ...(await importOriginal()),
CreateAppPage: () => create app
,
EditAppPage: () => ,
DashboardDesignPage: () => ,
diff --git a/packages/app-shell/src/console/__tests__/AppContent.declaredVisibilityKeys.test.tsx b/packages/app-shell/src/console/__tests__/AppContent.declaredVisibilityKeys.test.tsx
index e8ff431911..4d617f58d3 100644
--- a/packages/app-shell/src/console/__tests__/AppContent.declaredVisibilityKeys.test.tsx
+++ b/packages/app-shell/src/console/__tests__/AppContent.declaredVisibilityKeys.test.tsx
@@ -53,7 +53,8 @@ vi.mock('@object-ui/plugin-form', async (importOriginal) => ({
},
}));
-vi.mock('@object-ui/plugin-designer', () => ({
+vi.mock('@object-ui/plugin-designer', async (importOriginal) => ({
+ ...(await importOriginal()),
CreateAppPage: () => ,
EditAppPage: () => ,
DashboardDesignPage: () => ,
diff --git a/packages/app-shell/src/console/__tests__/AppContent.deniedVsUnpublished.test.tsx b/packages/app-shell/src/console/__tests__/AppContent.deniedVsUnpublished.test.tsx
index 37d9b4fd22..05c508ab63 100644
--- a/packages/app-shell/src/console/__tests__/AppContent.deniedVsUnpublished.test.tsx
+++ b/packages/app-shell/src/console/__tests__/AppContent.deniedVsUnpublished.test.tsx
@@ -66,7 +66,8 @@ import { ObjectStackAdapter } from '@object-ui/data-objectstack';
// Mocks — everything that takes part in the DECISION stays real.
// ---------------------------------------------------------------------------
-vi.mock('@object-ui/plugin-designer', () => ({
+vi.mock('@object-ui/plugin-designer', async (importOriginal) => ({
+ ...(await importOriginal()),
CreateAppPage: () => ,
EditAppPage: () => ,
DashboardDesignPage: () => ,
diff --git a/packages/app-shell/src/console/__tests__/AppContent.inaccessibleAppStrand.test.tsx b/packages/app-shell/src/console/__tests__/AppContent.inaccessibleAppStrand.test.tsx
index 83f929df99..e03995586e 100644
--- a/packages/app-shell/src/console/__tests__/AppContent.inaccessibleAppStrand.test.tsx
+++ b/packages/app-shell/src/console/__tests__/AppContent.inaccessibleAppStrand.test.tsx
@@ -69,7 +69,8 @@ import { MemoryRouter, Routes, Route, Navigate, useLocation, useNavigationType }
// guards, its nested ) stays real.
// ---------------------------------------------------------------------------
-vi.mock('@object-ui/plugin-designer', () => ({
+vi.mock('@object-ui/plugin-designer', async (importOriginal) => ({
+ ...(await importOriginal()),
CreateAppPage: () => create app
,
EditAppPage: () => ,
DashboardDesignPage: () => ,
diff --git a/packages/app-shell/src/console/__tests__/AppContent.missingRecheckKeying.test.tsx b/packages/app-shell/src/console/__tests__/AppContent.missingRecheckKeying.test.tsx
index ab9c135443..c3719b31c2 100644
--- a/packages/app-shell/src/console/__tests__/AppContent.missingRecheckKeying.test.tsx
+++ b/packages/app-shell/src/console/__tests__/AppContent.missingRecheckKeying.test.tsx
@@ -55,7 +55,8 @@ import { MemoryRouter, Routes, Route, useLocation, useNavigate } from 'react-rou
// Mocks — everything that takes part in the re-check DECISION stays real.
// ---------------------------------------------------------------------------
-vi.mock('@object-ui/plugin-designer', () => ({
+vi.mock('@object-ui/plugin-designer', async (importOriginal) => ({
+ ...(await importOriginal()),
CreateAppPage: () => ,
EditAppPage: () => ,
DashboardDesignPage: () => ,
diff --git a/packages/app-shell/src/console/__tests__/AppContent.noAppComponentRoutes.test.tsx b/packages/app-shell/src/console/__tests__/AppContent.noAppComponentRoutes.test.tsx
index f9713d3deb..4152c0c7af 100644
--- a/packages/app-shell/src/console/__tests__/AppContent.noAppComponentRoutes.test.tsx
+++ b/packages/app-shell/src/console/__tests__/AppContent.noAppComponentRoutes.test.tsx
@@ -127,7 +127,8 @@ vi.mock('../../views/metadata-admin', () => ({
MetadataDiagnosticsPage: () => ,
}));
-vi.mock('@object-ui/plugin-designer', () => ({
+vi.mock('@object-ui/plugin-designer', async (importOriginal) => ({
+ ...(await importOriginal()),
CreateAppPage: () => create app
,
EditAppPage: () => ,
DashboardDesignPage: () => ,
diff --git a/packages/app-shell/src/console/__tests__/AppContent.noAppsCta.test.tsx b/packages/app-shell/src/console/__tests__/AppContent.noAppsCta.test.tsx
index cd8f74b16e..eafe9a4159 100644
--- a/packages/app-shell/src/console/__tests__/AppContent.noAppsCta.test.tsx
+++ b/packages/app-shell/src/console/__tests__/AppContent.noAppsCta.test.tsx
@@ -76,12 +76,26 @@ import { MemoryRouter, Routes, Route, Navigate, useLocation } from 'react-router
// The CTA's target sits behind `React.lazy(() => import('@object-ui/plugin-designer'))`.
// Stubbing it keeps the assertion off the transform pipeline entirely (AGENTS.md
// §测试纪律: never let an unbounded module load race a bounded `findBy` window).
-vi.mock('@object-ui/plugin-designer', () => ({
+vi.mock('@object-ui/plugin-designer', async (importOriginal) => ({
+ ...(await importOriginal()),
CreateAppPage: () => create app
,
EditAppPage: () => ,
DashboardDesignPage: () => ,
}));
+// Pay the real designer barrel's load in the IMPORT phase, where no timeout
+// applies. `AppContent` reaches `CreateAppPage` only through
+// `React.lazy(() => import('@object-ui/plugin-designer'))`, so the factory
+// above -- which now awaits the real module -- first runs when that lazy
+// boundary resolves, i.e. INSIDE the `findByTestId` budget of the two cases
+// below that assert on `create-app-page`. Under a saturated transform pipeline
+// the barrel's graph does not fit in that budget and the file goes red on LOAD
+// rather than on behaviour (AGENTS.md, the flaky-test discipline: an unbounded
+// module load counted against a bounded window). The specifier is byte-
+// identical to the component's own, so ESM hands the lazy factory this
+// already-resolved module.
+import '@object-ui/plugin-designer';
+
vi.mock('@object-ui/i18n', async (importOriginal) => ({
...(await importOriginal>()),
useObjectTranslation: () => ({
diff --git a/packages/app-shell/src/console/__tests__/AppContent.pseudoRouteSegments.test.tsx b/packages/app-shell/src/console/__tests__/AppContent.pseudoRouteSegments.test.tsx
index 225fcea862..2fc7558b16 100644
--- a/packages/app-shell/src/console/__tests__/AppContent.pseudoRouteSegments.test.tsx
+++ b/packages/app-shell/src/console/__tests__/AppContent.pseudoRouteSegments.test.tsx
@@ -152,12 +152,26 @@ vi.mock('../marketplace/MarketplacePackagePage', () => ({
MarketplacePackagePage: () => ,
}));
-vi.mock('@object-ui/plugin-designer', () => ({
+vi.mock('@object-ui/plugin-designer', async (importOriginal) => ({
+ ...(await importOriginal()),
CreateAppPage: () => create app
,
EditAppPage: () => ,
DashboardDesignPage: () => ,
}));
+// Pay the real designer barrel's load in the IMPORT phase, where no timeout
+// applies. `AppContent` reaches `CreateAppPage` only through
+// `React.lazy(() => import('@object-ui/plugin-designer'))`, so the factory
+// above -- which now awaits the real module -- first runs when that lazy
+// boundary resolves, i.e. INSIDE the `findByTestId` budget of the two cases
+// below that assert on `create-app-page`. Under a saturated transform pipeline
+// the barrel's graph does not fit in that budget and the file goes red on LOAD
+// rather than on behaviour (AGENTS.md, the flaky-test discipline: an unbounded
+// module load counted against a bounded window). The specifier is byte-
+// identical to the component's own, so ESM hands the lazy factory this
+// already-resolved module.
+import '@object-ui/plugin-designer';
+
/**
* The probe that makes the bug visible: it reports WHICH app's shell rendered.
* The real `ConsoleLayout` drags in the whole console chrome (sidebar, header,
diff --git a/packages/app-shell/src/console/__tests__/AppContent.unresolvedAdmin-5619.test.tsx b/packages/app-shell/src/console/__tests__/AppContent.unresolvedAdmin-5619.test.tsx
index 1b45c2f2ed..89491a337f 100644
--- a/packages/app-shell/src/console/__tests__/AppContent.unresolvedAdmin-5619.test.tsx
+++ b/packages/app-shell/src/console/__tests__/AppContent.unresolvedAdmin-5619.test.tsx
@@ -46,7 +46,8 @@ import React from 'react';
import { render, screen } from '@testing-library/react';
import { MemoryRouter, Routes, Route, Navigate, useLocation } from 'react-router-dom';
-vi.mock('@object-ui/plugin-designer', () => ({
+vi.mock('@object-ui/plugin-designer', async (importOriginal) => ({
+ ...(await importOriginal()),
CreateAppPage: () => create app
,
EditAppPage: () => ,
DashboardDesignPage: () => ,
diff --git a/scripts/check-vi-mock-inherit.mjs b/scripts/check-vi-mock-inherit.mjs
index 1839a1868f..637684abf4 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 fifteen, and each joined by sweep
+ * actually been SWEPT to zero. Today that is sixteen, 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`:
*
@@ -579,11 +579,89 @@
* ⭐ The free confirmation is present: 5 of the 16 sites already inherited the
* real barrel on `main` and passed, all of them in the light `dom` project.
*
- * The remaining 50 stay on objectui#6892: `@object-ui/app-shell` (23, ALL
+ * `@object-ui/plugin-designer` joined as objectui#6892's ELEVENTH slice,
+ * re-derived on `ecf8e726e` by the same `scan()` method, the constant below
+ * again never widened-and-reverted:
+ *
+ * @object-ui/plugin-designer 10 judged, 0 inheriting, 10 frozen -> 0
+ *
+ * with the population moving 50 -> 40 frozen over 659 judged and no site moving
+ * the other way. The 10 sites are an `AppContent.*` SIBLING FAMILY in one
+ * syntactic shape -- the zero-parameter object-literal arrow, each hand-listing
+ * the same three of the barrel's 29 exports -- and this is the first slice on
+ * this worklist to reach OUTSIDE `packages/`: nine sit under
+ * `packages/app-shell` and one under `apps/console`, which runs in its own
+ * merged vitest project rather than in the root config's.
+ *
+ * STEP 0 was taken again rather than inherited: 619 modules and 6,825
+ * module-scope statements reached from `packages/plugin-designer/src/index.tsx`
+ * over fourteen workspace packages (`components` 206, `core` 95, `fields` 77,
+ * `react` 64, `plugin-grid` 31, `plugin-designer` 29, `plugin-form` 28, `i18n`
+ * 27, `types` 18, `mobile` 16, `permissions` 10, `sdui-parser` 8,
+ * `data-objectstack` 5, `providers` 5). NOT inert, and the slice proceeded on
+ * the CLASS of the effect: 130 module-scope `ComponentRegistry.register(...)`
+ * calls, ZERO of them bare. Every one carries a namespace (`ui` 89, `element`
+ * 10, `page` 7, `action` 5, `plugin-form` 4, `plugin-designer` 10, `plugin-grid`
+ * 2, `view` 2, `record` 1); the five rows in the `page.tsx` renderer that READ
+ * as bare carry `ui` through the spread `pageMeta` constant, so the deprecation
+ * `console.warn` in `register()` cannot fire. The remaining effects are the
+ * benign registration class slice 7 already measured in `packages/fields`: five
+ * `registerFieldRenderer(...)` map writes, one `setCellRendererResolver(...)`
+ * assignment and `registerAllFields()`. One CSS import, inert (the root config
+ * declares no `css` option). Empirically, importing the real barrel emits ZERO
+ * `console.warn` and ZERO `console.error` in BOTH projects and exports 29 names.
+ *
+ * ⭐ The import cost was taken in both projects the sites run in, and the two
+ * differ by an order of magnitude for the same reason slice 10 recorded: under
+ * the light `dom` project the isolated cold import costs a median 6.89s and
+ * moves the registry 0 -> 405 keys; under the console project, whose merged
+ * config uses the HEAVY dom setup, it costs a median 0.54s and moves the
+ * registry 391 -> 421. Neither number decides anything on its own. The marginal
+ * cost measured in the files that pay it is uniform and small -- an app-shell
+ * file 9.19s frozen -> 9.55s inheriting, the console file 18.84s -> 19.22s --
+ * and the aggregate over the ten files as ONE invocation is +3.6s on a ~36s
+ * median (four frozen runs against five inheriting ones, two of them
+ * interleaved A/B), i.e. inside the noise band of a shared box and nowhere near
+ * objectui#6580's STOP band. The mechanism is measured, not argued: every one
+ * of the ten files ALREADY holds 590 of the barrel's 619 modules at module
+ * scope, so inheriting adds exactly the 29 modules of the designer package
+ * itself.
+ *
+ * ⚠️ This slice met a failure mode the worklist had not met before, and it is
+ * NOT slice 6's collection death: two of the ten went red on LOAD TIMING. The
+ * console shell reaches `CreateAppPage` only through
+ * `React.lazy(() => import('@object-ui/plugin-designer'))`, so an inheriting
+ * factory first runs when that lazy boundary resolves -- inside the RTL
+ * `findBy` budget of the two files that assert on the rendered designer page.
+ * Alone they pass; in the ten-file invocation the transform pipeline is
+ * saturated and the 29 added modules do not fit in 1000ms, so the assertion
+ * fails while the shell is still booting. The repair is the one AGENTS.md
+ * prescribes for an unbounded module load counted against a bounded window --
+ * a module-scope `import '@object-ui/plugin-designer'` in those two files,
+ * which moves the cost into the import phase where no timeout applies. No
+ * assertion was touched. ⇒ CARRY-FORWARD: a specifier reached only through
+ * `React.lazy` defers the whole inheritance cost into a test's assertion
+ * window, so budget the timing check on the AGGREGATE invocation and never on
+ * the per-file run, which cannot see it.
+ *
+ * The neighbour reading found ZERO repairs owed and said so in advance: across
+ * the ten files every workspace neighbour already inherits (10 `@object-ui/auth`
+ * sites, 10 `@object-ui/i18n`, 8 `@object-ui/react`, 1 `@object-ui/plugin-form`)
+ * and there is not one third-party factory in the family at all -- 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` 106 times. The remaining
+ * neighbours are 39 local whole-module replacements, out of scope by
+ * construction. No file among the ten mocks `@object-ui/app-shell`, so the
+ * parked specifier stays parked.
+ *
+ * ⚠️ Like slices 4 and 7, this specifier had ZERO already-inheriting sites, so
+ * there was no free confirmation -- the suite runs themselves are the evidence.
+ *
+ * The remaining 40 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), `@object-ui/plugin-designer` (10, ALL frozen),
- * `@object-ui/plugin-list` (9 of 10) and `@object-ui/fields` (8 of 10).
+ * decide it), `@object-ui/plugin-list` (9 of 10) and `@object-ui/fields`
+ * (8 of 10).
*
* **The precondition for widening is a sweep, not a judgement.** Convert a
* specifier's frozen factories to the inheriting form, confirm this gate reads
@@ -683,6 +761,7 @@ export const COVERED_SPECIFIERS = Object.freeze([
'@object-ui/permissions',
'@object-ui/plugin-detail',
'@object-ui/plugin-chatbot',
+ '@object-ui/plugin-designer',
]);
/** Files the walk reads at all. */