Skip to content

feat(app-shell): Home's top bar searches, the greeting sums up approvals, compact builder chips and 56 px app tiles that say when they were last opened (objectui#12601) - #12638

Merged
objectstack-fleet[bot] merged 10 commits into
mainfrom
claude/issue-12601-home-top-and-apps
Oct 16, 2026
Merged

objectstack-fleet[bot] merged 10 commits into
mainfrom
claude/issue-12601-home-top-and-apps

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #12601
Clause-②: yes

Sections ① and ② of the approved artboard "系统首页 · 四段式" on /home: a search field in the top bar that opens the console's command palette, a 24 px greeting with a one-line work summary, the admin's two builder chips beside it, and an apps section with 112 px tiles, a 56 px icon, a compact last-opened line ("2 hr. ago"; zh "2小时前打开") read from the recent-items store, Setup moved off the tiles onto a "System Settings" link, and an admin's trailing "Add app" tile. Sections ③ and ④ are objectui#12602 and objectui#12604; they are not touched here.

Resumed work

This card's first dev (session session_01JZnppgHRp4sREcouhkQYDB) ran out of tokens after pushing 3cc9fa1, with no PR and no report. The seat took the card over (claim 6209656150). This PR is that commit, read hunk by hunk against the card, plus what it lacked:

Hunk (inherited 3cc9fa1) Decision
HomeLayout: mounts CommandPaletteProvider and the existing CommandPalette, scoped to Home's host app kept
AppHeader: the home variant centres the search field where a palette is mounted, 420 px from xl, labelled home.search kept; the only AppHeader change, no new prop
HomePage: greeting 24 px / 600, summary line, builder chips with the tooltip wrapper, 1120 px column, Setup off the tiles kept
HomeAppsStrip: 15 px heading and count pill, 112 px tiles, 56 px icon, settings link, "Add app" tile kept; one leftover blank line removed
HomePage.authoringCapabilityGate.test.tsx edit kept, see H3
two new test files kept; one case added, one mock widened
locale keys in all ten packs, changeset kept; one key added, three orphaned keys removed, changeset corrected
missing: the tile's last-opened time (card Target 6, Acceptance 1, fifth test) added (9aa8059)

Commits after the inherited one: f2ef2c1 merge of origin/main, 9aa8059 the last-opened line, efe6e9d the key removal and the changeset correction, 42e5761 a blank line.

What the tile's time reads

The recent-items store records no app visits. It records what was opened inside an app, each entry with the href it was opened at (/apps/SEGMENT/...) and its visitedAt. lastOpenedByApp (new, console/home/appLastOpened.ts) takes, for each app, the newest entry whose segment resolves to it through matchAppBySegment, so both the package id and the name alias count. An app with no entry left in the store gets no line. The line is home.appOpened with the locale's relative time in Intl's compact form (TILE_OPENED_TIME_FORMAT = { style: 'short', numeric: 'always' }, passed through timeAgo to formatRelativeTime, the helper the recent rail uses). A pack keeps a verb only where verb and time fit the 112 px tile at 11 px: zh, ko and ar keep theirs, ja reads the time plus に起動, and en, de, fr, es, pt and ru carry the time alone ("2 hr. ago"). Every pack's line from 6 s to 12 y is held to a derived 93 px budget by appTileOpenedLine-12601.test.ts. (Seat edit, patch round 2: this paragraph originally read "Opened 2 hours ago", which truncated in the live reading.)

Measurements against the seat's hypotheses

H1, public surface (measured on the built declarations). @object-ui/app-shell built at this branch and again with packages/app-shell/src at origin/main 63d00da, the declaration closure of dist/index.d.ts walked through relative specifiers: 180 files on both sides, the same file list. Two files differ, console/home/HomeLayout.d.ts and layout/AppHeader.d.ts, and both differ in doc comments only. HomePage() takes no props on either side; HomeLayoutProps and AppHeaderProps are byte-identical. Outside the closure, HomeAppsStrip.d.ts gains two optional props (settingsHref, lastOpened) and appLastOpened.d.ts is new; neither is reachable from the entry. On @object-ui/i18n, the exported en pack is typed by its literal content, so its type gains the new keys and loses the three removed ones. Patch round 2 also gives the exported formatRelativeTime an optional third argument (style / numeric of Intl.RelativeTimeFormat); omitted, the output is unchanged. The changeset states all of it.

H2, the summary's sources. On main the approvals count has a source: useSharedPendingApprovalsCount (the bell's badge read, GET /api/v1/approvals/requests?status=pending). Nothing on main classifies an item as "assigned to me": an inbox row carries a free-text topic and no declared kind. So the line names approvals only ("今天有 N 项待审批", or "今天没有待办" at zero). No endpoint or data source was added. objectui#12602's Target 5 names the same fork for its "分配给我" column.

