Skip to content

docs(scripts): record the measured framework attribution the ceiling raise could not (objectui#8542) - #8579

Merged
os-justin merged 1 commit into
mainfrom
claude/issue-8542-framework-chunk-ceiling
Sep 8, 2026
Merged

docs(scripts): record the measured framework attribution the ceiling raise could not (objectui#8542)#8579
os-justin merged 1 commit into
mainfrom
claude/issue-8542-framework-chunk-ceiling

Conversation

@os-justin

@os-justin os-justin commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

Part of #8542

Deliberately Part of, not a closing keyword — see "Why this does not close the card" at the bottom. This PR was opened with a closing keyword and corrected within the hour, on a card amendment posted after it.

⚠️ Read the first section before the diff. The premise this card was dispatched on is dead, and the change here is what is left of it.

main is already GREEN — fa9e76ccd landed the repair while this card was in flight

The card, its triage, and my dispatch brief all describe a red trunk: "every PR whose diff adds a byte to packages/core, packages/react or packages/types now fails a required check it cannot fix within its own appetite." Measured on e411c3e58 (the main tip this branch is cut from), that is no longer true:

⇒ There is no byte to trim, and both actions the dispatch forbade (raise the ceiling, revert f76f43628) are moot: one already happened above my floor, the other never will.

What IS left, and it is the thing the card was filed for

fa9e76ccd moved a ratchet 29,000 bytes and recorded, honestly, that it could not say what the bytes bought:

⛔ What the bytes buy: NOTHING IDENTIFIABLE, and that is the finding, not an omission. The failure message this raise silences asks the author to "say in the PR what the bytes buy". Nobody can: Bundle Analysis went red on main at f76f43628 with 40a7c538a the last green, and the commits in that window have never been bisected — this checker is a two-build predicate over them and no one has run it. ⚠️ So this raise does not answer the attribution question, it makes it HARDER TO ASK: the line that was holding the unexplained bytes in view now passes over them. objectui#8542 owns that attribution and stays open.

That paragraph is still in the tree, and it is what this PR replaces. The bisect has been run. This PR is prose only — ⛔ no constant moves, and that is proved mechanically below, not asserted.

⭐ The attribution — one apps/console build per point

build landed by framework gzip moved by chunk file gate
40a7c538a #8503 70,999 last GREEN, 1 byte under framework-nDOJv2Ij.js exit 0
512c84b16 #8519 70,999 0 framework-nDOJv2Ij.js exit 0
f76f43628 #8512 71,261 +262 — the crossing framework-DGfxffQ7.js exit 1, OVER by 261
e76634cc8 #8529 72,245 +984 framework-Dzpi76rg.js exit 1, OVER by 1,245
e411c3e58 #8562 72,248 +3 framework-Go_72ibC.js exit 0 (new ceiling)

70,999 + 262 + 984 = 72,245, and the e76634cc8 row reproduces the card's CI reading — framework 70.6 KB / 69.3 KB ceiling (OVER by 1.2 KB) — to the byte.

Method, stated because bundle readings in this repo are CWD-sensitive: one detached worktree, pnpm install once (pnpm-lock.yaml is identical across all five points, verified), then at each point pnpm turbo run build --filter='./packages/*' --concurrency=2 followed by pnpm --filter @object-ui/console build, both from the worktree ROOT, and framework read out of the apps/console/dist/eager-closure.json the build itself writes (reportVersion 2). Identical command, identical CWD, at every point. Every build went through the shared verify lock; each printed VERDICT command-exit 0.

⚠️ Finding 1 — TWO commits own the overage, and the larger one is OUTSIDE the window every card bounded

e76634cc8 (#8529) landed after the red had already started and carries 984 of the 1,246 bytes the pair added — 79% — against 262 for the commit the red first appeared on. ⛔ A repair scoped to the four-commit window, which is what this card, objectui#8541 and my own dispatch brief all specified, would have left main red. The two-build bisect that triage adopted as its handover instruction answers a question narrower than the defect.

⚠️ Finding 2 — objectui#8541's named suspect is measurably innocent

512c84b16 emits a byte-identical chunk to 40a7c538a — the same framework-nDOJv2Ij.js content hash — so d65b2baa4, 270f2825b and 512c84b16 together moved this chunk by zero. Corroborated structurally: git show --name-only 270f2825b touches 13 files and not one under packages/(core|react|types) (grep exit 1, control: 13 files present), so it has no path into this chunk at all.

⭐ What the bytes buy, which is what the gate's failure message asks for

Both contributors are silent-wrong-answer repairs on ONE file's filter path, packages/core's ValueDataSource:

The bytes ARE the refusals and the prescriptions that replaced that silence.

⛔ What this PR deliberately does not do

  • No ceiling is raised or lowered. Not PER_CHUNK_GZIP_CEILINGS, not PER_CHUNK_BASELINE, not REGRESSION_THIS_GATE_MUST_CATCH_BYTES, not the aggregate.
  • Nothing is reverted. f76f43628 and e76634cc8 are ruled correctness repairs.
  • Nothing is re-chunked. Moving budgeted bytes into an unbudgeted chunk turns the check green while the browser downloads the same bytes — the exact pattern objectui#5490 built the per-chunk half to catch.
  • The trim number is cited, not claimed. The 610-gzip-bytes-for-the-whole-diagnostic-surface figure is recorded on this card by the earlier run at issuecomment-5584083163; I did not re-measure it, and the prose says so in as many words.

Evidence

The diff cannot move the gate's verdict — proved, not argued

  • 47 lines added, 11 removed in the checker; 0 of them non-comment (classifier control: a real constant line is correctly rejected as code).
  • The checker with comments stripped is byte-identical to origin/main's: both 25,505 characters, == true, with the control that the raw files do differ.

Per-chunk numbers before and after — all four budgeted chunks, not just framework

before is a build of origin/main at e411c3e58; after is a build of this branch. Same command, same CWD.

chunk before (gzip) after (gzip) delta chunk file
framework 72,248 72,248 0 framework-Go_72ibC.js (identical hash)
vendor-objectstack 1,235,152 1,235,152 0 vendor-objectstack-TSYB5b1r.js (identical)
i18n-locales 452,100 452,100 0 i18n-locales-hFYzG_D0.js (identical)
ui-components 393,295 393,295 0 ui-components-B372jD9I.js (identical)
aggregate eager 3,558,850 3,558,850 0 50 of 518 chunks

⇒ ⭐ Nothing was pushed into a chunk that happened to have headroom. Every content hash is the same one origin/main emits.

Gates, exit codes captured by redirect before any pipe

command exit
pnpm exec vitest run scripts/__tests__/check-eager-closure-budget.test.ts 0 — 104 passed (104)
pnpm check:eager-closure on a full console build of this branch 0 — all five legs green
node scripts/check-control-bytes.mjs 0 — 6,767 tracked text files scanned
node scripts/check-changeset-fixed.mjs 0
node scripts/check-changeset-no-major.mjs 0
node scripts/check-changeset-presence.mjs 0 — no changeset owed; one added anyway
pnpm exec eslint . (repo-wide, ⛔ never --no-inline-config) 0 — 4,516 files, 0 errors, 12,267 pre-existing warnings
pnpm exec tsc -p tsconfig.scripts.json --noEmit 0
node scripts/check-governed-queue-guard.mjs --test on both changed paths 0 — NOT GOVERNED (lit control: AGENTS.md returns exit 3, GOVERNED)

⚠️ Ablation, and it came back NEGATIVE — reported rather than fitted to the guess

I injected an unanchored chunk count (which weighs 50 of 518 chunks) into the new prose to test whether the objectui#7528 pin reads this region. It does not fire. The mutation demonstrably reached disk — anchor line count 1 → 0, injected string 0 → 1, blob hash 1e108dfd…7e07c1cc… — and the suite still passed 104/104. ⇒ The honest reading is that a backticked commit hash elsewhere in the same JSDoc block anchors the whole block, so this narrative region carries no mechanical pin; the review is the guard on it. Restored by state, not by exit code: blob hash back to 1e108dfdbe3d385f1c5fd04e0f6db0ed0a2582b7, equal to git rev-parse HEAD:scripts/check-eager-closure-budget.mjs, and git diff HEAD --stat empty. The trap on EXIT INT TERM used absolute paths and git checkout HEAD --, never a bare restore.

⛔ Why this does not close the card

The card amendment at issuecomment-5585168282 puts objectui#8542 into two live branches, and this PR satisfies neither of them on its own:

  • If the maintainer confirms 100,000, the card's attribution deliverable is complete and it closes — but on that ruling, not on this PR.
  • If the maintainer does not confirm it, the card's queued work becomes re-tightening the ceiling to the file's own 0.10x convention (about 81,359 over the 72,245 baseline), maintainer-merged. ⛔ This PR does not do that and must not close the card out from under it.

Part of, not a closing keyword. This PR is the tree-side half of the attribution: it removes a sentence that is now false whichever way the maintainer answers.

Draft, and staying draft

⛔ Not flipped ready, ⛔ no auto-merge armed. check-governed-queue-guard says this diff is not on a governed surface, so that posture is my dispatch's instruction rather than the repo's requirement.

🤖 Generated with Claude Code

https://claude.ai/code/session_01YBWFb5YgMU5dw8p2VKj16S

…g raise could not (objectui#8542)

`fa9e76ccd` raised `PER_CHUNK_GZIP_CEILINGS.framework` to 100,000 and recorded,
honestly, that it could not say what the bytes bought: "the commits in that
window have never been bisected — this checker is a two-build predicate over
them and no one has run it." That is the one sentence this change replaces.

The bisect has now been run — one `apps/console` build per point, each from the
repo ROOT, `framework` read out of the `apps/console/dist/eager-closure.json`
the build itself writes:

  | build       | landed by | `framework` gzip | moved by                 |
  | `40a7c538a` | #8503     | 70,999           | last GREEN, 1 byte under |
  | `512c84b16` | #8519     | 70,999           |                        0 |
  | `f76f43628` | #8512     | 71,261           |                     +262 |
  | `e76634cc8` | #8529     | 72,245           |                     +984 |
  | `e411c3e58` | #8562     | 72,248           |                       +3 |

Two commits own the overage, not one, and the LARGER one is outside the window
every card bounded its reasoning to: `e76634cc8` landed after the red had
already started and carries 984 of the 1,246 bytes the pair added. A repair
scoped to that window would have left `main` red. `512c84b16` emitted a
byte-identical chunk to `40a7c538a` — the same `framework-nDOJv2Ij.js` content
hash — so the three commits between them moved this chunk by zero, and
`270f2825b` touches no file under `packages/(core|react|types)` at all.

What the bytes buy is therefore sayable, which is what the gate's own failure
message asks of a raise: both contributors are silent-wrong-answer fixes on one
file's filter path. `f76f43628` stopped an unrecognised `$` operator adding no
constraint and matching every row; `e76634cc8` stopped an array comparand and a
`{ $field }` reference being compared by reference, which selected every row
under `$ne` and no rows under `$eq` without saying so.

No constant moves. The prose that records what the raise COSTS is kept intact,
including that the attribution arrived after the ceiling did.

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

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 50 chunks) 3475.6 KB 3512.7 KB
Main entry chunk (gzip) 143.9 KB 350 KB
Entry file index-BH00rO6J.js
Status PASS

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


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 15.67KB 5.75KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 498.93KB 114.12KB
core (index.js) 7.48KB 2.96KB
create-plugin (index.js) 10.12KB 3.28KB
data-objectstack (index.js) 192.72KB 53.55KB
fields (index.js) 243.24KB 61.42KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 6.57KB 2.76KB
i18n (index.js) 3.65KB 1.47KB
i18n (pickLocalized.js) 7.62KB 3.26KB
i18n (provider.js) 26.89KB 9.04KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 38.84KB 10.94KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 4.39KB 1.66KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 11.71KB 4.29KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 5.12KB 1.74KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 15.16KB 3.68KB
plugin-calendar (index.js) 49.00KB 13.91KB
plugin-charts (index.js) 71.39KB 19.92KB
plugin-chatbot (index.js) 194.53KB 46.34KB
plugin-dashboard (index.js) 131.43KB 34.44KB
plugin-designer (index.js) 213.21KB 43.63KB
plugin-detail (index.js) 248.46KB 63.90KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 131.01KB 32.32KB
plugin-gantt (index.js) 167.16KB 40.99KB
plugin-grid (index.js) 208.30KB 56.63KB
plugin-kanban (index.js) 55.40KB 15.71KB
plugin-list (index.js) 112.74KB 27.70KB
plugin-map (index.js) 20.49KB 6.83KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.42KB 11.92KB
plugin-timeline (index.js) 30.10KB 8.74KB
plugin-tree (index.js) 9.33KB 3.25KB
plugin-view (index.js) 84.54KB 20.84KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 81.07KB 26.86KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 2.32KB 1.24KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.55KB 2.45KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 20.57KB 5.88KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 13.64KB 4.59KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 4.73KB 2.28KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

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

@os-justin
os-justin marked this pull request as ready for review September 8, 2026 13:28
@os-justin
os-justin enabled auto-merge September 8, 2026 13:28
@os-justin
os-justin added this pull request to the merge queue Sep 8, 2026
Merged via the queue into main with commit 57bad9b Sep 8, 2026
35 checks passed
@os-justin
os-justin deleted the claude/issue-8542-framework-chunk-ceiling branch September 8, 2026 13:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants