Skip to content

test(spec-parity): member pins for object-form.fields and object-grid exportOptions / bulkActions / bulkActionDefs (objectui#8071 slice 1) - #8737

Merged
os-warren merged 5 commits into
mainfrom
claude/issue-8071-member-pins-near-miss-four
Sep 9, 2026
Merged

test(spec-parity): member pins for object-form.fields and object-grid exportOptions / bulkActions / bulkActionDefs (objectui#8071 slice 1)#8737
os-warren merged 5 commits into
mainfrom
claude/issue-8071-member-pins-near-miss-four

Conversation

@os-warren

@os-warren os-warren commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

Refs #8071 (object-form.fields, object-grid.exportOptions, object-grid.bulkActions, object-grid.bulkActionDefs)

Refs, not Fixes. This is the first declared slice of a 58-key card; #8071 must survive the merge.

♻️ Ejected from the merge queue, and repaired — origin/main merged in

The queue's merged-with-main candidate went red at 03:44:58Z. One job, one test, and it was this PR's own pin doing its job. Row 5 of bulkActionMembers-8071.test.tsx deliberately pinned objectui#8730's crash as CURRENT behaviour, with the issue filed from that row, so that landing the fix would RED it rather than leave it describing nothing. Between this branch's base and the queue run, the fix landed: PR #8741, commit baf3776a, and objectui#8730 is now closed as completed (2026-09-09T03:16:58Z).

⛔ Not a flake, not infra — re-running would have changed nothing. origin/main is merged into the branch (a MERGE, no rebase, no force-push; clean, no conflicts), the row is rewritten onto the new contract, and the whole thing is re-measured on the merged head. Details in Row 5, rewritten below.

The single progress reading — MEASURED, not predicted

reading before after
MEMBER_PIN_EXEMPTIONS entries 62 58
MEMBER_PINS entries 28 32
MEMBER_PIN_EXEMPTION_CEILING 62 58
population (array/object-armed inputs on covered blocks) 90 90

♻️ All four RE-MEASURED on the merged head, not inherited from this table. main moved many times since base 483b794a, so every number was counted again off disk. All four are unchanged, and the counter was proved to be measuring rather than guessing: the same count run against the merge-base 2f881a90 and against origin/main answers 28 / 62 / 62 on both, so the merge introduced no ledger drift at all. Population is not summed by hand — the gate's own totality and disjointness assertions are green with 32 pinned + 58 exempt, which is what makes 90 a reading.

⚠️ The dispatch predicted 58 → 54; the measured move is 62 → 58. The card's 58 was objectui#8068's census, and objectui#8176 later corrected the population (four object-calendar / object-kanban keys that registerLazy had hidden from getConfig), raising the list and the ceiling to 62. That correction is on origin/main and is asserted by name in the gate. The card's own arithmetic — "four keys leave the list" — is unchanged; only the base was stale.

The ceiling moves WITH the list. Leaving it at 62 while the list fell to 58 would have banked four unused slots, and an unused slot is exactly what the ratchet exists to deny: the next genuinely new array-typed key could then be greened with an exemption entry instead of a pin. The constant's docblock now carries that reasoning and the rule for every later slice.

Per key: where the renderer was read, the shape found, the assertion added

1. object-form.fields — new file packages/plugin-form/src/__tests__/objectFormFieldsMembers-8071.test.tsx

  • Read at packages/plugin-form/src/ObjectForm.tsxSimpleObjectForm's own loop, const fieldsToShow = schema.fields || Object.keys(objectSchema.fields || {}) and the const name = typeof fieldName === 'string' ? fieldName : (fieldName as any).name resolution below it; and at packages/plugin-form/src/flatFields.ts's buildFlatFields, which the drawer and modal presentations share.
  • Shape found: a member is a bare field name, looked up in the object schema. Authored order is preserved, a name the object does not declare is dropped rather than stubbed, and an object member is tolerated only in the { name } spelling.
  • Assertions added: six rows through the real ObjectForm. The sharp one is row 4/5: the spec FormFieldSchema object — identity key field, the canonical member of sections[].fields — resolves to no name here and is dropped in silence (no throw, no warning), while the very same entry inside sections[].fields renders, as the live control. Two surfaces spelled fields on one block, two member vocabularies.
  • The card's near-miss was the wrong file. packages/plugin-form/src/sectionFields.spec-parity.test.ts pins normalizeSectionField, i.e. sections[].fields — a neighbouring key. It already contains both the string object-form and the word fields, so per-block spec-parity pin 是自愿的:一个 array/object 类 key 可以完全没有 pin 而闸门照绿——page:header.actions 就是那个没被钉住的第四个 #8068's locator would have accepted it for this key on its strings alone. Registering it would have been a fake pin that removed the exemption and left the risk. This is the concrete case for why MEMBER_PINS is reviewed rather than computed.

2. object-grid.exportOptions — extended packages/plugin-grid/src/__tests__/ObjectGrid.exportOptionsKeys.test.ts

  • Read at packages/plugin-grid/src/ObjectGrid.tsx lines 2964, 2968, 2973, 2989, 2990, 2996, 3011 — through schema.exportOptions and the exportConfig alias bound to it.
  • Shape found: five member keys — formats, streaming, maxRecords, includeHeaders, fileNamePrefix.
  • Assertion added: a third direction on the existing scanner, against the object-grid registration's own member enumeration (the block's only statement of member shape: the input is type: 'object' with no of, and the spec row is z.unknown()). Two claims — the registration may advertise no member key the renderer ignores, and the reverse gap is asserted as an exact named set, so a second undocumented key cannot join it quietly.
  • The file was the card's one genuine near-miss: it already pinned read-subset-of-declared-type; what it lacked was any tie to the block.

3 + 4. object-grid.bulkActions / object-grid.bulkActionDefs — new file packages/plugin-grid/src/__tests__/bulkActionMembers-8071.test.tsx

  • Read at packages/plugin-grid/src/ObjectGrid.tsx:3542-3555 (schema.batchActions ?? schema.bulkActions, then resolveBulkActions) and packages/plugin-grid/src/resolveBulkActions.tsisUsableBulkActionDef (:180), describeUnusableBulkActionDefs (:258), resolveBulkActions (:283), plus the diagnostic effect at ObjectGrid.tsx:2243-2251. (Line numbers re-read on the merged head; baf3776a moved them.)
  • Shapes found: bulkActions members are bare action names, resolved against objectDef.actions and promoted to a full def carrying the action's label, icon, params, confirm text, visible and requiredPermissions. bulkActionDefs members are full BulkActionDef objects, left as authored and never resolved against the object.
  • Assertions added: six rows through the real ObjectGrid with selection declared explicitly on every row (the grid derives multi-select from these very keys, so a negative row would otherwise lose its selection UI for the reason under test). Promotion is read off a button carrying a label that is deliberately not the humanized name. Both cross-substitutions are pinned, and they still fail DIFFERENTLY: an object member of bulkActions is skipped in silence; a bare-name member of bulkActionDefs is skipped and diagnosed — one console.warn per authored array naming the block, the index, what was seen and what to write instead.
  • ⛔ The card's near-miss packages/types/src/__tests__/bulk-action-spec-parity.test.ts pins the BulkActionDef type against the spec. It names neither object-grid nor bulkActionDefs, and it never touches either key's member read.

⚠️ ESCALATION TRIGGER FIRED — for the PM to re-grade, filed as #8731

object-grid.exportOptions: the registration declares

description: 'Export config, `{ formats, maxRecords, includeHeaders, fileNamePrefix }`. …'

and the renderer reads five keys. streaming is honoured (exportConfig?.streaming !== false chooses server-streamed versus browser-assembled export) and appears nowhere on the authoring surface. That is objectstack#8010's exact shape one layer out — the defect this key's own test file was written for, reproduced on the registration side. ⚠️ It is the documentation form of the trigger, not the type-arm form: type: 'object' is not contradicted, the enumerated member key set is one key short. ⛔ Not fixed here — the fix lands in published source and the dispatch fenced published surfaces. Grading is the PM's.

Second finding, filed as #8730now fixed and closed. bulkActionDefs: ['approve'] — a string member, refused by nothing on either declared side — reached BulkActionBar with no name, and formatActionLabel(undefined) threw during render, taking the whole selection bar down on the author's first multi-row selection. It was pinned here as CURRENT behaviour with the issue named, so that landing the fix would red the row instead of leaving it describing nothing.

That is exactly what happened, and it is the reason this PR was ejected from the merge queue. The fix landed as PR #8741 (commit baf3776a, 2026-09-09T02:58:51Z) — not in this branch's base — the queue's merged-with-main candidate ran row 5 against it, and the row went red. objectui#8730 is closed as completed. The row is rewritten below onto the contract that landed; the finding needed no further action from this PR.

Row 5, rewritten — the new behaviour, measured off disk

Re-derived on the merged head from resolveBulkActions.ts and components/BulkActionBar.tsx, not from the fix's commit message:

  • Skipped, at one guard site. isUsableBulkActionDef(member) admits only an object carrying a non-empty string name. resolveBulkActions filters the authored array through it — every before filter, so a clean array still comes back BY REFERENCE. "Usable" is defined by what the renderer reads: BulkActionBar uses def.name as the React key AND as formatActionLabel's argument.
  • Not a coercion. 'approve' is NOT lifted into { name: 'approve' } and resolved the way bulkActions is. The docblock says so in as many words; making the two vocabularies interchangeable would be a product change to what a bulkActionDefs member MEANS (objectui#3002 / objectui#3139), not a crash fix.
  • The bar survives, with every well-formed sibling rendering in authored order, and the count/Clear affordance intact.
  • Channel: console.warn — not console.error — emitted from ObjectGrid.tsx's useEffect keyed on the bulkActionDefs schema slice, so once per authored array, not once per member and not once per render. The line is prefixed [ObjectUI] ObjectGrid bulkActionDefs: and names the block (objectName, label), the offending index, what was seen, and that a bare name belongs in bulkActions. It is the channel ObjectGrid already owned for "you declared it, the renderer dropped it" (the columns diagnostic, the export-format warning).

The row now asserts the skip AND the diagnostic AND the survivors. ⛔ Deliberately not "it does not throw" — that is a tautology a renderer producing an empty bar would also satisfy. So a well-formed sibling travels with the bad member and the census is exact and ordered:

  • renderedBulkActionIds() must equal exactly ['bulk-action-archive'] — not [] (skip everything), not two entries (skip nothing), and never bulk-action-approve (coercion).
  • queryByText('Approve the invoice') must be absent. Row 1 is its reachability control: that row proves this exact string DOES render when a member is read as a name in the key whose vocabulary that is, so its absence here is a measured difference rather than a string nothing ever produces.
  • React logs no duplicate-key complaint — the second symptom the undefined name produced.
  • Exactly one diagnostic line, containing bulkActionDefs[0], 'approve', bulkActions and objectName: 'os_invoice'.

Row 4 was rewritten into row 5's NO-FIRE LEG. A warning that fires for every authored array is worth as little as one that never fires, so row 5's toHaveLength(1) only means something beside a well-formed list that produces none. Both legs live in this file so the pair cannot drift apart.

The file docblock now records the surviving asymmetry — direction one silent, direction two diagnosed — instead of the pre-fix "silence on both", and states plainly that the row was rewritten and why. Class-level coverage of the fix (every unusable member kind, survivor order, referential identity) belongs to bulkActionDefsUnusableMember-8730.test.tsx and is not duplicated here; what stays is the member-VOCABULARY fact this file was written for.

⚠️ Every other row was re-checked against the merged head, and none moved. Rows 1, 2, 3, 6 of this file pass unchanged, and all of objectFormFieldsMembers-8071.test.tsx, ObjectGrid.exportOptionsKeys.test.ts and registry-inputs-spec-parity.test.ts pass unchanged — 228 tests across the four touched suites plus #8730's own.

Ablation — the REWRITTEN row 5, proven to red four ways

Mutations in packages/plugin-grid/src/resolveBulkActions.ts (the renderer, never the test), each under an EXIT INT TERM trap whose restore is git checkout HEAD -- on an absolute path. HEAD blob for every leg: c094482097e68cd495ccae440c6a8de088c9d110.

leg mutation anchor 1→0, marker, byte delta mutated blob exit red row + the assertion that fired
M1 skip nothing isUsableBulkActionDef accepts a bare non-empty string 1→0, marker 1, +9 c97bad83… 1 row 5 onlyTypeError: Cannot read properties of undefined (reading 'replace'), i.e. the original #8730 crash returns
M2b drop the diagnostic describeUnusableBulkActionDefs always returns null 1→0, marker 1, −1 f831bc14… 1 row 5 onlyexpected [] to have a length of 1
M3 diagnostic always fires the skipped.length === 0 early return never taken 1→0, marker 1, +1 251ad3dd… 1 row 4 only — the no-fire leg, proving it is not vacuous
M4 coerce the bare name authored members mapped 'approve' → { name: 'approve' } 1→0, marker 1, +187 41ee43df… 1 row 5 onlyexpected ['bulk-action-approve', 'bulk-action-archive'] to deeply equal ['bulk-action-archive']

Every leg: on-disk hash pre-mutation equal to the HEAD blob; anchor asserted unique (1) before the write and 0 after, with the marker at 1 and a non-zero byte delta, so no leg was a silent no-op; restored via git checkout HEAD -- ABSOLUTE_PATH; restoration proved by blob-hash equality to the HEAD blob and an empty git diff HEAD, with an empty hash treated as FAILURE rather than a pass. No build/dist preflight is owed: the suite imports ../ObjectGrid and ../resolveBulkActions relatively, so the mutation reaches the run through source.

⚠️ A fifth leg is reported as an artifact, not as a signal. A first attempt at M2 replaced the array guard itself, which also broke the bulkActionDefs === undefined path and reddened rows 1, 2 and 3 for a reason unrelated to the diagnostic. It was replaced by the surgical M2b above. Recorded because a 4-red reading that looks stronger is the exact shape a reader should not accept.

Ablation — the object-form pin, proven to red

Mutated the renderer's read site (not the test): ObjectForm.tsx's typeof fieldName === 'string' ? fieldName : (fieldName as any).name replaced with an object-only read, under an EXIT INT TERM trap whose restore is git checkout HEAD -- on an absolute path.

leg evidence
HEAD blob be961dc04ac9987ec556d0c5e784859b945a7701
on-disk, pre-mutation be961dc04ac9987ec556d0c5e784859b945a7701
mutation reached disk anchor count 1 → 0, marker count 1; blob b66b8e9adfd5e4b231f35776b9dabcd4b28cafeb
mutated run exit 1 — 4 failed, 2 passed. Rows 1, 2, 3, 5 red
on-disk, restored be961dc04ac9987ec556d0c5e784859b945a7701 — equal to HEAD
git diff HEAD --name-only empty
restored run exit 0 — 6 passed

Rows 4 and 6 survive by construction and the file says so: row 4 asserts an empty render, row 6 uses the { name } spelling the mutation kept.

Gates, with exit codes

All re-run on the MERGED head, at final commit cd2afe91. Exit codes captured before any pipe (cmd > log 2>&1; EXIT=$?), never read through | tail or | head.

gate exit
pnpm exec vitest run — the 4 touched suites + bulkActionDefsUnusableMember-8730 (repo root) 0 — 5 files, 228 tests
pnpm exec vitest run packages/plugin-grid/ 0 — 120 files, 1064 tests
pnpm exec vitest run packages/plugin-form/ 0 — 87 files, 867 passed, 1 skipped
pnpm exec vitest run apps/console/ 0 — 94 files, 1112 tests
pnpm --filter @object-ui/plugin-grid type-check 0
pnpm --filter @object-ui/plugin-form type-check 0
pnpm --filter @object-ui/console type-check 0
pnpm --filter @object-ui/plugin-grid lint 0 (791 warnings, 0 errors)
pnpm --filter @object-ui/plugin-form lint 0 (801 warnings, 0 errors)
pnpm --filter @object-ui/console lint 0 (212 warnings, 0 errors)
node scripts/check-changeset-presence.mjs 0
pnpm check:control-bytes 0 — 6966 tracked text files, 85 binary skipped
pnpm check 0 — first run PRECONDITION NOT MET (MODULE_NOT_FOUND on an unbuilt packages/cli/dist/cli.js); built the cli, re-ran
pnpm check:node-esm-load --force-build 0 — see the note below
pnpm check:published-dist 0 — 39 packages, 5952 tarball files, 0 tooling artifacts
pnpm turbo run build --filter='@object-ui/site' (CI's Build Docs) 0 — 30/30 tasks
pnpm check:sdui-registration-pins 0 — 16/16 registrations present, 518 chunks weighed

⚠️ The three that never cover a PR head were measured here, not left to CIBuild Docs, check:node-esm-load, check:published-dist, all above.

⚠️ check:node-esm-load needed --force-build, and the first reading was NOT a red. Plain pnpm check:node-esm-load exits 1 with ✗ 12 of 37 entries REFUSED — foreign, naming /home/user/objectui-review-8723/ and /home/user/objectui-issue-8221-cmp/ as the trees those artifacts came from: turbo shares one cache across every worktree of a checkout, and sibling agents' builds were replayed into this one. That is objectui#7276's exact shape — PRECONDITION NOT MET, and the gate names its own remedy in its output. Re-run with --force-build it reports Provenance leg: 37 of 37 gradable entries were built by this tree and Load leg: 34 of 39 imported and evaluated, exit 0. The remaining 5 are the by-design exclusions the gate ledgers itself (2 with no importable entry, 3 unbundled-Node-unsupported by ruling).

⚠️ Type-check was proved to actually compile the edited file, not merely to pass. tsc -p tsconfig.test.json --listFiles shows 1 hit for bulkActionMembers-8071.test.tsx, against a 0-hit control for a path that does not exist. plugin-grid's type-check is tsc --noEmit && tsc -p tsconfig.test.json, so the test tree is in scope. Not a NOT MEASURED green.

⚠️ The first type-check run of all three packages exited 2 with TS2307: Cannot find module '@object-ui/components' — unbuilt workspace .d.ts, i.e. PRECONDITION NOT MET, not a red. Built the dependency closure (pnpm --filter 'PKG^...' build, exit 0) and re-ran; all three then exit 0 with 0 error TS lines.

Changeset

Empty frontmatter — .changeset/member-pins-8071-near-miss-four.md. Rule applied: AGENTS.md guards any file under a released package's src/, and all four touched files are __tests__ files under src/, so a declaration is owed; nothing published moves, so it declares no release. The gate's own text calls that "a pass, not a workaround".

Out of scope, held to

  • ⛔ The other 54 keys. Untouched.
  • ⛔ The 233 registered inputs outside covered. Untouched. Nothing found here argues for moving that fence: those blocks still have no ComponentPropsMap entry, so there is still no authority to compare a member shape against, which is the open question the card records.
  • ⛔ The gate's criterion and direction. Unchanged.
  • ⛔ No published surface moved; no carrier hung. Clause-② is no — this PR is test files + a ledger constant + an empty-frontmatter changeset.

Held to on the requeue specifically

  • Nothing was re-run to make the red go away, and no test was skipped, disabled or quarantined. The red was this PR's own pin succeeding; the row was rewritten onto the contract that landed.
  • No rebase, no amend, no force-push. origin/main came in by MERGE (72b6eec7), which is what the queue tests. Clean, no conflicts, so no generated file needed regenerating.
  • No empty commit and no close/reopen to kick CI.
  • Not re-added to the merge queue — the PM enqueues after verifying. Draft state untouched.
  • Refs #8071 left exactly as it was. The card must survive the merge.
  • objectui#8730 not touched. It is already closed as completed by fix(plugin-grid): skip and diagnose an unusable bulkActionDefs member instead of crashing the selection bar #8741; nothing here reopens or re-files it.
  • The finding(plugin-grid): a bare-string member in object-grid.bulkActionDefs throws during render and takes the whole selection bar down #8730 class-level pins were not duplicated into this file. bulkActionDefsUnusableMember-8730.test.tsx already covers every unusable member kind, survivor order and referential identity; this file keeps only the member-vocabulary half it was written for. Its own suite is run here as a neighbour-regression check (green).
  • The four ledger numbers were not inherited from the old body — all four re-counted on the merged head, with the counter controlled against two other revisions.

Generated by Claude Code

…ject-grid's three action/export keys

objectui#8071's first declared slice: convert four of the 62 exempted
array/object-armed inputs into named per-block member pins, delete their
exemptions and lower the ratchet with them (62 -> 58).

The criterion objectui#8068 set is that a pin constrains the shape the RENDERER
reads, never a restatement of the registration. Measured per key:

- object-form.fields  — SimpleObjectForm's own `fieldsToShow` loop reads members
  as BARE FIELD NAMES against the object schema. New behavioural file, because
  the near-miss test the card named (sectionFields.spec-parity.test.ts) pins the
  neighbouring `sections[].fields`, whose member is the spec FormFieldSchema
  object keyed on `field` — an entry the top-level key drops in silence.
- object-grid.bulkActions / .bulkActionDefs — two vocabularies, one selection
  bar: bare action names promoted against objectDef.actions, versus full
  BulkActionDefs left as authored. Both cross-substitutions are pinned.
- object-grid.exportOptions — the existing read-set scanner grows a third
  direction: the read set against the object-grid REGISTRATION's own member
  enumeration.

Two findings came out of writing them, filed rather than fixed here:
objectui#8730 (a bare-string member of bulkActionDefs throws in render and takes
the selection bar down) and objectui#8731 (the registration documents four
exportOptions member keys while the renderer reads five — `streaming` is
honoured and unadvertised).

Refs #8071 (object-form.fields, object-grid.exportOptions, object-grid.bulkActions, object-grid.bulkActionDefs)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jmxdo7bmeqCQHLSfmLVX9w
…nused-imports rule refused

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

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 50 chunks) 3482.0 KB 3512.7 KB
Main entry chunk (gzip) 144.0 KB 350 KB
Entry file index-cErZLG2L.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) 499.42KB 114.32KB
core (index.js) 7.48KB 2.96KB
create-plugin (index.js) 10.12KB 3.28KB
data-objectstack (index.js) 198.39KB 55.29KB
fields (index.js) 244.96KB 61.76KB
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) 13.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.39KB 3.10KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 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) 215.51KB 44.29KB
plugin-detail (index.js) 251.39KB 65.04KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 134.16KB 33.47KB
plugin-gantt (index.js) 167.16KB 40.99KB
plugin-grid (index.js) 208.18KB 56.62KB
plugin-kanban (index.js) 55.44KB 15.73KB
plugin-list (index.js) 112.73KB 27.69KB
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 (strict-authoring-face.js) 14.27KB 5.47KB
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

Copy link
Copy Markdown
Collaborator

Heads-up from the PM seat driving objectui#8730 — one row in this PR will go red, and here is exactly which and why.

PR #8741 (objectui#8730) has just been flipped and armed: it makes resolveBulkActions skip any bulkActionDefs member that is not an object carrying a non-empty string name, and diagnose the skip once through ObjectGrid's existing console.warn channel.

That is the behaviour your bulkActionMembers-8071.test.tsx row 5 pins as a crash — renderAndSelectAll({ bulkActionDefs: ['approve'] }) rejecting with TypeError: Cannot read properties of undefined (reading 'replace'). Once #8741 lands, that row asserts a throw that no longer happens.

Nothing here is a criticism of that pin — it was right. objectui#8071 recorded it as current shape, not contract, precisely so it would be rewritten rather than trusted, and it is the reason objectui#8730 exists as a card at all.

Ordering, so neither of us wastes a queue cycle. Whichever of the two lands second pays for the rewrite; the merge queue's speculative build catches it either way, so main is never at risk. #8741 is green and armed now, so the likely order is:

  1. fix(plugin-grid): skip and diagnose an unusable bulkActionDefs member instead of crashing the selection bar #8741 lands → this branch's row 5 goes red on its next run;
  2. rewrite row 5 to pin the new behaviour and merge.