H3, test ids and the edited test. home-build-app and home-start-template are on the chips' buttons; home-authoring-gate-reason and home-marketplace-disabled-reason are on the visually hidden reasons the chips are described by. The other ids the page had (browse-marketplace-btn, app-tile-NAME, apps-show-all, home-build-with-ai, home-ask-ai) are unchanged. The one edit to an existing test, HomePage.authoringCapabilityGate.test.tsx, line by line: it removed a comment saying the reason is "on screen — not only in a tooltip" and one assertion, getByTestId('home-authoring-gate-reason') has the text «home.build.noCapability»; it added the same getByTestId with the same toHaveTextContent, plus two assertions that home-build-app and home-start-template carry aria-describedby pointing at that reason. No assertion was weakened: the removed one never asserted visibility, and the visible paragraph it described is what the card moves into the tooltip wrapper.

H4, Setup, the time line, non-admins. Each has its own pin, and each pin fails when the behaviour is removed (ablations below).

H5, one palette. HomeLayout mounts CommandPaletteProvider and CommandPalette from chrome/CommandPalette.tsx, the component AppContent mounts inside an app, with the same props (apps, activeApp, objects, onAppChange, dataSource). The bar's existing action:command-palette:open button calls useCommandPalette().openCommandPalette, and AppHeader draws it only where useCommandPaletteProviderMounted() answers yes. /home mounts no ConsoleLayout, so this is the only palette in the tree. With no openable app (a zero-app workspace, or the app list still loading) no palette is mounted and no field is drawn.

Acceptance tests and their ablations

Each mutation landed through ablation-replace.mjs (anchor hit, blob changed), the file was restored and proven equal to HEAD. Run at 9aa8059; the later commits touch no line any of these anchors or tests read.

