Skip to content

test(app-shell,console): inherit the real surface in @object-ui/auth vi.mock factories - #8054

Merged
baozhoutao merged 3 commits into
mainfrom
claude/issue-6892-vi-mock-inherit-slice3-auth
Sep 6, 2026
Merged

baozhoutao merged 3 commits into
mainfrom
claude/issue-6892-vi-mock-inherit-slice3-auth

Conversation

@claude

@claude claude Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Part of #6892 — slice 3 of the per-specifier vi.mock sweep worklist: @object-ui/auth, the largest block on it by a factor of three.

All 102 frozen factories on @object-ui/auth now obtain the real module and spread it before their overrides, and the specifier joins COVERED_SPECIFIERS in scripts/check-vi-mock-inherit.mjs in the same PR — the gate's documented widening precondition.

Generic type arguments below are spelled as CAPITALISED WORDS rather than in angle brackets, because GitHub's body sanitizer silently deletes tag-shaped fragments — including inside backticks and fenced blocks (AGENTS.md, "GitHub 会改写你写进 issue/PR 正文的字节"). The code itself uses the real syntax.

STEP 0 — what does inheriting actually RUN?

Converting a freeze to inheritance loads the real barrel in every converted file, so a barrel with module-scope side effects has those effects restored in ~100 files at once. That is a measurement to take before converting, not a risk to discover mid-sweep, and slice 2 paid for the warning: both barrels it swept made 8 module-scope ComponentRegistry.register calls each.

packages/auth/src's barrel is 112 lines of re-exports — but "re-exports only by grep" is not the measurement. The whole static import graph was walked from index.ts and every top-level statement classified. 22 modules, and exactly 8 module-scope initialisers, all pure in-memory allocation:

file:line what runs at import
useWorkspaceAdminStatus.ts:11 ADMIN_ROLES — a Set of six literal strings
invitation-status.ts:66 AUTH_INVITATION_STATUSES — Object.values of a literal
invitation-status.ts:70 STATUS_LOOKUP — a Set over that array
AuthContext.ts:195 AuthCtx — createContext(null)
AuthContext.ts:196 AuthCtx.displayName = 'AuthContext'
auth-gate-events.ts:29 listeners — an empty Set
ActiveOrganizationStorage.ts:90 LEGACY_ACTIVE_ORG_KEY — an alias of another constant
ActiveOrganizationStorage.ts:109 DEVICE_SCOPED_KEYS — a Set of three literals

