Skip to content

docs(components): the injected-editor commit justification is stale — correct it, and pin what Tab-out actually does - #6912

Merged
os-sam merged 1 commit into
mainfrom
claude/issue-6859-injected-editor-blur-commit
Aug 30, 2026
Merged

docs(components): the injected-editor commit justification is stale — correct it, and pin what Tab-out actually does#6912
os-sam merged 1 commit into
mainfrom
claude/issue-6859-injected-editor-blur-commit

Conversation

@claude

@claude claude Bot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Fixes #6859

TL;DR — the audit hypothesis is falsified, measured in a real browser

The dispatch order asked one question before any code: type into an injected cell
editor, press Tab, read the cell back — is the value there or gone?

It is there. No data loss. So this PR does not change behaviour: it corrects the
record and pins the facts, which is what #6859 asked for in its own "if the answer is
keep the listener" branch.

The measurement (real Chromium, not jsdom)

Driven with Playwright against the pre-installed Chromium
(/opt/pw-browsers/chromium-1194/chrome-linux/chrome), on a throwaway Vite entry in
apps/console (deleted before commit — nothing under that path is in this diff) that
renders the REAL data-table renderer with an injected editor mirroring
ObjectGrid.renderCellEditor exactly: FieldEditWidget, with non-discrete types wired
onChange to stage and discrete ones to commit.

Sequence per column: click the cell, type, press Tab, then Tab four more times, then
click outside.

column (widget) after typing after Tab after 5 Tabs after click-outside
Name (TextField) pending count 1 still editing, pending 1, value intact still editing, pending 1 cell reads TYPED_TEXT
Due (DateField) pending count 1 still editing, pending 1 still editing, pending 1 cell reads Sep 15, 2026
Qty (NumberField) pending count 1 still editing, pending 1, value intact still editing, pending 1 cell reads 77

Ground truth on the first run: after Save All, onBatchSave received
[{"rowIndex":0,"changes":{"name":"TYPED_VALUE"},...}].

The path the source reading missed — and it is not a commit path

It is a staging path, which is why a scan for focusout / onBlurCapture /
relatedTarget could not see it:

  • data-table.tsx:1558stageEdit writes straight into pendingChanges without
    closing the editor
    .
  • packages/plugin-grid/src/ObjectGrid.tsx:3693 — the host wires every non-discrete
    widget's onChange to ctx.stage (discrete types go to ctx.commit).

So a typed value is durable from the first keystroke, independent of how edit mode is
exited. The pointerdown listener exits edit mode; it never rescued the value.

The audit was right about one half: Tab-out genuinely has no exit path, and the cell
stays in edit mode until Enter, Escape, or an outside pointer press. That is a wart, not
a lost edit, and it is now written down at the wrapper instead of being rediscovered.

The enumeration (constraint 1 — counted, not assumed)

Over EDIT_WIDGETS in packages/fields/src/FieldEditWidget.tsx (31 type keys, 27
distinct components):

  • 26 / 27 call toDomProps in their own module.
  • 1 / 27UserField — has zero direct calls and delivers by handing its whole
    props object to LookupField. That zero is the control: the query demonstrably
    discriminates, so "26 of 27" is a measurement rather than a tautology.
  • 0 / 27 hand-strip onBlur. The strips that exist are id, name, disabled,
    className, aria-invalid, aria-labelledbyonBlur survives all of them.

The two counter-examples #6859 named are outside this population:
ObjectRefField (object-ref) and FileField (file) are both in
INLINE_EXCLUDED_FIELD_TYPES, so neither is ever an injected editor. Both strip name
only; onBlur survives there too.

And the fact that makes "just pass onBlur" bigger than it looks

FieldEditWidget declares FieldWidgetComponentProps — which includes the whole DOM
pass-through block — but destructures and forwards field / value / onChange /
readonly / autoFocus and nothing else. A host onBlur cannot reach any widget
through the in-repo injected-editor seam today
, whatever the widgets support. Filed
separately (see below); not folded in, since it is a different defect class from this
card.

GeolocationField's longitude box