Acceptance item Pin Mutation Result
the search field opens the command palette HomeLayout.searchOpensPalette-12601.test.tsx › the search field opens the command palette HomeLayout: {hostApp ? ( to {false ? ( 4 failed, 1 passed (the CONTROL)
a non-admin renders no builder chips HomePage.greetingAndApps-12601.test.tsx › a non-admin renders no builder chips {isAdmin && ( to {true && ( 1 failed, 13 passed
a disabled chip explains itself through the tooltip wrapper › a chip withheld for want of the capability explains itself through the tooltip wrapper if (!disabled) return button; to return button; 2 failed, 12 passed
Setup is not among the tiles › Setup is not among the tiles launcherApps set to activeApps 2 failed, 12 passed
a tile shows the last-opened time from the store › a tile shows when its app was last opened, read from the recent-items store lastOpened={lastOpened} to lastOpened={undefined} 1 failed, 13 passed

appLastOpened-12601.test.ts pins the reading itself: the newest entry wins in any order, the name alias resolves to the same app as the package id, and an entry outside every app, under an unknown app or with no readable time names nothing.

Verification (at 42e5761; superseded for the patch rounds by the section below)

Every local reading below was taken on 42e5761 (git rev-parse --short HEAD), after the last commit, through the container's shared verify lock where it builds or tests. Wall-clock figures are from a shared box.

Command Result
pnpm --filter '@object-ui/app-shell^...' build (dependency closure) exit 0
pnpm --filter @object-ui/i18n build exit 0
pnpm --filter @object-ui/app-shell type-check (tsc --noEmit && tsc -p tsconfig.test.json, the second covers src/**/*.test.ts(x)) exit 0
pnpm --filter @object-ui/i18n type-check exit 0
pnpm exec vitest run packages/app-shell/src/console/home/ packages/app-shell/src/layout/ packages/app-shell/src/console/__tests__/ packages/app-shell/src/__tests__/ packages/app-shell/src/chrome/ plus views/__tests__/phase1-page-blocks.render.test.tsx and views/metadata-admin/previews/__tests__/exclusion-reason-truthfulness.test.ts Test Files 171 passed (171), Tests 1476 passed (1476)
pnpm exec vitest run packages/i18n/ Test Files 83 passed (83), Tests 1321 passed, 13 skipped (1334)
pnpm exec vitest run over the seven apps/console tests that mount DefaultHomeLayout or the app Test Files 7 passed (7), Tests 277 passed (277)
pnpm check:i18n-keys, check:i18n-drift, check:i18n-dead-keys exit 0 each; the dead-key sweep no longer lists the three removed keys and lists none of the new ones
pnpm check:test-path-roots, check:changeset-claims, changeset:check, check:unreferenced-sources, check:esm-specifiers, check:self-import exit 0 each
node scripts/check-changeset-presence.mjs, check-changeset-overwrite.mjs, check-new-cross-file-line-citations.mjs, check-control-bytes.mjs, check-vi-mock-inherit.mjs, check-vi-mock-override-shape.mjs, check-vi-mock-specifiers.mjs exit 0 each
pnpm exec eslint over the 19 changed .ts / .tsx files exit 0, 0 errors (33 warnings, no-explicit-any and unused stub arguments, the same kinds the files and the stub idiom they copy already carry)

pnpm check:i18n named on the card does not exist in this repository; the three check:i18n-* gates above are the real ones. The gate list is derived by hand from package.json and .github/workflows/, against this diff.

Patch rounds (seat-appended)

Seat REWORK round 1 is recorded on objectui#12601; the dev's reports are comments 6211824280 (round 2) and 6212550215 (round 3).

  • Round 1 → fc73410:
    • AppLike is no longer hand-declared, so check:spec-symbols is green.
    • The summary line is empty unless the approvals read is ready. The status travels through useHomeInbox, the page's one inbox seam.
    • Root cause of the seven red home harnesses at 042577e: a direct approvals read escaped their fetch guard. Ablations S1/S2 go 4 red each.
  • Round 2 → 70bfa2f:
    • The tile's last-opened line uses the compact relative time described above. Ablation T1 (short → long) and T2 (en back to "Opened …") each turn the 93 px budget pin red.
    • The changeset's Greeting bullet now says the count is the shared pending-approvals read, the one the bell uses for the approvals part of its badge.
  • Readings at 70bfa2f:
    • pnpm exec vitest run packages/app-shell/src/console/home/ packages/app-shell/src/hooks/ packages/app-shell/src/layout/ packages/i18n/: Test Files 252 passed (252), Tests 2596 passed, 13 skipped.
    • Type-check for app-shell and i18n: 0. The i18n, changeset, spec-symbol and vi-mock gates: 0.
    • Surface widened, additively: useHomeInbox.ts, sharedUserFeeds.ts (both not exported), @object-ui/i18n formatRelativeTime (optional argument), app-shell utils/relativeTime.ts, and one LEGITIMATE_IDENTITIES entry for home.appOpened in untranslated-identity-4376.test.ts.

NOT MEASURED

  • NOT MEASURED: screenshots, reason: the seat takes one shared browser reading for the resumed cards at review, before ACCEPT.
  • NOT MEASURED locally: the full @object-ui/app-shell package run (1436 test files) and the full pnpm test; narrowed to the directories that import the changed modules and the tests that name them. CI's sharded pnpm test runs all of it.
  • NOT MEASURED locally: Bundle Analysis (performance-budget.yml, eager closure), reason: it needs every package and the console built; it runs on this PR in CI. HomeLayout now imports CommandPalette statically and HomePage imports resolveSetupAppPath from ConsoleShell.

Acceptance notes

  • Top bar height. The artboard's bar is 48 px; Home's stays 56 px (h-14). The same 56 px header is drawn by AppShell, HomeLayout, the organization layouts and the AI chat page, so changing Home alone would make the bar jump on the way into an app. Carrier: objectui#12639 (filed by the seat; both approved artboards draw header style="height:48px"), which lands after this PR. (Seat edit: this line originally named objectui#12605 as the carrier.)

  • The bar's right side (help, a 28 px avatar) is left as it is: AppHeader changes are limited to the /home search entry while objectui#12605 holds the file. The left side already matches (a 28 px mark on --primary, the 14 px / 600 name, the preview chip).

  • The search field keeps the shared trigger's rounded-md and 12 px label; the artboard draws an 8 px radius and 13 px text. One element serves Home and every app.

  • The summary's zero claim is fixed in this PR (patch round 1, fc73410). The line speaks only when the approvals read is an answer (ready); while it loads, after it fails or before it is asked, the line is empty. A 404 (no approvals plugin) is the store's ruled ready answer of 0, so the line says "Nothing is waiting for you today" there, which the seat accepts. The status travels through useHomeInbox (pendingApprovalsStatus). (Seat edit: this line originally carried the defect to objectui#12602.)

  • Tile colour. The tile keeps the launcher's deterministic gradient per app, which the artboard draws too; it does not read branding.primaryColor (the ruling that AppMark implements names the bar's pill, the switcher rows and the drawer header). Carrier: none.

  • packages/i18n/src/__tests__/makerEmptyState-v1-scope-8329.test.ts names home.build.subtitle in a scope comment; the key is removed here. Comment only, left as it is.

  • Adds no product-specific widget, dialog, hook or string (see AGENTS.md › Product-neutral renderer)

Session: https://claude.ai/code/session_011K9g23W67dy2zwnyzaoB6o (the domain:ui seat 1 PM; this run is its os-dev subagent).


Generated by Claude Code

…als, builder chips and 56 px app tiles (objectui#12601)

Sections one and two of the approved home artboard:

- HomeLayout mounts the console's command palette, scoped to Home's host
  app, so the home bar draws its search field (centred, 420 px from xl)
  and Cmd+K opens the same palette as inside an app.
- The greeting is 24 px / 600 with a 13 px line from the approvals count;
  "assigned to me" has no classifiable source yet, so the line names
  approvals only.
- The two builder cover cards become two 32 px chips for admins; a
  withheld chip explains itself through the objectui#12303 tooltip
  wrapper, keeping the existing test ids.
- The apps strip draws 112 px tiles with a 56 px icon; Setup leaves the
  tiles for a muted System Settings link; an admin gets a trailing
  Add app tile on the marketplace route, gated as the shortcut is.
- New keys home.search, home.summary.*, home.addApp in all ten packs.

Claude-Session: https://claude.ai/code/session_01JZnppgHRp4sREcouhkQYDB
Co-authored-by: Claude <noreply@anthropic.com>
…rom the recent-items store (objectui#12601)

The card's sixth target item and its fifth acceptance test were not on the
inherited branch: each tile now draws an 11 px "Opened 2 hours ago" line under
its name. The time is the newest recent-items entry opened inside the app (its
`/apps/<segment>/...` href, resolved to the app with `matchAppBySegment`); an
app with no entry left in the store draws no line. New key `home.appOpened`
in all ten packs.

Claude-Session: https://claude.ai/code/session_011K9g23W67dy2zwnyzaoB6o
Co-authored-by: Claude <noreply@anthropic.com>
…ards read (objectui#12601)

`home.heroTagline`, `home.build.subtitle` and `home.template.subtitle` had
one reader each, the hero tagline and the two cover cards this card retires;
`pnpm check:i18n-dead-keys` listed them after that change. Removed from all
ten packs. The changeset now says so, and states the `@object-ui/i18n` half
of the public surface: the exported `en` pack is typed by its literal
content, so its type moves with the keys.

Claude-Session: https://claude.ai/code/session_011K9g23W67dy2zwnyzaoB6o
Co-authored-by: Claude <noreply@anthropic.com>
… left in HomeAppsStrip (objectui#12601)

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

github-actions Bot commented Oct 16, 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/11659-console-record-ux.md

  • names HomePage.tsx → packages/app-shell/src/console/home/HomePage.tsx — edited by this change

    The backup-password reminder no longer appears in the user's first session. 「建议设置一个备用密码」 showed on the environment home right after a new user built their first app: the reminder was gated on a home-visit count (quiet on the first home mount, shown on the second), and coming back to home after building is the second mount inside the first sitting. It now stays quiet for 12 hours after the first home visit on the device, so it first shows on a later day's visit. The first-visit record (os:recovery-pw-first-seen) now holds a timestamp; a device that holds the old '1' flag starts the 12 hours over rather than reading it as long ago. When storage is unavailable it stays quiet. RecoveryPasswordReminder moves out of HomePage.tsx into its own module; it is not exported from the package entry, and its other conditions (dismissed, SSO-enforced, has a local password) are unchanged.

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 8ed7e5a8f (merge-base with origin/main): 27 file(s) changed outside .changeset/, read against 559 pending declaration(s) that publish a body (579 pending in total). · run

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 70 chunks) 3094.3 KB 3119.4 KB
Main entry chunk (gzip) 73.8 KB 350 KB
Entry file index-Bp_P85d-.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) 21.19KB 7.76KB
app-shell (runtime-config.js) 22.59KB 7.89KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.62KB 0.83KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 41.19KB 11.12KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
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) 27.26KB 8.03KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (commentAuthorship.js) 1.39KB 0.78KB
collaboration (index.js) 1.93KB 0.85KB
collaboration (useCollaborationTranslation.js) 6.50KB 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) 598.42KB 144.26KB
core (index.js) 10.18KB 4.04KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 248.20KB 69.22KB
fields (index.js) 283.13KB 72.14KB
i18n (LocalizationContext.js) 2.92KB 1.42KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.52KB 2.39KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 36.87KB 9.88KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 40.67KB 11.85KB
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) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 15.35KB 5.51KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.82KB 2.38KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
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) 16.04KB 3.92KB
plugin-calendar (index.js) 54.94KB 16.05KB
plugin-charts (index.js) 84.97KB 23.36KB
plugin-chatbot (index.js) 201.89KB 48.13KB
plugin-dashboard (index.js) 146.15KB 39.55KB
plugin-designer (index.js) 233.95KB 50.08KB
plugin-detail (index.js) 262.91KB 69.49KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 180.92KB 46.72KB
plugin-gantt (index.js) 178.36KB 45.08KB
plugin-grid (index.js) 265.09KB 73.23KB
plugin-kanban (index.js) 53.23KB 16.71KB
plugin-list (index.js) 129.90KB 33.12KB
plugin-map (index.js) 27.07KB 8.96KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 46.66KB 13.13KB
plugin-timeline (index.js) 39.21KB 11.85KB
plugin-tree (index.js) 15.07KB 5.33KB
plugin-view (index.js) 93.43KB 23.94KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 12.07KB 3.68KB
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) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.07KB 1.30KB
sdui-parser (index.js) 7.30KB 3.12KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.81KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 23.87KB 7.83KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
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) 1.13KB 0.65KB
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) 5.78KB 2.70KB
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 (node-slots.js) 7.18KB 2.34KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-approval-decision.js) 0.20KB 0.20KB
types (record-components.js) 0.20KB 0.19KB
types (record-panels.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) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.26KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.48KB 3.50KB
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

…als count is an answer; no spec-named local type (objectui#12601)

Seat patch round 1 on PR #12638, two items.

The line under the greeting said "Nothing is waiting for you today" while the
approvals read was in flight, after it failed, or before it was asked: the
count hook hands back the value and drops the feed's status. A sibling,
`useSharedPendingApprovals`, returns the store's `SharedFeedSnapshot` (the
count hook now reads `.value` off it, so its two callers are unchanged), and
the line speaks only on `ready`. On anything else it keeps its height and
stays empty. Not exported from the package entry.

`lastOpenedByApp` declared a local `AppLike`, a name `@objectstack/spec/system`
exports, and `pnpm check:spec-symbols` refused it. It now takes the app list
as `matchAppBySegment`'s own parameter type and the store entry as
`Pick<RecentItem, 'href' | 'visitedAt'>`, so no second shape is declared.

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

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 70 chunks) 3094.4 KB 3119.4 KB
Main entry chunk (gzip) 73.8 KB 350 KB
Entry file index-kJOyby-V.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) 21.19KB 7.76KB
app-shell (runtime-config.js) 22.59KB 7.89KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.62KB 0.83KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 41.19KB 11.12KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
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) 27.26KB 8.03KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (commentAuthorship.js) 1.39KB 0.78KB
collaboration (index.js) 1.93KB 0.85KB
collaboration (useCollaborationTranslation.js) 6.50KB 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) 598.42KB 144.26KB
core (index.js) 10.18KB 4.04KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 248.20KB 69.22KB
fields (index.js) 283.13KB 72.14KB
i18n (LocalizationContext.js) 2.92KB 1.42KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.52KB 2.39KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 36.87KB 9.88KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 40.67KB 11.85KB
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) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 15.35KB 5.51KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.82KB 2.38KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
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) 16.04KB 3.92KB
plugin-calendar (index.js) 54.94KB 16.05KB
plugin-charts (index.js) 84.97KB 23.36KB
plugin-chatbot (index.js) 201.89KB 48.13KB
plugin-dashboard (index.js) 146.15KB 39.55KB
plugin-designer (index.js) 233.95KB 50.08KB
plugin-detail (index.js) 262.91KB 69.49KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 180.92KB 46.72KB
plugin-gantt (index.js) 178.36KB 45.08KB
plugin-grid (index.js) 265.09KB 73.23KB
plugin-kanban (index.js) 53.23KB 16.71KB
plugin-list (index.js) 129.90KB 33.12KB
plugin-map (index.js) 27.07KB 8.96KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 46.66KB 13.13KB
plugin-timeline (index.js) 39.21KB 11.85KB
plugin-tree (index.js) 15.07KB 5.33KB
plugin-view (index.js) 93.43KB 23.94KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 12.07KB 3.68KB
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) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.07KB 1.30KB
sdui-parser (index.js) 7.30KB 3.12KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.81KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 23.87KB 7.83KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
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) 1.13KB 0.65KB
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) 5.78KB 2.70KB
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 (node-slots.js) 7.18KB 2.34KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-approval-decision.js) 0.20KB 0.20KB
types (record-components.js) 0.20KB 0.19KB
types (record-panels.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) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.26KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.48KB 3.50KB
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

… its one inbox seam (objectui#12601)

042577e had HomePage call `useSharedPendingApprovals` directly, beside the
`useHomeInbox` it already reads. Every HomePage harness mocks `useHomeInbox`
and routes `fetch`, so the new direct read sent a real approvals request:
each file's afterEach (no request escapes the double) failed, its `cleanup()`
after that assertion never ran, and the next case found the previous DOM
still mounted ("Found multiple elements") — seven files in CI shards 5, 10,
13, 14 and 15.

The status now travels the page's one seam: `useHomeInbox` reads the
approvals snapshot and returns `pendingApprovalsStatus` beside the count, as
it returns `notificationsStatus` for the inbox. HomePage reads only
`useHomeInbox`. `HomeActionCenter.unansweredInbox` dials the count through
the snapshot read it now goes through; `useInboxBell` keeps the count hook.
A new hook test pins the pass-through (loading, ready with the count, error,
and a 404 as the store's ready answer); the Home last-opened case gains an
entry with no readable time, which draws no line. The changeset states the
ready-only line.

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

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 70 chunks) 3094.4 KB 3119.4 KB
Main entry chunk (gzip) 73.8 KB 350 KB
Entry file index-CfkAEz5S.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) 21.19KB 7.76KB
app-shell (runtime-config.js) 22.59KB 7.89KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.62KB 0.83KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 41.19KB 11.12KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
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) 27.26KB 8.03KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (commentAuthorship.js) 1.39KB 0.78KB
collaboration (index.js) 1.93KB 0.85KB
collaboration (useCollaborationTranslation.js) 6.50KB 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) 598.49KB 144.31KB
core (index.js) 10.18KB 4.04KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 248.20KB 69.22KB
fields (index.js) 283.17KB 72.17KB
i18n (LocalizationContext.js) 2.92KB 1.42KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.52KB 2.39KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 36.87KB 9.88KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 40.67KB 11.85KB
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) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 15.35KB 5.51KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.82KB 2.38KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
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) 16.04KB 3.92KB
plugin-calendar (index.js) 54.94KB 16.05KB
plugin-charts (index.js) 84.97KB 23.36KB
plugin-chatbot (index.js) 201.89KB 48.13KB
plugin-dashboard (index.js) 146.15KB 39.55KB
plugin-designer (index.js) 233.95KB 50.08KB
plugin-detail (index.js) 262.91KB 69.49KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 180.92KB 46.73KB
plugin-gantt (index.js) 178.36KB 45.08KB
plugin-grid (index.js) 265.13KB 73.29KB
plugin-kanban (index.js) 53.23KB 16.71KB
plugin-list (index.js) 129.90KB 33.12KB
plugin-map (index.js) 27.07KB 8.96KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 46.66KB 13.13KB
plugin-timeline (index.js) 39.21KB 11.85KB
plugin-tree (index.js) 15.07KB 5.33KB
plugin-view (index.js) 93.43KB 23.94KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 12.07KB 3.68KB
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) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.07KB 1.30KB
sdui-parser (index.js) 7.30KB 3.12KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.81KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 23.87KB 7.83KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
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) 1.13KB 0.65KB
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) 5.78KB 2.70KB
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 (node-slots.js) 7.18KB 2.34KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-approval-decision.js) 0.20KB 0.20KB
types (record-components.js) 0.20KB 0.19KB
types (record-panels.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) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.26KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.48KB 3.50KB
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

…n every pack (objectui#12601)

Seat patch round 2 on PR #12638, two items.

Measured live at 1280 px, en: "Opened 6 seconds ago" read "Opened 6 secon..."
in the 112 px tile. The line is now drawn in Intl's compact form,
`TILE_OPENED_TIME_FORMAT` = `{ style: 'short', numeric: 'always' }`
("3 hr. ago", "1 day ago", zh "3小时前打开"). `formatRelativeTime`
(@object-ui/i18n) and `timeAgo` (app-shell) take Intl's own `style` /
`numeric` as an optional argument; without it their output is unchanged, so
one helper keeps the unit thresholds. `home.appOpened` keeps a verb only
where verb and time still fit: zh, ko and ar unchanged, ja "{{time}}に起動",
en, de, fr, es, pt and ru the time alone. `appTileOpenedLine-12601.test.ts`
holds every pack's line, 6 s to 12 y, to a 93 px budget (112 - 2 x 8 px
padding - 3 px reserve for the width estimate's measured error), pins the
en and zh strings at 6 s, 5 min, 3 h and 2 d, and shows the old long form
over budget.

The changeset's Greeting bullet said the count is "the approvals count the
bell badges"; the badge also adds unread notification topics. It now names
the shared pending-approvals read and says what the badge adds, and the Apps
bullet and the i18n surface sentence describe the compact line and the new
optional argument.

Claude-Session: https://claude.ai/code/session_011K9g23W67dy2zwnyzaoB6o
Co-authored-by: Claude <noreply@anthropic.com>
…t raw characters (objectui#12601)

The file was written with the two full-width ranges materialized as raw
characters, U+3000 (ideographic space) among them, which
`no-irregular-whitespace` refuses. Same regex, escape spelling.

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

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 70 chunks) 3095.3 KB 3119.4 KB
Main entry chunk (gzip) 74.2 KB 350 KB
Entry file index-CX_D8m9j.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) 21.19KB 7.76KB
app-shell (runtime-config.js) 22.59KB 7.89KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 20.39KB 6.02KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.62KB 0.83KB
auth (authStyles.js) 5.27KB 1.86KB
auth (createAuthClient.js) 41.19KB 11.12KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
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) 27.26KB 8.03KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (commentAuthorship.js) 1.39KB 0.78KB
collaboration (index.js) 1.93KB 0.85KB
collaboration (useCollaborationTranslation.js) 6.50KB 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) 598.49KB 144.31KB
core (index.js) 10.18KB 4.04KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 248.20KB 69.22KB
fields (index.js) 283.17KB 72.17KB
i18n (LocalizationContext.js) 2.92KB 1.42KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.52KB 2.39KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 36.87KB 9.88KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 40.67KB 11.85KB
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) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 15.35KB 5.51KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.82KB 2.38KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
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) 16.04KB 3.92KB
plugin-calendar (index.js) 54.94KB 16.05KB
plugin-charts (index.js) 84.97KB 23.36KB
plugin-chatbot (index.js) 201.89KB 48.13KB
plugin-dashboard (index.js) 146.15KB 39.55KB
plugin-designer (index.js) 233.95KB 50.08KB
plugin-detail (index.js) 262.91KB 69.49KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 180.92KB 46.73KB
plugin-gantt (index.js) 178.36KB 45.08KB
plugin-grid (index.js) 265.13KB 73.29KB
plugin-kanban (index.js) 53.23KB 16.71KB
plugin-list (index.js) 129.90KB 33.12KB
plugin-map (index.js) 27.07KB 8.96KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 46.66KB 13.13KB
plugin-timeline (index.js) 39.21KB 11.85KB
plugin-tree (index.js) 15.07KB 5.33KB
plugin-view (index.js) 93.43KB 23.94KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 12.07KB 3.68KB
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) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.07KB 1.30KB
sdui-parser (index.js) 7.30KB 3.12KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.81KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 23.87KB 7.83KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
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) 1.13KB 0.65KB
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) 5.78KB 2.70KB
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 (node-slots.js) 7.18KB 2.34KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-approval-decision.js) 0.20KB 0.20KB
types (record-components.js) 0.20KB 0.19KB
types (record-panels.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) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.26KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.48KB 3.50KB
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

