Skip to content

fix(plugin-detail): name the activity panel's landmark by the heading it draws, not 'Discussion' - #10237

Merged
objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/issue-9998-activity-landmark-name
Sep 24, 2026
Merged

objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/issue-9998-activity-landmark-name

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #9998
Clause-②: no

What was wrong

RecordActivityTimeline named its section landmark with a fixed aria-label from t('detail.discussion'). The visible h2 inside that section reads titleLabel ?? t('detail.activity') followed by an (N) count. record:activity passes no titleLabel, so its region's accessible name was "Discussion" under a heading reading "Activity (N)". record:chatter passes titleLabel={t('detail.discussion')} on both of RecordChatterPanel's paths (sidebar and inline), so its heading and landmark agreed. That difference between two mounts of the same component is the control.

The contract is this repo's own objectui#4118 pin, in ReportConfigPanel.panelTitle.test.tsx: "A speech-input user says what they see, so the landmark's spoken name must be the heading, not a paraphrase of it."

The change (net diff against base 62597c58: 5 files — the claimed landing site, plus the objectui#4645 changeset's prose correction the seat added in round 2)

  • packages/plugin-detail/src/RecordActivityTimeline.tsx: the component reads const title = titleLabel ?? t('detail.activity') once and uses it for both the heading's title and the section's aria-label. The heading's markup is byte-identical to base; the only DOM change is the value of the section's aria-label. The titleLabel doc comment now says it names both.
  • New pin packages/plugin-detail/src/__tests__/RecordActivityTimeline.landmarkNamedByHeading-9998.test.tsx, read through the real en pack and the accessibility tree:
    • record:activity (real renderer, no titleLabel): the landmark is named "Activity", the heading's title, and no region named "Discussion" exists;
    • record:chatter, inline path and sidebar path: still "Discussion" = heading (the control);
    • an authored titleLabel ("Deal history") names both the heading and the landmark.
  • objectui#4645 pin (detail-landmark-aria-i18n-4645.test.tsx): the premise sentence is corrected and dated, and none of its 20 assertions were deleted. Its ten timeline cases now expect each pack's detail.activity where they used to expect detail.discussion. The ten HeaderHighlight cases are unchanged.
  • .changeset/9998-activity-landmark-named-by-heading.md: @object-ui/plugin-detail patch.
  • .changeset/record-detail-builtin-label-i18n-4645.md: prose-only correction of its timeline sentences (round 2, commit 31542304), frontmatter untouched.

Mechanism decisions (dispatch Zone 2, each measured)

  1. Premise: re-read at 62597c58 and confirmed. The fixed aria-label on the section is t('detail.discussion'); the heading reads titleLabel ?? t('detail.activity'); RecordChatterPanel passes titleLabel={t('detail.discussion')} on both paths. The failing pin reproduced the defect before any source edit (see Evidence).

  2. aria-labelledby, the card's suggestion, was tried first, then measured and dropped. It shipped in the first commit, 9eb61082. It needs a per-instance id, because a record:activity and a record:chatter can share one page and a fixed id would collide. The only such id is React.useId(), and its value differs on every mount. Two existing checks compare two mounts' HTML byte for byte, and both went red on that id alone (_r_0_ against _r_6_):

    • apps/console record-block-record-reach.test.tsx, whose stability control failed with the message "Find the unstable output (an id, …)";
    • @object-ui/app-shell palette-discussion-alias.test.tsx, where the alias and the canonical block's HTML must be identical.

    Both are outside this card's file surface, and loosening either would weaken it. The final route is the objectui#4118 precedent's own shape: an aria-label equal to the heading text, read from one variable. The name and the heading cannot drift, and output is deterministic.

  3. The (N) count is excluded from the name. It is live status: filtered.length moves with the filter dropdown, and it is styled as secondary text. People say "Activity" to name the panel, not the count. The card itself treats record:chatter's "Discussion" landmark under a "Discussion (N)" heading as agreeing, and that is only true with the count left out. Including it would turn the card's own control into a second instance of the defect. The pin still asserts that the count is on screen.

  4. Authored aria names: no caller can pass one into the timeline, because it has no aria prop. As objectui#9946's closed measurement found, a block's authored aria bag lands on the renderer's outer container through useRecordAriaProps. The objectui#9556 composition pin (recordComponentAria-9556.test.tsx) is green and unchanged: its selector section[aria-label] still matches, and the inner name "Activity" is not the authored one.

  5. The objectui#4645 premise sentence was false on the day it was written, not just today. The card said it was once true. The section and its h2 were introduced together in 86c04f1ff2 (2026-05-21, the de-boxing that replaced the Card), and the console i18n residual on 17.0.0 GA: built-in record-detail tabs untranslated in ja-JP / es-ES (zh-CN fine), plus two English aria-labels in every locale #4645 pin landed in 8033ad14d6 (2026-09-09). I read the file at both shas through the contents API.

  6. axe-core / vitest-axe: not used. A pin built on them could not go red for this defect. objectui#9946's axe-core 4.13.0 run (wcag2a/2aa/21a/21aa/22aa/best-practice) on the unfixed tree, with "Discussion" under "Activity (N)", found zero landmark violations. No axe rule relates a region's name to its visible heading.

Evidence (final head 95fe1497 unless stated)

  • Red before the fix (new pin alone on unfixed source): Tests 2 failed | 2 passed (4). record:activity: expected accessible name "Activity", received "Discussion". Authored titleLabel: expected "Deal history", received "Discussion". Both chatter controls passed.
  • Targeted union at 95fe1497, from the repo root: pnpm exec vitest run over the new pin, the console i18n residual on 17.0.0 GA: built-in record-detail tabs untranslated in ja-JP / es-ES (zh-CN fine), plus two English aria-labels in every locale #4645 pin, the finding(plugin-detail): aria is declared on six record component interfaces and read by one of them — while record:quick_actions, the renderer that reads it hardest, has no declared props interface at all #9556 pin, the six app-shell RecordDetailView discussion/activity tests, palette-discussion-alias, canvas-display-meta, PagePreview, console record-block-record-reach, and i18n raw-key-call-sites-3546. Result: Test Files 14 passed (14), Tests 170 passed (170), lock VERDICT command-exit 0.
  • Whole package pnpm exec vitest run packages/plugin-detail/ at 066dbc32: Test Files 198 passed (198), Tests 1989 passed (1989). 95fe1497 differs from it only in the new pin's fixture typing (satisfies instead of an as any cast), and the union above ran that file at 95fe1497.
  • type-check: built the dependency closure with pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-detail^...' build (exit 0), then ran pnpm --filter @object-ui/plugin-detail type-check (tsc --noEmit && tsc -p tsconfig.test.json, exit 0) on the 95fe1497 tree. tsc -p tsconfig.test.json --listFilesOnly lists all three touched .ts/.tsx files.
  • Ablation at 95fe1497: scripts/ablation-replace.mjs put the old aria-label={t('detail.discussion')} back in place of aria-label={title}. The mutation landed on disk (anchor 1 to 0, blob 3d38c741 to abcc219a) and ran with a restore trap. Result: Tests 12 failed | 12 passed (24).
  • Gates at 95fe1497, all exit 0:
    • pnpm check:control-bytes
    • pnpm check:new-line-citations: 0 new citations
    • node scripts/check-changeset-presence.mjs
    • pnpm check:changeset-claims
    • node scripts/check-vi-mock-override-shape.mjs
    • node scripts/check-test-path-roots.mjs
    • pnpm check:i18n-keys, pnpm check:i18n-drift and pnpm check:pending-changeset-literals, run at 066dbc32; the last commit touched no call site.
  • Lint: eslint . in packages/plugin-detail (the package's own lint script): 256 files per the JSON output, 0 errors. The config has no type-aware linting, so this diff cannot change a verdict on an untouched file. The three touched files also pass with --max-warnings 0.

Acceptance notes

  • The pending objectui#4645 changeset's timeline sentences are corrected in this PR (prose only, frontmatter untouched, commit 31542304), at the seat's direction in round 2: the review-tier record found it would otherwise publish a sentence this PR proves false.
  • The APG-preferred aria-labelledby + useId shape cannot be used by any record:* block while the two byte-compare checks named above stay as they are. This is recorded as an observation, not a proposal.
  • NOT MEASURED: what NVDA, JAWS or VoiceOver actually announce. There is no assistive technology in this container; the accessibility tree was measured, the announcement was not.
  • CI was not awaited. If Spec Main Shape Gate is red, that is the known objectui#10229 drift on test files this change does not touch.

Generated by Claude Code

… it draws

RecordActivityTimeline named its section landmark with a fixed
t('detail.discussion') while the visible h2 read
titleLabel ?? t('detail.activity'). A record:activity mount passes no
titleLabel, so its region was spoken "Discussion" under a heading
reading "Activity (N)" - against the objectui#4118 rule that the
landmark's spoken name must be the heading. record:chatter passes
titleLabel = discussion, so it agreed; that asymmetry is the control.

The section now takes its name from the heading's title text via
aria-labelledby (the (N) count stays visible and out of the name), so
an authored titleLabel names both.

- new pin: both mounts plus an authored titleLabel
- objectui#4645 pin: premise sentence corrected and dated; the ten
  locale cases now assert detail.activity via the accessible name
- objectui#9556 pin: reads the inner section's name off the a11y tree
  instead of an aria-label attribute selector
… not aria-labelledby

aria-labelledby needs a per-instance id (record:activity and
record:chatter can share a page), and React.useId() differs on every
mount. Two instruments byte-compare two mounts' HTML and went red on it:
the record-block reach probe (apps/console) and the record:chatter alias
pin (app-shell). The section's aria-label now reads the same `title`
value the heading prints - one value, both places - which is the
objectui#4118 precedent's own shape.

The objectui#9556 pin returns to its base bytes (its section[aria-label]
selector holds again), and the objectui#4645 pin keeps reading the
attribute, now expecting detail.activity.
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3035.6 KB 3104.5 KB
Main entry chunk (gzip) 147.5 KB 350 KB
Entry file index-Dh5lKTJM.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.68KB 6.20KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 546.84KB 130.95KB
core (index.js) 8.94KB 3.59KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 222.47KB 61.83KB
fields (index.js) 252.81KB 63.78KB
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) 33.36KB 10.88KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.02KB 11.00KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.39KB 3.10KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 14.81KB 3.63KB
plugin-calendar (index.js) 51.44KB 14.62KB
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) 257.23KB 66.95KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 143.93KB 36.81KB
plugin-gantt (index.js) 167.99KB 41.37KB
plugin-grid (index.js) 214.64KB 58.59KB
plugin-kanban (index.js) 48.71KB 15.17KB
plugin-list (index.js) 113.53KB 27.99KB
plugin-map (index.js) 21.74KB 7.07KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.49KB 11.97KB
plugin-timeline (index.js) 30.68KB 8.95KB
plugin-tree (index.js) 10.58KB 3.72KB
plugin-view (index.js) 85.18KB 21.05KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 106.60KB 35.16KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.38KB 1.98KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.74KB 2.54KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 15.71KB 5.30KB
types (ai.js) 4.11KB 2.06KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 17.15KB 6.32KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 95fe1497