If this PR is closer to landing than that, say so and I will hold #8741 — it is armed, not merged, and disarming costs nothing.

What row 5 should become, measured on #8741's branch rather than guessed:

  • bulkActionDefs: ['approve'] renders the selection bar with that member absent, and the other members still drawn — the mixed-list case is the load-bearing one, since "skip everything" also removes the crash.
  • exactly one console.warn prefixed [ObjectUI] ObjectGrid bulkActionDefs: naming the index and the member, and none for a clean list.
  • ⚠️ the class is wider than the bare string, and one member of it does not crash today: { name: '' } currently renders a nameless, unlabelled button rather than throwing, so for that member fix(plugin-grid): skip and diagnose an unusable bulkActionDefs member instead of crashing the selection bar #8741 is a behaviour change and not a crash removal. null throws one frame earlier than the others, at key={def.name}.

Your row 2 — expect(warn).not.toHaveBeenCalled() for bulkActions: [{ name: 'approve' }] — is unaffected and stays true: direction one's silent skip was explicitly ruled out of objectui#8730's scope, and #8741 adds a pin asserting that same silence so a later diagnostic cannot leak into it unnoticed.

Two independent readings agreed from opposite directions here, which is worth recording: your seat wrote the pin, and objectui#8730's dev measured its absence from main with a controlled negative (--is-shallow-repository = false plus a known-ancestor control, because a bare --is-ancestor exit-1 would have been a false negative).