…s a legitimate identity (objectui#12601)

`home.appOpened` is the tile's time hole plus a verb where both fit the
112 px tile; ru, like en, has no room for one, so its value equals en's
`{{time}}`. `untranslated-identity-4376` names that case's remedy: a
format string goes in LEGITIMATE_IDENTITIES with its reason, as
`grid.summary.pattern` does.

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

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 70 chunks) 3095.3 KB 3119.4 KB
Main entry chunk (gzip) 74.2 KB 350 KB
Entry file index-CX_D8m9j.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) 21.19KB 7.76KB
app-shell (runtime-config.js) 22.59KB 7.89KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 20.39KB 6.02KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.62KB 0.83KB
auth (authStyles.js) 5.27KB 1.86KB
auth (createAuthClient.js) 41.19KB 11.12KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
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) 27.26KB 8.03KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (commentAuthorship.js) 1.39KB 0.78KB
collaboration (index.js) 1.93KB 0.85KB
collaboration (useCollaborationTranslation.js) 6.50KB 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) 598.49KB 144.31KB
core (index.js) 10.18KB 4.04KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 248.20KB 69.22KB
fields (index.js) 283.17KB 72.17KB
i18n (LocalizationContext.js) 2.92KB 1.42KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.52KB 2.39KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 36.87KB 9.88KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 40.67KB 11.85KB
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) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 15.35KB 5.51KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.82KB 2.38KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
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) 16.04KB 3.92KB
plugin-calendar (index.js) 54.94KB 16.05KB
plugin-charts (index.js) 84.97KB 23.36KB
plugin-chatbot (index.js) 201.89KB 48.13KB
plugin-dashboard (index.js) 146.15KB 39.55KB
plugin-designer (index.js) 233.95KB 50.08KB
plugin-detail (index.js) 262.91KB 69.49KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 180.92KB 46.73KB
plugin-gantt (index.js) 178.36KB 45.08KB
plugin-grid (index.js) 265.13KB 73.29KB
plugin-kanban (index.js) 53.23KB 16.71KB
plugin-list (index.js) 129.90KB 33.12KB
plugin-map (index.js) 27.07KB 8.96KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 46.66KB 13.13KB
plugin-timeline (index.js) 39.21KB 11.85KB
plugin-tree (index.js) 15.07KB 5.33KB
plugin-view (index.js) 93.43KB 23.94KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 12.07KB 3.68KB
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) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.07KB 1.30KB
sdui-parser (index.js) 7.30KB 3.12KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.81KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 23.87KB 7.83KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
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) 1.13KB 0.65KB
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) 5.78KB 2.70KB
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 (node-slots.js) 7.18KB 2.34KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-approval-decision.js) 0.20KB 0.20KB
types (record-components.js) 0.20KB 0.19KB
types (record-panels.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) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.26KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.48KB 3.50KB
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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: TIER_DEFAULT
Head-sha: 70bfa2fe3d821b81f091a276481d8ce5a334b7e0
Local-runs: none