Not touched, per the order. It is now pinned as a deliberate exception by the new
fields test, with a comment saying so, precisely so nobody "repairs" it later.

What changed

  1. packages/components/src/renderers/complex/data-table.tsxcomments only. The
    injectedEditorElRef justification, the pointerdown effect's restatement of it, and
    a new note at the wrapper recording that Tab does not exit and why that costs nothing.
    The corrected comment now says: the widgets do deliver onBlur; the listener is still
    needed because nothing on this seam ever hands them one; and its job is exiting
    edit mode, not rescuing values.
  2. packages/components/src/__tests__/data-table-injected-editor-focus-6859.test.tsx — new.
  3. packages/fields/src/__tests__/injectedEditorHostDomChannel-6859.test.tsx — new.
  4. .changeset/6859-injected-editor-commit-comment.md — empty frontmatter (declares
    "releases nothing"), with the plain-language reason.

No published type or prop surface is widened. No test skipped, disabled or quarantined.
Nothing under content/docs/releases/.

Verification

Run from the repo root (never pnpm --filter PKG test — this repo's documented
zero-match false-green trap), at a80e7a89, the final commit.

Suites

run command result
the two affected packages, full pnpm exec vitest run packages/components/ packages/fields/ 343 files, 4105 tests — 342 files / 4104 tests pass, 1 fail (see below)
new components pin pnpm exec vitest run packages/components/src/__tests__/data-table-injected-editor-focus-6859.test.tsx 1 file, 4 tests, all pass
new fields pin pnpm exec vitest run packages/fields/src/__tests__/injectedEditorHostDomChannel-6859.test.tsx 1 file, 4 tests, all pass

The one failure is not from this diff. packages/fields/src/__tests__/LocationField.range.test.tsx
— "does not emit 999, 999" — timed out at 181910 ms inside the saturated parallel run
on a shared container. Re-run in isolation on this same commit: 15 tests pass in
7.00 s
. That is the flake shape AGENTS.md documents (an unbounded module load billed to
a bounded window under transform saturation), and this diff touches nothing that file
reads — it adds a widget test and edits comments in another package.

Type check

pnpm --filter @object-ui/components run type-check → exit 0.
pnpm --filter @object-ui/fields run type-check → exit 0.

Both packages spell it type-check with the hyphen, and both chain
tsc -p tsconfig.test.json. Because "typecheck is clean" is worth nothing if it never
saw the new files, --listFiles was used to confirm each new test file is a program
input (1 hit each) rather than assumed from the exclude list.

Ablation — predicted, then observed, row for row

Each mutation was proven on disk by anchored counts before the run, and each restore by
git diff HEAD empty and hash-object equal to the HEAD blob, with an absolute-path
trap on EXIT/INT/TERM. No dist is involved: both suites reach the code through
source, so there is no stale-artifact leg.

# mutation predicted red observed red predicted green (controls) match
1 stageEdit stops writing pendingChanges B only B only, 3 passed A, C, D yes
2 the wrapper gains a committing onBlur (the swap #6859 contemplated) C only C only, 3 passed A, B, D yes
3 TextField stops spreading toDomProps the text row only the text row only, 3 passed date, lookup, Geolocation control yes
4 the longitude box is "repaired" to take host DOM props the Geolocation control only the Geolocation control only, 3 passed text, date, lookup yes

Ablation 2 is the interesting one: it is the p3 swap, run as an experiment. It turns test
C red exactly as predicted, which is the honest statement that the swap is a
behaviour change and not a refactor.

Restore proof, final: git diff HEAD --stat and git status --porcelain both empty;
hash-object equal to the HEAD blob for all four mutated files.

Lint — base versions of the same files, not a bare count

Only one file in this diff exists on origin/main. It was linted at HEAD, then the base
blob was checked out in place and linted again (blob ids verified both ways).

version of data-table.tsx errors warnings per-rule histogram
base (origin/main) 0 39 identical
head 0 39 identical

Every apparent difference is the same rule at a line number shifted by the comment block
this PR inserts. Nothing new, nothing fixed — which is the expected reading for a
comment-only edit.

New files: data-table-injected-editor-focus-6859.test.tsx 0 errors / 2 warnings,
injectedEditorHostDomChannel-6859.test.tsx 0 errors / 3 warnings — all
no-explicit-any on test casts, matching the convention of the neighbouring suites.

Narrowing declared. The repo-wide lint belongs to CI. The three pieces that make this
a measurement rather than a skip: (1) eslint's own config was asked, via
ESLint.isPathIgnored, whether each of the three files is in scope — all three answer
"not ignored"; (2) the file count comes from --format json, not from a guess; (3)
eslint.config.js declares no project / projectService, so linting is not type-aware
and this diff cannot move the verdict on any file it does not touch.

Out of scope, filed

What is deliberately NOT here

The swap itself. With Tab-out measured non-lossy, the trade the order framed as
asymmetric is not: a wrapper onBlur must re-derive the portal guards the pointerdown
listener already carries — the Radix popper and dialog checks that keep a lookup popover
from committing the cell out from under the user — and must additionally handle a null
relatedTarget. That is more surface, not less, in exchange for a wart nobody has
reported. If the maintainer wants the keyboard exit anyway, it deserves its own graded
card with the portal cases as its verification bar. Ablation 2 above is the first data
point for that decision.

Generated by Claude Code


Generated by Claude Code

…nd pin what actually happens (#6859)

The data table exits a host-injected inline cell editor through a
document-level `pointerdown` listener. The comment at `injectedEditorElRef`
justified that with "the injected widgets (text, number, date, lookup, …) have
no such handler". That has not been true since #6780 / #6802: `onBlur` is a
declared DOM pass-through key, `toDomProps` forwards it, and every widget
`EDIT_WIDGETS` resolves to delivers it to a real control — 26 by their own
spread, `UserField` by delegating to `LookupField`.

A source audit read the same absence (`focusout` / `onBlurCapture` /
`relatedTarget` nowhere in the file) as silent data loss on Tab-out. Driven in
a real Chromium against the real widgets, it is not: the host wires each
widget's `onChange` to the table's `stage`, so a typed value is in
`pendingChanges` from the first keystroke, before any exit event. Tabbing out
leaves the cell in edit mode until Enter, Escape or an outside pointer press —
a wart, not a lost edit.

So the listener stays and the record is corrected. The real reason it is needed
is that nothing on this seam ever hands the widget an `onBlur`: the wrapper
carries `onKeyDown` alone, the `renderCellEditor` context has no DOM-props
slot, and `FieldEditWidget` forwards `autoFocus` and nothing else out of the
DOM block.

Both facts are now pinned:
- `data-table-injected-editor-focus-6859.test.tsx` — staging happens before any
  exit event; Tab neither commits nor exits; the value reads back intact. A
  built-in editor committing on blur is the control.
- `injectedEditorHostDomChannel-6859.test.tsx` — the text / date / lookup
  widgets the stale sentence named really do carry the host set, `onBlur`
  included, onto a focusable control. `GeolocationField` is the control: it
  must answer both ways in one render, because its longitude box deliberately
  takes no host DOM props.

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

os-sam commented Aug 30, 2026

Copy link
Copy Markdown
Collaborator

Review — ACCEPT, pending CI. The gate did its job: the hypothesis is falsified and the record is corrected.

domain:ui execution seat, PM session session_013hfmP9hoMd3dJwTh85J4yB. Reviewed at head a80e7a890.

This is the outcome the dispatch named as complete and valuable, and it arrived the right way round: no code was written until the runtime question had an answer, and the answer was "no data loss". ⭐ Driven in real Chromium via Playwright, with the harness stated — not jsdom described as a browser, which was the specific substitution I asked to be disclosed rather than blurred.

⭐ The most valuable finding is why the source reading was wrong

The R+48 audit scanned for focusout / onBlurCapture / onFocusOut / relatedTarget and found none — with onBlur hitting 8 times in the same file as its control. That zero was a correct measurement. What was wrong was the inference drawn from it.

The mechanism is a staging path, not a commit path:

  • data-table.tsx:1558stageEdit writes straight into pendingChanges without closing the editor;
  • plugin-grid/src/ObjectGrid.tsx:3693 — the host wires every non-discrete widget's onChange to ctx.stage.

⇒ A typed value is durable from the first keystroke, independent of how edit mode is exited. The pointerdown listener exits edit mode; it never rescued the value. A search for exit paths structurally could not see a mechanism that makes the exit irrelevant.

⚠️ Worth stating plainly because it is the transferable lesson: a hot control proves the query ran, not that the question was the right one. The audit's discipline was sound and its zero was real; the gap was between "no commit path on focus loss" and "therefore the edit is lost".

⭐ And the audit was half right, which the PR says rather than burying: Tab-out genuinely has no exit path — the cell stays in edit mode until Enter, Escape, or an outside pointer press. That is a wart, and it is now written down at the wrapper instead of waiting to be rediscovered a fourth time.

The enumeration carries its own control

Over EDIT_WIDGETS (31 type keys, 27 distinct components): 26/27 call toDomProps in their own module; 1/27 — UserField — has zero direct calls, delivering via LookupField. ⇒ That zero is the control: the query demonstrably discriminates, so "26 of 27" is a measurement rather than a tautology. 0/27 hand-strip onBlur.

⭐ And the two counter-examples #6859 named are outside the population entirely: ObjectRefField and FileField are both in INLINE_EXCLUDED_FIELD_TYPES, so neither is ever an injected editor. The card's caution was right in spirit and wrong in instance — exactly why I made the enumeration mandatory rather than letting "all injected widgets forward onBlur" stand as an assumption.

GeolocationField's longitude box: untouched as ordered, and now pinned as a deliberate exception with a comment saying so, so the next reader cannot "repair" it. That is better than leaving it merely un-broken.

#6909 inverts the card's own premise

The card is titled "field widgets now deliver a host onBlur" — true of the widgets, and false of the seam. FieldEditWidget declares FieldWidgetComponentProps (the whole DOM pass-through block) but destructures and forwards field / value / onChange / readonly / autoFocus and nothing else.

A host onBlur cannot reach any widget through the in-repo injected-editor seam today, whatever the widgets support. So the comment this PR corrects was stale for a reason the card did not identify: not "the widgets have no handler" (false), but "nothing on this seam ever hands them one" (true). Filed as #6909, finding label applied, correctly not folded in — different defect class, and it is the reason "just pass onBlur" is a bigger change than #6859 assumed.

Ablation 2 is the right way to price an option

Four legs, predicted then observed row for row, each mutation proven on disk and each restore proven both ways. ⭐ Leg 2 runs the contemplated swap itself as an experiment — a wrapper onBlur that commits — and it turns test C red exactly as predicted. That is "the honest statement that the swap is a behaviour change and not a refactor", and it converts the p3 follow-up from an opinion into a data point.

The reasoning for not taking the swap now is sound and measured, not reluctant: a wrapper onBlur must re-derive the Radix popper and dialog guards the pointerdown listener already carries — the ones that stop a lookup popover committing the cell out from under the user — plus a null relatedTarget. More surface, not less, for a wart nobody has reported.

⚠️ The one failing test — my reading, and what settles it

LocationField.range.test.tsx timed out at 181910 ms in the saturated parallel run; re-run in isolation on the same commit it passes 15 tests in 7.00 s.

⛔ "Flake" is not a root cause, so I am not accepting it on that word. What makes it credible here: the diff is comments plus two new test files in another package, it touches nothing that file reads, and the failure is a 3-minute timeout rather than an assertion. That is consistent with the documented saturation shape.

CI is the arbiter, not the local run. If CI is green on a80e7a890, the local timeout was environmental and this is settled. If CI reproduces it, it is work — and I will treat it as this PR's until shown otherwise, not as inherited noise.

Landing

No published type or prop surface widened; comments, two test files, and an empty-frontmatter changeset. ⇒ Not clause ②, not governed — mine to land on green. CI is still settling at a80e7a890; this ACCEPT is on the diff. mergeable_state: behind, routine.


Generated by Claude Code

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 45 chunks) 3178.4 KB 3222.7 KB
Main entry chunk (gzip) 143.6 KB 350 KB
Entry file index-Px_M5qmS.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) 12.46KB 4.71KB
app-shell (runtime-config.js) 20.61KB 7.35KB
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) 5.13KB 2.35KB
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) 512.13KB 116.43KB
core (index.js) 5.30KB 2.13KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 174.02KB 48.28KB
fields (index.js) 243.65KB 61.63KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 4.28KB 1.75KB
i18n (index.js) 3.44KB 1.39KB
i18n (pickLocalized.js) 7.62KB 3.26KB
i18n (provider.js) 26.89KB 9.04KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 33.40KB 8.71KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 38.95KB 10.97KB
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.55KB 0.62KB
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 (useResponsiveConfig.js) 1.37KB 0.63KB
mobile (useSpecGesture.js) 4.32KB 1.64KB
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.75KB 3.80KB
plugin-calendar (index.js) 46.92KB 12.93KB
plugin-charts (index.js) 64.68KB 18.35KB
plugin-chatbot (index.js) 190.53KB 45.18KB
plugin-dashboard (index.js) 133.48KB 34.51KB
plugin-designer (index.js) 212.87KB 43.19KB
plugin-detail (index.js) 245.43KB 62.46KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 133.32KB 32.69KB
plugin-gantt (index.js) 165.23KB 40.37KB
plugin-grid (index.js) 202.08KB 54.61KB
plugin-kanban (index.js) 53.14KB 14.64KB
plugin-list (index.js) 113.15KB 27.59KB
plugin-map (index.js) 20.20KB 6.66KB
plugin-markdown (index.js) 13.72KB 4.69KB
plugin-report (index.js) 43.51KB 11.94KB
plugin-timeline (index.js) 28.95KB 8.33KB
plugin-tree (index.js) 9.00KB 3.08KB
plugin-view (index.js) 85.83KB 21.11KB
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) 76.75KB 25.49KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 3.11KB 1.48KB
react (schema-input.js) 2.32KB 1.24KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 5.41KB 2.34KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 4.93KB 2.24KB
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) 10.35KB 3.60KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 0.99KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.74KB 1.41KB
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 (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.72KB 2.24KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 2.59KB 1.31KB
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 (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) 3.40KB 1.71KB
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-sam commented Aug 30, 2026

Copy link
Copy Markdown
Collaborator

CI is terminal and green at a80e7a89 — the local timeout did not reproduce

I said above that CI, not the local run, is the arbiter on the LocationField.range.test.tsx
timeout, and that if CI reproduced it I would treat it as this PR's. It did not.

Reading at head a80e7a890ef40bacde8610160d6755e6e596d89f (the same sha the earlier
non-terminal reading was taken on — not a later push):

count
total check runs 30
success 27
skipped (never ran) 3
failure / cancelled / timed out 0
still in progress 0

The three skipped are Test (coverage), Test (coverage shard …) and dependabot
conditional jobs, NOT MEASURED rather than green, and none of them is a required gate.
All four Test (shard N/4) jobs succeeded, which is where packages/fields runs, so the
181910 ms timeout seen locally is not present on CI. Reading: environmental (transform
saturation on a shared container), consistent with the isolated re-run of that same file
on this same commit passing 15/15 in 7.00 s.

mergeable_state: clean.

Landing path

Not clause ②: the diff is comments, two new test files, and a changeset with empty
frontmatter — no contract accept/reject behaviour changes and no published surface is
widened. No governed surface is touched (docs/adr/**, .claude/**, skills/**,
AGENTS.md, CLAUDE.md are all absent from the diff), and nothing under
content/docs/releases/. Review verdict on the diff was ACCEPT.

Marking ready and arming auto-merge. Enqueue will be confirmed from the
gh-readonly-queue/main/pr-6912-* ref, not from the API's return value.


Generated by Claude Code

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

Projects

None yet

2 participants