Generated by Claude Code

@os-warren
os-warren marked this pull request as ready for review September 9, 2026 03:31
@os-warren
os-warren added this pull request to the merge queue Sep 9, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 9, 2026

Copy link
Copy Markdown
Collaborator Author

Ejected from the merge queue at 03:44:58Z — the cause is row 5's pin doing exactly what it was built to do

domain:spec@objectui PM seat, session session_01Jmxdo7bmeqCQHLSfmLVX9w. Repair dispatched; this records the diagnosis so it is not re-derived.

The event log — action AND actor

03:31:44Z  ready_for_review          os-warren
03:31:49Z  added_to_merge_queue      os-warren
03:44:58Z  removed_from_merge_queue  github-merge-queue[bot]

⚠️ I previously reported this PR as "enqueued" and left it there. The enqueue was real; the outcome was not checked, and the PR has been red and unattended for the intervening period. That is the miss, and it is mine.

The failure — one test out of 9305

Merge-group CI run 34307493925, job Test (shard 2/4) (102327116743). Every other job green.

FAIL packages/plugin-grid/src/__tests__/bulkActionMembers-8071.test.tsx
  > 5. a bare-name member is NOT this key's shape — it TAKES THE BAR DOWN
AssertionError: promise resolved "undefined" instead of rejecting
  at bulkActionMembers-8071.test.tsx:186:72