Face: the Clause-②: yes declaration on the takeover claim 6209656150 (objectui#12601). The committed tree has no published schema and no governed path (check-governed-merges --pr: 0 of 28 paths, NOT governed; 1888 changed lines). Inputs: the diff, the card, the REWORK records on the card, and this head's check-runs (33 success, 3 skipped by design).

① Derived judgments

  • @object-ui/app-shell entry: no widening. The entry's declaration closure was measured at 42e5761: the same 180 files on both sides, with HomeLayout.d.ts and AppHeader.d.ts differing in doc comments only. HomePage() takes no props, and HomeLayoutProps and AppHeaderProps are byte-identical. The patch rounds add only modules that the entry does not export: useSharedPendingApprovals in hooks/sharedUserFeeds.ts, pendingApprovalsStatus on the non-exported HomeInboxData, console/home/appLastOpened.ts, and timeAgo's optional argument in utils/relativeTime.ts. packages/app-shell/src/index.ts at this head names none of them. Correct.
  • @object-ui/i18n, the exported en pack type. It gains home.search, home.summary.approvals (a count family), home.summary.none, home.addApp and home.appOpened. It loses home.heroTagline, home.build.subtitle and home.template.subtitle, whose only readers were the retired hero and cover cards. check:i18n-dead-keys and check:i18n-keys are green. Correct: an additive widening plus a declared narrowing of dead keys.
  • @object-ui/i18n, formatRelativeTime. The exported function gains an optional third argument, Pick of Intl.RelativeTimeFormatOptions style / numeric, passed through unchanged. Omitted, it keeps { numeric: 'auto', style: 'long' }, so existing callers see the same output. Correct, additive.
  • Test allowlist. untranslated-identity-4376.test.ts gains one LEGITIMATE_IDENTITIES entry, home.appOpened. Its value is the bare {{time}} hole in packs where no verb fits the tile, the pure-format-string remedy that test names. The tile budget pin appTileOpenedLine-12601.test.ts holds that decision, and its ablation T2 turns it red. Accepted; not a weakened guard.

② Semver level

@object-ui/app-shell minor and @object-ui/i18n minor: an additive optional argument, new keys, and three dead keys removed. Under objectui's no-major policy in pre mode, Changeset Bump Policy and Changeset Fixed Group Check pass on this head. The changeset's Clause-②: yes paragraph states every one of these points. Consistent.

③ Boundary flags

  • The dev's open questions were answered on the card: the 404 reading is ruled A (the store's ruled ready answer of 0).
  • The 48 px bar height moved to objectui#12639.
  • zh reads 1天前打开 where the artboard illustrates 昨天打开. This follows from numeric: 'always', chosen because the auto phrases are the longest any pack produces. The information is the same. Accepted.
  • No flag is left open.

Implemented-by: claude/issue-12601-home-top-and-apps
Reviewed-by: session_011K9g23W67dy2zwnyzaoB6o

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · ACCEPT · domain:ui seat 1 · session_011K9g23W67dy2zwnyzaoB6o · 2026-10-16T09:38Z

Reviewed head 70bfa2fe3d821b81f091a276481d8ce5a334b7e0 against objectui#12601. The takeover claim is 6209656150 (Clause-②: yes, mode:subagent, resumed from 3cc9fa19d0). Before this ACCEPT the PR went through two seat REWORK rounds on the card, at the round-1 REWORK and at the round-2 comment. The contract review of record is 6212627233 (TIER_DEFAULT, PASS, this head).

  1. Shape: draft PR to main. Fixes #12601 is the first line and the only closing keyword in the body. Clause-②: yes starts a line, and the assignee is os-tesla. check-governed-merges --pr reports NOT governed, 1888 changed lines (under 3000). No content/docs/releases/ change. The changeset was checked sentence by sentence against the code at this head. The PR body's stale lines were corrected by the seat, and each correction is marked as a seat edit.
  2. Live readings were taken by the seat's reading session session_01CQVvdrcshAD3iT7azpF5NT against the published @objectstack/*@18.0.0-next.1 backend. PNGs are at claude/issue-12616-evidence, a261e30 and e073448, under evidence/12601/.
    • Search: a centred 420 px field with ⌘K. A click, Ctrl+K and Meta+K each open one palette.
    • Greeting: 24 px / 600, with the name in --primary.
    • Summary: "You have 3 approvals waiting today" (zh 今天有 3 项待审批), which matches GET /api/v1/approvals/requests?status=pending = 3. While loading, the summary is empty and never shows "Nothing is waiting".
    • Layout: a 1120 px column with no bordered card. Tiles are 112 px with a 56 px icon. Setup is not a tile. At 390 px the page fits.
    • Last-opened line: at this head it reads "6 sec. ago" in en and 17秒前打开 in zh, at 11 px, clientWidth 96 = scrollWidth 96, with no ellipsis. The previous head cut it to "Opened 6 secon…".
  3. Gates (check-runs pinned to this head):
    • 33 success and 3 skipped by design. These include Lint, Repo Gates, Type Check, Test (shard 1–16/16), Build & E2E, Bundle Analysis (eager closure 3095.3 KB of 3119.4 KB) and Live E2E (informational).
    • The dev's ablations each turn their pins red: the five acceptance pins, S1/S2 for the approvals status, and T1/T2 for the tile budget.
  4. Accepted deviations:
    • Admin-only parts not measured live: the builder chips, the disabled-chip tooltip, the Browse marketplace / System Settings links and the Add app tile. On this stack the seeded admin's session reads role=user, isPlatformAdmin=false. The evidence of record is the unit pins with ablations (A2, A3).
    • Summary scope: the summary names approvals only. Nothing on main classifies an inbox item as "assigned to me", and objectui#12602 carries the same fork.
    • Top bar height: the bar stays 56 px; objectui#12639 carries the 48 px.
    • Search trigger styling: the trigger keeps the shared rounded-md and 12 px label.
    • zh "1 day ago": zh reads 1天前打开 rather than 昨天打开.
    • No verb in some packs: en, de, fr, es, pt and ru show the time without a verb.
    • Widened file surface: sharedUserFeeds.ts, useHomeInbox.ts, relativeTime.ts, formatting.ts (formatRelativeTime's optional argument) and one test allowlist entry, recorded on the card.
  5. Out of scope: none filed. The bell badge counts approvals plus unread notification topics, and the changeset now says so. makerEmptyState-v1-scope-8329.test.ts names a removed key in a comment only.
  6. Landing: ready, then auto-merge into the merge queue. After the merge, verify by content, close the card through Fixes, strip pm:dispatched, and archive the reading session.

Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 16, 2026 09:40
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 16, 2026 09:40
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 16, 2026
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.

Console home: search in the top bar, a greeting with a work summary, compact builder actions and 56 px app tiles

2 participants