Rendered by an isolated review subagent spawned by this seat. It was fed only the card, the PR and the two trees. Its served tier was checked by this seat against the stamp in its transcript. Adopted by this seat.

① Derived judgments

  • Exported surface: unchanged.
    • exports is . only.
    • RecordActivityTimeline and RecordActivityTimelineProps are still exported, unchanged. No symbol, prop, barrel entry or locale key is added or retyped.
    • The only public-facing delta is the JSDoc on the existing titleLabel. RIGHT.
  • Name vs heading on every mount: one title = titleLabel ?? t('detail.activity') feeds both the section's aria-label and the h2.
    • record:activity ⇒ "Activity";
    • record:chatter (passes titleLabel = discussion on both its sidebar and inline mounts) ⇒ "Discussion";
    • an authored titleLabel ⇒ both. RIGHT.
  • Excluding the (N) count is consistent with objectui#4118. Its literal assertion never addressed a count. The card's own control (chatter "Discussion" under "Discussion (N)") presupposes excluding it, and a filter-driven live count would make the spoken name unstable. It is documented in the component and encoded in the pin.
    • ⚠️ Edge, with no caller: titleLabel="" now yields aria-label="".
  • Authored aria names: none can be overridden. The timeline has no aria prop, and the record blocks spread useRecordAriaProps onto their outer div. The objectui#9556 pin was edited and restored: base-vs-head diff empty.
  • The objectui#4645 pin: 20 assertions before and after. Only the 10 timeline expectations moved (detail.discussion → detail.activity), and all ten locale values were verified against the packs. Nothing weakened.
  • The dropped aria-labelledby approach: the stated reason is TRUE. A per-mount useId breaks the byte-compare in console record-block-record-reach and in app-shell palette-discussion-alias.