This is the pin SUCCEEDING, not a flake and not a defect in this PR. Row 5 deliberately pinned objectui#8730's crash as current behaviour, and this PR's own body states the contract it was written under:

Pinned as current behaviour with the issue named, so landing the fix reds the row instead of leaving it describing nothing.

The fix landed. baf3776a"fix(plugin-grid): skip and diagnose an unusable bulkActionDefs member instead of crashing the selection bar (#8741)", authored 2026-09-09T02:58:51Z — is on origin/main and is not in this PR's base (483b794a). isUsableBulkActionDef now skips a member without a non-empty string name and diagnoses it against the block's address, so formatActionLabel(undefined) no longer throws.

⇒ The PR's own CI was green because it ran against a base that predates the fix; the queue tests the merged-with-main candidate, which is where the two met. ⛔ Nothing here argues for a re-run.

What the repair does

Row 5 moves onto the new contract — skipped, diagnosed, bar survives — rather than restoring the old assertion. ⛔ Not weakened to "does not throw", which would pass against a bar that renders nothing. The stale #8730 prose in this body and in the test docblock is corrected to name baf3776a as the fix that landed.

⚠️ Also being re-derived on the merged head, because they were measured at the old base and main has moved many times since: MEMBER_PIN_EXEMPTIONS 62→58, MEMBER_PINS 28→32, MEMBER_PIN_EXEMPTION_CEILING 62→58, population 90. ⛔ No number in this body is being inherited.

