Skip to content

fix(app-shell): route three more publish-drafts call sites through the advisory reporting seam (objectui#10039) - #10147

Merged
os-tesla merged 2 commits into
mainfrom
claude/issue-10039-publish-drafts-advisories
Sep 20, 2026
Merged

os-tesla merged 2 commits into
mainfrom
claude/issue-10039-publish-drafts-advisories

Conversation

@os-tesla

Copy link
Copy Markdown
Collaborator

Fixes #10039

Clause-②: no — three call sites move onto an existing client method. No exported symbol and no key on a published payload moves.

Three app-shell call sites still fired POST /packages/:id/publish-drafts with a bare fetch, outside the seam that can report. The server has answered per-draft advisories on each published[] element since objectstack#9343 landed, and objectui#6965 / PR #10038 built the client half for the two call sites that card named. On these three the findings were parsed by nobody.

Session reference, in prose because a footer does not reliably survive an edit: https://claude.ai/code/session_018HrVaotisyhgmot9o2MLRq

The enumeration, re-taken rather than inherited — and it does NOT reproduce the card's control

Every figure below is a READING at the sha it names, taken with the instrument spelled beside it. None of them is a live count and nothing re-derives them after this paragraph is written; re-run the instrument rather than trusting the number.

Instrument (uncapped, counted before any row was read — no head -N anywhere in it):

git grep -n -- 'publish-drafts' REV -- packages/app-shell/src apps/console/src
reading non-test rows files incl. tests
what the card states it measured, at 030a675b0 9 11
the SAME instrument re-run at 030a675b0 15 11
the SAME instrument at today's origin/main f760064ea 14 11

So the card's file count reproduces exactly and its non-test row count does not — not at today's head, and not at the sha the card itself names. Three narrower spellings were tried against the card's own pair and none produces 9 rows over 11 files (/publish-drafts gives 8 rows over 7 files; the backtick-terminated spelling gives 7 over 7). The finding the card reports is unaffected — the three call sites it names were all still bare fetch calls on today's origin/main — but its control figure is not a number this branch could re-derive, and it is reported rather than repeated.

Why enumerations of this route keep coming up short, measured rather than guessed. A sweep for await fetch( on the same line as the route sees 2 of the 3, because AiChatPage wraps its call arguments and the URL sits on its own line. A multiline-aware reader — one that allows whitespace and a newline between fetch( and the /api/v1/packages/ URL — answers 1 per file for all three. The route-name sweep in the table above sees all three, at the cost of also matching eleven comments.

On today's origin/main, three bare-fetch call sites of this route existed and this branch routes all three. After the change the same multiline-aware reader finds none in packages/app-shell/src + apps/console/src, beside a control on the same tree: 13 files still mention the route (in prose, in tests and at the five routed call sites).

The repair

Each of the three takes its client from useMetadataClient and calls MetadataClient.publishPackageDrafts, exactly as PR #10038 did for preview/usePublishAllDrafts.ts and views/metadata-admin/PackagesPage.tsx. useMetadataClient is the layer that hands the console's advisory toast renderer to the client factory, so taking the client from there is the whole mechanism — nothing new was invented.

Carried along with the route, at all three:

  • A non-2xx raises MetadataError inside the client instead of being read off res.ok. The message is still the server's own, and the ADR-0112 producer-marked error.userMessage now outranks the diagnostic error.message where a refusal carries one — the rule objectui#7959 landed on PackagesPage, reaching these surfaces through the same seam rather than as a fourth copy. StudioDesignSurface keeps its field-anchored issue rendering: parseError already puts error.details.issues on MetadataError.issues, which is what its formatMetadataError reads.
  • failed[], failedCount and seedApplied are read through ONE spelling. The client unwraps the dispatcher's { success, data } for this route — the one route whose spec declaration says the body arrives inside one — so the two server compositions are reconciled before a caller sees them, where each bare-fetch site carried its own payload?.data?.x ?? payload?.x ladder.
  • The 2xx batch verdict stays each surface's own, unchanged: success: false is not a refusal on this route and the three disagree on purpose about what a partial or rolled-back batch should say. Where a 2xx refusal used to end in HTTP ${res.status}, the status is no longer in hand, so the last rung is a sentence — PackagesPage's own key for this route on the Studio surface, the existing console.ai.publishFailed on the chat one.

How the advisories are presented, one line per surface

They present identically on all three, and that is not a compromise — the presentation belongs to the client, not to the surface. publishPackageDrafts emits one MetadataSaveAdvisoryEvent per advised published[] element into the sink useMetadataClient wires, and emitSaveAdvisories renders it as one warning toast titled "Published — the authoring check raised N advisory finding(s)" with the findings as its description. So:

  • console/ai/PendingDraftsBar (the AI build pane's standing unpublished-changes bar) — the advisory toast, beside the bar's own existing probe/seed toast. Both now fire from one publish; neither replaces the other.
  • views/studio-design/StudioDesignSurface (the Studio workbench's package-level publish) — the advisory toast, beside this surface's own publishedAll success toast or its formatPublishFailures error toast.
  • console/ai/AiChatPage (the chat transcript's draft-card publish) — the advisory toast. This surface additionally hands an ADR-0038 L3 health object back to the chat card so the Published card grows a build-health line; that hand-off is unchanged and is a different channel from the advisories, which have no chat-card representation and did not need one.

No surface was found that cannot present them, so nothing was dropped and no blocker is reported on that count.

Evidence

RED before / GREEN after, with the file state verified in the same command as each run. Each pin was written and run first with all three implementation files byte-identical to origin/main 3ac2de829 — proved by printing git hash-object FILE beside git rev-parse HEAD:FILE for each, in the same shell command as the run, not by an exit code. All three failed on expect(toast.warning).toHaveBeenCalled(): no advisory toast at all. After the repair all three pass.

Each pin asserts the finding REACHES the author, not that a function was called. The fixture is one finding in the gate's D3 shape with all six required keys — readSaveAdvisories drops a half-shaped one, so a fixture missing a key would make the file pass or fail for the wrong reason. The assertions read the toast's title (it must start with "Published", which proves the door discriminator survived the whole seam) and its description, which must contain the finding's own message, rule and hint.

Each pin deliberately does NOT mock useMetadataClient. That is the point: useMetadataClient.advisorySink.test.tsx records that 51 suites mock that module and, before it existed, exactly zero imported the real hook — the seam was mocked away everywhere it appeared, which is how this class of hole stays invisible. Real here: the component, the hook, its useCallback sink, createConsoleMetadataClient, the authenticated fetch, MetadataClient, its published[] walk, readSaveAdvisories and emitSaveAdvisories. Stubbed: sonner (a module binding, so it cannot be handed over), globalThis.fetch, and — per surface — the consumer that merely calls the handler under test.

Every zero carries a same-subject control in the same command. Each pin has a CONTROL case: the same drive against a clean batch body (the server omits advisories), asserting the publish really travelled the chain (the POST count, and the surface's own success toast or its verdict to the chat card) while the advisory sink stays silent. So "nothing was toasted" is a reading about an empty advisory list, not about a chain that never ran.

Gates re-run as the last action before the push, with the tree proved equal to the pushed commitgit write-tree printed equal to HEAD^{tree} and git status --porcelain empty, in the same command as the gate runs. Green and each one SELECTING these files rather than collapsing:

  • check-changeset-presence — exit 0, and it names the selection: "4 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)". The changeset decision was made by running this gate, not from memory.
  • check-changeset-no-major, check-changeset-overwrite — exit 0.
  • check:control-bytes — exit 0 over 8120 tracked text files. Plus a direct scan of the eight touched paths: 0 control bytes, beside a control of 8033 printable-character hits in the same files.
  • check:i18n-keys — exit 0; it reports 2756 interpolation call sites and 3005 en keys judged, so it saw the two t() calls this change adds or moves.
  • check:vi-mock-specifiers / -inherit / -override-shape — exit 0 over 3372 test-named files; the three new suites are inside that population.
  • check:test-path-roots, check:metadata-write-doors, check:unreferenced-sources, check:phantom-deps, check:unused-deps, check:i18n-drift, check:i18n-dead-keys — exit 0.
  • check:new-line-citations — 0 new cross-file line citations; report-only, so this is a reading and not a verdict. check:changeset-claims is also report-only, and its own output says two of its three sub-readings measured nothing on this event; its one actionable finding is answered below.

Tests. @object-ui/app-shell in full, in two shards: 371 files / 3545 tests + 1 skipped, and 370 files / 3782 tests — both exit 0 with no failure. The two directories this change touches, run together: 85 files / 488 tests, exit 0. pnpm --filter @object-ui/app-shell run type-check exit 0, and the script it echoed is tsc --noEmit && tsc -p tsconfig.test.json, so the new test files are type-checked too. That run needed pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' build first; a first attempt passed --concurrency=2 after the filter, which pnpm forwards verbatim into tsup — that run is recorded as not-a-verdict and was re-run properly.

Lint. pnpm --filter @object-ui/app-shell run lint exit 0 (3048 pre-existing warnings, 0 errors). Narrower reading, to show this change adds none: eslint over exactly the 8 touched paths reports 0 errors and 49 warnings, and 0 of those 49 fall inside a hunk this branch adds (computed against the new-side line ranges of git diff -U0), beside the control that all 49 fall outside them. The narrowing is safe because this repo's eslint.config.js declares no type-aware linting: 0 hits for projectService or project:, beside a control of 13 hits for rules in the same file — so no untouched file's verdict can move with this diff.

The pending changesets check:changeset-claims asked this seat to re-read, re-read:

  • .changeset/6169-chatbot-authoring-face-type.md names AiChatPage.tsx as the live consumer of the autoResponse display fields. This change touches neither those fields nor that consumer relationship. Still true.
  • .changeset/6681-declared-lazy-marketplace-routes.md names StudioDesignSurface.tsx as the eager static importer of components/SuggestedBindingsPanel.tsx, and quotes an eager-closure byte delta. That import is untouched, and the byte figures are that change's own measured delta rather than a live total. Still true.

The eager closure, stated rather than measured here. check:eager-closure needs a built console dist and is CI's run, not this branch's. What is cheap and was checked: both modules newly imported by these files are ALREADY in the eager closure — views/metadata-admin/useMetadata.js through StudioDesignSurface's own existing import of it, and utils/apiErrorEnvelope.js through packages/app-shell/src/index.ts, which re-exports readEnvelopeFailureText from the barrel. So this change adds edges between already-eager modules and puts no new module into the closure. Chunk assignment is still CI's to weigh.

One test fixture had to grow, and the reason is the repair. PendingDraftsBar.test.tsx answered its fetch stub with { ok, status, json } object literals. The console's authenticated fetch reads response.headers on every /api/ call (the set-auth-token session rotation), and a literal has no headers, so it threw inside the wrapper, the bar reported a failed publish and skipped the bus pulse — leaving that file's "then hides" pin red for a reason entirely its fixture's. The stub now answers with real Response objects; the assertions are unchanged.

Noted, outside the declared file surface

The triage seat asked how a FOURTH call site would be prevented, and that is the right question — two rounds, two counts. The repo already owns the answer's SHAPE, one route over: scripts/check-object-metadata-write-doors.mjs enumerates DOORS rather than writers, on the stated ground that "a ruling that enumerates writers is only as good as the enumeration", and it was built after exactly this pattern (objectui#7714 named two writers, objectui#8057 hit a third, objectui#8676's sweep found nine more). A sibling door census for POST /packages/:id/publish-drafts — every in-repo call of that route must reach MetadataClient.publishPackageDrafts — would close this class by construction. It lives in scripts/, outside this card's declared file surface, so it is reported here for the seat that routes rather than taken.


Generated by Claude Code

…e advisory reporting seam

Three app-shell call sites still fired `POST /packages/:id/publish-drafts`
with a bare `fetch`, outside the seam that can report — the AI build
pane's standing unpublished-changes bar, the Studio workbench's
package-level publish, and the chat transcript's draft-card publish. The
server has answered per-draft `advisories` on each `published[]` element
since objectstack#9343, and objectui#6965 / PR objectui#10038 built the
client half for the two call sites that card named. On these three the
findings were parsed by nobody.

Each now takes its client from `useMetadataClient` and calls
`MetadataClient.publishPackageDrafts`. The advisory toast belongs to the
client, so all three present identically to the two already routed — one
warning per advised item, naming that item's own `type` / `name`, through
the sink, event, renderer and wording every other write door uses. No new
presentation was invented and none was dropped.

What moves with the route:

- A non-2xx raises `MetadataError` inside the client rather than being
  read off `res.ok`. The message is still the server's own, and the
  ADR-0112 producer-marked `error.userMessage` now outranks the diagnostic
  where a refusal carries one. `StudioDesignSurface` keeps its
  field-anchored issue rendering: `parseError` already puts
  `error.details.issues` on `MetadataError.issues`, which is what its
  `formatMetadataError` reads.
- `failed[]` / `failedCount` / `seedApplied` read through ONE spelling.
  The client unwraps the dispatcher's `{ success, data }` for this route —
  the one route whose spec declaration says the body arrives inside one —
  so the two server compositions are reconciled before a caller sees them,
  where each bare-fetch site carried its own `payload?.data?.x ?? payload?.x`
  ladder.
- The 2xx batch verdict stays each surface's own. `success: false` is not a
  refusal on this route and the three disagree on purpose about what a
  partial or rolled-back batch should say.

Pins: one per surface, each driving that surface's own publish affordance
against the batch body the gate actually sends and asserting the finding's
prose reaches the sink — with a clean-publish control in the same file, so
the silence is a reading about an empty advisory list rather than about a
chain that never ran. Each deliberately does NOT mock `useMetadataClient`:
mocking that hook is exactly how this class of hole stays invisible.

`PendingDraftsBar.test.tsx`'s fetch stub now answers with real `Response`
objects. The console's authenticated fetch reads `response.headers` on
every `/api/` call, which a `{ ok, status, json }` literal does not have.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018HrVaotisyhgmot9o2MLRq
@github-actions

github-actions Bot commented Sep 20, 2026

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 2 pending changeset(s) describe a file this change touches

Their bodies publish verbatim into the CHANGELOG at the next release, so this is a request to re-read them against your diff — addressed here because you are the one seat that can answer it without re-deriving anything.

⛔ Nothing here blocks, and nothing here is a verdict on your change. This gate exits 0, is not a required context, and judges name resolution, never meaning: it asked whether a pending body names a file you touched. "Is this sentence still true?" is the one question it will not answer, and the one you are being asked to answer.

.changeset/6169-chatbot-authoring-face-type.md

  • names packages/app-shell/src/console/ai/AiChatPage.tsxpackages/app-shell/src/console/ai/AiChatPage.tsx — edited by this change

    • showTimestamp, userAvatarUrl, userAvatarFallback, assistantAvatarUrl, assistantAvatarFallback, maxHeight — display fields. - autoResponse, autoResponseText, autoResponseDelay — the local auto-response (demo/playground) fields, already live via a real consumer (packages/app-shell/src/console/ai/AiChatPage.tsx). - onSend?: (content: string, messages: ChatMessage[]) => void — the send-callback, now typed against the published ChatMessage shape rather than the plugin's internal runtime message type.

.changeset/6681-declared-lazy-marketplace-routes.md

  • names views/studio-design/StudioDesignSurface.tsxpackages/app-shell/src/views/studio-design/StudioDesignSurface.tsx — edited by this change

    Both marketplace chunks were held by CHUNK CO-TENANCY, not by any import of the page: rolldown had parked components/SuggestedBindingsPanel.tsx (statically imported by the eager views/studio-design/StudioDesignSurface.tsx) in the first, and console/marketplace/InstalledListWidget.tsx (bare-imported by the package barrel for its SDUI registration) in the second. An app-shell-eager-leaves group in apps/console/vite.config.ts isolates those co-tenants so the three declared-lazy pages chunk by their own dynamic-only reachability. The console eager closure moves 3180.2 KB → 3171.5 KB gzipped (−8,888 bytes, 48 → 45 eager chunks) with the three per-chunk ceilings unmoved.

Read the paragraph, not the line: both false halves of the objectui#8617 claim sat in one paragraph, and correcting either alone would have left it asserting the same wrong thing.

If a claim did go false, correct the body. That is precedented and prose-only, frontmatter untouched; check-changeset-overwrite.mjs will report the correction as its own case 2 ("correcting a declaration on purpose … legitimate"), which is the intended shape — one gate asks for the read, the other records the write.

Not covered, stated so nobody reads this as more: a born-false claim that spells no line address at all (objectui#9495 coordinated one by ORDINAL — "a grep finds that member first" — and deciding that means reading what the sentence means), a claim spelled as a symbol or a package rather than a backticked file name, and a file named ambiguously.

Compared the checked-out tree with cbda340f0 (merge-base with origin/main): 7 file(s) changed outside .changeset/, read against 1236 pending declaration(s) that publish a body (1801 pending in total). · run

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Console Performance Budget — gauge not trustworthy

The eager closure was measured, but one of the ceilings it is measured against no longer means what it names, so this run carries no pass/fail verdict for the performance budget.

This is not a budget violation. Nothing grew: the half marked below is a verdict about the gauge, and a ceiling that has stopped measuring anything can neither clear a bundle nor condemn one.

Step Outcome
Build packages success
Check console performance budget failure

Which half objected:

Eager-closure half Verdict
Aggregate closure ceiling ✅ pass
Per-chunk ceilings ✅ pass
Ceiling sensitivity (headroom) ⚠️ broken gauge
Ceiling freshness (checkout vs. base branch) ✅ pass

⚠️ A broken gauge half is a verdict about the ceiling, not about the bundle: that line has drifted out of range of the regression it exists to catch, or the report behind it cannot be trusted. It does not say anything grew. The Check console performance budget step log carries the ceiling and the number it was compared against.

Reason: The entry chunk measured 146.9 KB, but the eager-closure half of this gate returned no trustworthy VERDICT: the report could not be read, a ceiling has drifted out of range of the regression it must catch, or (objectui#6245) a ceiling was replaced on the base branch after this checkout was made. The step log says which. This is not a passing budget — and it is not a size regression either.

See the workflow run for details.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.68KB 6.20KB
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) 11.08KB 4.58KB
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) 545.92KB 130.72KB
core (index.js) 8.94KB 3.59KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 221.99KB 61.72KB
fields (index.js) 251.81KB 63.47KB
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) 8.87KB 3.64KB
i18n (index.js) 5.22KB 2.26KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 32.15KB 10.49KB
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.90KB 10.97KB
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) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.52KB 4.88KB
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) 8.39KB 3.10KB
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) 14.81KB 3.63KB
plugin-calendar (index.js) 51.08KB 14.50KB
plugin-charts (index.js) 71.73KB 20.08KB
plugin-chatbot (index.js) 198.20KB 47.14KB
plugin-dashboard (index.js) 132.96KB 35.17KB
plugin-designer (index.js) 215.94KB 44.33KB
plugin-detail (index.js) 255.17KB 66.48KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 139.56KB 35.40KB
plugin-gantt (index.js) 167.99KB 41.37KB
plugin-grid (index.js) 213.40KB 58.19KB
plugin-kanban (index.js) 48.71KB 15.17KB
plugin-list (index.js) 113.53KB 27.99KB
plugin-map (index.js) 21.48KB 6.99KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.49KB 11.97KB
plugin-timeline (index.js) 30.68KB 8.95KB
plugin-tree (index.js) 10.58KB 3.72KB
plugin-view (index.js) 85.18KB 21.05KB
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) 109.04KB 36.08KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.38KB 1.98KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.74KB 2.54KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 15.71KB 5.30KB
types (ai.js) 4.11KB 2.06KB
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.93KB 1.49KB
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) 5.00KB 2.39KB
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 (strict-authoring-face.js) 14.04KB 5.36KB
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

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3059.0 KB 3104.5 KB
Main entry chunk (gzip) 146.8 KB 350 KB
Entry file index-Bk9p22oq.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) 16.68KB 6.20KB
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) 11.08KB 4.58KB
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) 545.92KB 130.72KB
core (index.js) 8.94KB 3.59KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 221.99KB 61.72KB
fields (index.js) 251.81KB 63.47KB
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) 8.87KB 3.64KB
i18n (index.js) 5.22KB 2.26KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 32.15KB 10.49KB
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.90KB 10.97KB
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) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.52KB 4.88KB
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) 8.39KB 3.10KB
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) 14.81KB 3.63KB
plugin-calendar (index.js) 51.08KB 14.50KB
plugin-charts (index.js) 71.73KB 20.08KB
plugin-chatbot (index.js) 198.20KB 47.14KB
plugin-dashboard (index.js) 132.96KB 35.17KB
plugin-designer (index.js) 215.94KB 44.33KB
plugin-detail (index.js) 255.17KB 66.48KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 139.56KB 35.40KB
plugin-gantt (index.js) 167.99KB 41.37KB
plugin-grid (index.js) 213.40KB 58.19KB
plugin-kanban (index.js) 48.71KB 15.17KB
plugin-list (index.js) 113.53KB 27.99KB
plugin-map (index.js) 21.48KB 6.99KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.49KB 11.97KB
plugin-timeline (index.js) 30.68KB 8.95KB
plugin-tree (index.js) 10.58KB 3.72KB
plugin-view (index.js) 85.18KB 21.05KB
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) 109.04KB 36.08KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.38KB 1.98KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.74KB 2.54KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 15.71KB 5.30KB
types (ai.js) 4.11KB 2.06KB
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.93KB 1.49KB
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) 5.00KB 2.39KB
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 (strict-authoring-face.js) 17.15KB 6.32KB
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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

1 participant