② Semver level

'@object-ui/plugin-detail': patch is RIGHT. The history sentence is TRUE, read at all 13 commits of the section's life: 86c04f1ff2 introduced the section, its aria-label and the h2 in one hunk. So the objectui#4645 premise sentence was born false for the timeline.

Two items were sent back for a prose-only re-review:

③ Boundary flags

  • The Acceptance notes are accurate.
  • Fixes #9998 is warranted.
  • Clause-②: no is TRUE: no prop, export, key or schema change.
  • Check-runs on 95fe1497: 43, all terminal: 39 green and 3 skipped. 1 red, Spec Main Shape Gate: TS2345 on untouched ObjectSchema.safeParse helper files ⇒ the objectui#10229 drift, ⛔ not this PR's.

Implemented-by: claude/issue-9998-activity-landmark-name
Reviewed-by: session_01BA3nKVUwKQJf8DBxrSVtNC

VERDICT: PASS

…the #9998 names as accessible names

Prose only, frontmatter untouched in both files.

- record-detail-builtin-label-i18n-4645: the timeline sentences stop
  publishing what objectui#9998 proves false. Its section always had a
  visible heading, and its landmark is named by that heading's title
  (detail.activity, or an authored titleLabel). The HeaderHighlight half
  is unchanged in substance.
- 9998-activity-landmark-named-by-heading: the unmeasured AT
  "announced" phrasings become the measured accessible names, and the
  closing paragraph no longer describes the #4645 entry as still saying
  what this commit corrects.
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3035.6 KB 3104.5 KB
Main entry chunk (gzip) 147.5 KB 350 KB
Entry file index-Dh5lKTJM.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.68KB 6.20KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 546.84KB 130.95KB
core (index.js) 8.94KB 3.59KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 222.47KB 61.83KB
fields (index.js) 252.81KB 63.78KB
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) 33.36KB 10.88KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.02KB 11.00KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.39KB 3.10KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 14.81KB 3.63KB
plugin-calendar (index.js) 51.44KB 14.62KB
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) 257.23KB 66.95KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 143.93KB 36.81KB
plugin-gantt (index.js) 167.99KB 41.37KB
plugin-grid (index.js) 214.64KB 58.59KB
plugin-kanban (index.js) 48.71KB 15.17KB
plugin-list (index.js) 113.53KB 27.99KB
plugin-map (index.js) 21.74KB 7.07KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.49KB 11.97KB
plugin-timeline (index.js) 30.68KB 8.95KB
plugin-tree (index.js) 10.58KB 3.72KB
plugin-view (index.js) 85.18KB 21.05KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 106.60KB 35.16KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.38KB 1.98KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.74KB 2.54KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 15.71KB 5.30KB
types (ai.js) 4.11KB 2.06KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 17.15KB 6.32KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review — prose-only re-review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 31542304
Prior record: PASS at 95fe1497 (5813311828). Code unchanged since: 95fe1497..31542304 is one commit touching only the two changeset files. The objectui#4645 frontmatter is byte-identical at origin/main, 95fe1497 and head.

② Changeset prose

record-detail-builtin-label-i18n-4645.md: every moved sentence is TRUE, checked against the #4645 landing commit 8033ad14d6 and the tree at head.

The one claim dropped (that #4645 routed the timeline through detail.discussion) is correctly dropped, because that state never ships.

9998-activity-landmark-named-by-heading.md: the moved passages now state the accessible name, which is what the pin measures (toHaveAccessibleName). No assistive-tech announcement is stated as fact.

③ Boundary flags

  • Diff scope: clean.
  • PR body: the Acceptance notes agree with the files. Two stale spots outside them (the "4 files" count and one "announced" phrase) were corrected by the seat after this reading; the read-back is identical.
  • Check-runs on 31542304: 0 failed at the reading. The changeset gates, Lint, Type Check, Build & E2E and dist pins are green. The shards and Spec Main Shape Gate ran on identical code at 95fe1497, where the shards were green and the gate was the objectui#10229 drift.

Rendered by an isolated review subagent spawned by this seat; its served tier was checked against its transcript stamp. Adopted by this seat.

Implemented-by: claude/issue-9998-activity-landmark-name
Reviewed-by: session_01BA3nKVUwKQJf8DBxrSVtNC

VERDICT: PASS

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3035.6 KB 3104.5 KB
Main entry chunk (gzip) 147.5 KB 350 KB
Entry file index-Dh5lKTJM.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.68KB 6.20KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 546.84KB 130.95KB
core (index.js) 8.94KB 3.59KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 222.47KB 61.83KB
fields (index.js) 252.81KB 63.78KB
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) 33.36KB 10.88KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.02KB 11.00KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.39KB 3.10KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 14.81KB 3.63KB
plugin-calendar (index.js) 51.44KB 14.62KB
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) 257.23KB 66.95KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 143.93KB 36.81KB
plugin-gantt (index.js) 167.99KB 41.37KB
plugin-grid (index.js) 214.64KB 58.59KB
plugin-kanban (index.js) 48.71KB 15.17KB
plugin-list (index.js) 113.53KB 27.99KB
plugin-map (index.js) 21.74KB 7.07KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.49KB 11.97KB
plugin-timeline (index.js) 30.68KB 8.95KB
plugin-tree (index.js) 10.58KB 3.72KB
plugin-view (index.js) 85.18KB 21.05KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 106.60KB 35.16KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.38KB 1.98KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.74KB 2.54KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 15.71KB 5.30KB
types (ai.js) 4.11KB 2.06KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 17.15KB 6.32KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

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

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

Projects

None yet

1 participant