And zero of the things that would have stopped this slice: no registrations, no timers, no globals, no fetch, no storage access at module scope, and no side-effect-only imports. Two column-anchored greps back the AST walk, both returning no match (grep exit 1): module-scope touches of window / document / globalThis / localStorage / sessionStorage / setTimeout / setInterval / fetch / navigator, and module-scope IDENT.register( / .init( / .configure( / .addEventListener( calls. The five localStorage / window.location hits in the package are all indented inside function bodies.

⇒ Inert, and strictly more so than what slice 2 absorbed. Proceeding, with one independent confirmation: 33 of the 135 judged @object-ui/auth sites already inherited the real barrel before this PR (27 in app-shell, 6 in console) and are green on main. The real barrel demonstrably loads in both packages' test environments today; this PR takes that from 33 files to 135.

⛔ That verdict does not generalise to the next barrel. Take the measurement.

STEP 1 — the derived table

Re-derived with the fixed classifier through the guard's exported scan() with covered set to all 22 workspace specifiers the tree names. ⛔ The constant in the tree was never widened-and-reverted, so there was no window in which a mutated constant could have been committed. Nothing was inherited from the card's table.

judged frozen before frozen after
@object-ui/auth 135 102 0

All-specifier population on the sweep's own base 06761b3: 311 → 209 frozen, judged unchanged at 640, and every other one of the 21 rows byte-identical between the two runs — zero sites moving the other way.

The PM's grep upper bound (135 files: 116 app-shell + 19 console) over-counted, as expected: the actual frozen set is 102 sites, 89 under packages/app-shell and 13 under apps/console.

STEP 2 — the conversion

Three shapes, all converted to obtain-and-spread with the spread first:

  • 77 sites — multi-line object-literal arrow. () => becomes async (importOriginal) => and a spread of await importOriginal() (generic argument RECORD-OF-STRING-TO-UNKNOWN) becomes the first property.
  • 16 sites — the same factory written on one line; expanded to the multi-line form so the spread reads as the first property rather than being buried mid-line.
  • 9 sites — block-bodied arrow (() => { ...; return { ... } }). The head becomes async (importOriginal) => and the spread becomes the first property of the return object, leaving the pre-return locals (a stable getAuthConfig identity, a shared authFetch double) exactly where they were and doing exactly what they did.

Verification is per file and does not trust the conversion script's exit code: all 102 files parse clean, the spread is confirmed first in all 102, and the gate's own per-file verdict plus both packages' full suites are the actual evidence.

No site was a deliberate freeze. Nothing in the 102 was written to prove a module is not loaded, so nothing was left converted-blindly or reported as an exception. ⛔ No exemption table, ⛔ no per-site opt-out.

No file died during collection. The failure class this worklist exists for did not fire once: app-shell reports the same 632 files / 6077 tests as before the sweep, console the same 89 / 981.

Residuals — none

⇒ auth reads 0 frozen on this tree with nothing held back, so the COVERED_SPECIFIERS line ships in full.

Ablation — six legs, three shapes, from the committed tree

One site per converted shape, two legs each. Mutate by reversing the conversion on that one factory; restore with git checkout HEAD -- ABSOLUTE_PATH under a trap on EXIT INT TERM.

site shape spread marker mutated gate restore
RecordApprovalsPanel.test.tsx:30 multi-line 1 → 0 exit 1, 1 site line, names this file blob 5879cb084, git diff HEAD empty, gate exit 0
FavoritesProvider.test.tsx:15 was inline 1 → 0 exit 1, 1 site line, names this file blob 041e7c1b9, git diff HEAD empty, gate exit 0
AppHeader.singleMembershipOrg.test.tsx:131 block-bodied 3 → 2 exit 1, 1 site line, names this file blob 300b827c7, git diff HEAD empty, gate exit 0

The third site is the load-bearing one: that file holds three inheriting factories on different specifiers, and the mutation removed exactly one — proof the reversal was surgical rather than a broad delete. Restore is proven by git hash-object equalling the HEAD blob and an empty git diff HEAD, never by a git checkout exit code. No dist preflight is needed: the root vitest.config.mts aliases @object-ui/auth to packages/auth/src, and the gate is a source-text scanner.

Gates — pinned to head 8d7235c19

gate result
pnpm check:vi-mock-inherit exit 0 — 369 call sites on eight covered specifiers judged, 369 inherit, 0 auto-mocked (was 233 on seven)
vitest scripts/__tests__/check-vi-mock-inherit.test.ts exit 0, 69/69 — unchanged, no pin edit needed
vitest packages/app-shell/ exit 0, 632 files / 6077 passed + 1 skipped, 1141.48s
vitest apps/console/ exit 0, 89 files / 981 passed, 300.15s
pnpm check:vi-mock-specifiers exit 0
pnpm type-check:scripts exit 0
pnpm check:control-bytes exit 0 (6457 files) + grep -naP self-scan of all 104 changed paths, no match
node scripts/check-changeset-presence.mjs exit 0 — empty-frontmatter changeset added
pnpm changeset:check exit 0 (fixed group, no major)
node scripts/check-lint-coverage.mjs exit 0, 46/46 packages, 0 outstanding errors
node scripts/check-governed-queue-guard.mjs --test (104 paths) NOT GOVERNED
app-shell type-check exit 0 both programs; non-vacuous — --listFiles names 89 of 89 edited files in a 4421-file program
console type-check exit 0 both; non-vacuous — names 13 of 13 edited files in a 3510-file program
app-shell / console lint exit 0; 1087 and 189 files in --format json, 0 errors; intersecting every lint message against the diff's added line numbers gives 0 messages on any line this PR adds
examples byo-backend-console / console-starter type-check exit 0 each (turbo-affected by graph only)

Both suites were measured at 71250f56b, the sweep commit. origin/main then moved 5 commits and was merged (never rebased); the 102 converted files are byte-identical between that head and 8d7235c19, so the suite reading transfers — everything else in the merge is main's own already-landed work. Every gate in the table above was re-run at 8d7235c19. Live E2E (informational) is red on every branch today for an upstream reason (#7990) — not this change.

One finding worth carrying to slice 4

The merge is a second observed instance of slice 2's growth warning, this time inside a single slice: in the ~40 minutes between deriving the table and opening this PR, other PRs landed two new frozen sites (@object-ui/plugin-form, @object-ui/plugin-grid) and one new inheriting @object-ui/react site. The population reads 211 over 643 judged on the merged head — none of it auth, which stays at 0. Re-derive per slice, on the merge base, every time. The header records which number belongs to which tree.

Next by yield: @object-ui/collaboration (33/33) and @object-ui/plugin-form (31/32). @object-ui/app-shell (24) still reads #6580 first.


Generated by Claude Code

…vi.mock factories

objectui#6892 slice 3. All 102 frozen factories on `@object-ui/auth` -- the
largest block on the worklist by a factor of three -- now obtain the real module
and spread it before their overrides, and the specifier joins
`COVERED_SPECIFIERS` in `scripts/check-vi-mock-inherit.mjs` in the same commit,
which is the gate's documented widening precondition.

STEP 0 first, because inheriting RUNS whatever the barrel does at module scope,
in every converted file at once. `packages/auth/src`'s 22-module static import
graph was walked and every top-level statement classified before a single
conversion: 8 module-scope initialisers, all pure in-memory allocation (two
`Set`s of literal strings, an `Object.values` and a `Set` over it,
`createContext(null)` plus its `displayName`, an empty listener `Set`, one
alias), and zero registrations, timers, globals, `fetch` or side-effect-only
imports. Inert -- strictly more so than the two barrels slice 2 absorbed, which
each made 8 module-scope `ComponentRegistry.register` calls.

Counts re-derived on this tree through the guard's exported `scan()` with
`covered` set to all 22 workspace specifiers, never by widening the constant:
`@object-ui/auth` 135 judged / 102 frozen -> 0, all-specifier population
311 -> 209 frozen, judged unchanged at 640, with every other row byte-identical
between the two runs -- zero sites moving the other way.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr
…re measured on

The 311 -> 209 pair is the sweep's own before/after on `06761b351`. Merging
`origin/main` mid-slice then took the population to 211 over 643 judged, none of
it this change: two new frozen sites on `@object-ui/plugin-form` and
`@object-ui/plugin-grid` plus one new inheriting `@object-ui/react` site landed
from other PRs during verification. Recording which number belongs to which tree
keeps the header from reading stale, and gives the growth warning a second
observed instance -- this time inside a single slice.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 50 chunks) 3186.0 KB 3191.4 KB
Main entry chunk (gzip) 143.5 KB 350 KB
Entry file index-DuMkzIKe.js —
Status PASS —

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

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 15.67KB 5.75KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 5.13KB 2.35KB
collaboration (CommentThread.js) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 497.06KB 113.79KB
core (index.js) 6.96KB 2.79KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 182.08KB 50.62KB
fields (index.js) 242.44KB 61.25KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 4.28KB 1.75KB
i18n (index.js) 3.65KB 1.47KB
i18n (pickLocalized.js) 7.62KB 3.26KB
i18n (provider.js) 26.89KB 9.04KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 38.84KB 10.94KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 4.39KB 1.66KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 11.71KB 4.29KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 5.12KB 1.74KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 15.16KB 3.68KB
plugin-calendar (index.js) 47.29KB 13.18KB
plugin-charts (index.js) 70.43KB 19.71KB
plugin-chatbot (index.js) 193.53KB 46.05KB
plugin-dashboard (index.js) 131.41KB 34.43KB
plugin-designer (index.js) 211.51KB 43.01KB
plugin-detail (index.js) 247.59KB 63.48KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 131.01KB 32.32KB
plugin-gantt (index.js) 167.16KB 40.99KB
plugin-grid (index.js) 208.56KB 56.63KB
plugin-kanban (index.js) 52.30KB 14.49KB
plugin-list (index.js) 113.24KB 27.66KB
plugin-map (index.js) 20.35KB 6.77KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.42KB 11.92KB
plugin-timeline (index.js) 29.95KB 8.67KB
plugin-tree (index.js) 9.19KB 3.19KB
plugin-view (index.js) 84.33KB 20.75KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 81.07KB 26.86KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 2.32KB 1.24KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 5.41KB 2.34KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 4.93KB 2.24KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 20.57KB 5.88KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 10.35KB 3.60KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.74KB 1.41KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 4.73KB 2.28KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

Copy link
Copy Markdown
Contributor

Standing down on Live E2E (informational): that check is red on main itself today (base-red, anchored on objectui#7990 / objectstack-ai/objectstack#16186), it is informational (not required), and this PR changes 102 unit-test files, the vi-mock gate's constant and header, and an empty changeset — nothing the live lane exercises. No fix is ported because none exists yet upstream. The flip to ready happens only once every non-informational check on 8d7235c19 is green.


Generated by Claude Code

@baozhoutao
baozhoutao marked this pull request as ready for review September 6, 2026 13:33
@baozhoutao
baozhoutao added this pull request to the merge queue Sep 6, 2026
Merged via the queue into main with commit 951fa8e Sep 6, 2026
33 of 34 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-6892-vi-mock-inherit-slice3-auth branch September 6, 2026 13:48
baozhoutao pushed a commit that referenced this pull request Sep 6, 2026
…notice

Keeps this branch on the current main (#8054 landed while this was in flight).
Disjoint by file: that change is app-shell/console vi.mock factories plus
scripts/check-vi-mock-inherit.mjs; this branch touches only
scripts/check-skill-examples.mjs and its pin test.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants