Skip to content

feat(data-objectstack,app-shell): route "publish whole app" through the advisory reporting seam (objectui#6965) - #10038

Merged
os-tesla merged 4 commits into
mainfrom
claude/issue-6965-batch-publish-advisories
Sep 19, 2026
Merged

os-tesla merged 4 commits into
mainfrom
claude/issue-6965-batch-publish-advisories

Conversation

@os-tesla

@os-tesla os-tesla commented Sep 19, 2026

Copy link
Copy Markdown
Collaborator

Fixes #6965

Studio's "publish whole app" showed the author none of the runtime authoring gate's findings, although the server had been sending them since objectstack#9343 landed. Both client call sites fired POST /packages/:id/publish-drafts outside the seam that can report — a bare fetch in usePublishAllDrafts, and the page-private apiJson in PackagesPage under a declared response type holding two counts and failed[], with no published[] at all. The same button's own client-side capability lint was raising a toast the whole time, so the one thing that could not reach the person pressing it was a finding from the server.

Readings below were taken in a worktree off origin/main 030a675b0, 2026-09-19T18:30Z onwards.

The premise, re-verified rather than inherited

  • @objectstack/spec INSTALLED in this worktree: 17.4.0 (node_modules/@objectstack/spec/package.json). PublishPackageDraftsResponseSchema in its own source declares published[].advisories as an optional array of RuntimeAuthoringIssueSchema, "riding each element rather than a parallel top-level map" — the ruled shape, in the schema's own prose.
  • Both call sites were still bypassing the seam at that sha, exactly as the card and the claim comment read them.
  • check:spec-floors resolved the DECLARED floor @objectstack/spec@17.2.0 from the registry and judged data-objectstack's built artifact against it with no finding, so the symbol this package now imports is present at the floor it declares, not only at the version installed here.

1. The seam

MetadataClient.publishPackageDrafts(packageId) expresses the route and emits one MetadataSaveAdvisoryEvent per advised published[] element, each naming that element's own type / name, through the same sink, event and renderer the save and single-item publish doors use. Both call sites go through it.

Three decisions worth reviewing, each stated in the code where it is made:

  • The envelope is unwrapped on this route, and only on this route. PublishPackageDraftsResponseSchema says it describes the full body "inside the dispatcher's { success, data } envelope", so the declared object is the inner one. publishDraft still refuses to unwrap, because its schema describes the full body of a route the REST server answers verbatim (objectui#6962). Same rule, read per route.
  • Failure shapes stay the callers'. Non-2xx raises MetadataError as every other method does; a 2xx is returned unexamined, because success: false is not a refusal on this route (outcome: 'nothing_to_publish' answers it too) and the two callers judge it differently today. PackagesPage keeps the objectui#7959 ADR-0112 ladder — a producer-marked error.userMessage outranks the diagnostic — by re-reading it off the raised error's captured body.
  • The path is unscoped by environment, byte-for-byte the one both call sites already used. An /environments/:id/packages mirror is a route nothing in this repo has shown exists, and scoping to it would trade a working call for a 404. Pinned.

2. Why door: 'publish' — and why the fall-back clause did NOT fire

The dispatch bounded me: a design needing a third value in the published door union could not be built here, and the correct move in that case was to stop and report. It did not come to that, and here is the reading rather than an assurance.

door has exactly one consumer: advisoryTitle in providers/saveAdvisoryToast.ts, whose only door-dependent output is the frame's verb — "Saved" for 'save', "Published" for 'publish'. Nothing else in the renderer branches on it. Every item a batch event names really was promoted to active, so "Published" is the true verb for it; a third value would have to render the same word. The per-item identity the author needs in order to go and fix something is carried by type / name, one event per advised item, so nothing about the batch is lost by sharing the value.

What that argument does NOT say, stated in the type's own docblock so the next reader cannot take it for more: it is not a claim that one call produces one event. The batch emits as many events as it has advised items, which is exactly why each one names its own.

The exhaustive switch with the never check is untouched, so a third door remains a compile error rather than a silently wrong verb.

3. The flipped pin — RED first, then GREEN

The absence pin does NOT render advisories buried in a batch-shaped published[] body is flipped, not deleted, and what it was really carrying — the client renders only what the server sent — is pinned in both directions.

Reading A — the OLD assertion against the NEW code. The flipped case's assertion was replaced by the old one, expect(events).toEqual([]), on the committed tree. Anchor occurrences before the edit: 1; after: 0, with the injected text present on disk (an anchored replace that refuses a no-op, rather than sed -i, which exits 0 on zero matches).

Tests  1 failed | 29 passed (30)
FAIL  metadata-client.publishAdvisories.test.ts > MetadataClient.publishPackageDrafts
      renders the advisories the server sent on a published[] element
AssertionError: expected [ { type: 'flow', …(4) } ] to deeply equal []

So the flip is a real behaviour change and not a rewording. Restored with git checkout HEAD --; git diff HEAD empty and the worktree blob equal to HEAD's (6bfaa8f94d88cf18c4a3719ad0a2e9e8d5143362).

Reading B — the implementation ablated. The per-element emit loop was removed from publishPackageDrafts (anchor 1 before, 0 after, injected marker on disk; the file's other two emitAdvisories call sites left standing):

Tests  5 failed | 25 passed (30)
  × renders the advisories the server sent on a published[] element
  × names the item each finding is about — one event per advised element
  × reports the PUBLISH door, so the frame reads "Published" and not "Saved"
  × reads the elements through the dispatcher envelope this route declares
  × INVENTS NOTHING: a half-shaped finding on an element is dropped, not rendered

Restored the same way, blob equal to HEAD's (1d5fa99c3b73d276e3af10ea2d053ae2e7e192b4).

⭐ Worth naming: two of the three "INVENTS NOTHING" cases stayed GREEN under ablation, because a pin that asserts an absence cannot fail when the emitter is gone. That is the honest reason the presence cases have to exist beside them, and why one green would have proved nothing here.

Reading C — green on the restored tree. Tests 30 passed (30).

4. The two falsified sentences, retired — and a third the card did not know about

  • metadata-client.ts, publishDraft's docblock: the paragraph asserting the batch route "discards per-draft advisories server-side; that is objectstack#9343 and nothing here compensates for it" now records that the card landed, and keeps the half that is still true and still about THIS method — it reads the top level of the single-item body and nothing else, so a batch-shaped body arriving there reports nothing. That is pinned.
  • metadata-client.publishAdvisories.test.ts, the module docblock's scope-control section: rewritten around what the file now pins, in both directions.
  • ⭐ A THIRD instance, outside the declared file face: .changeset/render-publish-advisory-findings-5026.md carried the same claim in the present tense — "still discards ... A test pins the absence" — and a pending changeset publishes VERBATIM into the CHANGELOG at the next release, which makes this the last moment it is correctable. Corrected in its own commit, prose only; check-changeset-overwrite.mjs reports it as its case 2 ("correcting a declaration on purpose") and prints the frontmatter on both sides, unchanged.

5. Scope

Declared file face, all four touched: metadata-client.ts, metadata-client.publishAdvisories.test.ts, usePublishAllDrafts.ts, PackagesPage.tsx. Two files beyond it, both declared here: the new changeset this change owes, and the pending changeset correction above.

MetadataPublishPackageDraftsResult is deliberately NOT added to the package barrel: the published surface grows by the one method deliverable 1 requires and nothing else.

Validation

  • pnpm exec vitest run packages/data-objectstack/ — 67 files, 926 passed.
  • pnpm exec vitest run packages/app-shell/src/views/metadata-admin/ packages/app-shell/src/preview/ — 298 files, 3160 passed, 1 skipped.
  • pnpm --filter @object-ui/data-objectstack run type-check⚠️ RED on the first pushed head (29768c3e6): TS2493 on the new pin's fetch spy, caught by CI (Type Check, job 105950929212) and then reproduced locally byte-for-byte. GREEN on 723dd32b1, exit 0. The exit-0 this line carried before was a real reading of a different tree — it was taken right after the dependency-closure build, when the failing test case did not exist yet, and nothing run afterwards could see it (vitest type-checks nothing, and app-shell's type-check reads this package's built .d.ts, never its src). The general form, stated because it is the reusable part: a measurement must follow the last edit to what it measures.
  • pnpm --filter @object-ui/app-shell run type-check — exit 0 (tsc --noEmit and the test tsconfig), after building the dependency closure under the shared verify lock (pnpm --filter '@object-ui/app-shell^...' build, exit 0). Re-run on 723dd32b1 after the base merge.
  • The correction above was applied to this body by the domain:ui#2 PM seat (session session_018HrVaotisyhgmot9o2MLRq) at the dev's request, recorded on objectui#6965. The dev writes this body once at creation and does not edit it; ⛔ nothing else here was changed.
  • pnpm exec eslint --no-inline-config on the four changed source files — exit 0, 0 errors. 29 warnings, and the attribution is measured rather than asserted: intersecting the JSON report's line numbers with this branch's added lines gives 0 findings on a line this branch added, 29 on untouched lines. Control for that zero: the same intersection counts 21 / 66 / 314 / 212 added lines in the four files, so the instrument was looking at real additions.
  • Gates: check:control-bytes, check:spec-symbols, check:installed-pin-claims, check:new-line-citations (0 new), check:test-path-roots, check:vi-mock-specifiers, check:i18n-keys, check:self-import, check:changeset-presence, check:changeset-no-major, check:changeset-fixed, check:pending-changeset-literals — all exit 0. check-governed-queue-guard.mjs --test on all six paths: NOT GOVERNED.
  • check:spec-floors is NOT MEASURED as a whole: it exits 1 on an unbuilt tree with four no-artifact findings (app-shell, plugin-gantt, plugin-timeline, plugin-tree — "produced no build output to judge"), which needs a full workspace build. The package whose spec-symbol usage this change moves, data-objectstack, WAS inspected in that run and produced no finding.
  • Repo-wide pnpm lint and the full suite are CI's runs. The eslint narrowing above is a measurement rather than a skip: the population is eslint's own flat config, the file count is read off --format json, and no type-aware linting is configured in eslint.config.js (no parserOptions.project, no projectService), so this diff cannot move the verdict on a file it does not touch.

Acceptance notes

  • Three more batch call sites exist and are NOT in this change. StudioDesignSurface.tsx, console/ai/PendingDraftsBar.tsx and console/ai/AiChatPage.tsx each fire the same route with their own fetch, so an author publishing from Studio's design surface or the chat bar still sees no advisories. Same defect, same fix shape, outside the declared file face and outside a dispatch that said not to do more. Filed as a finding in the report, with dedupe words: batch publish-drafts bare fetch, StudioDesignSurface, PendingDraftsBar, AiChatPage, advisory seam.
  • The Changeset Claim Re-read request, answered. That gate flags .changeset/publish-envelope-one-spelling-6962.md because it names metadata-client.ts. Its paragraph is still TRUE: this change does not touch either single-item method's envelope behaviour, and the new method's unwrap is the other route's declared shape, stated beside it.
  • Noted, not filed: publishDraft's older sentence about listDrafts tolerances and this file's other per-route notes are unaffected; no successor is needed.

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

🤖 Generated with Claude Code

https://claude.ai/code/session_018HrVaotisyhgmot9o2MLRq


Generated by Claude Code


Generated by Claude Code

…he reporting seam (objectui#6965)

The batch publish door answers the runtime authoring gate's per-draft
advisories on each `published[]` element (objectstack#9343), and the author
saw none of them: both client call sites fired the route outside the seam
that reports — a bare `fetch` in `usePublishAllDrafts`, and `apiJson` in
`PackagesPage` under a declared response type with no `published[]` at all.

- `MetadataClient.publishPackageDrafts` expresses the route and emits one
  advisory event per advised element, each naming that element's own
  type / name, into the sink and renderer both other write doors use.
- `door: 'publish'` is reused rather than extended: every item the event
  names really was published, and the verb is the renderer's only
  door-dependent output.
- Only what the server sent, where the published schema declares it — a
  half-shaped finding, an element that cannot name its item and a top-level
  `advisories` all report nothing.
- The batch absence pin is flipped to a presence pin, keeping the
  invent-nothing half it was really carrying, and the two sentences that
  said the batch route still discards advisories are retired.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018HrVaotisyhgmot9o2MLRq
… in the pending objectui#5026 declaration

Prose only, frontmatter byte-identical (the overwrite gate prints both, and
they match). The paragraph asserted, in the present tense, that the batch
publish door "still discards per-draft advisories server-side" and that "a
test pins the absence". Both went false: objectstack#9343 landed, and this
branch flips that pin to a presence pin. A pending changeset publishes
VERBATIM into the CHANGELOG at the next release, which is the last moment
this is correctable — afterwards it is historical record.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018HrVaotisyhgmot9o2MLRq
@github-actions

github-actions Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 1 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/publish-envelope-one-spelling-6962.md

  • names metadata-client.tspackages/data-objectstack/src/metadata-client.ts — edited by this change

    The two methods sit ~250 lines apart in metadata-client.ts and both POST /api/v1/meta/:type/:name/publish. publishDraft tolerated a dispatcher-shaped envelope and returned the inner object; publish returned the body as parsed. Nothing said which was right, and the card explicitly refused to settle it from PublishMetaItemResponseSchema alone — an inference from a declaration is not a measurement of the server.

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 0febe1a59 (merge-base with origin/main): 4 file(s) changed outside .changeset/, read against 1216 pending declaration(s) that publish a body (1776 pending in total). · run

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3056.9 KB 3104.5 KB
Main entry chunk (gzip) 145.8 KB 350 KB
Entry file index-CIaE7oNu.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.69KB 6.21KB
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) 249.62KB 63.02KB
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.83KB 10.95KB
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) 50.26KB 14.36KB
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.18KB 66.49KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 139.56KB 35.40KB
plugin-gantt (index.js) 167.62KB 41.26KB
plugin-grid (index.js) 213.44KB 58.21KB
plugin-kanban (index.js) 48.71KB 15.17KB
plugin-list (index.js) 113.55KB 27.99KB
plugin-map (index.js) 21.48KB 6.99KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.41KB 11.93KB
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) 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 (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

@os-tesla
os-tesla marked this pull request as ready for review September 19, 2026 19:13
@os-tesla
os-tesla enabled auto-merge September 19, 2026 19:13
@os-tesla
os-tesla disabled auto-merge September 19, 2026 19:28
…sories

objectui#8637's PR #10034 landed while this branch was reporting, so the base
moved. Merge rather than rebase: this branch is pushed and may be checked out
elsewhere, and the repo's convention is that history on a pushed branch is
never rewritten. The squash merge drops this commit from main.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018HrVaotisyhgmot9o2MLRq
…ll tuple has an element 0

`tsc --noEmit` (the package's own `type-check`, which covers `src/**`) refused
the new route pin with TS2493, "Tuple type '[]' of length '0' has no element at
index '0'": the spy was `vi.fn(async () => …)`, declaring no parameters, so
vitest inferred the call tuple as `[]` and the non-null assertion silenced the
outer index rather than the inner one.

Typed like `fetch`, which is the spelling `exportDownload.test.ts` in this same
package already uses and documents for exactly this reason. `_url: string`
rather than `RequestInfo | URL` because this client builds its URL as a string
and the assertion is meant to keep checking that: with the parameters declared,
the destructured element is typed `string`, so the pin still fails on a wrong
URL and still refuses a non-string one — neither of which an `as any` on the
assertion would have preserved.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018HrVaotisyhgmot9o2MLRq
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3056.9 KB 3104.5 KB
Main entry chunk (gzip) 145.9 KB 350 KB
Entry file index-CzPy82eH.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.69KB 6.21KB
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) 249.62KB 63.02KB
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) 50.26KB 14.36KB
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.18KB 66.49KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 139.56KB 35.40KB
plugin-gantt (index.js) 167.62KB 41.26KB
plugin-grid (index.js) 213.44KB 58.21KB
plugin-kanban (index.js) 48.71KB 15.17KB
plugin-list (index.js) 113.55KB 27.99KB
plugin-map (index.js) 21.48KB 6.99KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.41KB 11.93KB
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) 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 (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

@os-tesla
os-tesla added this pull request to the merge queue Sep 19, 2026
Merged via the queue into main with commit ce986aa Sep 19, 2026
37 checks passed
@os-tesla
os-tesla deleted the claude/issue-6965-batch-publish-advisories branch September 19, 2026 20:25
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.

Studio: render advisories on the BATCH publish door ("publish whole app") — blocked until objectstack#9343 stops discarding them server-side

2 participants