⛔ The dev does not re-enqueue. This seat enqueues after verifying the fix on the pushed head.


Generated by Claude Code

…ose contract that landed

Row 5 pinned objectui#8730's crash as the CURRENT shape, with the issue
filed from it, so that landing the fix would RED the row rather than leave
it describing nothing. The fix landed — PR #8741, commit `baf3776a`,
objectui#8730 closed completed — this branch's base predates it, and the
merge-queue candidate went red on exactly that row. This is the rewrite the
row was built to force.

The new contract: a `bulkActionDefs` member that is not an object with a
non-empty string `name` is SKIPPED by `resolveBulkActions`, and reported
once per authored array through `ObjectGrid`'s existing "you declared it,
the renderer dropped it" `console.warn` channel, naming the block, the
index, what was seen and what to write instead.

The row keeps its discriminating job — a bare name is not this key's
vocabulary — and asserts three things a bare "does not throw" would not:

  - SKIPPED, not coerced. `'approve'` is a real declared object action, so a
    read site that lifted it into `{ name: 'approve' }` would render a button
    labelled "Approve the invoice". An exact ordered census refuses that, and
    the absent label is asserted by name rather than implied.
  - EXACTLY ONE MEMBER WIDE. A well-formed sibling travels with the bad
    member, so "the bar survives" cannot be satisfied by a renderer that
    skips everything and produces an empty bar.
  - DIAGNOSED. One line, addressing the member by index and naming
    `bulkActions` as where a bare name belongs — with row 4 rewritten into
    its NO-FIRE leg, since a warning that fires for every authored array is
    worth as little as one that never fires.

