Repository navigation
feat(plugin-list,app-shell): read an absent userActions.editInline as on, the v18 spec default (objectui#12086) - #12092
Conversation
… on, the v18 spec default (objectui#12086) ListView's inlineEditOffered and the ADR-0047 interface page now read an absent `userActions.editInline` as on (`!== false`), the consumer half of objectstack#22605. The permission gate and the inlineEdit fold are unchanged. Pins flip to "declares nothing + update grant -> offered", "declares nothing + no update grant -> not offered" and "`editInline: false` -> not offered"; comments and test titles the flip made false are corrected. Claude-Session: https://claude.ai/code/session_01B1gHb9baeX7oioD5sHVm7z Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B1gHb9baeX7oioD5sHVm7z Co-authored-by: Claude <noreply@anthropic.com>
✅ Console Performance Budget
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
Size Limits
|
…ctui#5144 entry (objectui#12086) The pending objectui#5144 changeset stated the absent-key default as off. With objectui#12086 in the same release that is false in net, so its default sentences now read on (objectstack-ai/objectstack#22605), with `editInline: false` as the opt-out, and point to the objectui#12086 entry for the flip. Frontmatter unchanged. This PR's own changeset drops its quote of the old 5144 sentence and says the previous release already offered the toggle for an undeclared view. Claude-Session: https://claude.ai/code/session_01B1gHb9baeX7oioD5sHVm7z Co-authored-by: Claude <noreply@anthropic.com>
✅ Console Performance Budget
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
Size Limits
|
|
✅ Console Performance Budget
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
Size Limits
|
Contract reviewServed-tier: ① Derived judgmentsRead against the card (body and all five comments), the PR body and its 14-file net diff against The default flip — right.
The merge — clean. The head is a merge commit with parents Public surface. One behavioural default flips for every consumer whose list view declares neither Check-runs on the head. 43 runs: 40 success, 3 skipped (two coverage shards and dependabot, the expected skips). ② Semver level
③ Boundary flagsFrom the dev's Deviations (five) — each answered.
Open questions (two) — each answered by the seat, and the answer holds against the code.
Out-of-scope findings (three) — each dispositioned.
Other flags. The two NOT MEASURED local gates ( Implemented-by: VERDICT: PASS Generated by Claude Code |
Fixes #12086
Clause-②: no
The consumer half of objectstack-ai/objectstack#22605 (the v18 default flip, landed as objectstack-ai/objectstack#22629). List views read an absent
userActions.editInlineas on (!== false): a list view is editable in place by default, under the permission gate that already exists, anduserActions: { editInline: false }makes it read-only in place. TheinlineEditfold is unchanged, and so is the gate.What changed
ListView(@object-ui/plugin-list):inlineEditOfferedreturnsfalseonly for an expliciteditInline: false; anything else falls through to the unchangedlistInlineEditaffordance verdict (the object editable in place, and the principal'supdategrant). The Gap 2 docblock now states the v18 default and the opt-out.@object-ui/app-shell,InterfaceListPage):inlineEdit: userActions.editInline !== false, and the "default off" comment is corrected.ListView.permissions.test.tsx: a view that declares nothing is offered the toggle for a principal withupdateand not for one without it (same schema, permission differs); with noPermissionProviderit is offered (fail-open kept); an absenteditInlinereads on and the grid opens out of edit mode; the compact popover offers the entry for an absent key, and its control withholds it foreditInline: false;editInline: falsewithholds the toggle from a fully permitted principal. The storedinlineEdit: truecase (offered, opens in edit mode) is unchanged and still green.InterfaceListPage.editInlineFold-5144.test.tsx: an absent pageeditInline, and a page with nouserActionsblock, now read on on both sides of the fold; an expliciteditInline: falseis the opt-out.normalize-list-view.inlineEditFold-5144.test.ts: the fold's table is unchanged (the fold applies no default); its docblock now says which reader the flip changes.content/docs/plugins/plugin-view.mdx, the "neither key" row of the inline-editing table now reads "offered | no" (opens out of edit mode), and the prose says on by default, witheditInline: falseas the opt-out..changeset/12086-edit-inline-default-on.md,minorfor@object-ui/plugin-listand@object-ui/app-shell, with the behaviour change in the prose.Measured before writing (the PM's three mechanism assumptions)
origin/main.packages/spec/src/ui/view.zod.tsdeclareseditInline: z.boolean().default(true)(read withgit show origin/main:;git merge-base --is-ancestor f53f14bb36 origin/mainanswered exit 0, which self-certifies). The installed@objectstack/spechere is 17.7.0, whose dist still declareseditInline: z.boolean().default(false). Does any objectui code read the installed default? No runtime reader does. The quoted-name grep forUserActionsConfigSchemaand forListViewSchema/ViewSchema.parse(/.safeParse(acrosspackages/*/srcandapps/finds the parse calls only in tests and in twoFormViewSchemareads (positive control: the same grep finds those two). The one test that parses the installed defaults,normalize-list-view.foldOutputAuthorable-5435.test.ts("the ON/OFF default asymmetry"), assertsgroup/hideFields/rowColoronly, noteditInline, so it does not fight the new read. One display-only reader exists: the metadata-admin View inspector derives its JSON Schema from the installedViewSchemawithz.toJSONSchema. It writes nothing, and its boolean switch renders!!valueand ignores a schema default. See Acceptance notes.editInlinereader inpackages/*/srcoutside tests, from the quoted exact-name grep (positive control: the same grep hits the knownListView.tsxandInterfaceListPage.tsxsites):ListViewinlineEditOffered(was!== true);InterfaceListPage(was=== true); thenormalizeListViewSchemafold (typeof === 'boolean', no default); and the@object-ui/plugin-viewObjectViewuserActionsmerge (a spread of three folded layers, no default). The other hits are comments, thedetail.editInline*i18n keys (a different namespace), and the grid's ownuserActionscomments. The assumption holds. TheinlineEditreaders carry the edit MODE (!!schema.inlineEdit, the named-view relay,ObjectGrid'seditable); none reads an absenteditInlineas off.ListView-rendered path. The quoted grep foreditInline,inlineEditanduserActionsoverapps/andexamples/hits 0 (positive control: the same grep findslistViews/object-grid/object-viewthere). The list views that do exist there (examples/byo-backend-console'sobject-viewwith a namedgridview, the schema-catalogobject-view/object-gridentries,apps/console's devobject-grid) render throughObjectGriddirectly, with no hostrenderListView. On that pathObjectGrid'seditablecomes from the view'sinlineEditand never fromeditInline, so this change does not move them.The cloud window (named, as triage directs)
Cloud consumes objectui
mainon its frozen v17 framework. There, a list view that declares neitheruserActions.editInlinenorinlineEditnow offers the inline-edit toggle on the console object page. An ADR-0047 interface page that declares nothing now opens its grid editable in place. Both happen before cloud's spec says the default is on. Both stay under the permission gate: a principal withoutupdateon the object, or an object that is not editable in place, gets neither. This is the maintainer's chosen posture, so no hold is asked for. The cloud apps are not in this container, so whether any cloud view relied on the v17 default for a read-only list was not measured here. The spec card's own measurement names one cloud interface page that already declareseditInline: falseexplicitly. That is a reading carried from objectstack-ai/objectstack#22605, not re-taken here.One mechanism note for the seat (the interface page)
The interface page wires no inline-edit toggle: no
onInlineEditChange, nocompactToolbar. ItsuserActions.editInlinetherefore reachesListViewas the grid's edit MODE (inlineEdit), which the fold also turns into the "offered" key. So with this flip, an interface page that declares nothing does not "gain the toggle". It opens its grid editable in place, for a principal the gate admits. That is what the card's!== falseorders for this site, and it is what the spec's newdescribesays ("a user who may update the object edits a cell in place"). A literal toggle on this page would be a new host wiring and is not done here. It is raised in the report.File surface
Within the claim:
ListView.tsx(inlineEditOfferedand its docblock),InterfaceListPage.tsx(the read and its comment),ListView.permissions.test.tsx,normalize-list-view.inlineEditFold-5144.test.ts, the interface-page tests (InterfaceListPage.editInlineFold-5144.test.tsx, and theinlineEditreason string inInterfaceListPage.relayCensus-11572.test.ts),plugin-view.mdx, and one changeset.In-surface consequences: comments and test titles this flip made false. These are text-only, with no code or assertion change, and they sit outside the claim's file list:
packages/core/src/utils/normalize-list-view.ts: two docblocks said the spec default is.default(false)and thatListViewreads an absent pair as off.packages/app-shell/src/views/ObjectView.tsx: thekeepInlineEditModeForTheSessiondocblock quoted the v17describe("the list is read-only unless the author opts in").packages/app-shell/src/views/ObjectView.inlineEditSessionOnly-5144.test.tsx: one test title said "reads off by the spec default". Its assertion (the fold leaves both keys absent) is unchanged.packages/plugin-list/src/__tests__/ListView.test.tsx: two comments cited the spec's.default(false).packages/plugin-view/src/__tests__/ObjectView.namedViewEditInlineFold-5144.test.tsx: the docblock saidListViewoffers inline editing "only where that readstrue".Nothing is added to a package entry: no prop, export, type member or locale key.
Verification
All runs below are on this branch. Heavy runs went through the shared verify lock, and each line quotes that run's own
VERDICT command-exitline. Test runs use the repo-root formpnpm exec vitest run --maxWorkers=2 PATHS.9cd778d1d(after mergingorigin/mainde302c73): the four touched pin files, the five otherInterfaceListPage*tests,ObjectView.inlineEditSessionOnly-5144, the twonormalize-list-viewfold tests and the plugin-view named-view fold test. Result:Test Files 13 passed (13),Tests 264 passed (264),VERDICT command-exit 0. The same 13 files gave the same counts onefa9e08f1, before the merge.@object-ui/plugin-list, whole package, onefa9e08f1, plus the four app-shellObjectViewtests that render the realListViewwith role-based button queries or import the interface page (kanbanLane-8193,storedOptionsBag-10380,listUrlState-11860,viewWriteRefusal-11583). Result:Test Files 129 passed (129),Tests 1444 passed (1444),VERDICT command-exit 0.ablation-replace.mjs, whose anchor hit x1 and went to x0, and whose blob changed. Each was restored to the HEAD blob withgit diff HEADempty, so the restore was proven on disk.inlineEditOffered(?.editInline !== true).ListView.permissions.test.tsxwent4 failed | 19 passed (23). The four red cases are exactly the predicted ones: offered withupdateon a view that declares nothing; offered with noPermissionProvider; an absenteditInlinereads on; the compact entry is offered for an absent key. "WITHOUT update loses it" stays green under both reads, as expected.inlineEdit: userActions.editInline === trueback on the interface page.InterfaceListPage.editInlineFold-5144.test.tsxwent2 failed | 2 passed (4): the two absent cases.pnpm --filter PKG type-check, which istsc --noEmit && tsc -p tsconfig.test.json), after building the dependency closure withturbo run build --filter=PKG^... --concurrency=2(28 successful, 28 total).@object-ui/core,@object-ui/plugin-list,@object-ui/plugin-viewand@object-ui/app-shellall exit 0 with 0error TSonefa9e08f1.@object-ui/app-shellexits 0 again on9cd778d1d, since main's two merged PRs touched app-shell source..ts/.tsxfiles (--format json, counted from its output): 0 errors. Every file's error/warning count is identical to its base-blob count (lint run overgit show 023f00d46:FILEvia--stdin). The repo'seslint.config.jssets noparserOptions/projectService, so linting is not type-aware, and this diff cannot move a verdict on an untouched file.9cd778d1d:check:new-line-citations(0 new citation(s)),check:control-bytes,check-changeset-presence,changeset:check(nomajor),check-changeset-overwrite,check:changeset-claims,check:pending-changeset-literals,check:doc-fences,check:doc-typesandcheck-doc-links. All exit 0. The fourvi.mock/ test-path gates exit 0 onefa9e08f1.check:doc-snippetsandcheck:doc-examples. Reason: exit 2, PREREQUISITE NOT MET. Both need a scoped build of more packages than this run built (app-shell,cli,plugin-ai… unbuilt). Their input is unchanged by this diff, measured instead. The fenced blocks ofplugin-view.mdxextracted at base and at head are byte-identical (md53fd26d2a…both, 18 blocks). The diff touches 0 lines carrying@exampleor a fence inpackages/*/src. Control:ListView.tsxcarries one@example, which is untouched.@object-ui/app-shell's full suite was not run locally; CI runs it. The local app-shell set is every test that importsInterfaceListPage, the session-only toggle pin, and theObjectViewtests above. This is a declared narrowing, not a proof that nothing else in app-shell observes the toggle.Acceptance notes
Observations only. Not filed, and not changed here.
Metadata-admin View inspector shows default-true booleans as off.
SchemaForm's boolean branch renderschecked={!!value}and ignores the JSON Schemadefault. So in the View inspector, an absentuserActions.search/sort/filter(defaulttrue) already shows OFF while the toolbar reads it ON.userActions.editInlinejoins that set once objectui installs a spec 18 build. The installed 17.x schema still saysdefault: false, so the switch shows off either way, and after this PR the list reads on. This was read from source; no public door was exercised, so it is not filed. Carrier: none.The direct
ObjectGridpath does not readeditInline. On an authoredobject-viewwith a namedgridview and no hostrenderListView,ObjectGrid'seditableis the named view'sinlineEdit(ortable.editable).userActions.editInlineis not read there. SoeditInline: falsedoes not withhold edit mode from a named view that also saysinlineEdit: true, and a view with neither key has no toggle to enter edit mode. This predates and is unchanged by this PR. No named producer declares both keys on such a view, so it is not filed. Carrier: none.The pending objectui#5144 changeset — corrected in this PR (patch round, the seat's answer B; written into this body by the seat,
domain:uiseat 3)..changeset/5144-editinline-fold.mdis unreleased, and in net it stated the opposite default to this release. This PR's change made it false, so it is corrected here. Its frontmatter is byte-identical (same bump declarations). Before → after:userActions.editInlinewith the spec's default, off." → "… with the spec's default, on since spec:ListView.userActions.editInlinedefaults to true in v18 andeditInline: falseis the opt-out; objectui reads an absent key as on (maintainer ruling 2026-10-10, after objectui#5144) objectstack#22605 (editInline: z.boolean().default(true)), andeditInline: falseis the opt-out."userActions.editInlinewith.default(false): the list is read-only unless the author opts in." → "… with.default(true)(spec:ListView.userActions.editInlinedefaults to true in v18 andeditInline: falseis the opt-out; objectui reads an absent key as on (maintainer ruling 2026-10-10, after objectui#5144) objectstack#22605): a list view is editable in place by default, under the permission gate, andeditInline: falseis the opt-out."userActions.editInline: true. The toggle then stays offered whatever the user does with it." → "What to do. A list whose records are read-only by nature declaresuserActions.editInline: false. A view that declaresuserActions.editInline: truekeeps the toggle offered whatever the user does with it."Unchanged: the other fold bullets, the session-only toggle, the named-view precedence, the two costs and the no-export line. This PR's own
.changeset/12086-edit-inline-default-on.mdwas corrected in the same round, because its quote of the deleted 5144 sentence became false. It now says the previous release (17.7.0) also offered the toggle for an undeclared view, measured from the parent of objectui#12036, and the interface-page heading carries the behaviour change.Generated by Claude Code