fix(non-grid,i18n,react): correct the row ceiling changeset, its pins and their rationale comments - #7517

Merged
os-project-manager merged 2 commits into
mainfrom
claude/issue-7507-7391-correctives
Sep 3, 2026
Merged

fix(non-grid,i18n,react): correct the row ceiling changeset, its pins and their rationale comments#7517
os-project-manager merged 2 commits into
mainfrom
claude/issue-7507-7391-correctives

Conversation

@claude

@claudeclaudeBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Fixes#7507

Six of the seven post-merge correctives the Clause-② audit of #7391 found (audit comment 5527977938). The seventh — the five symbols published on @object-ui/react's sole entry — is a maintainer decision on #7508 and is not touched here: this branch adds, moves, renames and retires zero exported symbols. Clause-② remains no.

Verified at a221c9288: 170 test files / 1687 tests green (plugin-calendar, plugin-map, plugin-gantt, plugin-tree, i18n, and the react ceiling unit), plus type-check green for all six touched packages via turbo (21 tasks, deps built first).


What was re-measured, and what it said

Nothing below was taken on the audit's say-so. Every claim was re-derived on this branch first; where an ablation is quoted, the mutation was proven on disk by grepping for the injected marker and the removed text, and the restore was proven byte-identical against the HEAD blob hash. Vitest resolves every @object-ui/* specifier to that package's src through the root config's alias table, so these ablations need no rebuild — there is no dist in the resolution path to go stale.

Baseline, before any change: 5 files / 16 tests green.

1. Changeset level and copy — .changeset/7210-non-grid-row-ceiling.md

  • The four view packages move patchminor. They carry the behaviour break (a result set above 2000 rows is no longer fully drawn); the fixed group makes the released version identical either way, but the per-package CHANGELOG would have filed a break under "Patch Changes".

  • The example footnote is replaced with the copy that actually renders. Measured, not copied: a throwaway probe rendered NonGridRowCeilingNote three ways and asserted a deliberately wrong string so the run could not pass silently — 3 failed, 3 printed values:

    PROBE_NO_PROVIDER = [Showing the first 2000 of 41234 records. Narrow the filter.]
    PROBE_PROVIDER = [Showing the first 2000 of 41234 records. Narrow the filter.]
    PROBE_UNKNOWN = [Showing the first 2000 records. Narrow the filter.]
    

    (delimiters shown as brackets; the probe printed them as angle runs.)

    No separators on either path. The i18next instance declares no format (packages/i18n/src/i18n.ts) and the provider-less fallback interpolates through String(v) (fallbackInterpolation.ts). The probe file was deleted.

  • NonGridCeilingResult joins the export list. It is already exported (packages/react/src/index.ts, export type { NonGridCeilingResult }) — listing it is documentation of a published symbol, not a new export.

2. The map and calendar pins now grade the cap they are named for

Audit finding reproduced first. With setData(capped.rows) replaced by setData((result as any).data ?? capped.rows) in both components, ObjectMap.rowCeiling-7210 and ObjectCalendar.rowCeiling-7210 stayed green, 4/4, drawing 2001 rows. They pinned $top and the footnote and never "draws at most N".

  • CalendarCalendarView is stubbed the way the gantt pin stubs GanttView (and the way ObjectCalendar.unscheduled-7071 already stubs it, via importOriginal), exposing data-event-count. The above-ceiling case asserts it equals NON_GRID_ROW_CEILING; the below-ceiling case asserts 12, so the pair cannot be satisfied by a view that caps everything unconditionally.
  • Map — a case of its own, because clustering is the map's own defence and it folds the count away: above 100 markers the DOM holds bubbles, not markers. enableClustering={false} makes the count observable without changing what reached the view (clustering is a pure function of the marker array), and the DOM marker count is then literally the ruling's "the DOM row count equals the ceiling". The below-ceiling case asserts 20 markers with no prop at all — 20 is under the map's own clustering threshold.

Ablation, prediction stated before the run: under the same uncapped mutation both pins go red at the new count assertion, and the new externalDataCeiling-7507 pin goes red at its count waitFor. Measured: exactly that — 3 failed / 4 passed, red at ObjectCalendar.rowCeiling-7210.test.tsx:124, ObjectMap.rowCeiling-7210.test.tsx:125, ObjectCalendar.externalDataCeiling-7507.test.tsx:120, each 2001 against 2000. Restored byte-identically; the pins are green again.

3. Four docblocks stated a reverse-verification mechanism that does not happen

Measured by deleting $top: NON_GRID_ROW_CEILING_TOP from each component in turn:

pindocblock predictedmeasured
ganttred "at the FOOTNOTE assertion"red at the $top assertion, 1 failed / 2 passed
treered "at BOTH the row count and the footnote"red at the $top assertion only; the row count stays 2000
calendarred "at the footnote assertion"red at the $top assertion only
mapred "at the footnote assertion"red at the $top assertion only

One mechanism explains all four: an adapter with no $top answers with the whole filtered set, so applyNonGridRowCeiling still sees more rows than the ceiling, still slices to it, and still reports truncated from the rows in hand. The drawn count stays 2000 and the note still names both numbers. Losing the $top is a bandwidth regression, not a correctness one — which is exactly why the $top assertion is not redundant with the footnote.

The calendar and map docblocks were re-measured after their new count assertions landed, as asked: the $top ablation is unchanged (still $top-only, at :115 and :94), so each of the four now records the measured mechanism, and calendar and map additionally record the second ablation their count assertions exist for.

4. Calendar external-data sync left rowCeiling stale

ObjectCalendar.tsx had five setData paths; four also reset rowCeiling, the external-data sync did not. A component that drew its own truncated fetch and was then handed a short data array kept a footnote describing rows no longer on screen. Latent today — ObjectView passes data from mount — and fixed with the one line the other four paths already carry.

Pinned in ObjectCalendar.externalDataCeiling-7507.test.tsx, with a live control: the first assertion proves the note really was raised by this component's own fetch, so its later absence is a state change and not a query that matched nothing.

Ablation, prediction stated before the run: remove the reset and the new pin goes red at expect(screen.queryByRole('note')).toBeNull(), while rowCeiling-7210 stays green. Measured: exactly that — 1 failed / 3 passed, red at ObjectCalendar.externalDataCeiling-7507.test.tsx:131.

5. The false dependency comment — packages/react/src/index.ts

"the only package all four already depend on" is measured false: packages/plugin-{gantt,calendar,map,tree}/package.json each also list @object-ui/core, @object-ui/components and @object-ui/types. (@object-ui/i18n is not common to all four — plugin-map does not depend on it.) The comment now states the real reason — the round's barrel fence over exactly those three, plus @object-ui/react having no subpath export — and cross-links #7508 so the next reader finds the open decision instead of a settled-sounding rationale. Comment text only; the export statements are untouched.

6. Stale headroom comment — packages/i18n/src/locales/*.ts (ten packs)

"~1 KB of headroom" named a budget line that no longer holds these bytes. Since #7399 the catalogues have their own chunk: i18n-locales, ceiling 455_000 against a recorded baseline of 446_0768,924 B, about sixty short keys' worth across ten locales at the ~147 gzipped bytes/key the gate's own docblock measures. (framework, which the old comment was implicitly about, is now 71_000 over 61_465.) Read live from PER_CHUNK_GZIP_CEILINGS / PER_CHUNK_BASELINE.

⚠️ Stated honestly in the comment as the ceiling's distance from the baseline it was measured from, not as today's build: three commits have added locale keys since that baseline was recorded, so the live figure is somewhat smaller. The comment points at pnpm check:eager-closure for the number in force. A fresh figure needs a full apps/console build, which is Bundle Analysis's job on this PR.


Verification

whatresult
vitest runplugin-calendar, plugin-map, plugin-gantt, plugin-tree, i18n, react ceiling unit, at a221c9288170 files / 1687 tests passed
turbo run type-check — the six touched packages, --concurrency=2 (deps built first)21 tasks successful, all six type-check tasks executed
check:control-bytes, check:vi-mock-specifiers, check:vi-mock-inherit, check:i18n-keys, check:i18n-drift, check:i18n-dead-keysall exit 0 at a221c9288
node scripts/check-changeset-presence.mjs✅ 17 source files of 6 released packages changed, 1 changeset added
eslint --no-inline-config --format json over the changed set17 files judged, 0 errors, 103 warnings, all @typescript-eslint/no-explicit-any in the fixtures' as any idiom (lint.yml sets no --max-warnings)

The lint narrowing is a measurement, not a skip. The population came from eslint's own config, not from a guess: its one files entry is **/*.{ts,tsx}, so 17 of the 19 changed files are in scope (the two .changeset/*.md are not), and --format json reported 17 results — every in-scope changed file judged. The config declares no parserOptions.project / projectService, so type-aware linting is not enabled: a file's verdict is a function of that file's own source and the shared config, neither of which this diff moves for any untouched file. pnpm lint runs the whole farm on this PR regardless.

One check is NOT MEASURED rather than green:check:readme-exports exits 1 on this tree with its type entry ./dist/index.d.ts is not on disk — run pnpm build first and a population COLLAPSED verdict. That is a prerequisite failure, not a finding: it needs every package built. It cannot go red on this diff either way — the gate judges README docs against the export surface, and this branch changes no export.

Fences observed

Changeset

.changeset/7507-non-grid-ceiling-correctives.md uses the empty-frontmatter exemption, deliberately: every corrective here lands inside a change that has not been released — .changeset/7210-non-grid-row-ceiling.md is still pending on main — so the calendar fix repairs a defect no user has seen, and the release note it belongs to is the #7210 changeset, corrected in place.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC


Generated by Claude Code

…e comments
Post-merge correctives to #7210's platform row ceiling (#7507), from the
Clause-② review that ran as an audit after the PR landed ungated.
- Changeset: the four view packages carry the behaviour break, so they move
from `patch` to `minor`; the example footnote is replaced with the copy that
actually renders (measured: no thousands separators on either the provider
or the provider-less path); `NonGridCeilingResult` joins the export list.
- Map and calendar pins now grade the cap they are named for. Both were green
under a mutation that drew 2,001 rows, because they asserted `$top` and the
footnote and never the count that reached the view.
- `ObjectCalendar`'s external-`data` sync clears `rowCeiling`, the one
`setData` path that did not. Latent today, pinned now.
- Comment-only: the false "the only package all four already depend on"
rationale on `@object-ui/react`'s entry (all four also depend on `core`,
`components` and `types` — the real reason was the round's barrel fence, and
the home is an open decision on #7508), and the stale "~1 KB of headroom"
note in the ten locale packs, which named a chunk that no longer holds them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC
…ocblocks
All four predicted a mechanism that does not happen. Measured on this branch,
each ablation proven on disk and restored byte-identically:
- gantt, tree, calendar, map: deleting `$top: NON_GRID_ROW_CEILING_TOP` goes
red at the `$top` ASSERTION and nowhere else. Not at the footnote (gantt,
calendar, map) and not at the row count (tree): an adapter with no `$top`
answers with the whole filtered set, `applyNonGridRowCeiling` slices it to
the ceiling from the rows in hand, and both the drawn count and the note stay
correct. The probe row bounds the response; it is not the detector's only
input once an unbounded response has arrived.
- calendar and map additionally record the second ablation their new count
assertions exist for: handing the view the raw response instead of the capped
rows is red at the count, 2001 against 2000 — the mutation that left both
files green at 4/4 before this branch.
A pin whose docblock names the wrong discriminator is worse than one that names
none: the next reader trusts it while deciding what an edit may safely break.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 50 chunks)3181.9 KB3191.4 KB
Main entry chunk (gzip)143.2 KB350 KB
Entry fileindex-geK0qt0o.js
StatusPASS

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

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)15.67KB5.75KB
app-shell (runtime-config.js)20.68KB7.36KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)516.19KB117.80KB
core (index.js)6.12KB2.42KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)178.20KB49.60KB
fields (index.js)242.42KB61.26KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)34.34KB9.17KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.98KB10.98KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)48.15KB13.35KB
plugin-charts (index.js)70.87KB19.72KB
plugin-chatbot (index.js)196.19KB46.43KB
plugin-dashboard (index.js)132.82KB34.64KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)251.07KB64.12KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)132.87KB32.66KB
plugin-gantt (index.js)167.50KB41.08KB
plugin-grid (index.js)209.25KB56.71KB
plugin-kanban (index.js)52.71KB14.55KB
plugin-list (index.js)113.33KB27.60KB
plugin-map (index.js)20.55KB6.80KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)30.84KB8.85KB
plugin-tree (index.js)9.40KB3.23KB
plugin-view (index.js)85.22KB20.93KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)81.07KB26.86KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)4.63KB2.18KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.74KB2.25KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)8.11KB3.32KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

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

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

Projects

None yet

2 participants

@os-project-manager@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(non-grid,i18n,react): correct the row ceiling changeset, its pins and their rationale comments - #7517

Merged
os-project-manager merged 2 commits into
mainfrom
claude/issue-7507-7391-correctives
Sep 3, 2026
Merged

fix(non-grid,i18n,react): correct the row ceiling changeset, its pins and their rationale comments#7517
os-project-manager merged 2 commits into
mainfrom
claude/issue-7507-7391-correctives

Conversation

@claude

@claudeclaudeBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Fixes#7507

Six of the seven post-merge correctives the Clause-② audit of #7391 found (audit comment 5527977938). The seventh — the five symbols published on @object-ui/react's sole entry — is a maintainer decision on #7508 and is not touched here: this branch adds, moves, renames and retires zero exported symbols. Clause-② remains no.

Verified at a221c9288: 170 test files / 1687 tests green (plugin-calendar, plugin-map, plugin-gantt, plugin-tree, i18n, and the react ceiling unit), plus type-check green for all six touched packages via turbo (21 tasks, deps built first).


What was re-measured, and what it said

Nothing below was taken on the audit's say-so. Every claim was re-derived on this branch first; where an ablation is quoted, the mutation was proven on disk by grepping for the injected marker and the removed text, and the restore was proven byte-identical against the HEAD blob hash. Vitest resolves every @object-ui/* specifier to that package's src through the root config's alias table, so these ablations need no rebuild — there is no dist in the resolution path to go stale.

Baseline, before any change: 5 files / 16 tests green.

1. Changeset level and copy — .changeset/7210-non-grid-row-ceiling.md

  • The four view packages move patchminor. They carry the behaviour break (a result set above 2000 rows is no longer fully drawn); the fixed group makes the released version identical either way, but the per-package CHANGELOG would have filed a break under "Patch Changes".

  • The example footnote is replaced with the copy that actually renders. Measured, not copied: a throwaway probe rendered NonGridRowCeilingNote three ways and asserted a deliberately wrong string so the run could not pass silently — 3 failed, 3 printed values:

    PROBE_NO_PROVIDER = [Showing the first 2000 of 41234 records. Narrow the filter.]
    PROBE_PROVIDER = [Showing the first 2000 of 41234 records. Narrow the filter.]
    PROBE_UNKNOWN = [Showing the first 2000 records. Narrow the filter.]
    

    (delimiters shown as brackets; the probe printed them as angle runs.)

    No separators on either path. The i18next instance declares no format (packages/i18n/src/i18n.ts) and the provider-less fallback interpolates through String(v) (fallbackInterpolation.ts). The probe file was deleted.

  • NonGridCeilingResult joins the export list. It is already exported (packages/react/src/index.ts, export type { NonGridCeilingResult }) — listing it is documentation of a published symbol, not a new export.

2. The map and calendar pins now grade the cap they are named for

Audit finding reproduced first. With setData(capped.rows) replaced by setData((result as any).data ?? capped.rows) in both components, ObjectMap.rowCeiling-7210 and ObjectCalendar.rowCeiling-7210 stayed green, 4/4, drawing 2001 rows. They pinned $top and the footnote and never "draws at most N".

  • CalendarCalendarView is stubbed the way the gantt pin stubs GanttView (and the way ObjectCalendar.unscheduled-7071 already stubs it, via importOriginal), exposing data-event-count. The above-ceiling case asserts it equals NON_GRID_ROW_CEILING; the below-ceiling case asserts 12, so the pair cannot be satisfied by a view that caps everything unconditionally.
  • Map — a case of its own, because clustering is the map's own defence and it folds the count away: above 100 markers the DOM holds bubbles, not markers. enableClustering={false} makes the count observable without changing what reached the view (clustering is a pure function of the marker array), and the DOM marker count is then literally the ruling's "the DOM row count equals the ceiling". The below-ceiling case asserts 20 markers with no prop at all — 20 is under the map's own clustering threshold.

Ablation, prediction stated before the run: under the same uncapped mutation both pins go red at the new count assertion, and the new externalDataCeiling-7507 pin goes red at its count waitFor. Measured: exactly that — 3 failed / 4 passed, red at ObjectCalendar.rowCeiling-7210.test.tsx:124, ObjectMap.rowCeiling-7210.test.tsx:125, ObjectCalendar.externalDataCeiling-7507.test.tsx:120, each 2001 against 2000. Restored byte-identically; the pins are green again.

3. Four docblocks stated a reverse-verification mechanism that does not happen

Measured by deleting $top: NON_GRID_ROW_CEILING_TOP from each component in turn:

pindocblock predictedmeasured
ganttred "at the FOOTNOTE assertion"red at the $top assertion, 1 failed / 2 passed
treered "at BOTH the row count and the footnote"red at the $top assertion only; the row count stays 2000
calendarred "at the footnote assertion"red at the $top assertion only
mapred "at the footnote assertion"red at the $top assertion only

One mechanism explains all four: an adapter with no $top answers with the whole filtered set, so applyNonGridRowCeiling still sees more rows than the ceiling, still slices to it, and still reports truncated from the rows in hand. The drawn count stays 2000 and the note still names both numbers. Losing the $top is a bandwidth regression, not a correctness one — which is exactly why the $top assertion is not redundant with the footnote.

The calendar and map docblocks were re-measured after their new count assertions landed, as asked: the $top ablation is unchanged (still $top-only, at :115 and :94), so each of the four now records the measured mechanism, and calendar and map additionally record the second ablation their count assertions exist for.

4. Calendar external-data sync left rowCeiling stale

ObjectCalendar.tsx had five setData paths; four also reset rowCeiling, the external-data sync did not. A component that drew its own truncated fetch and was then handed a short data array kept a footnote describing rows no longer on screen. Latent today — ObjectView passes data from mount — and fixed with the one line the other four paths already carry.

Pinned in ObjectCalendar.externalDataCeiling-7507.test.tsx, with a live control: the first assertion proves the note really was raised by this component's own fetch, so its later absence is a state change and not a query that matched nothing.

Ablation, prediction stated before the run: remove the reset and the new pin goes red at expect(screen.queryByRole('note')).toBeNull(), while rowCeiling-7210 stays green. Measured: exactly that — 1 failed / 3 passed, red at ObjectCalendar.externalDataCeiling-7507.test.tsx:131.

5. The false dependency comment — packages/react/src/index.ts

"the only package all four already depend on" is measured false: packages/plugin-{gantt,calendar,map,tree}/package.json each also list @object-ui/core, @object-ui/components and @object-ui/types. (@object-ui/i18n is not common to all four — plugin-map does not depend on it.) The comment now states the real reason — the round's barrel fence over exactly those three, plus @object-ui/react having no subpath export — and cross-links #7508 so the next reader finds the open decision instead of a settled-sounding rationale. Comment text only; the export statements are untouched.

6. Stale headroom comment — packages/i18n/src/locales/*.ts (ten packs)

"~1 KB of headroom" named a budget line that no longer holds these bytes. Since #7399 the catalogues have their own chunk: i18n-locales, ceiling 455_000 against a recorded baseline of 446_0768,924 B, about sixty short keys' worth across ten locales at the ~147 gzipped bytes/key the gate's own docblock measures. (framework, which the old comment was implicitly about, is now 71_000 over 61_465.) Read live from PER_CHUNK_GZIP_CEILINGS / PER_CHUNK_BASELINE.

⚠️ Stated honestly in the comment as the ceiling's distance from the baseline it was measured from, not as today's build: three commits have added locale keys since that baseline was recorded, so the live figure is somewhat smaller. The comment points at pnpm check:eager-closure for the number in force. A fresh figure needs a full apps/console build, which is Bundle Analysis's job on this PR.


Verification

whatresult
vitest runplugin-calendar, plugin-map, plugin-gantt, plugin-tree, i18n, react ceiling unit, at a221c9288170 files / 1687 tests passed
turbo run type-check — the six touched packages, --concurrency=2 (deps built first)21 tasks successful, all six type-check tasks executed
check:control-bytes, check:vi-mock-specifiers, check:vi-mock-inherit, check:i18n-keys, check:i18n-drift, check:i18n-dead-keysall exit 0 at a221c9288
node scripts/check-changeset-presence.mjs✅ 17 source files of 6 released packages changed, 1 changeset added
eslint --no-inline-config --format json over the changed set17 files judged, 0 errors, 103 warnings, all @typescript-eslint/no-explicit-any in the fixtures' as any idiom (lint.yml sets no --max-warnings)

The lint narrowing is a measurement, not a skip. The population came from eslint's own config, not from a guess: its one files entry is **/*.{ts,tsx}, so 17 of the 19 changed files are in scope (the two .changeset/*.md are not), and --format json reported 17 results — every in-scope changed file judged. The config declares no parserOptions.project / projectService, so type-aware linting is not enabled: a file's verdict is a function of that file's own source and the shared config, neither of which this diff moves for any untouched file. pnpm lint runs the whole farm on this PR regardless.

One check is NOT MEASURED rather than green:check:readme-exports exits 1 on this tree with its type entry ./dist/index.d.ts is not on disk — run pnpm build first and a population COLLAPSED verdict. That is a prerequisite failure, not a finding: it needs every package built. It cannot go red on this diff either way — the gate judges README docs against the export surface, and this branch changes no export.

Fences observed

Changeset

.changeset/7507-non-grid-ceiling-correctives.md uses the empty-frontmatter exemption, deliberately: every corrective here lands inside a change that has not been released — .changeset/7210-non-grid-row-ceiling.md is still pending on main — so the calendar fix repairs a defect no user has seen, and the release note it belongs to is the #7210 changeset, corrected in place.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC


Generated by Claude Code

…e comments
Post-merge correctives to #7210's platform row ceiling (#7507), from the
Clause-② review that ran as an audit after the PR landed ungated.
- Changeset: the four view packages carry the behaviour break, so they move
from `patch` to `minor`; the example footnote is replaced with the copy that
actually renders (measured: no thousands separators on either the provider
or the provider-less path); `NonGridCeilingResult` joins the export list.
- Map and calendar pins now grade the cap they are named for. Both were green
under a mutation that drew 2,001 rows, because they asserted `$top` and the
footnote and never the count that reached the view.
- `ObjectCalendar`'s external-`data` sync clears `rowCeiling`, the one
`setData` path that did not. Latent today, pinned now.
- Comment-only: the false "the only package all four already depend on"
rationale on `@object-ui/react`'s entry (all four also depend on `core`,
`components` and `types` — the real reason was the round's barrel fence, and
the home is an open decision on #7508), and the stale "~1 KB of headroom"
note in the ten locale packs, which named a chunk that no longer holds them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC
…ocblocks
All four predicted a mechanism that does not happen. Measured on this branch,
each ablation proven on disk and restored byte-identically:
- gantt, tree, calendar, map: deleting `$top: NON_GRID_ROW_CEILING_TOP` goes
red at the `$top` ASSERTION and nowhere else. Not at the footnote (gantt,
calendar, map) and not at the row count (tree): an adapter with no `$top`
answers with the whole filtered set, `applyNonGridRowCeiling` slices it to
the ceiling from the rows in hand, and both the drawn count and the note stay
correct. The probe row bounds the response; it is not the detector's only
input once an unbounded response has arrived.
- calendar and map additionally record the second ablation their new count
assertions exist for: handing the view the raw response instead of the capped
rows is red at the count, 2001 against 2000 — the mutation that left both
files green at 4/4 before this branch.
A pin whose docblock names the wrong discriminator is worse than one that names
none: the next reader trusts it while deciding what an edit may safely break.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 50 chunks)3181.9 KB3191.4 KB
Main entry chunk (gzip)143.2 KB350 KB
Entry fileindex-geK0qt0o.js
StatusPASS

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

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)15.67KB5.75KB
app-shell (runtime-config.js)20.68KB7.36KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)516.19KB117.80KB
core (index.js)6.12KB2.42KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)178.20KB49.60KB
fields (index.js)242.42KB61.26KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)34.34KB9.17KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.98KB10.98KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)48.15KB13.35KB
plugin-charts (index.js)70.87KB19.72KB
plugin-chatbot (index.js)196.19KB46.43KB
plugin-dashboard (index.js)132.82KB34.64KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)251.07KB64.12KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)132.87KB32.66KB
plugin-gantt (index.js)167.50KB41.08KB
plugin-grid (index.js)209.25KB56.71KB
plugin-kanban (index.js)52.71KB14.55KB
plugin-list (index.js)113.33KB27.60KB
plugin-map (index.js)20.55KB6.80KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)30.84KB8.85KB
plugin-tree (index.js)9.40KB3.23KB
plugin-view (index.js)85.22KB20.93KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)81.07KB26.86KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)4.63KB2.18KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.74KB2.25KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)8.11KB3.32KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

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

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

Projects

None yet

2 participants

@os-project-manager@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(non-grid,i18n,react): correct the row ceiling changeset, its pins and their rationale comments - #7517

Merged
os-project-manager merged 2 commits into
mainfrom
claude/issue-7507-7391-correctives
Sep 3, 2026
Merged

fix(non-grid,i18n,react): correct the row ceiling changeset, its pins and their rationale comments#7517
os-project-manager merged 2 commits into
mainfrom
claude/issue-7507-7391-correctives

Conversation

@claude

@claudeclaudeBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Fixes#7507

Six of the seven post-merge correctives the Clause-② audit of #7391 found (audit comment 5527977938). The seventh — the five symbols published on @object-ui/react's sole entry — is a maintainer decision on #7508 and is not touched here: this branch adds, moves, renames and retires zero exported symbols. Clause-② remains no.

Verified at a221c9288: 170 test files / 1687 tests green (plugin-calendar, plugin-map, plugin-gantt, plugin-tree, i18n, and the react ceiling unit), plus type-check green for all six touched packages via turbo (21 tasks, deps built first).


What was re-measured, and what it said

Nothing below was taken on the audit's say-so. Every claim was re-derived on this branch first; where an ablation is quoted, the mutation was proven on disk by grepping for the injected marker and the removed text, and the restore was proven byte-identical against the HEAD blob hash. Vitest resolves every @object-ui/* specifier to that package's src through the root config's alias table, so these ablations need no rebuild — there is no dist in the resolution path to go stale.

Baseline, before any change: 5 files / 16 tests green.

1. Changeset level and copy — .changeset/7210-non-grid-row-ceiling.md

  • The four view packages move patchminor. They carry the behaviour break (a result set above 2000 rows is no longer fully drawn); the fixed group makes the released version identical either way, but the per-package CHANGELOG would have filed a break under "Patch Changes".

  • The example footnote is replaced with the copy that actually renders. Measured, not copied: a throwaway probe rendered NonGridRowCeilingNote three ways and asserted a deliberately wrong string so the run could not pass silently — 3 failed, 3 printed values:

    PROBE_NO_PROVIDER = [Showing the first 2000 of 41234 records. Narrow the filter.]
    PROBE_PROVIDER = [Showing the first 2000 of 41234 records. Narrow the filter.]
    PROBE_UNKNOWN = [Showing the first 2000 records. Narrow the filter.]
    

    (delimiters shown as brackets; the probe printed them as angle runs.)

    No separators on either path. The i18next instance declares no format (packages/i18n/src/i18n.ts) and the provider-less fallback interpolates through String(v) (fallbackInterpolation.ts). The probe file was deleted.

  • NonGridCeilingResult joins the export list. It is already exported (packages/react/src/index.ts, export type { NonGridCeilingResult }) — listing it is documentation of a published symbol, not a new export.

2. The map and calendar pins now grade the cap they are named for

Audit finding reproduced first. With setData(capped.rows) replaced by setData((result as any).data ?? capped.rows) in both components, ObjectMap.rowCeiling-7210 and ObjectCalendar.rowCeiling-7210 stayed green, 4/4, drawing 2001 rows. They pinned $top and the footnote and never "draws at most N".

  • CalendarCalendarView is stubbed the way the gantt pin stubs GanttView (and the way ObjectCalendar.unscheduled-7071 already stubs it, via importOriginal), exposing data-event-count. The above-ceiling case asserts it equals NON_GRID_ROW_CEILING; the below-ceiling case asserts 12, so the pair cannot be satisfied by a view that caps everything unconditionally.
  • Map — a case of its own, because clustering is the map's own defence and it folds the count away: above 100 markers the DOM holds bubbles, not markers. enableClustering={false} makes the count observable without changing what reached the view (clustering is a pure function of the marker array), and the DOM marker count is then literally the ruling's "the DOM row count equals the ceiling". The below-ceiling case asserts 20 markers with no prop at all — 20 is under the map's own clustering threshold.

Ablation, prediction stated before the run: under the same uncapped mutation both pins go red at the new count assertion, and the new externalDataCeiling-7507 pin goes red at its count waitFor. Measured: exactly that — 3 failed / 4 passed, red at ObjectCalendar.rowCeiling-7210.test.tsx:124, ObjectMap.rowCeiling-7210.test.tsx:125, ObjectCalendar.externalDataCeiling-7507.test.tsx:120, each 2001 against 2000. Restored byte-identically; the pins are green again.

3. Four docblocks stated a reverse-verification mechanism that does not happen

Measured by deleting $top: NON_GRID_ROW_CEILING_TOP from each component in turn:

pindocblock predictedmeasured
ganttred "at the FOOTNOTE assertion"red at the $top assertion, 1 failed / 2 passed
treered "at BOTH the row count and the footnote"red at the $top assertion only; the row count stays 2000
calendarred "at the footnote assertion"red at the $top assertion only
mapred "at the footnote assertion"red at the $top assertion only

One mechanism explains all four: an adapter with no $top answers with the whole filtered set, so applyNonGridRowCeiling still sees more rows than the ceiling, still slices to it, and still reports truncated from the rows in hand. The drawn count stays 2000 and the note still names both numbers. Losing the $top is a bandwidth regression, not a correctness one — which is exactly why the $top assertion is not redundant with the footnote.

The calendar and map docblocks were re-measured after their new count assertions landed, as asked: the $top ablation is unchanged (still $top-only, at :115 and :94), so each of the four now records the measured mechanism, and calendar and map additionally record the second ablation their count assertions exist for.

4. Calendar external-data sync left rowCeiling stale

ObjectCalendar.tsx had five setData paths; four also reset rowCeiling, the external-data sync did not. A component that drew its own truncated fetch and was then handed a short data array kept a footnote describing rows no longer on screen. Latent today — ObjectView passes data from mount — and fixed with the one line the other four paths already carry.

Pinned in ObjectCalendar.externalDataCeiling-7507.test.tsx, with a live control: the first assertion proves the note really was raised by this component's own fetch, so its later absence is a state change and not a query that matched nothing.

Ablation, prediction stated before the run: remove the reset and the new pin goes red at expect(screen.queryByRole('note')).toBeNull(), while rowCeiling-7210 stays green. Measured: exactly that — 1 failed / 3 passed, red at ObjectCalendar.externalDataCeiling-7507.test.tsx:131.

5. The false dependency comment — packages/react/src/index.ts

"the only package all four already depend on" is measured false: packages/plugin-{gantt,calendar,map,tree}/package.json each also list @object-ui/core, @object-ui/components and @object-ui/types. (@object-ui/i18n is not common to all four — plugin-map does not depend on it.) The comment now states the real reason — the round's barrel fence over exactly those three, plus @object-ui/react having no subpath export — and cross-links #7508 so the next reader finds the open decision instead of a settled-sounding rationale. Comment text only; the export statements are untouched.

6. Stale headroom comment — packages/i18n/src/locales/*.ts (ten packs)

"~1 KB of headroom" named a budget line that no longer holds these bytes. Since #7399 the catalogues have their own chunk: i18n-locales, ceiling 455_000 against a recorded baseline of 446_0768,924 B, about sixty short keys' worth across ten locales at the ~147 gzipped bytes/key the gate's own docblock measures. (framework, which the old comment was implicitly about, is now 71_000 over 61_465.) Read live from PER_CHUNK_GZIP_CEILINGS / PER_CHUNK_BASELINE.

⚠️ Stated honestly in the comment as the ceiling's distance from the baseline it was measured from, not as today's build: three commits have added locale keys since that baseline was recorded, so the live figure is somewhat smaller. The comment points at pnpm check:eager-closure for the number in force. A fresh figure needs a full apps/console build, which is Bundle Analysis's job on this PR.


Verification

whatresult
vitest runplugin-calendar, plugin-map, plugin-gantt, plugin-tree, i18n, react ceiling unit, at a221c9288170 files / 1687 tests passed
turbo run type-check — the six touched packages, --concurrency=2 (deps built first)21 tasks successful, all six type-check tasks executed
check:control-bytes, check:vi-mock-specifiers, check:vi-mock-inherit, check:i18n-keys, check:i18n-drift, check:i18n-dead-keysall exit 0 at a221c9288
node scripts/check-changeset-presence.mjs✅ 17 source files of 6 released packages changed, 1 changeset added
eslint --no-inline-config --format json over the changed set17 files judged, 0 errors, 103 warnings, all @typescript-eslint/no-explicit-any in the fixtures' as any idiom (lint.yml sets no --max-warnings)

The lint narrowing is a measurement, not a skip. The population came from eslint's own config, not from a guess: its one files entry is **/*.{ts,tsx}, so 17 of the 19 changed files are in scope (the two .changeset/*.md are not), and --format json reported 17 results — every in-scope changed file judged. The config declares no parserOptions.project / projectService, so type-aware linting is not enabled: a file's verdict is a function of that file's own source and the shared config, neither of which this diff moves for any untouched file. pnpm lint runs the whole farm on this PR regardless.

One check is NOT MEASURED rather than green:check:readme-exports exits 1 on this tree with its type entry ./dist/index.d.ts is not on disk — run pnpm build first and a population COLLAPSED verdict. That is a prerequisite failure, not a finding: it needs every package built. It cannot go red on this diff either way — the gate judges README docs against the export surface, and this branch changes no export.

Fences observed

Changeset

.changeset/7507-non-grid-ceiling-correctives.md uses the empty-frontmatter exemption, deliberately: every corrective here lands inside a change that has not been released — .changeset/7210-non-grid-row-ceiling.md is still pending on main — so the calendar fix repairs a defect no user has seen, and the release note it belongs to is the #7210 changeset, corrected in place.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC


Generated by Claude Code

…e comments
Post-merge correctives to #7210's platform row ceiling (#7507), from the
Clause-② review that ran as an audit after the PR landed ungated.
- Changeset: the four view packages carry the behaviour break, so they move
from `patch` to `minor`; the example footnote is replaced with the copy that
actually renders (measured: no thousands separators on either the provider
or the provider-less path); `NonGridCeilingResult` joins the export list.
- Map and calendar pins now grade the cap they are named for. Both were green
under a mutation that drew 2,001 rows, because they asserted `$top` and the
footnote and never the count that reached the view.
- `ObjectCalendar`'s external-`data` sync clears `rowCeiling`, the one
`setData` path that did not. Latent today, pinned now.
- Comment-only: the false "the only package all four already depend on"
rationale on `@object-ui/react`'s entry (all four also depend on `core`,
`components` and `types` — the real reason was the round's barrel fence, and
the home is an open decision on #7508), and the stale "~1 KB of headroom"
note in the ten locale packs, which named a chunk that no longer holds them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC
…ocblocks
All four predicted a mechanism that does not happen. Measured on this branch,
each ablation proven on disk and restored byte-identically:
- gantt, tree, calendar, map: deleting `$top: NON_GRID_ROW_CEILING_TOP` goes
red at the `$top` ASSERTION and nowhere else. Not at the footnote (gantt,
calendar, map) and not at the row count (tree): an adapter with no `$top`
answers with the whole filtered set, `applyNonGridRowCeiling` slices it to
the ceiling from the rows in hand, and both the drawn count and the note stay
correct. The probe row bounds the response; it is not the detector's only
input once an unbounded response has arrived.
- calendar and map additionally record the second ablation their new count
assertions exist for: handing the view the raw response instead of the capped
rows is red at the count, 2001 against 2000 — the mutation that left both
files green at 4/4 before this branch.
A pin whose docblock names the wrong discriminator is worse than one that names
none: the next reader trusts it while deciding what an edit may safely break.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 50 chunks)3181.9 KB3191.4 KB
Main entry chunk (gzip)143.2 KB350 KB
Entry fileindex-geK0qt0o.js
StatusPASS

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

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)15.67KB5.75KB
app-shell (runtime-config.js)20.68KB7.36KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)516.19KB117.80KB
core (index.js)6.12KB2.42KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)178.20KB49.60KB
fields (index.js)242.42KB61.26KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)34.34KB9.17KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.98KB10.98KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)48.15KB13.35KB
plugin-charts (index.js)70.87KB19.72KB
plugin-chatbot (index.js)196.19KB46.43KB
plugin-dashboard (index.js)132.82KB34.64KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)251.07KB64.12KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)132.87KB32.66KB
plugin-gantt (index.js)167.50KB41.08KB
plugin-grid (index.js)209.25KB56.71KB
plugin-kanban (index.js)52.71KB14.55KB
plugin-list (index.js)113.33KB27.60KB
plugin-map (index.js)20.55KB6.80KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)30.84KB8.85KB
plugin-tree (index.js)9.40KB3.23KB
plugin-view (index.js)85.22KB20.93KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)81.07KB26.86KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)4.63KB2.18KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.74KB2.25KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)8.11KB3.32KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

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

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

Projects

None yet

2 participants

@os-project-manager@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(non-grid,i18n,react): correct the row ceiling changeset, its pins and their rationale comments - #7517

Merged
os-project-manager merged 2 commits into
mainfrom
claude/issue-7507-7391-correctives
Sep 3, 2026
Merged

fix(non-grid,i18n,react): correct the row ceiling changeset, its pins and their rationale comments#7517
os-project-manager merged 2 commits into
mainfrom
claude/issue-7507-7391-correctives

Conversation

@claude

@claudeclaudeBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Fixes#7507

Six of the seven post-merge correctives the Clause-② audit of #7391 found (audit comment 5527977938). The seventh — the five symbols published on @object-ui/react's sole entry — is a maintainer decision on #7508 and is not touched here: this branch adds, moves, renames and retires zero exported symbols. Clause-② remains no.

Verified at a221c9288: 170 test files / 1687 tests green (plugin-calendar, plugin-map, plugin-gantt, plugin-tree, i18n, and the react ceiling unit), plus type-check green for all six touched packages via turbo (21 tasks, deps built first).


What was re-measured, and what it said

Nothing below was taken on the audit's say-so. Every claim was re-derived on this branch first; where an ablation is quoted, the mutation was proven on disk by grepping for the injected marker and the removed text, and the restore was proven byte-identical against the HEAD blob hash. Vitest resolves every @object-ui/* specifier to that package's src through the root config's alias table, so these ablations need no rebuild — there is no dist in the resolution path to go stale.

Baseline, before any change: 5 files / 16 tests green.

1. Changeset level and copy — .changeset/7210-non-grid-row-ceiling.md

  • The four view packages move patchminor. They carry the behaviour break (a result set above 2000 rows is no longer fully drawn); the fixed group makes the released version identical either way, but the per-package CHANGELOG would have filed a break under "Patch Changes".

  • The example footnote is replaced with the copy that actually renders. Measured, not copied: a throwaway probe rendered NonGridRowCeilingNote three ways and asserted a deliberately wrong string so the run could not pass silently — 3 failed, 3 printed values:

    PROBE_NO_PROVIDER = [Showing the first 2000 of 41234 records. Narrow the filter.]
    PROBE_PROVIDER = [Showing the first 2000 of 41234 records. Narrow the filter.]
    PROBE_UNKNOWN = [Showing the first 2000 records. Narrow the filter.]
    

    (delimiters shown as brackets; the probe printed them as angle runs.)

    No separators on either path. The i18next instance declares no format (packages/i18n/src/i18n.ts) and the provider-less fallback interpolates through String(v) (fallbackInterpolation.ts). The probe file was deleted.

  • NonGridCeilingResult joins the export list. It is already exported (packages/react/src/index.ts, export type { NonGridCeilingResult }) — listing it is documentation of a published symbol, not a new export.

2. The map and calendar pins now grade the cap they are named for

Audit finding reproduced first. With setData(capped.rows) replaced by setData((result as any).data ?? capped.rows) in both components, ObjectMap.rowCeiling-7210 and ObjectCalendar.rowCeiling-7210 stayed green, 4/4, drawing 2001 rows. They pinned $top and the footnote and never "draws at most N".

  • CalendarCalendarView is stubbed the way the gantt pin stubs GanttView (and the way ObjectCalendar.unscheduled-7071 already stubs it, via importOriginal), exposing data-event-count. The above-ceiling case asserts it equals NON_GRID_ROW_CEILING; the below-ceiling case asserts 12, so the pair cannot be satisfied by a view that caps everything unconditionally.
  • Map — a case of its own, because clustering is the map's own defence and it folds the count away: above 100 markers the DOM holds bubbles, not markers. enableClustering={false} makes the count observable without changing what reached the view (clustering is a pure function of the marker array), and the DOM marker count is then literally the ruling's "the DOM row count equals the ceiling". The below-ceiling case asserts 20 markers with no prop at all — 20 is under the map's own clustering threshold.

Ablation, prediction stated before the run: under the same uncapped mutation both pins go red at the new count assertion, and the new externalDataCeiling-7507 pin goes red at its count waitFor. Measured: exactly that — 3 failed / 4 passed, red at ObjectCalendar.rowCeiling-7210.test.tsx:124, ObjectMap.rowCeiling-7210.test.tsx:125, ObjectCalendar.externalDataCeiling-7507.test.tsx:120, each 2001 against 2000. Restored byte-identically; the pins are green again.

3. Four docblocks stated a reverse-verification mechanism that does not happen

Measured by deleting $top: NON_GRID_ROW_CEILING_TOP from each component in turn:

pindocblock predictedmeasured
ganttred "at the FOOTNOTE assertion"red at the $top assertion, 1 failed / 2 passed
treered "at BOTH the row count and the footnote"red at the $top assertion only; the row count stays 2000
calendarred "at the footnote assertion"red at the $top assertion only
mapred "at the footnote assertion"red at the $top assertion only

One mechanism explains all four: an adapter with no $top answers with the whole filtered set, so applyNonGridRowCeiling still sees more rows than the ceiling, still slices to it, and still reports truncated from the rows in hand. The drawn count stays 2000 and the note still names both numbers. Losing the $top is a bandwidth regression, not a correctness one — which is exactly why the $top assertion is not redundant with the footnote.

The calendar and map docblocks were re-measured after their new count assertions landed, as asked: the $top ablation is unchanged (still $top-only, at :115 and :94), so each of the four now records the measured mechanism, and calendar and map additionally record the second ablation their count assertions exist for.

4. Calendar external-data sync left rowCeiling stale

ObjectCalendar.tsx had five setData paths; four also reset rowCeiling, the external-data sync did not. A component that drew its own truncated fetch and was then handed a short data array kept a footnote describing rows no longer on screen. Latent today — ObjectView passes data from mount — and fixed with the one line the other four paths already carry.

Pinned in ObjectCalendar.externalDataCeiling-7507.test.tsx, with a live control: the first assertion proves the note really was raised by this component's own fetch, so its later absence is a state change and not a query that matched nothing.

Ablation, prediction stated before the run: remove the reset and the new pin goes red at expect(screen.queryByRole('note')).toBeNull(), while rowCeiling-7210 stays green. Measured: exactly that — 1 failed / 3 passed, red at ObjectCalendar.externalDataCeiling-7507.test.tsx:131.

5. The false dependency comment — packages/react/src/index.ts

"the only package all four already depend on" is measured false: packages/plugin-{gantt,calendar,map,tree}/package.json each also list @object-ui/core, @object-ui/components and @object-ui/types. (@object-ui/i18n is not common to all four — plugin-map does not depend on it.) The comment now states the real reason — the round's barrel fence over exactly those three, plus @object-ui/react having no subpath export — and cross-links #7508 so the next reader finds the open decision instead of a settled-sounding rationale. Comment text only; the export statements are untouched.

6. Stale headroom comment — packages/i18n/src/locales/*.ts (ten packs)

"~1 KB of headroom" named a budget line that no longer holds these bytes. Since #7399 the catalogues have their own chunk: i18n-locales, ceiling 455_000 against a recorded baseline of 446_0768,924 B, about sixty short keys' worth across ten locales at the ~147 gzipped bytes/key the gate's own docblock measures. (framework, which the old comment was implicitly about, is now 71_000 over 61_465.) Read live from PER_CHUNK_GZIP_CEILINGS / PER_CHUNK_BASELINE.

⚠️ Stated honestly in the comment as the ceiling's distance from the baseline it was measured from, not as today's build: three commits have added locale keys since that baseline was recorded, so the live figure is somewhat smaller. The comment points at pnpm check:eager-closure for the number in force. A fresh figure needs a full apps/console build, which is Bundle Analysis's job on this PR.


Verification

whatresult
vitest runplugin-calendar, plugin-map, plugin-gantt, plugin-tree, i18n, react ceiling unit, at a221c9288170 files / 1687 tests passed
turbo run type-check — the six touched packages, --concurrency=2 (deps built first)21 tasks successful, all six type-check tasks executed
check:control-bytes, check:vi-mock-specifiers, check:vi-mock-inherit, check:i18n-keys, check:i18n-drift, check:i18n-dead-keysall exit 0 at a221c9288
node scripts/check-changeset-presence.mjs✅ 17 source files of 6 released packages changed, 1 changeset added
eslint --no-inline-config --format json over the changed set17 files judged, 0 errors, 103 warnings, all @typescript-eslint/no-explicit-any in the fixtures' as any idiom (lint.yml sets no --max-warnings)

The lint narrowing is a measurement, not a skip. The population came from eslint's own config, not from a guess: its one files entry is **/*.{ts,tsx}, so 17 of the 19 changed files are in scope (the two .changeset/*.md are not), and --format json reported 17 results — every in-scope changed file judged. The config declares no parserOptions.project / projectService, so type-aware linting is not enabled: a file's verdict is a function of that file's own source and the shared config, neither of which this diff moves for any untouched file. pnpm lint runs the whole farm on this PR regardless.

One check is NOT MEASURED rather than green:check:readme-exports exits 1 on this tree with its type entry ./dist/index.d.ts is not on disk — run pnpm build first and a population COLLAPSED verdict. That is a prerequisite failure, not a finding: it needs every package built. It cannot go red on this diff either way — the gate judges README docs against the export surface, and this branch changes no export.

Fences observed

Changeset

.changeset/7507-non-grid-ceiling-correctives.md uses the empty-frontmatter exemption, deliberately: every corrective here lands inside a change that has not been released — .changeset/7210-non-grid-row-ceiling.md is still pending on main — so the calendar fix repairs a defect no user has seen, and the release note it belongs to is the #7210 changeset, corrected in place.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC


Generated by Claude Code

…e comments
Post-merge correctives to #7210's platform row ceiling (#7507), from the
Clause-② review that ran as an audit after the PR landed ungated.
- Changeset: the four view packages carry the behaviour break, so they move
from `patch` to `minor`; the example footnote is replaced with the copy that
actually renders (measured: no thousands separators on either the provider
or the provider-less path); `NonGridCeilingResult` joins the export list.
- Map and calendar pins now grade the cap they are named for. Both were green
under a mutation that drew 2,001 rows, because they asserted `$top` and the
footnote and never the count that reached the view.
- `ObjectCalendar`'s external-`data` sync clears `rowCeiling`, the one
`setData` path that did not. Latent today, pinned now.
- Comment-only: the false "the only package all four already depend on"
rationale on `@object-ui/react`'s entry (all four also depend on `core`,
`components` and `types` — the real reason was the round's barrel fence, and
the home is an open decision on #7508), and the stale "~1 KB of headroom"
note in the ten locale packs, which named a chunk that no longer holds them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC
…ocblocks
All four predicted a mechanism that does not happen. Measured on this branch,
each ablation proven on disk and restored byte-identically:
- gantt, tree, calendar, map: deleting `$top: NON_GRID_ROW_CEILING_TOP` goes
red at the `$top` ASSERTION and nowhere else. Not at the footnote (gantt,
calendar, map) and not at the row count (tree): an adapter with no `$top`
answers with the whole filtered set, `applyNonGridRowCeiling` slices it to
the ceiling from the rows in hand, and both the drawn count and the note stay
correct. The probe row bounds the response; it is not the detector's only
input once an unbounded response has arrived.
- calendar and map additionally record the second ablation their new count
assertions exist for: handing the view the raw response instead of the capped
rows is red at the count, 2001 against 2000 — the mutation that left both
files green at 4/4 before this branch.
A pin whose docblock names the wrong discriminator is worse than one that names
none: the next reader trusts it while deciding what an edit may safely break.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 50 chunks)3181.9 KB3191.4 KB
Main entry chunk (gzip)143.2 KB350 KB
Entry fileindex-geK0qt0o.js
StatusPASS

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

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)15.67KB5.75KB
app-shell (runtime-config.js)20.68KB7.36KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)516.19KB117.80KB
core (index.js)6.12KB2.42KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)178.20KB49.60KB
fields (index.js)242.42KB61.26KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)34.34KB9.17KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.98KB10.98KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)48.15KB13.35KB
plugin-charts (index.js)70.87KB19.72KB
plugin-chatbot (index.js)196.19KB46.43KB
plugin-dashboard (index.js)132.82KB34.64KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)251.07KB64.12KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)132.87KB32.66KB
plugin-gantt (index.js)167.50KB41.08KB
plugin-grid (index.js)209.25KB56.71KB
plugin-kanban (index.js)52.71KB14.55KB
plugin-list (index.js)113.33KB27.60KB
plugin-map (index.js)20.55KB6.80KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)30.84KB8.85KB
plugin-tree (index.js)9.40KB3.23KB
plugin-view (index.js)85.22KB20.93KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)81.07KB26.86KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)4.63KB2.18KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.74KB2.25KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)8.11KB3.32KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

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

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

Projects

None yet

2 participants

@os-project-manager@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(non-grid,i18n,react): correct the row ceiling changeset, its pins and their rationale comments - #7517

Merged
os-project-manager merged 2 commits into
mainfrom
claude/issue-7507-7391-correctives
Sep 3, 2026
Merged

fix(non-grid,i18n,react): correct the row ceiling changeset, its pins and their rationale comments#7517
os-project-manager merged 2 commits into
mainfrom
claude/issue-7507-7391-correctives

Conversation

@claude

@claudeclaudeBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Fixes#7507

Six of the seven post-merge correctives the Clause-② audit of #7391 found (audit comment 5527977938). The seventh — the five symbols published on @object-ui/react's sole entry — is a maintainer decision on #7508 and is not touched here: this branch adds, moves, renames and retires zero exported symbols. Clause-② remains no.

Verified at a221c9288: 170 test files / 1687 tests green (plugin-calendar, plugin-map, plugin-gantt, plugin-tree, i18n, and the react ceiling unit), plus type-check green for all six touched packages via turbo (21 tasks, deps built first).


What was re-measured, and what it said

Nothing below was taken on the audit's say-so. Every claim was re-derived on this branch first; where an ablation is quoted, the mutation was proven on disk by grepping for the injected marker and the removed text, and the restore was proven byte-identical against the HEAD blob hash. Vitest resolves every @object-ui/* specifier to that package's src through the root config's alias table, so these ablations need no rebuild — there is no dist in the resolution path to go stale.

Baseline, before any change: 5 files / 16 tests green.

1. Changeset level and copy — .changeset/7210-non-grid-row-ceiling.md

  • The four view packages move patchminor. They carry the behaviour break (a result set above 2000 rows is no longer fully drawn); the fixed group makes the released version identical either way, but the per-package CHANGELOG would have filed a break under "Patch Changes".

  • The example footnote is replaced with the copy that actually renders. Measured, not copied: a throwaway probe rendered NonGridRowCeilingNote three ways and asserted a deliberately wrong string so the run could not pass silently — 3 failed, 3 printed values:

    PROBE_NO_PROVIDER = [Showing the first 2000 of 41234 records. Narrow the filter.]
    PROBE_PROVIDER = [Showing the first 2000 of 41234 records. Narrow the filter.]
    PROBE_UNKNOWN = [Showing the first 2000 records. Narrow the filter.]
    

    (delimiters shown as brackets; the probe printed them as angle runs.)

    No separators on either path. The i18next instance declares no format (packages/i18n/src/i18n.ts) and the provider-less fallback interpolates through String(v) (fallbackInterpolation.ts). The probe file was deleted.

  • NonGridCeilingResult joins the export list. It is already exported (packages/react/src/index.ts, export type { NonGridCeilingResult }) — listing it is documentation of a published symbol, not a new export.

2. The map and calendar pins now grade the cap they are named for

Audit finding reproduced first. With setData(capped.rows) replaced by setData((result as any).data ?? capped.rows) in both components, ObjectMap.rowCeiling-7210 and ObjectCalendar.rowCeiling-7210 stayed green, 4/4, drawing 2001 rows. They pinned $top and the footnote and never "draws at most N".

  • CalendarCalendarView is stubbed the way the gantt pin stubs GanttView (and the way ObjectCalendar.unscheduled-7071 already stubs it, via importOriginal), exposing data-event-count. The above-ceiling case asserts it equals NON_GRID_ROW_CEILING; the below-ceiling case asserts 12, so the pair cannot be satisfied by a view that caps everything unconditionally.
  • Map — a case of its own, because clustering is the map's own defence and it folds the count away: above 100 markers the DOM holds bubbles, not markers. enableClustering={false} makes the count observable without changing what reached the view (clustering is a pure function of the marker array), and the DOM marker count is then literally the ruling's "the DOM row count equals the ceiling". The below-ceiling case asserts 20 markers with no prop at all — 20 is under the map's own clustering threshold.

Ablation, prediction stated before the run: under the same uncapped mutation both pins go red at the new count assertion, and the new externalDataCeiling-7507 pin goes red at its count waitFor. Measured: exactly that — 3 failed / 4 passed, red at ObjectCalendar.rowCeiling-7210.test.tsx:124, ObjectMap.rowCeiling-7210.test.tsx:125, ObjectCalendar.externalDataCeiling-7507.test.tsx:120, each 2001 against 2000. Restored byte-identically; the pins are green again.

3. Four docblocks stated a reverse-verification mechanism that does not happen

Measured by deleting $top: NON_GRID_ROW_CEILING_TOP from each component in turn:

pindocblock predictedmeasured
ganttred "at the FOOTNOTE assertion"red at the $top assertion, 1 failed / 2 passed
treered "at BOTH the row count and the footnote"red at the $top assertion only; the row count stays 2000
calendarred "at the footnote assertion"red at the $top assertion only
mapred "at the footnote assertion"red at the $top assertion only

One mechanism explains all four: an adapter with no $top answers with the whole filtered set, so applyNonGridRowCeiling still sees more rows than the ceiling, still slices to it, and still reports truncated from the rows in hand. The drawn count stays 2000 and the note still names both numbers. Losing the $top is a bandwidth regression, not a correctness one — which is exactly why the $top assertion is not redundant with the footnote.

The calendar and map docblocks were re-measured after their new count assertions landed, as asked: the $top ablation is unchanged (still $top-only, at :115 and :94), so each of the four now records the measured mechanism, and calendar and map additionally record the second ablation their count assertions exist for.

4. Calendar external-data sync left rowCeiling stale

ObjectCalendar.tsx had five setData paths; four also reset rowCeiling, the external-data sync did not. A component that drew its own truncated fetch and was then handed a short data array kept a footnote describing rows no longer on screen. Latent today — ObjectView passes data from mount — and fixed with the one line the other four paths already carry.

Pinned in ObjectCalendar.externalDataCeiling-7507.test.tsx, with a live control: the first assertion proves the note really was raised by this component's own fetch, so its later absence is a state change and not a query that matched nothing.

Ablation, prediction stated before the run: remove the reset and the new pin goes red at expect(screen.queryByRole('note')).toBeNull(), while rowCeiling-7210 stays green. Measured: exactly that — 1 failed / 3 passed, red at ObjectCalendar.externalDataCeiling-7507.test.tsx:131.

5. The false dependency comment — packages/react/src/index.ts

"the only package all four already depend on" is measured false: packages/plugin-{gantt,calendar,map,tree}/package.json each also list @object-ui/core, @object-ui/components and @object-ui/types. (@object-ui/i18n is not common to all four — plugin-map does not depend on it.) The comment now states the real reason — the round's barrel fence over exactly those three, plus @object-ui/react having no subpath export — and cross-links #7508 so the next reader finds the open decision instead of a settled-sounding rationale. Comment text only; the export statements are untouched.

6. Stale headroom comment — packages/i18n/src/locales/*.ts (ten packs)

"~1 KB of headroom" named a budget line that no longer holds these bytes. Since #7399 the catalogues have their own chunk: i18n-locales, ceiling 455_000 against a recorded baseline of 446_0768,924 B, about sixty short keys' worth across ten locales at the ~147 gzipped bytes/key the gate's own docblock measures. (framework, which the old comment was implicitly about, is now 71_000 over 61_465.) Read live from PER_CHUNK_GZIP_CEILINGS / PER_CHUNK_BASELINE.

⚠️ Stated honestly in the comment as the ceiling's distance from the baseline it was measured from, not as today's build: three commits have added locale keys since that baseline was recorded, so the live figure is somewhat smaller. The comment points at pnpm check:eager-closure for the number in force. A fresh figure needs a full apps/console build, which is Bundle Analysis's job on this PR.


Verification

whatresult
vitest runplugin-calendar, plugin-map, plugin-gantt, plugin-tree, i18n, react ceiling unit, at a221c9288170 files / 1687 tests passed
turbo run type-check — the six touched packages, --concurrency=2 (deps built first)21 tasks successful, all six type-check tasks executed
check:control-bytes, check:vi-mock-specifiers, check:vi-mock-inherit, check:i18n-keys, check:i18n-drift, check:i18n-dead-keysall exit 0 at a221c9288
node scripts/check-changeset-presence.mjs✅ 17 source files of 6 released packages changed, 1 changeset added
eslint --no-inline-config --format json over the changed set17 files judged, 0 errors, 103 warnings, all @typescript-eslint/no-explicit-any in the fixtures' as any idiom (lint.yml sets no --max-warnings)

The lint narrowing is a measurement, not a skip. The population came from eslint's own config, not from a guess: its one files entry is **/*.{ts,tsx}, so 17 of the 19 changed files are in scope (the two .changeset/*.md are not), and --format json reported 17 results — every in-scope changed file judged. The config declares no parserOptions.project / projectService, so type-aware linting is not enabled: a file's verdict is a function of that file's own source and the shared config, neither of which this diff moves for any untouched file. pnpm lint runs the whole farm on this PR regardless.

One check is NOT MEASURED rather than green:check:readme-exports exits 1 on this tree with its type entry ./dist/index.d.ts is not on disk — run pnpm build first and a population COLLAPSED verdict. That is a prerequisite failure, not a finding: it needs every package built. It cannot go red on this diff either way — the gate judges README docs against the export surface, and this branch changes no export.

Fences observed

Changeset

.changeset/7507-non-grid-ceiling-correctives.md uses the empty-frontmatter exemption, deliberately: every corrective here lands inside a change that has not been released — .changeset/7210-non-grid-row-ceiling.md is still pending on main — so the calendar fix repairs a defect no user has seen, and the release note it belongs to is the #7210 changeset, corrected in place.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC


Generated by Claude Code

…e comments
Post-merge correctives to #7210's platform row ceiling (#7507), from the
Clause-② review that ran as an audit after the PR landed ungated.
- Changeset: the four view packages carry the behaviour break, so they move
from `patch` to `minor`; the example footnote is replaced with the copy that
actually renders (measured: no thousands separators on either the provider
or the provider-less path); `NonGridCeilingResult` joins the export list.
- Map and calendar pins now grade the cap they are named for. Both were green
under a mutation that drew 2,001 rows, because they asserted `$top` and the
footnote and never the count that reached the view.
- `ObjectCalendar`'s external-`data` sync clears `rowCeiling`, the one
`setData` path that did not. Latent today, pinned now.
- Comment-only: the false "the only package all four already depend on"
rationale on `@object-ui/react`'s entry (all four also depend on `core`,
`components` and `types` — the real reason was the round's barrel fence, and
the home is an open decision on #7508), and the stale "~1 KB of headroom"
note in the ten locale packs, which named a chunk that no longer holds them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC
…ocblocks
All four predicted a mechanism that does not happen. Measured on this branch,
each ablation proven on disk and restored byte-identically:
- gantt, tree, calendar, map: deleting `$top: NON_GRID_ROW_CEILING_TOP` goes
red at the `$top` ASSERTION and nowhere else. Not at the footnote (gantt,
calendar, map) and not at the row count (tree): an adapter with no `$top`
answers with the whole filtered set, `applyNonGridRowCeiling` slices it to
the ceiling from the rows in hand, and both the drawn count and the note stay
correct. The probe row bounds the response; it is not the detector's only
input once an unbounded response has arrived.
- calendar and map additionally record the second ablation their new count
assertions exist for: handing the view the raw response instead of the capped
rows is red at the count, 2001 against 2000 — the mutation that left both
files green at 4/4 before this branch.
A pin whose docblock names the wrong discriminator is worse than one that names
none: the next reader trusts it while deciding what an edit may safely break.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 50 chunks)3181.9 KB3191.4 KB
Main entry chunk (gzip)143.2 KB350 KB
Entry fileindex-geK0qt0o.js
StatusPASS

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

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)15.67KB5.75KB
app-shell (runtime-config.js)20.68KB7.36KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)516.19KB117.80KB
core (index.js)6.12KB2.42KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)178.20KB49.60KB
fields (index.js)242.42KB61.26KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)34.34KB9.17KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.98KB10.98KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)48.15KB13.35KB
plugin-charts (index.js)70.87KB19.72KB
plugin-chatbot (index.js)196.19KB46.43KB
plugin-dashboard (index.js)132.82KB34.64KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)251.07KB64.12KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)132.87KB32.66KB
plugin-gantt (index.js)167.50KB41.08KB
plugin-grid (index.js)209.25KB56.71KB
plugin-kanban (index.js)52.71KB14.55KB
plugin-list (index.js)113.33KB27.60KB
plugin-map (index.js)20.55KB6.80KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)30.84KB8.85KB
plugin-tree (index.js)9.40KB3.23KB
plugin-view (index.js)85.22KB20.93KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)81.07KB26.86KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)4.63KB2.18KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.74KB2.25KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)8.11KB3.32KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

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

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

Projects

None yet

2 participants

@os-project-manager@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(non-grid,i18n,react): correct the row ceiling changeset, its pins and their rationale comments - #7517

Merged
os-project-manager merged 2 commits into
mainfrom
claude/issue-7507-7391-correctives
Sep 3, 2026
Merged

fix(non-grid,i18n,react): correct the row ceiling changeset, its pins and their rationale comments#7517
os-project-manager merged 2 commits into
mainfrom
claude/issue-7507-7391-correctives

Conversation

@claude

@claudeclaudeBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Fixes#7507

Six of the seven post-merge correctives the Clause-② audit of #7391 found (audit comment 5527977938). The seventh — the five symbols published on @object-ui/react's sole entry — is a maintainer decision on #7508 and is not touched here: this branch adds, moves, renames and retires zero exported symbols. Clause-② remains no.

Verified at a221c9288: 170 test files / 1687 tests green (plugin-calendar, plugin-map, plugin-gantt, plugin-tree, i18n, and the react ceiling unit), plus type-check green for all six touched packages via turbo (21 tasks, deps built first).


What was re-measured, and what it said

Nothing below was taken on the audit's say-so. Every claim was re-derived on this branch first; where an ablation is quoted, the mutation was proven on disk by grepping for the injected marker and the removed text, and the restore was proven byte-identical against the HEAD blob hash. Vitest resolves every @object-ui/* specifier to that package's src through the root config's alias table, so these ablations need no rebuild — there is no dist in the resolution path to go stale.

Baseline, before any change: 5 files / 16 tests green.

1. Changeset level and copy — .changeset/7210-non-grid-row-ceiling.md

  • The four view packages move patchminor. They carry the behaviour break (a result set above 2000 rows is no longer fully drawn); the fixed group makes the released version identical either way, but the per-package CHANGELOG would have filed a break under "Patch Changes".

  • The example footnote is replaced with the copy that actually renders. Measured, not copied: a throwaway probe rendered NonGridRowCeilingNote three ways and asserted a deliberately wrong string so the run could not pass silently — 3 failed, 3 printed values:

    PROBE_NO_PROVIDER = [Showing the first 2000 of 41234 records. Narrow the filter.]
    PROBE_PROVIDER = [Showing the first 2000 of 41234 records. Narrow the filter.]
    PROBE_UNKNOWN = [Showing the first 2000 records. Narrow the filter.]
    

    (delimiters shown as brackets; the probe printed them as angle runs.)

    No separators on either path. The i18next instance declares no format (packages/i18n/src/i18n.ts) and the provider-less fallback interpolates through String(v) (fallbackInterpolation.ts). The probe file was deleted.

  • NonGridCeilingResult joins the export list. It is already exported (packages/react/src/index.ts, export type { NonGridCeilingResult }) — listing it is documentation of a published symbol, not a new export.

2. The map and calendar pins now grade the cap they are named for

Audit finding reproduced first. With setData(capped.rows) replaced by setData((result as any).data ?? capped.rows) in both components, ObjectMap.rowCeiling-7210 and ObjectCalendar.rowCeiling-7210 stayed green, 4/4, drawing 2001 rows. They pinned $top and the footnote and never "draws at most N".

  • CalendarCalendarView is stubbed the way the gantt pin stubs GanttView (and the way ObjectCalendar.unscheduled-7071 already stubs it, via importOriginal), exposing data-event-count. The above-ceiling case asserts it equals NON_GRID_ROW_CEILING; the below-ceiling case asserts 12, so the pair cannot be satisfied by a view that caps everything unconditionally.
  • Map — a case of its own, because clustering is the map's own defence and it folds the count away: above 100 markers the DOM holds bubbles, not markers. enableClustering={false} makes the count observable without changing what reached the view (clustering is a pure function of the marker array), and the DOM marker count is then literally the ruling's "the DOM row count equals the ceiling". The below-ceiling case asserts 20 markers with no prop at all — 20 is under the map's own clustering threshold.

Ablation, prediction stated before the run: under the same uncapped mutation both pins go red at the new count assertion, and the new externalDataCeiling-7507 pin goes red at its count waitFor. Measured: exactly that — 3 failed / 4 passed, red at ObjectCalendar.rowCeiling-7210.test.tsx:124, ObjectMap.rowCeiling-7210.test.tsx:125, ObjectCalendar.externalDataCeiling-7507.test.tsx:120, each 2001 against 2000. Restored byte-identically; the pins are green again.

3. Four docblocks stated a reverse-verification mechanism that does not happen

Measured by deleting $top: NON_GRID_ROW_CEILING_TOP from each component in turn:

pindocblock predictedmeasured
ganttred "at the FOOTNOTE assertion"red at the $top assertion, 1 failed / 2 passed
treered "at BOTH the row count and the footnote"red at the $top assertion only; the row count stays 2000
calendarred "at the footnote assertion"red at the $top assertion only
mapred "at the footnote assertion"red at the $top assertion only

One mechanism explains all four: an adapter with no $top answers with the whole filtered set, so applyNonGridRowCeiling still sees more rows than the ceiling, still slices to it, and still reports truncated from the rows in hand. The drawn count stays 2000 and the note still names both numbers. Losing the $top is a bandwidth regression, not a correctness one — which is exactly why the $top assertion is not redundant with the footnote.

The calendar and map docblocks were re-measured after their new count assertions landed, as asked: the $top ablation is unchanged (still $top-only, at :115 and :94), so each of the four now records the measured mechanism, and calendar and map additionally record the second ablation their count assertions exist for.

4. Calendar external-data sync left rowCeiling stale

ObjectCalendar.tsx had five setData paths; four also reset rowCeiling, the external-data sync did not. A component that drew its own truncated fetch and was then handed a short data array kept a footnote describing rows no longer on screen. Latent today — ObjectView passes data from mount — and fixed with the one line the other four paths already carry.

Pinned in ObjectCalendar.externalDataCeiling-7507.test.tsx, with a live control: the first assertion proves the note really was raised by this component's own fetch, so its later absence is a state change and not a query that matched nothing.

Ablation, prediction stated before the run: remove the reset and the new pin goes red at expect(screen.queryByRole('note')).toBeNull(), while rowCeiling-7210 stays green. Measured: exactly that — 1 failed / 3 passed, red at ObjectCalendar.externalDataCeiling-7507.test.tsx:131.

5. The false dependency comment — packages/react/src/index.ts

"the only package all four already depend on" is measured false: packages/plugin-{gantt,calendar,map,tree}/package.json each also list @object-ui/core, @object-ui/components and @object-ui/types. (@object-ui/i18n is not common to all four — plugin-map does not depend on it.) The comment now states the real reason — the round's barrel fence over exactly those three, plus @object-ui/react having no subpath export — and cross-links #7508 so the next reader finds the open decision instead of a settled-sounding rationale. Comment text only; the export statements are untouched.

6. Stale headroom comment — packages/i18n/src/locales/*.ts (ten packs)

"~1 KB of headroom" named a budget line that no longer holds these bytes. Since #7399 the catalogues have their own chunk: i18n-locales, ceiling 455_000 against a recorded baseline of 446_0768,924 B, about sixty short keys' worth across ten locales at the ~147 gzipped bytes/key the gate's own docblock measures. (framework, which the old comment was implicitly about, is now 71_000 over 61_465.) Read live from PER_CHUNK_GZIP_CEILINGS / PER_CHUNK_BASELINE.

⚠️ Stated honestly in the comment as the ceiling's distance from the baseline it was measured from, not as today's build: three commits have added locale keys since that baseline was recorded, so the live figure is somewhat smaller. The comment points at pnpm check:eager-closure for the number in force. A fresh figure needs a full apps/console build, which is Bundle Analysis's job on this PR.


Verification

whatresult
vitest runplugin-calendar, plugin-map, plugin-gantt, plugin-tree, i18n, react ceiling unit, at a221c9288170 files / 1687 tests passed
turbo run type-check — the six touched packages, --concurrency=2 (deps built first)21 tasks successful, all six type-check tasks executed
check:control-bytes, check:vi-mock-specifiers, check:vi-mock-inherit, check:i18n-keys, check:i18n-drift, check:i18n-dead-keysall exit 0 at a221c9288
node scripts/check-changeset-presence.mjs✅ 17 source files of 6 released packages changed, 1 changeset added
eslint --no-inline-config --format json over the changed set17 files judged, 0 errors, 103 warnings, all @typescript-eslint/no-explicit-any in the fixtures' as any idiom (lint.yml sets no --max-warnings)

The lint narrowing is a measurement, not a skip. The population came from eslint's own config, not from a guess: its one files entry is **/*.{ts,tsx}, so 17 of the 19 changed files are in scope (the two .changeset/*.md are not), and --format json reported 17 results — every in-scope changed file judged. The config declares no parserOptions.project / projectService, so type-aware linting is not enabled: a file's verdict is a function of that file's own source and the shared config, neither of which this diff moves for any untouched file. pnpm lint runs the whole farm on this PR regardless.

One check is NOT MEASURED rather than green:check:readme-exports exits 1 on this tree with its type entry ./dist/index.d.ts is not on disk — run pnpm build first and a population COLLAPSED verdict. That is a prerequisite failure, not a finding: it needs every package built. It cannot go red on this diff either way — the gate judges README docs against the export surface, and this branch changes no export.

Fences observed

Changeset

.changeset/7507-non-grid-ceiling-correctives.md uses the empty-frontmatter exemption, deliberately: every corrective here lands inside a change that has not been released — .changeset/7210-non-grid-row-ceiling.md is still pending on main — so the calendar fix repairs a defect no user has seen, and the release note it belongs to is the #7210 changeset, corrected in place.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC


Generated by Claude Code

…e comments
Post-merge correctives to #7210's platform row ceiling (#7507), from the
Clause-② review that ran as an audit after the PR landed ungated.
- Changeset: the four view packages carry the behaviour break, so they move
from `patch` to `minor`; the example footnote is replaced with the copy that
actually renders (measured: no thousands separators on either the provider
or the provider-less path); `NonGridCeilingResult` joins the export list.
- Map and calendar pins now grade the cap they are named for. Both were green
under a mutation that drew 2,001 rows, because they asserted `$top` and the
footnote and never the count that reached the view.
- `ObjectCalendar`'s external-`data` sync clears `rowCeiling`, the one
`setData` path that did not. Latent today, pinned now.
- Comment-only: the false "the only package all four already depend on"
rationale on `@object-ui/react`'s entry (all four also depend on `core`,
`components` and `types` — the real reason was the round's barrel fence, and
the home is an open decision on #7508), and the stale "~1 KB of headroom"
note in the ten locale packs, which named a chunk that no longer holds them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC
…ocblocks
All four predicted a mechanism that does not happen. Measured on this branch,
each ablation proven on disk and restored byte-identically:
- gantt, tree, calendar, map: deleting `$top: NON_GRID_ROW_CEILING_TOP` goes
red at the `$top` ASSERTION and nowhere else. Not at the footnote (gantt,
calendar, map) and not at the row count (tree): an adapter with no `$top`
answers with the whole filtered set, `applyNonGridRowCeiling` slices it to
the ceiling from the rows in hand, and both the drawn count and the note stay
correct. The probe row bounds the response; it is not the detector's only
input once an unbounded response has arrived.
- calendar and map additionally record the second ablation their new count
assertions exist for: handing the view the raw response instead of the capped
rows is red at the count, 2001 against 2000 — the mutation that left both
files green at 4/4 before this branch.
A pin whose docblock names the wrong discriminator is worse than one that names
none: the next reader trusts it while deciding what an edit may safely break.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 50 chunks)3181.9 KB3191.4 KB
Main entry chunk (gzip)143.2 KB350 KB
Entry fileindex-geK0qt0o.js
StatusPASS

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

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)15.67KB5.75KB
app-shell (runtime-config.js)20.68KB7.36KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)516.19KB117.80KB
core (index.js)6.12KB2.42KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)178.20KB49.60KB
fields (index.js)242.42KB61.26KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)34.34KB9.17KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.98KB10.98KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)48.15KB13.35KB
plugin-charts (index.js)70.87KB19.72KB
plugin-chatbot (index.js)196.19KB46.43KB
plugin-dashboard (index.js)132.82KB34.64KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)251.07KB64.12KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)132.87KB32.66KB
plugin-gantt (index.js)167.50KB41.08KB
plugin-grid (index.js)209.25KB56.71KB
plugin-kanban (index.js)52.71KB14.55KB
plugin-list (index.js)113.33KB27.60KB
plugin-map (index.js)20.55KB6.80KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)30.84KB8.85KB
plugin-tree (index.js)9.40KB3.23KB
plugin-view (index.js)85.22KB20.93KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)81.07KB26.86KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)4.63KB2.18KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.74KB2.25KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)8.11KB3.32KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

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

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

Projects

None yet

2 participants

@os-project-manager@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(non-grid,i18n,react): correct the row ceiling changeset, its pins and their rationale comments - #7517

Merged
os-project-manager merged 2 commits into
mainfrom
claude/issue-7507-7391-correctives
Sep 3, 2026
Merged

fix(non-grid,i18n,react): correct the row ceiling changeset, its pins and their rationale comments#7517
os-project-manager merged 2 commits into
mainfrom
claude/issue-7507-7391-correctives

Conversation

@claude

@claudeclaudeBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Fixes#7507

Six of the seven post-merge correctives the Clause-② audit of #7391 found (audit comment 5527977938). The seventh — the five symbols published on @object-ui/react's sole entry — is a maintainer decision on #7508 and is not touched here: this branch adds, moves, renames and retires zero exported symbols. Clause-② remains no.

Verified at a221c9288: 170 test files / 1687 tests green (plugin-calendar, plugin-map, plugin-gantt, plugin-tree, i18n, and the react ceiling unit), plus type-check green for all six touched packages via turbo (21 tasks, deps built first).


What was re-measured, and what it said

Nothing below was taken on the audit's say-so. Every claim was re-derived on this branch first; where an ablation is quoted, the mutation was proven on disk by grepping for the injected marker and the removed text, and the restore was proven byte-identical against the HEAD blob hash. Vitest resolves every @object-ui/* specifier to that package's src through the root config's alias table, so these ablations need no rebuild — there is no dist in the resolution path to go stale.

Baseline, before any change: 5 files / 16 tests green.

1. Changeset level and copy — .changeset/7210-non-grid-row-ceiling.md

  • The four view packages move patchminor. They carry the behaviour break (a result set above 2000 rows is no longer fully drawn); the fixed group makes the released version identical either way, but the per-package CHANGELOG would have filed a break under "Patch Changes".

  • The example footnote is replaced with the copy that actually renders. Measured, not copied: a throwaway probe rendered NonGridRowCeilingNote three ways and asserted a deliberately wrong string so the run could not pass silently — 3 failed, 3 printed values:

    PROBE_NO_PROVIDER = [Showing the first 2000 of 41234 records. Narrow the filter.]
    PROBE_PROVIDER = [Showing the first 2000 of 41234 records. Narrow the filter.]
    PROBE_UNKNOWN = [Showing the first 2000 records. Narrow the filter.]
    

    (delimiters shown as brackets; the probe printed them as angle runs.)

    No separators on either path. The i18next instance declares no format (packages/i18n/src/i18n.ts) and the provider-less fallback interpolates through String(v) (fallbackInterpolation.ts). The probe file was deleted.

  • NonGridCeilingResult joins the export list. It is already exported (packages/react/src/index.ts, export type { NonGridCeilingResult }) — listing it is documentation of a published symbol, not a new export.

2. The map and calendar pins now grade the cap they are named for

Audit finding reproduced first. With setData(capped.rows) replaced by setData((result as any).data ?? capped.rows) in both components, ObjectMap.rowCeiling-7210 and ObjectCalendar.rowCeiling-7210 stayed green, 4/4, drawing 2001 rows. They pinned $top and the footnote and never "draws at most N".

  • CalendarCalendarView is stubbed the way the gantt pin stubs GanttView (and the way ObjectCalendar.unscheduled-7071 already stubs it, via importOriginal), exposing data-event-count. The above-ceiling case asserts it equals NON_GRID_ROW_CEILING; the below-ceiling case asserts 12, so the pair cannot be satisfied by a view that caps everything unconditionally.
  • Map — a case of its own, because clustering is the map's own defence and it folds the count away: above 100 markers the DOM holds bubbles, not markers. enableClustering={false} makes the count observable without changing what reached the view (clustering is a pure function of the marker array), and the DOM marker count is then literally the ruling's "the DOM row count equals the ceiling". The below-ceiling case asserts 20 markers with no prop at all — 20 is under the map's own clustering threshold.

Ablation, prediction stated before the run: under the same uncapped mutation both pins go red at the new count assertion, and the new externalDataCeiling-7507 pin goes red at its count waitFor. Measured: exactly that — 3 failed / 4 passed, red at ObjectCalendar.rowCeiling-7210.test.tsx:124, ObjectMap.rowCeiling-7210.test.tsx:125, ObjectCalendar.externalDataCeiling-7507.test.tsx:120, each 2001 against 2000. Restored byte-identically; the pins are green again.

3. Four docblocks stated a reverse-verification mechanism that does not happen

Measured by deleting $top: NON_GRID_ROW_CEILING_TOP from each component in turn:

pindocblock predictedmeasured
ganttred "at the FOOTNOTE assertion"red at the $top assertion, 1 failed / 2 passed
treered "at BOTH the row count and the footnote"red at the $top assertion only; the row count stays 2000
calendarred "at the footnote assertion"red at the $top assertion only
mapred "at the footnote assertion"red at the $top assertion only

One mechanism explains all four: an adapter with no $top answers with the whole filtered set, so applyNonGridRowCeiling still sees more rows than the ceiling, still slices to it, and still reports truncated from the rows in hand. The drawn count stays 2000 and the note still names both numbers. Losing the $top is a bandwidth regression, not a correctness one — which is exactly why the $top assertion is not redundant with the footnote.

The calendar and map docblocks were re-measured after their new count assertions landed, as asked: the $top ablation is unchanged (still $top-only, at :115 and :94), so each of the four now records the measured mechanism, and calendar and map additionally record the second ablation their count assertions exist for.

4. Calendar external-data sync left rowCeiling stale

ObjectCalendar.tsx had five setData paths; four also reset rowCeiling, the external-data sync did not. A component that drew its own truncated fetch and was then handed a short data array kept a footnote describing rows no longer on screen. Latent today — ObjectView passes data from mount — and fixed with the one line the other four paths already carry.

Pinned in ObjectCalendar.externalDataCeiling-7507.test.tsx, with a live control: the first assertion proves the note really was raised by this component's own fetch, so its later absence is a state change and not a query that matched nothing.

Ablation, prediction stated before the run: remove the reset and the new pin goes red at expect(screen.queryByRole('note')).toBeNull(), while rowCeiling-7210 stays green. Measured: exactly that — 1 failed / 3 passed, red at ObjectCalendar.externalDataCeiling-7507.test.tsx:131.

5. The false dependency comment — packages/react/src/index.ts

"the only package all four already depend on" is measured false: packages/plugin-{gantt,calendar,map,tree}/package.json each also list @object-ui/core, @object-ui/components and @object-ui/types. (@object-ui/i18n is not common to all four — plugin-map does not depend on it.) The comment now states the real reason — the round's barrel fence over exactly those three, plus @object-ui/react having no subpath export — and cross-links #7508 so the next reader finds the open decision instead of a settled-sounding rationale. Comment text only; the export statements are untouched.

6. Stale headroom comment — packages/i18n/src/locales/*.ts (ten packs)

"~1 KB of headroom" named a budget line that no longer holds these bytes. Since #7399 the catalogues have their own chunk: i18n-locales, ceiling 455_000 against a recorded baseline of 446_0768,924 B, about sixty short keys' worth across ten locales at the ~147 gzipped bytes/key the gate's own docblock measures. (framework, which the old comment was implicitly about, is now 71_000 over 61_465.) Read live from PER_CHUNK_GZIP_CEILINGS / PER_CHUNK_BASELINE.

⚠️ Stated honestly in the comment as the ceiling's distance from the baseline it was measured from, not as today's build: three commits have added locale keys since that baseline was recorded, so the live figure is somewhat smaller. The comment points at pnpm check:eager-closure for the number in force. A fresh figure needs a full apps/console build, which is Bundle Analysis's job on this PR.


Verification

whatresult
vitest runplugin-calendar, plugin-map, plugin-gantt, plugin-tree, i18n, react ceiling unit, at a221c9288170 files / 1687 tests passed
turbo run type-check — the six touched packages, --concurrency=2 (deps built first)21 tasks successful, all six type-check tasks executed
check:control-bytes, check:vi-mock-specifiers, check:vi-mock-inherit, check:i18n-keys, check:i18n-drift, check:i18n-dead-keysall exit 0 at a221c9288
node scripts/check-changeset-presence.mjs✅ 17 source files of 6 released packages changed, 1 changeset added
eslint --no-inline-config --format json over the changed set17 files judged, 0 errors, 103 warnings, all @typescript-eslint/no-explicit-any in the fixtures' as any idiom (lint.yml sets no --max-warnings)

The lint narrowing is a measurement, not a skip. The population came from eslint's own config, not from a guess: its one files entry is **/*.{ts,tsx}, so 17 of the 19 changed files are in scope (the two .changeset/*.md are not), and --format json reported 17 results — every in-scope changed file judged. The config declares no parserOptions.project / projectService, so type-aware linting is not enabled: a file's verdict is a function of that file's own source and the shared config, neither of which this diff moves for any untouched file. pnpm lint runs the whole farm on this PR regardless.

One check is NOT MEASURED rather than green:check:readme-exports exits 1 on this tree with its type entry ./dist/index.d.ts is not on disk — run pnpm build first and a population COLLAPSED verdict. That is a prerequisite failure, not a finding: it needs every package built. It cannot go red on this diff either way — the gate judges README docs against the export surface, and this branch changes no export.

Fences observed

Changeset

.changeset/7507-non-grid-ceiling-correctives.md uses the empty-frontmatter exemption, deliberately: every corrective here lands inside a change that has not been released — .changeset/7210-non-grid-row-ceiling.md is still pending on main — so the calendar fix repairs a defect no user has seen, and the release note it belongs to is the #7210 changeset, corrected in place.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC


Generated by Claude Code

…e comments
Post-merge correctives to #7210's platform row ceiling (#7507), from the
Clause-② review that ran as an audit after the PR landed ungated.
- Changeset: the four view packages carry the behaviour break, so they move
from `patch` to `minor`; the example footnote is replaced with the copy that
actually renders (measured: no thousands separators on either the provider
or the provider-less path); `NonGridCeilingResult` joins the export list.
- Map and calendar pins now grade the cap they are named for. Both were green
under a mutation that drew 2,001 rows, because they asserted `$top` and the
footnote and never the count that reached the view.
- `ObjectCalendar`'s external-`data` sync clears `rowCeiling`, the one
`setData` path that did not. Latent today, pinned now.
- Comment-only: the false "the only package all four already depend on"
rationale on `@object-ui/react`'s entry (all four also depend on `core`,
`components` and `types` — the real reason was the round's barrel fence, and
the home is an open decision on #7508), and the stale "~1 KB of headroom"
note in the ten locale packs, which named a chunk that no longer holds them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC
…ocblocks
All four predicted a mechanism that does not happen. Measured on this branch,
each ablation proven on disk and restored byte-identically:
- gantt, tree, calendar, map: deleting `$top: NON_GRID_ROW_CEILING_TOP` goes
red at the `$top` ASSERTION and nowhere else. Not at the footnote (gantt,
calendar, map) and not at the row count (tree): an adapter with no `$top`
answers with the whole filtered set, `applyNonGridRowCeiling` slices it to
the ceiling from the rows in hand, and both the drawn count and the note stay
correct. The probe row bounds the response; it is not the detector's only
input once an unbounded response has arrived.
- calendar and map additionally record the second ablation their new count
assertions exist for: handing the view the raw response instead of the capped
rows is red at the count, 2001 against 2000 — the mutation that left both
files green at 4/4 before this branch.
A pin whose docblock names the wrong discriminator is worse than one that names
none: the next reader trusts it while deciding what an edit may safely break.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 50 chunks)3181.9 KB3191.4 KB
Main entry chunk (gzip)143.2 KB350 KB
Entry fileindex-geK0qt0o.js
StatusPASS

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

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)15.67KB5.75KB
app-shell (runtime-config.js)20.68KB7.36KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)516.19KB117.80KB
core (index.js)6.12KB2.42KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)178.20KB49.60KB
fields (index.js)242.42KB61.26KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)34.34KB9.17KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.98KB10.98KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)48.15KB13.35KB
plugin-charts (index.js)70.87KB19.72KB
plugin-chatbot (index.js)196.19KB46.43KB
plugin-dashboard (index.js)132.82KB34.64KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)251.07KB64.12KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)132.87KB32.66KB
plugin-gantt (index.js)167.50KB41.08KB
plugin-grid (index.js)209.25KB56.71KB
plugin-kanban (index.js)52.71KB14.55KB
plugin-list (index.js)113.33KB27.60KB
plugin-map (index.js)20.55KB6.80KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)30.84KB8.85KB
plugin-tree (index.js)9.40KB3.23KB
plugin-view (index.js)85.22KB20.93KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)81.07KB26.86KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)4.63KB2.18KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.74KB2.25KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)8.11KB3.32KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

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

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

Projects

None yet

2 participants

@os-project-manager@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(non-grid,i18n,react): correct the row ceiling changeset, its pins and their rationale comments - #7517

Merged
os-project-manager merged 2 commits into
mainfrom
claude/issue-7507-7391-correctives
Sep 3, 2026
Merged

fix(non-grid,i18n,react): correct the row ceiling changeset, its pins and their rationale comments#7517
os-project-manager merged 2 commits into
mainfrom
claude/issue-7507-7391-correctives

Conversation

@claude

@claudeclaudeBot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Fixes#7507

Six of the seven post-merge correctives the Clause-② audit of #7391 found (audit comment 5527977938). The seventh — the five symbols published on @object-ui/react's sole entry — is a maintainer decision on #7508 and is not touched here: this branch adds, moves, renames and retires zero exported symbols. Clause-② remains no.

Verified at a221c9288: 170 test files / 1687 tests green (plugin-calendar, plugin-map, plugin-gantt, plugin-tree, i18n, and the react ceiling unit), plus type-check green for all six touched packages via turbo (21 tasks, deps built first).


What was re-measured, and what it said

Nothing below was taken on the audit's say-so. Every claim was re-derived on this branch first; where an ablation is quoted, the mutation was proven on disk by grepping for the injected marker and the removed text, and the restore was proven byte-identical against the HEAD blob hash. Vitest resolves every @object-ui/* specifier to that package's src through the root config's alias table, so these ablations need no rebuild — there is no dist in the resolution path to go stale.

Baseline, before any change: 5 files / 16 tests green.

1. Changeset level and copy — .changeset/7210-non-grid-row-ceiling.md

  • The four view packages move patchminor. They carry the behaviour break (a result set above 2000 rows is no longer fully drawn); the fixed group makes the released version identical either way, but the per-package CHANGELOG would have filed a break under "Patch Changes".

  • The example footnote is replaced with the copy that actually renders. Measured, not copied: a throwaway probe rendered NonGridRowCeilingNote three ways and asserted a deliberately wrong string so the run could not pass silently — 3 failed, 3 printed values:

    PROBE_NO_PROVIDER = [Showing the first 2000 of 41234 records. Narrow the filter.]
    PROBE_PROVIDER = [Showing the first 2000 of 41234 records. Narrow the filter.]
    PROBE_UNKNOWN = [Showing the first 2000 records. Narrow the filter.]
    

    (delimiters shown as brackets; the probe printed them as angle runs.)

    No separators on either path. The i18next instance declares no format (packages/i18n/src/i18n.ts) and the provider-less fallback interpolates through String(v) (fallbackInterpolation.ts). The probe file was deleted.

  • NonGridCeilingResult joins the export list. It is already exported (packages/react/src/index.ts, export type { NonGridCeilingResult }) — listing it is documentation of a published symbol, not a new export.

2. The map and calendar pins now grade the cap they are named for

Audit finding reproduced first. With setData(capped.rows) replaced by setData((result as any).data ?? capped.rows) in both components, ObjectMap.rowCeiling-7210 and ObjectCalendar.rowCeiling-7210 stayed green, 4/4, drawing 2001 rows. They pinned $top and the footnote and never "draws at most N".

  • CalendarCalendarView is stubbed the way the gantt pin stubs GanttView (and the way ObjectCalendar.unscheduled-7071 already stubs it, via importOriginal), exposing data-event-count. The above-ceiling case asserts it equals NON_GRID_ROW_CEILING; the below-ceiling case asserts 12, so the pair cannot be satisfied by a view that caps everything unconditionally.
  • Map — a case of its own, because clustering is the map's own defence and it folds the count away: above 100 markers the DOM holds bubbles, not markers. enableClustering={false} makes the count observable without changing what reached the view (clustering is a pure function of the marker array), and the DOM marker count is then literally the ruling's "the DOM row count equals the ceiling". The below-ceiling case asserts 20 markers with no prop at all — 20 is under the map's own clustering threshold.

Ablation, prediction stated before the run: under the same uncapped mutation both pins go red at the new count assertion, and the new externalDataCeiling-7507 pin goes red at its count waitFor. Measured: exactly that — 3 failed / 4 passed, red at ObjectCalendar.rowCeiling-7210.test.tsx:124, ObjectMap.rowCeiling-7210.test.tsx:125, ObjectCalendar.externalDataCeiling-7507.test.tsx:120, each 2001 against 2000. Restored byte-identically; the pins are green again.

3. Four docblocks stated a reverse-verification mechanism that does not happen

Measured by deleting $top: NON_GRID_ROW_CEILING_TOP from each component in turn:

pindocblock predictedmeasured
ganttred "at the FOOTNOTE assertion"red at the $top assertion, 1 failed / 2 passed
treered "at BOTH the row count and the footnote"red at the $top assertion only; the row count stays 2000
calendarred "at the footnote assertion"red at the $top assertion only
mapred "at the footnote assertion"red at the $top assertion only

One mechanism explains all four: an adapter with no $top answers with the whole filtered set, so applyNonGridRowCeiling still sees more rows than the ceiling, still slices to it, and still reports truncated from the rows in hand. The drawn count stays 2000 and the note still names both numbers. Losing the $top is a bandwidth regression, not a correctness one — which is exactly why the $top assertion is not redundant with the footnote.

The calendar and map docblocks were re-measured after their new count assertions landed, as asked: the $top ablation is unchanged (still $top-only, at :115 and :94), so each of the four now records the measured mechanism, and calendar and map additionally record the second ablation their count assertions exist for.

4. Calendar external-data sync left rowCeiling stale

ObjectCalendar.tsx had five setData paths; four also reset rowCeiling, the external-data sync did not. A component that drew its own truncated fetch and was then handed a short data array kept a footnote describing rows no longer on screen. Latent today — ObjectView passes data from mount — and fixed with the one line the other four paths already carry.

Pinned in ObjectCalendar.externalDataCeiling-7507.test.tsx, with a live control: the first assertion proves the note really was raised by this component's own fetch, so its later absence is a state change and not a query that matched nothing.

Ablation, prediction stated before the run: remove the reset and the new pin goes red at expect(screen.queryByRole('note')).toBeNull(), while rowCeiling-7210 stays green. Measured: exactly that — 1 failed / 3 passed, red at ObjectCalendar.externalDataCeiling-7507.test.tsx:131.

5. The false dependency comment — packages/react/src/index.ts

"the only package all four already depend on" is measured false: packages/plugin-{gantt,calendar,map,tree}/package.json each also list @object-ui/core, @object-ui/components and @object-ui/types. (@object-ui/i18n is not common to all four — plugin-map does not depend on it.) The comment now states the real reason — the round's barrel fence over exactly those three, plus @object-ui/react having no subpath export — and cross-links #7508 so the next reader finds the open decision instead of a settled-sounding rationale. Comment text only; the export statements are untouched.

6. Stale headroom comment — packages/i18n/src/locales/*.ts (ten packs)

"~1 KB of headroom" named a budget line that no longer holds these bytes. Since #7399 the catalogues have their own chunk: i18n-locales, ceiling 455_000 against a recorded baseline of 446_0768,924 B, about sixty short keys' worth across ten locales at the ~147 gzipped bytes/key the gate's own docblock measures. (framework, which the old comment was implicitly about, is now 71_000 over 61_465.) Read live from PER_CHUNK_GZIP_CEILINGS / PER_CHUNK_BASELINE.

⚠️ Stated honestly in the comment as the ceiling's distance from the baseline it was measured from, not as today's build: three commits have added locale keys since that baseline was recorded, so the live figure is somewhat smaller. The comment points at pnpm check:eager-closure for the number in force. A fresh figure needs a full apps/console build, which is Bundle Analysis's job on this PR.


Verification

whatresult
vitest runplugin-calendar, plugin-map, plugin-gantt, plugin-tree, i18n, react ceiling unit, at a221c9288170 files / 1687 tests passed
turbo run type-check — the six touched packages, --concurrency=2 (deps built first)21 tasks successful, all six type-check tasks executed
check:control-bytes, check:vi-mock-specifiers, check:vi-mock-inherit, check:i18n-keys, check:i18n-drift, check:i18n-dead-keysall exit 0 at a221c9288
node scripts/check-changeset-presence.mjs✅ 17 source files of 6 released packages changed, 1 changeset added
eslint --no-inline-config --format json over the changed set17 files judged, 0 errors, 103 warnings, all @typescript-eslint/no-explicit-any in the fixtures' as any idiom (lint.yml sets no --max-warnings)

The lint narrowing is a measurement, not a skip. The population came from eslint's own config, not from a guess: its one files entry is **/*.{ts,tsx}, so 17 of the 19 changed files are in scope (the two .changeset/*.md are not), and --format json reported 17 results — every in-scope changed file judged. The config declares no parserOptions.project / projectService, so type-aware linting is not enabled: a file's verdict is a function of that file's own source and the shared config, neither of which this diff moves for any untouched file. pnpm lint runs the whole farm on this PR regardless.

One check is NOT MEASURED rather than green:check:readme-exports exits 1 on this tree with its type entry ./dist/index.d.ts is not on disk — run pnpm build first and a population COLLAPSED verdict. That is a prerequisite failure, not a finding: it needs every package built. It cannot go red on this diff either way — the gate judges README docs against the export surface, and this branch changes no export.

Fences observed

Changeset

.changeset/7507-non-grid-ceiling-correctives.md uses the empty-frontmatter exemption, deliberately: every corrective here lands inside a change that has not been released — .changeset/7210-non-grid-row-ceiling.md is still pending on main — so the calendar fix repairs a defect no user has seen, and the release note it belongs to is the #7210 changeset, corrected in place.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC


Generated by Claude Code

…e comments
Post-merge correctives to #7210's platform row ceiling (#7507), from the
Clause-② review that ran as an audit after the PR landed ungated.
- Changeset: the four view packages carry the behaviour break, so they move
from `patch` to `minor`; the example footnote is replaced with the copy that
actually renders (measured: no thousands separators on either the provider
or the provider-less path); `NonGridCeilingResult` joins the export list.
- Map and calendar pins now grade the cap they are named for. Both were green
under a mutation that drew 2,001 rows, because they asserted `$top` and the
footnote and never the count that reached the view.
- `ObjectCalendar`'s external-`data` sync clears `rowCeiling`, the one
`setData` path that did not. Latent today, pinned now.
- Comment-only: the false "the only package all four already depend on"
rationale on `@object-ui/react`'s entry (all four also depend on `core`,
`components` and `types` — the real reason was the round's barrel fence, and
the home is an open decision on #7508), and the stale "~1 KB of headroom"
note in the ten locale packs, which named a chunk that no longer holds them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC
…ocblocks
All four predicted a mechanism that does not happen. Measured on this branch,
each ablation proven on disk and restored byte-identically:
- gantt, tree, calendar, map: deleting `$top: NON_GRID_ROW_CEILING_TOP` goes
red at the `$top` ASSERTION and nowhere else. Not at the footnote (gantt,
calendar, map) and not at the row count (tree): an adapter with no `$top`
answers with the whole filtered set, `applyNonGridRowCeiling` slices it to
the ceiling from the rows in hand, and both the drawn count and the note stay
correct. The probe row bounds the response; it is not the detector's only
input once an unbounded response has arrived.
- calendar and map additionally record the second ablation their new count
assertions exist for: handing the view the raw response instead of the capped
rows is red at the count, 2001 against 2000 — the mutation that left both
files green at 4/4 before this branch.
A pin whose docblock names the wrong discriminator is worse than one that names
none: the next reader trusts it while deciding what an edit may safely break.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EMrWaQw3XS5DxTHxp4yRyC
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 50 chunks)3181.9 KB3191.4 KB
Main entry chunk (gzip)143.2 KB350 KB
Entry fileindex-geK0qt0o.js
StatusPASS

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

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)15.67KB5.75KB
app-shell (runtime-config.js)20.68KB7.36KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)516.19KB117.80KB
core (index.js)6.12KB2.42KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)178.20KB49.60KB
fields (index.js)242.42KB61.26KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)34.34KB9.17KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.98KB10.98KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)11.71KB4.29KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)6.24KB2.16KB
permissions (discardProofCache.js)1.04KB0.55KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)4.83KB2.27KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)48.15KB13.35KB
plugin-charts (index.js)70.87KB19.72KB
plugin-chatbot (index.js)196.19KB46.43KB
plugin-dashboard (index.js)132.82KB34.64KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)251.07KB64.12KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)132.87KB32.66KB
plugin-gantt (index.js)167.50KB41.08KB
plugin-grid (index.js)209.25KB56.71KB
plugin-kanban (index.js)52.71KB14.55KB
plugin-list (index.js)113.33KB27.60KB
plugin-map (index.js)20.55KB6.80KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)30.84KB8.85KB
plugin-tree (index.js)9.40KB3.23KB
plugin-view (index.js)85.22KB20.93KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)81.07KB26.86KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)4.63KB2.18KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.74KB2.25KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)8.11KB3.32KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

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

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

Projects

None yet

2 participants

@os-project-manager@claude