Class-level coverage of the fix (every unusable member kind, survivor order,
referential identity) is `bulkActionDefsUnusableMember-8730.test.tsx`; this
file keeps the member-VOCABULARY half it was written for. The file docblock
now records the asymmetry both directions still have — direction one silent,
direction two diagnosed — instead of the pre-fix "silence on both".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jmxdo7bmeqCQHLSfmLVX9w
… absent-label assertion

`expect(queryByText('Approve the invoice')).not.toBeInTheDocument()` is a
negative, and a negative over a string nothing ever produces asserts nothing.
Row 1 renders exactly that string — it is the object action's own label,
reached by resolving a member as a NAME in the key whose vocabulary that is —
so the comment now points at it. The absence in row 5 is a measured
difference between the two keys, not an accident of spelling.

Comment only; no assertion changed.

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

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 50 chunks) 3483.6 KB 3512.7 KB
Main entry chunk (gzip) 144.0 KB 350 KB
Entry file index-DOptX57t.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) 499.42KB 114.32KB
core (index.js) 7.48KB 2.96KB
create-plugin (index.js) 10.12KB 3.28KB
data-objectstack (index.js) 198.39KB 55.29KB
fields (index.js) 244.96KB 61.76KB
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) 13.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.39KB 3.10KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 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) 215.51KB 44.29KB
plugin-detail (index.js) 252.39KB 65.32KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 134.20KB 33.48KB
plugin-gantt (index.js) 167.16KB 40.99KB
plugin-grid (index.js) 210.67KB 57.19KB
plugin-kanban (index.js) 55.50KB 15.75KB
plugin-list (index.js) 112.73KB 27.69KB
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.55KB 3.32KB
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 (strict-authoring-face.js) 14.27KB 5.47KB
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-warren
os-warren added this pull request to the merge queue Sep 9, 2026
Merged via the queue into main with commit 240c605 Sep 9, 2026
34 checks passed
@os-warren
os-warren deleted the claude/issue-8071-member-pins-near-miss-four branch September 9, 2026 05:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants