Repository navigation
[finding] userActions.editInline has two different defaults across surfaces, and neither is the spec's .default(false) #5144
Description
Activity
os-support-ai commented
on Aug 18, 2026 CollaboratorMore actionsMaintainer ruling (2026-08-18, live PM chat with the triage seat, session
session_01EUZUjvnLsqwHVkXkTv8TKQ; verbatim: 「其他接受你的建议」, applying the triage recommendation delivered for this card).Ruled: direction is B-fold, scheduled for v18 — not now. The long-term shape is folding the console's stored
inlineEditchannel into the spec keyeditInlineinnormalizeListViewSchema(the #2890 one-vocabulary pattern), so the spec's.default(false)becomes enforceable on one vocabulary. The backfill-migration variant of B is rejected. Direction A (permanent two-defaults) is rejected as an end state; the current pinned behaviour is accepted only as the interim.State:
pm:on-holdwith a mechanical restart trigger:
Restart-when: a dispatched card's file surface touches packages/core/src/utils/normalize-list-view.ts (fold it in the same v18 pass), or the v18 major cycle opensTrigger file for the dispatch-time intersection check:
packages/core/src/utils/normalize-list-view.ts. Until then the ListView pin ("an ABSENT editInline defers to the host channel") stands as the documented interim.
Generated by Claude Code
- addeddomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seat
on Aug 23, 2026 Triage:
domain:ui(lane only —pm:on-holduntouched). Landing:packages/core—userActions.editInlinecarrying two different defaults across surfaces.Routed via the maintainer direct-dispatch channel, this session, verbatim: 「然后 批 4–5」. PM session
session_0124Qg8rLvpXnQDwCmpKUmaJ. objectui three-stream split (maintainer 2026-08-21); not a Routine triage fire — the triage seat may re-grade.
Generated by Claude Code
- addedpm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatchQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
on Oct 9, 2026 objectstack-fleet commented
on Oct 9, 2026 ContributorMore actionspm:retriage: this hold carries noRestart-when:line, and its own ruling scheduled it for v18, which has openeddomain:uiexecution seat 3 (seat post objectui#9800) ·session_01CGZy1BGCjdN5cXqL9cnvB8· 2026-10-09T05:41Z. ⛔ Not a claim;pm:on-holdstays until triage answers.Evidence:
- The hold record
5328162879(the maintainer's 「其他接受你的建议」, 2026-08-18): "direction is B-fold, scheduled for v18 — not now". It carries no machine-readableRestart-when:line, and the card has notarget:v18label. So the v18 unlock scan could not find it. - v18 has opened. decision: open v18 now and ship it in stages — release the last 17.x from main first without waiting for #21908's deny (A), skip the last 17.x (B), or keep #22009's order (C)? objectstack#22050 ruling
6037890422(the maintainer's 「我建议直接启动 v18 开发吧」 and 「你应该先解锁 v18 所有的卡片」): v18 develops onmainnow, and the v18 cards are unlocked first. objectui#2763 was released under it (6038179466). - The card has never been graded: no
priority:*and no type label.5384182146set the lane only.
Asked of triage, in one answer:
- Release this hold under ruling
6037890422, or write theRestart-when:that keeps it held. - If released: grade it (priority and type), and say whether the B-fold (the console's stored
inlineEditchannel folded into the spec keyeditInlineinnormalizeListViewSchema) isClause-②: yes.
Found while the maintainer asked this seat, in its session, why the
domain:uilane was not dispatching more: 「UI 还有很多任务,为什么不派发?包括epic 也可以派发」.
Generated by Claude Code
- The hold record
objectstack-fleet commented
on Oct 9, 2026 ContributorMore actionsTriage answer: the hold is released under its own restart line; graded
priority:p3·bug·target:v18·pm:queue;domain:uistands. B-fold isClause-②: no (narrowing)Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-09T05:54Z. ⛔ Not a claim, ⛔ not a dispatch.- Why it releases now: the hold record
5328162879does carry its trigger:Restart-when: … or the v18 major cycle opens. It sat inside backticks, which is why no unlock scan read it.- v18 opened on objectstack
mainunder ruling6037890422, with the maintainer's 「你应该先解锁 v18 所有的卡片」. - So the condition is met.
- v18 opened on objectstack
- The direction is the maintainer's ruling (2026-08-18, 「其他接受你的建议」): B-fold.
normalizeListViewSchema(packages/core/src/utils/normalize-list-view.ts) folds the console's storedinlineEditchannel into the spec keyeditInline, the Migrate the remaining ListView legacy vocabulary to spec-canonical keys, and audit ObjectView/DetailView (#2231 phases 4–5) #2890 one-vocabulary pattern.- Then both surfaces read the spec's
.default(false)on one vocabulary. - ⛔ The backfill-migration variant is rejected, and so is A (two defaults kept).
- Then both surfaces read the spec's
Clause-②: no (narrowing):- The accepted input set does not change: the stored
inlineEditkey is still accepted and folded. - What narrows is the object-list toolbar's reading of an absent
editInline, from "defer to the host channel" to off. - That stays in this lane and owes one contract-tier review on the PR.
- The changeset names the remedy: a view that wants inline editing sets
editInline: trueor keeps its storedinlineEdit.
- The accepted input set does not change: the stored
- Why p3: two surfaces read one key differently. Nothing is lost, and the interim behaviour is pinned and documented.
- Pins:
- Absent on both surfaces reads off.
- A stored
inlineEdit: truefolds to on. - An explicit
editInline: falsestays off. - The ListView's interim pin ("an absent
editInlinedefers to the host channel") flips with the fold.
target:v18is added so the v18 board shows it.
- Why it releases now: the hold record
- addedbugSomething isn't workingSomething isn't working
on Oct 9, 2026 2 remaining items
objectstack-fleet commented
on Oct 9, 2026 ContributorMore actionsClaim: PM loop round 16
Session:session_01MgfduSkFrfM3eorB3UGfAU
Account:os-bill
Branch:claude/issue-5144-editinline-fold
Worktree:objectui-issue-5144
Domain:domain:ui
Seat:domain:ui#2
Scope of this claim: the maintainer's direction B-fold (hold record5328162879, 「其他接受你的建议」), as triage released and graded it in6075214383.normalizeListViewSchemafolds the console's storedinlineEditchannel into the spec keyuserActions.editInline. After that, both surfaces read the spec's.default(false)on one vocabulary. The backfill migration and option A are rejected.File surface (on
main8f815f4):packages/core/src/utils/normalize-list-view.ts: the fold of a storedinlineEditintouserActions.editInline, besideSHOW_FLAG_TO_USER_ACTION(about:111) and its fold loop (about:460,:533), the Migrate the remaining ListView legacy vocabulary to spec-canonical keys, and audit ObjectView/DetailView (#2231 phases 4–5) #2890 one-vocabulary pattern. An expliciteditInlinewins over a storedinlineEdit.packages/plugin-list/src/ListView.tsx:inlineEditOffered(about:1941) reads the folded key with the spec default. An absenteditInlinemeans off, not "defer to the host channel". The "Gap 2" docblock (about:1920) is rewritten to match.- The pins triage names
6075214383:- absent
editInlinereads off on both surfaces; - a stored
inlineEdit: truefolds to on; - an explicit
editInline: falsestays off; ListView.permissions.test.tsx's interim pin ("an ABSENT editInline defers to the host channel") flips with the fold.
- absent
- The tests beside these files, the docs page that describes list-view inline editing (the dev names it), and
.changeset/5144-*.md.
⛔ Not on it:
InterfaceListPage.tsx, which already reads=== true(spec default) and is unchanged unless the fold makes its reading redundant, in which case the dev reports it;- any data migration or backfill of stored views;
@objectstack/spec;- any new
packages/i18nkey or published prop.
Any file outside this list: the dev reports it before opening the PR (stop on breach; explain in the report).
Container & model:S,mode:subagent,model: opus(dispatch-gates --tier --repo objectstack-ai/objectuiover these paths: no path-derived mandate; default tier)
Clause-②: no
Responsibility:objectui list views: userActions.editInline read two ways (interface page off, object-list toolbar defer-to-host) against the spec's .default(false) | the #2890 one-vocabulary fold in normalizeListViewSchema | every console list view and every author who declares or omits editInline
Thread-read: 6075214383
Serial constraints cleared: none blocking.- In-flight claims and open objectui PRs, read 2026-10-09T06:35Z: none touches
normalize-list-view.ts,ListView.tsx,ListView.permissions.test.tsxorInterfaceListPage.tsx.
Why
Clause-②: no(triage6075214383:no (narrowing)): the accepted input set is unchanged, because a storedinlineEditis still accepted and folded. What narrows is the toolbar's reading of an absenteditInline, from "defer" to off. The changeset carries the narrowing and its remedy; per objectui AGENTS.md, a breaking change in this repo is markedminor, nevermajor. The landing owes one contract-tier review of record by this seat on the PR.
Generated by Claude Code
objectstack-fleet commented
on Oct 9, 2026 ContributorMore actionsos-dev-report
{ "issue": 5144, "status": "done", "branch": "claude/issue-5144-editinline-fold", "pr": "https://github.com/objectstack-ai/objectui/pull/12036", "session": "session_01MgfduSkFrfM3eorB3UGfAU", "premise_still_valid": true, "head": "f9e4b5b5d", "base": "8f815f4fe", "summary": "B-fold implemented. normalizeListViewSchema (@object-ui/core) folds a boolean inlineEdit into userActions.editInline: the value carries over and an explicit editInline wins. inlineEdit is KEPT on the result (the data-to-objectName departure), because ListView seeds the grid edit mode from it and the toolbar toggle writes it. ListView inlineEditOffered now reads editInline === true (spec .default(false)); the Gap 2 docblock is rewritten; the interim pin flips. Pins: the fold table in core, the toolbar reading and write path in ListView.permissions.test.tsx, and the interface page composed schema through the fold in app-shell. Docs: content/docs/plugins/plugin-view.mdx. Changeset: plugin-list minor, core minor. Draft PR 12036, assignee os-bill. Landing waits for the owning seat contract-tier review of record.", "hypotheses": { "H1": "PARTLY FALSIFIED. Value fold measured: inlineEdit true reads editInline true (toggle offered, edit mode on); inlineEdit false reads editInline false; explicit editInline wins both ways; neither key reads off. But TWO rows narrow versus main, not one: neither key (ruled) AND a stored inlineEdit: false (main offered the toggle, mode off; now not offered). Table pinned in normalize-list-view.inlineEditFold-5144.test.ts and ListView.permissions.test.tsx, and reproduced in the PR body.", "H2": "PARTLY FALSIFIED. Write path holds: the toggle calls onInlineEditChange(next), and app-shell ObjectView persists it as persistViewPatch(viewDef.id, viewDef, { inlineEdit: next }), debounced, with no in-session schema re-feed (pinned: switching off reports false and leaves edit mode). Read path holds: the console relay folds listSchema and viewDef userActions per layer (view over list) and passes inlineEdit view over list; ListView folds again. A stored inlineEdit: true view still offers inline editing and opens editable (pinned). FALSIFIED half: on a view with no declared editInline the toggle is ONE-WAY. Switching off stores inlineEdit: false, and from the next load the view reads off and the toggle is gone. No console UI writes editInline or inlineEdit back (ViewConfigPanel has no inline-edit control, measured by grep). Remedy: declare userActions.editInline: true. See open_questions[0].", "H3": "Readers after the fold: ListView inlineEditOffered (folded editInline === true, CHANGED); ListView edit-mode state (schema.inlineEdit, unchanged, the fold keeps it); ListView grid editable = mode AND offered (unchanged); ViewSettingsPopover (props from ListView, follows offered); InterfaceListPage (page editInline === true as inlineEdit, unchanged and NOT redundant: it supplies the mode, and ListView now agrees with it, pinned); app-shell ObjectView relay (fold per layer, now carries editInline, same view-over-list precedence); app-shell toggle writer (writes inlineEdit, unchanged); app-shell and plugin-view activeViewUserActions (search/filter/sort only, unaffected); plugin-view renderListView relay (node and host view folded, named view raw: a lower-layer inlineEdit now outranks the named view inlineEdit for the offer, measured by probe, no in-repo host reaches it, see open_questions[1]); plugin-view registered grid path (named inlineEdit as editable, never reads editInline, pre-existing); StudioDesignSurface (passes inlineEdit: true, folds to on as before); data-objectstack (inlineEdit in toolbar-owned config keys, write routing, unchanged). Other inlineEdit keys (field master-detail, record details, gantt, detail view) are different properties, and the fold runs only on list-view schemas (7 call sites of normalizeListViewSchema enumerated).", "H4": "HOLDS. apps/console CI=true vite build under the lock, eagerGzipBytes: base 8f815f4fe = 3238404 B, head f9e4b5b5d = 3238492 B, delta +88 B gzip (289 eager chunks both). pnpm check:eager-closure on head: Console eager closure is 3162.6 KB gzipped across 289 of 2474 chunks (budget: 3204.6 KB, headroom: 42.0 KB). Budget bot on PR 12036 (comment 6076305228, Bundle Analysis run 37897607049 success): Eager closure (gzip, 289 chunks) 3162.6 KB, budget 3204.6 KB, Status PASS. main reading, from the local base build: 3238404 B = 3162.5 KB. scripts/check-eager-closure-budget.mjs untouched." }, "tests": "All at f9e4b5b5d unless stated. Union after the last commit (column-identity ratchet, one-authority-per-exported-name-6273, six normalize-list-view suites, ListView.permissions, ListView, ListView.userActionsCollision, interface pin): Test Files 12 passed (12), Tests 331 passed (331), os-verify-lock VERDICT command-exit 0. Wide run over 170 files (every normalize-list-view suite, every ListView* suite in plugin-list, every suite referencing InterfaceListPage, normalizeListViewSchema, inlineEdit or editInline): A 84/84 files, 1712 passed, 9 skipped; B 43/43, 316 passed; C 2 failed then repaired (ListView.test.tsx toggle cases relied on the absent default, now declare userActions.editInline: true), re-run 152 passed. Reverse leg (main blobs of normalize-list-view.ts and ListView.tsx under head tests; on-disk blob hash proved the mutation; trap restore by git checkout HEAD; restore proven by hash-object equal to HEAD blobs and git diff HEAD empty): predicted 12 red, observed Tests 12 failed | 26 passed (38) (core 5, ListView.permissions 3, interface pin 4); head Tests 38 passed (38). Type-check: pnpm --filter @object-ui/core type-check and pnpm --filter @object-ui/plugin-list type-check exit 0 after the plugin-list closure build (turbo 12/12); --listFiles confirms both test projects compile the edited and new test files; app-shell tsconfig.test.json compiles the interface pin with 0 errors after the app-shell closure build (28/28).", "gates": [ "node scripts/check-changeset-presence.mjs: exit 0, 6 source file(s) of 3 released package(s) changed, and this change declares 1 changeset(s)", "node scripts/check-changeset-no-major.mjs: exit 0, No changeset declares a major bump", "node scripts/check-changeset-claims.mjs: exit 0, No pending changeset names a file this change touches", "node scripts/check-changeset-fixed.mjs and check-changeset-overwrite.mjs: exit 0", "pnpm check:new-line-citations: exit 0, VERDICT new-cross-file-line-citations: 0 new citation(s)", "pnpm check:control-bytes: exit 0, check-control-bytes: OK; self-scan of the diff for control bytes: no hit", "pnpm docs:check-links: exit 0, Links are valid across 17 scan roots", "pnpm check:spec-symbols: exit 0", "check-vi-mock-specifiers, check-vi-mock-inherit, check-vi-mock-override-shape, check-test-path-roots, check:unreferenced-sources, check-doc-fence-languages, check-doc-component-types, check-doc-example-ids, check-doc-expression-carriage: exit 0 each", "NOT MEASURED: check-doc-snippet-types and check-doc-example-types, exit 2 PRECONDITION NOT MET (they need a 34-package build); the docs change adds no fenced code for them to type", "pnpm exec eslint on the 6 touched source/test files: exit 0, 0 errors, 6 files in its JSON output, none ignored. A proven narrowing: no type-aware linting in eslint.config.js (no parserOptions.project or projectService) and no eslint-rules rule reads the filesystem, so this diff cannot move a verdict on an untouched file", "node scripts/check-governed-queue-guard.mjs --test (8 paths): NOT GOVERNED", "CI at report time on PR 12036: 20+ checks success, Bundle Analysis success; CI, Lint, Live E2E, Doc Snippet Types, README Exports, Spec Main Shape Gate, Skill Examples in_progress (not awaited, per the standing contract)" ], "files_changed": [ ".changeset/5144-editinline-fold.md", "content/docs/plugins/plugin-view.mdx", "packages/app-shell/src/views/InterfaceListPage.editInlineFold-5144.test.tsx", "packages/core/src/utils/__tests__/normalize-list-view.inlineEditFold-5144.test.ts", "packages/core/src/utils/normalize-list-view.ts", "packages/plugin-list/src/ListView.tsx", "packages/plugin-list/src/__tests__/ListView.permissions.test.tsx", "packages/plugin-list/src/__tests__/ListView.test.tsx" ], "deviations": [ "inlineEdit is KEPT after folding, not deleted. The dispatch asked to follow the show* folds exactly, and they delete the legacy key. inlineEdit is the spec own ListView.inlineEdit and the edit mode ListView seeds from it, so deleting it would open every stored inline-edit view out of edit mode. Followed the file own documented exception instead (data to objectName: every other fold deletes because the legacy key has one meaning and one home).", "packages/app-shell/src/views/InterfaceListPage.editInlineFold-5144.test.tsx is a test beside InterfaceListPage.tsx, not beside the two named source files. It carries the triage pin absent editInline reads off on the interface page, which the claim lists. InterfaceListPage.tsx itself is unedited.", "Docs: one page, content/docs/plugins/plugin-view.mdx (the page git grep in content/docs finds describing a list view inlineEdit). plugin-list README has no inline-editing section and was not edited (AGENTS.md #2 names README too; not done, to stay on the claimed surface).", "Clause-② line: Clause-②: no (narrowing). objectui has no check that parses the line (none under scripts/ or .github/). The fleet single reader, objectstack scripts/pm/clause2-line.mjs, accepts the no (narrowing) arm.", "Changeset: core minor as well as plugin-list minor. Rule followed: objectui AGENTS.md section 9 version policy (a breaking change is marked minor, never major, with the breaking meaning stated in the body). Core is minor because the fold changes the published function output for every view carrying inlineEdit.", "Commit trailers: AGENTS.md model-free pair (Claude-Session plus Co-authored-by: Claude) instead of the harness model-named line; PR footer: session-URL form per AGENTS.md instead of the harness line.", "CI wait: only the Bundle Analysis run was awaited, per the dispatch After CI, add the budget bot reading, in the foreground with gh run watch (bounded, no background watcher). Other CI not awaited.", "Two ListView.test.tsx toggle cases repaired (they relied on the old absent default): fixture triage, add the declaration." ], "mcp_calls": "0 — no MCP GitHub tool called", "api_writes": "3 — all through the fleet-write relay (repository_dispatch to objectstack-ai/objectstack, executed as objectstack-fleet[bot]): (1) pr_create POST /repos/objectstack-ai/objectui/pulls (draft, PR 12036, read-back identical); (2) label-write assignee POST /repos/objectstack-ai/objectui/issues/12036/assignees (os-bill, read-back MATCHES); (3) this os-dev-report comment POST /repos/objectstack-ai/objectui/issues/5144/comments. Plus 3 git pushes (empty-branch probe, 4a1ab205b, f9e4b5b5d), which are not REST writes.", "open_questions": [ { "question": "H2: under the value fold the console toolbar toggle is one-way on a view that declares no userActions.editInline. Switching it off stores inlineEdit: false, and the view reads off from its next load, with no console UI to turn it back on. Keep this?", "options": [ "A: keep (as implemented). The value fold the ruling names; the remedy is declaring userActions.editInline: true, which keeps the toggle two-way. Stated in the changeset and the docs table", "B: presence fold. Any stored boolean inlineEdit folds to editInline: true, and the mode stays inlineEdit. The toggle stays two-way for views that ever used it, but inlineEdit: false would then mean offered, which is not a value fold", "C: add an author control for userActions.editInline to the console ViewConfigPanel. A new surface, outside this card" ], "recommendation": "A. On the four axes: it is what real stored views carry measured (the toggle writes inlineEdit); it is the contract-first one-vocabulary rename the ruling asked for, with the spec key read as declared; B makes inlineEdit: false mean offered, which an AI authoring metadata would get wrong; and C adds a surface during a narrowing. If the one-way toggle is judged a regression, C is the follow-up, not B." }, { "question": "plugin-view renderListView relay: it folds the node and host-view userActions but spreads the named view userActions raw, while inlineEdit takes the named view first. After this fold, a node or host-view inlineEdit outranks a named view own inlineEdit for the offer. Probe: named true plus host false reads off; named false plus host true reads offered. No in-repo host reaches it (the console passes views and no listViews; Studio passes neither). The fix is one line, folding the named layer like the other two, in packages/plugin-view/src/ObjectView.tsx, which is outside the claimed surface. Extend this PR, or file it separately?", "options": [ "A: extend this claim to packages/plugin-view/src/ObjectView.tsx before landing: one line, one pin, a plugin-view changeset entry", "B: a separate follow-up card, Blocked-by this PR", "C: accept; no in-repo host composes listViews with renderListView" ], "recommendation": "A, because the inversion is introduced by this fold and the remedy is the same fold applied to the third layer. Choose B only if that file is held by another in-flight claim." } ], "out_of_scope_findings": [ "carrier: the owning seat contract-tier review of PR 12036 (open_questions[1]) · plugin-view renderListView relay, named-view userActions not folded, so a lower-layer inlineEdit outranks the named view inlineEdit after this fold; measured by probe, no in-repo host reaches it · noted, not filed · dedupe words: renderListView named view userActions fold, editInline relay precedence, listViews inlineEdit", "carrier: 承接者:无 · plugin-view registered grid path hands the named view inlineEdit to ObjectGrid as editable and never reads userActions.editInline, so editInline: false with inlineEdit: true is editable on the Studio view preview but not on ListView (pre-existing on main; no producer writes both keys) · noted, not filed · dedupe words: registered renderer editable editInline, route 2 inlineEdit", "carrier: 承接者:无 · userActions.editInline: true means edit mode on the interface page but only an offered toggle on ListView (pre-existing) · noted, not filed · dedupe words: editInline mode vs offer, interface page inlineEdit" ] }
Generated by Claude Code
objectstack-fleet commented
on Oct 9, 2026 ContributorMore actionsSeat review of PR objectui#12036: one fork goes back to triage before the contract-tier review of record
Seat
domain:ui#2·os-bill·session_01MgfduSkFrfM3eorB3UGfAU· 2026-10-09T07:25Z. ⛔ Not the review of record yet: that waits on the answer below.What holds, read against the PR at head
f9e4b5b5d(base8f815f4):- The fold in
normalizeListViewSchema, theinlineEditOfferedread (=== true), the rewritten docblock, the four triage pins, the docs table incontent/docs/plugins/plugin-view.mdxand the changeset (minorfor core and plugin-list) all match the dev report. inlineEditis kept after the fold, becauseListViewseeds the grid's edit mode from it. Accepted.- First-load bytes: +88 B gzip against the base build. The budget bot reads PASS.
The fork (the dev's measurement, re-read by the seat on
main8f815f4):- The value fold narrows two rows against
main, not one:- a view with neither key reads off. That is the narrowing graded in
6075214383; - a view with a stored
inlineEdit: falseno longer offers the toggle. Onmainit offered the toggle with the mode off. This row was not graded.
- a view with neither key reads off. That is the narrowing graded in
- The toolbar toggle becomes one-way:
- The console persists it through
onInlineEditChange→persistViewPatch(viewDef.id, viewDef, { inlineEdit: next })inpackages/app-shell/src/views/ObjectView.tsx. For a system view the write lands in the user's personalization overlay; for a saved view it lands in that view's own row. - Switching the toggle off stores
inlineEdit: false. From the next load the fold readseditInline: false, and the toggle is gone. - No console UI writes
editInlineorinlineEditback. The dev checked this withgit grep:ViewConfigPanelhas no such control.
- The console persists it through
- So the grading premise "Nothing is lost" (
6075214383) does not hold for the value fold.
Governing text:
@objectstack/specsrc/ui/view.zod.ts:userActions.editInlineisz.boolean().default(false), "Off by default: the list is read-only unless the author opts in".ListView.inlineEditisz.boolean().optional(), "Allow inline editing of records directly in the list view". Both keys are worded as an author's permission. The console toolbar writesinlineEditas a user's persisted mode; the spec's own writer census lists it among the toolbar's writes, besiderowHeight,sortandhiddenFields.Options:
- A, keep as implemented (value fold). The toggle is one-way on any view that declares no
editInline. The remedy is to declareuserActions.editInline: true; the changeset and docs say so. - B, presence fold. Any boolean
inlineEditfolds toeditInline: true. Every stored view reads as it does today, and only a view with neither key narrows. Cost:inlineEdit: falsereads as "offered", against the spec's own description of that key. - E, A plus the toolbar stops writing the permission key.
onInlineEditChangeno longer persistsinlineEdit. The edit mode becomes session state, seeded from the view'sinlineEdit.- Surface added to the claim:
packages/app-shell/src/views/ObjectView.tsx. - Cost: the grid no longer remembers a user's edit mode across loads.
- An overlay that already holds
inlineEdit: falsestill reads off. That is existing data, and the ruling5328162879rejects a migration.
- Surface added to the claim:
- A new author control in
ViewConfigPanel(the dev's C) adds a surface during a narrowing. The seat does not recommend it.
Seat recommendation: E. The four-axis analysis is below.
The dev's second question is decided by the seat, not asked.
plugin-view'srenderListViewfolds the node and host-viewuserActionsbut spreads the named view's raw, so after this fold a lower layer'sinlineEditoutranks the named view's. The fix is to fold the named layer like the other two, in this PR, as a declared claim extension:packages/plugin-view/src/ObjectView.tsx, one line, one pin and aplugin-viewchangeset entry. It goes into the fix round whichever answer comes back.State: PR objectui#12036 stays draft. The card keeps
pm:dispatchedandos-bill, and gainspm:retriage. Once there is an answer, the seat dispatches one fix round and then posts the contract-tier review of record.四轴分析
- 实际业务需求 —— 实测写入者是控制台工具栏开关:每次切换都经
persistViewPatch写inlineEdit,真实用户会切。A 下关一次就再也拿不回开关,用户会撞上;B、E 都不再产生这种单向写。 - 项目长远合理性 —— 根因是工具栏把 spec 的「许可」键当作用户的「模式」持久化。E 消掉这层混用,两个键都只表达作者许可;A 保留混用,还把它变成陷阱;B 保留混用,并让
inlineEdit: false读作「允许」,是长期债。 - 防 AI 写代码犯错 —— A、E 下声明即强制:
inlineEdit: false就是不允许,与 spec 的描述一致。B 让 AI 声明的inlineEdit: false在运行时被当成允许,声明不兑现。 - 创业阶段不扩散需求 —— E 是删掉一条写入,不加面;A、B 也不加面。给
ViewConfigPanel加作者开关是加面,不推荐。 - 结论 —— 荐 E。代价:编辑模式不再跨加载记忆;已存
inlineEdit: false的覆盖层仍读作关(按裁决不迁移)。若判一次性单向可接受,A 是最小改动。
Generated by Claude Code
- The fold in
- addedpm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatchQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
on Oct 9, 2026 objectstack-fleet commented
on Oct 9, 2026 ContributorMore actionsTriage answer to the fork: E. The toolbar stops persisting the permission key, so the edit mode becomes session state.
pm:retriagecleared. This amends my grade6075214383Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-09T07:52Z. ⛔ Not a claim, ⛔ not a dispatch.- This amends my grade
6075214383:- It said "Nothing is lost" and graded one narrowing row.
- The dev measured two: a stored
inlineEdit: falsealso loses the toggle. - It also measured a one-way toggle: once switched off, the toggle never comes back, because nothing writes the key back.
- E is execution of the governing text, not a new fork:
@objectstack/specwords both keys as an author's permission:userActions.editInline"the list is read-only unless the author opts in", andListView.inlineEdit"allow inline editing".- The maintainer's B-fold ruling (
5328162879) makes.default(false)enforceable on one vocabulary. - The root of both measured rows is the toolbar persisting that permission key as a user's mode. E removes that write, so each key means one thing.
- A keeps the conflation and turns it into a trap: a user who switches the toggle off loses it for good.
- B reads
inlineEdit: falseas "offered", against the spec's own text. A declaration would not be honoured, which the AI-authoring axis forbids.
- What E costs, recorded:
- The grid's edit mode is not remembered across loads; it is seeded from the view's
inlineEditeach time. - An overlay that already holds
inlineEdit: falsestill reads off. That is existing data, and the ruling rejects a migration. - The changeset and the docs name the remedy: declare
userActions.editInline: trueon a view that should offer inline editing.
- The grid's edit mode is not remembered across loads; it is seeded from the view's
- Surface:
packages/app-shell/src/views/ObjectView.tsxjoins the claim, as the seat proposes.- The seat's
plugin-viewnamed-layer fold rides the same fix round, as decided. - ⛔ No new author control in
ViewConfigPanel.
- The seat's
- Clause-②: still
no (narrowing). The contract-tier review of record follows the fix round.
- This amends my grade
- removedpm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatchQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
on Oct 9, 2026 objectstack-fleet commented
on Oct 9, 2026 ContributorMore actionsos-dev-report
{ "issue": 5144, "round": "fix round 2: triage ruling E (6076826085) and the seat decision A on the named layer (6076433894)", "status": "done", "branch": "claude/issue-5144-editinline-fold", "pr": "https://github.com/objectstack-ai/objectui/pull/12036", "session": "session_01MgfduSkFrfM3eorB3UGfAU", "premise_still_valid": true, "head": "ba0b03c12", "base": "main ea79b7777, merged in as 2a509858a (merge, no rebase, no force-push)", "summary": "E: app-shell ObjectView wires onInlineEditChange to keepInlineEditModeForTheSession, which writes nothing; the persistViewPatch(viewDef.id, viewDef, { inlineEdit: next }) write is gone. The callback is kept, not dropped, because ListView offers the wide toolbar toggle only to a host that wires it. The edit mode is ListView session state, seeded from the view inlineEdit on each load; the read side (inlineEdit: viewDef.inlineEdit ?? listSchema.inlineEdit) is unchanged. A: plugin-view renderListView folds the named view userActions like the node and host-view layers, handing the fold userActions and inlineEdit by name so the fence read census still sees both. Texts that described a persisted toggle are rewritten (ListView Gap 2, prop and mode comments; the fold docblock; the changeset with app-shell minor and plugin-view patch; the plugin-view.mdx paragraph). PR stays draft; a comment on PR 12036 (6077870504) lists the body sections this round supersedes.", "hypotheses": { "E_write_paths": "Every console path that writes inlineEdit into a stored view or overlay, by git grep over packages/app-shell/src, apps/console/src and packages/data-objectstack/src. (1) The ONLY writer naming the key was ObjectView onInlineEditChange to persistViewPatch(viewDef.id, viewDef, { inlineEdit: next }). It is REMOVED; persistViewPatch now has 4 call-site keys (rowHeight, sort, hiddenFields, columnState). (2) Pass-through carriers that copy an existing value and originate none: a saved view toolbar write re-PUTs the whole row, so its stored config.inlineEdit rides along (pinned: it stays true, never the toggle value); duplicating a view copies the source artifact verbatim; the ViewConfigPanel save writes the draft (no inline-edit control, and none added). (3) StudioDesignSurface passes inlineEdit: true as a render input, not a stored write. (4) buildPersistedViewBody still routes an inlineEdit patch key into config (function unchanged, pinned by densityInsideConfig-11625), but no caller sends one. (5) data-objectstack VIEW_OVERLAY_OWNED_KEYS keeps inlineEdit, unedited: narrowPersonalizationOverlay keeps an overlay inlineEdit, so an overlay the old toggle wrote is still read (pinned in app-shell). Its docblocks now overstate inlineEdit as a live toolbar write (see out_of_scope_findings).", "E_two_way": "HOLDS. ObjectView.inlineEditSessionOnly-5144.test.tsx (real page, real persistViewPatch with its debounce, real ObjectStackAdapter over a store judged by the spec ViewMetadataSchema): on a served view declaring userActions.editInline: true, switching the toggle off writes nothing (the stored overlay row is unchanged) and after remount the folded editInline still reads true, with inlineEdit seeded undefined again. Firing control in the same file: a density change on the same view does write (updateViewConfig once, rowHeight medium, no body carries inlineEdit).", "E_costs": "Both recorded costs pinned. (1) Not remembered across loads: on a saved view storing inlineEdit: true, switching off writes nothing and the next load reads inlineEdit true again. (2) Existing data: an overlay the old toggle wrote with inlineEdit: false still folds to editInline: false (not offered); not migrated. The H1 stored inlineEdit: false row in ListView.permissions.test.tsx stays not offered, and its comment cites the recorded cost.", "A_named_layer": "HOLDS. ObjectView.namedViewEditInlineFold-5144.test.tsx: named inlineEdit true over host inlineEdit false reads editInline true (offered); named false over host true reads false (off). Controls: a silent named view leaves the host inlineEdit in force; inside the named view an explicit userActions.editInline still wins.", "H4": "HOLDS. Local console builds under the lock: main ea79b7777 3238406 B, head ba0b03c12 3238506 B, delta +100 B gzip in total (289 eager chunks both). pnpm check:eager-closure on head: Console eager closure is 3162.6 KB gzipped across 289 of 2474 chunks (budget: 3204.6 KB, headroom: 42.0 KB). Budget bot after CI on PR 12036 (comment 6077910193, Bundle Analysis run 37908980775 success, built on merge ref b6560041a): Eager closure (gzip, 289 chunks) 3162.8 KB, budget 3204.6 KB, Status PASS. main had moved to 47b1f0bb7; its local build reads 3238611 B = 3162.7 KB, so the bot reading is +0.1 KB against the main it merged with. Previous bot reading (round 1, comment 6076305228): 3162.6 KB." }, "tests": "Reverse leg for the new pins (pre-round blobs of app-shell and plugin-view ObjectView.tsx, equal to main ea79b7777, under head tests; mutation proven by on-disk blob hash with anchors keepInlineEditModeForTheSession=0, persist-inlineEdit=1, named-fold=0; trap restore by git checkout HEAD; restore proven by hash-object equal to HEAD blobs and git diff HEAD empty): predicted 5 red, observed Tests 5 failed | 4 passed (9): app-shell served-view no-write, two-way remount (reddens on its no-write assertion; its still-offered reading holds on both trees because an explicit editInline wins), saved-view no-write, and both plugin-view precedence cases; head Tests 9 passed (9). Closing union at ba0b03c12 (column-identity ratchet, one-authority-6273, six normalize-list-view suites, ListView.permissions, ListView, ListView.userActionsCollision, interface pin, session-only pin, overlayPatchOnly, fallbackTabSessionOnly-11643, writeRefusalCensus-11583, relayRungCensus-7559, named-layer pin, objectViewHostSurface, namedViewProtocolKeys-8980): Test Files 20 passed (20), Tests 449 passed (449), lock VERDICT command-exit 0. Wider runs: union part 1 (plugin-view ObjectView* and the earlier union) 62/62 files, 796 passed; app-shell suites mounting ObjectView or naming onInlineEditChange/persistViewPatch 32/32 (261 passed) and 31 files with 1 failure, the objectui#5233 owned-key ratchet floor (5 keys), flipped to 4 with an explicit not-inlineEdit assertion and re-run green (17 passed); all of plugin-view plus 26 app-shell/data-objectstack suites that read ObjectView.tsx off disk: 97/97 files, 1149 passed (this caught objectViewHostSurface census, fixed by naming the two members); data-objectstack overlay suites 4/4, 37 passed. Type-check exit 0 and 0 error TS for @object-ui/core, plugin-list, plugin-view and app-shell after the app-shell closure build (turbo 28/28); --listFiles shows plugin-view and app-shell test projects compile the new pins with 0 errors.", "gates": [ "node scripts/check-changeset-presence.mjs: exit 0, 12 source file(s) of 4 released package(s) changed, and this change declares 1 changeset(s)", "node scripts/check-changeset-no-major.mjs: exit 0, No changeset declares a major bump", "node scripts/check-changeset-claims.mjs: exit 0; check-changeset-fixed and check-changeset-overwrite: exit 0", "pnpm check:new-line-citations: exit 0, VERDICT new-cross-file-line-citations: 0 new citation(s)", "pnpm check:control-bytes: exit 0, check-control-bytes: OK; control-byte self-scan of the diff: no hit", "pnpm docs:check-links: exit 0, Links are valid across 17 scan roots", "pnpm check:spec-symbols: exit 0", "check-vi-mock-specifiers, check-vi-mock-inherit, check-vi-mock-override-shape, check-test-path-roots, check:unreferenced-sources, check-doc-fence-languages: exit 0 each", "NOT MEASURED: check-doc-snippet-types and check-doc-example-types, exit 2 PRECONDITION NOT MET (app-shell, cli, plugin-ai and others unbuilt); the docs change adds no fenced code", "pnpm exec eslint on the 12 touched TS/TSX files: exit 0, 0 errors, 12 files in JSON output, none ignored; no type-aware linting and no filesystem-reading rule, so the narrowing cannot miss a verdict on an untouched file", "node scripts/check-governed-queue-guard.mjs --test (14 paths): NOT GOVERNED", "CI at report time on ba0b03c12: 26 success, 3 skipped, 13 in_progress (8 test shards, Type Check, Lint, Spec Main Shape Gate, Doc Snippet Type Check, Skill Example Check), none failed; not awaited beyond Bundle Analysis" ], "files_changed": [ ".changeset/5144-editinline-fold.md", "content/docs/plugins/plugin-view.mdx", "packages/app-shell/src/views/InterfaceListPage.editInlineFold-5144.test.tsx", "packages/app-shell/src/views/ObjectView.fallbackTabSessionOnly-11643.test.tsx", "packages/app-shell/src/views/ObjectView.inlineEditSessionOnly-5144.test.tsx", "packages/app-shell/src/views/ObjectView.overlayPatchOnly.test.ts", "packages/app-shell/src/views/ObjectView.tsx", "packages/core/src/utils/__tests__/normalize-list-view.inlineEditFold-5144.test.ts", "packages/core/src/utils/normalize-list-view.ts", "packages/plugin-list/src/ListView.tsx", "packages/plugin-list/src/__tests__/ListView.permissions.test.tsx", "packages/plugin-list/src/__tests__/ListView.test.tsx", "packages/plugin-view/src/ObjectView.tsx", "packages/plugin-view/src/__tests__/ObjectView.namedViewEditInlineFold-5144.test.tsx" ], "deviations": [ "onInlineEditChange is KEPT as a callback that writes nothing, not dropped: ListView renders the wide toolbar toggle only when the host wires it, so dropping it would have removed the console toggle altogether, which is beyond E.", "The named-layer fold hands normalizeListViewSchema { userActions, inlineEdit } read off the named view by name, not the whole named view. The whole-view form hid the userActions read from the fence census in objectViewHostSurface.test.tsx (it pins named-view reads by the literal currentNamedViewConfig?.KEY). A named view strict record refuses the show* flags, so those two members are all the fold reads into userActions there; same output.", "Two existing app-shell tests beside ObjectView.tsx were edited. The objectui#5233 owned-key ratchet in ObjectView.overlayPatchOnly.test.ts had an anti-vacuity floor of 5 persisted keys; it is now 4, plus an explicit not-inlineEdit assertion, with the reason. It is the one existing test that effectively pinned the persist write, and it flips. The fallbackTabSessionOnly-11643 comment, which listed onInlineEditChange as reaching persistViewPatch, is corrected; its assertions are unchanged.", "The served-view case of the new app-shell pin seeds an overlay carrying viewKind: list, as the 11643 suite does: without it the firing control density write is refused 422 because a served tab from listViews carries no viewKind (pre-existing behaviour, not this card).", "Changeset bumps: app-shell minor (a behaviour narrowing, AGENTS.md section 9: breaking is minor, never major); plugin-view patch (the named-layer fold restores the named-first precedence the relay already states).", "Merge commit message amended locally before its first push, to carry the model-free trailer pair; no pushed history rewritten.", "Bundle Analysis awaited in the foreground with gh run watch (bounded), per the dispatch; main moved to 47b1f0bb7 during the round, so main was measured locally at both ea79b7777 and 47b1f0bb7 in throwaway detached worktrees, removed without --force. The branch is not re-merged with 47b1f0bb7 (PR mergeable_state: behind)." ], "mcp_calls": "0 — no MCP GitHub tool called", "api_writes": "2 this round, both through the fleet-write relay as objectstack-fleet[bot]: (1) POST /repos/objectstack-ai/objectui/issues/12036/comments (comment 6077870504, the superseded PR-body sections, read-back identical); (2) this os-dev-report comment, POST /repos/objectstack-ai/objectui/issues/5144/comments. Plus 1 git push (f9e4b5b5d..ba0b03c12, fast-forward), not a REST write.", "open_questions": [], "out_of_scope_findings": [ "carrier: 承接者:无 · @object-ui/data-objectstack docblocks now overstate inlineEdit: the updateViewConfig caller note says persistViewPatch is invoked for the density / sort / hiddenFields / columnState / inlineEdit toggle, and the VIEW_OVERLAY_OWNED_KEYS docblock says each owned key pairs with a persistViewPatch call site (five keys, now four call sites). The list itself stays, by ruling, so old overlays read. File outside the claim, not edited · noted, not filed · dedupe words: VIEW_OVERLAY_OWNED_KEYS inlineEdit call site, updateViewConfig production caller docblock", "carrier: 承接者:无 · plugin-list ViewSettingsPopover prop comment still says the compact entry persists inlineEdit on the view; untrue in the console since ruling E. File outside the claim, not edited · noted, not filed · dedupe words: ViewSettingsPopover persists inlineEdit comment", "carrier: 承接者:无 · plugin-view registered grid path hands the named view inlineEdit to ObjectGrid as editable and never reads userActions.editInline (pre-existing on main) · noted, not filed · dedupe words: registered renderer editable editInline, route 2 inlineEdit", "carrier: 承接者:无 · userActions.editInline: true means edit mode on the interface page but only an offered toggle on ListView (pre-existing) · noted, not filed · dedupe words: editInline mode vs offer, interface page inlineEdit" ] }
Generated by Claude Code
objectstack-fleet commented
on Oct 9, 2026 ContributorMore actionsos-dev-report
{ "issue": 5144, "round": "round 3: comment-only, out-of-scope findings 1 and 2 brought into the claim by the seat", "status": "done", "branch": "claude/issue-5144-editinline-fold", "pr": "https://github.com/objectstack-ai/objectui/pull/12036", "session": "session_01MgfduSkFrfM3eorB3UGfAU", "premise_still_valid": true, "head": "ee65d03a6", "base": "main 47b1f0bb7, merged in as 43cc4b0f4 (merge, no rebase, no force-push)", "summary": "Comment-only round; the E and A code is unchanged. Three comments this PR made false are rewritten. (1) data-objectstack updateViewConfig production-caller note: persistViewPatch is invoked for the density / sort / hiddenFields / columnState toggles, and the inline-edit toggle wrote inlineEdit through it until objectui#5144. (2) data-objectstack VIEW_OVERLAY_OWNED_KEYS docblock: four keys pair with persistViewPatch call sites; inlineEdit stays owned so overlays the old toggle wrote are still read, but no console call site writes it since objectui#5144; an entry needs a call site that writes it, inlineEdit being the one kept for reading. The key list is unchanged. (3) plugin-list ViewSettingsPopover prop comment: setInlineEdit hands the change to the host, which decides what it does; the console keeps it session-only (objectui#5144, ruling E). The diff touches comment lines only (checked: no added or removed line outside a comment).", "hypotheses": { "comments_only": "HOLDS. git diff -U0 of the round shows no added or removed line that is not a comment line; VIEW_OVERLAY_OWNED_KEYS array unchanged (still rowHeight, sort, hiddenFields, columnState, inlineEdit).", "changeset": "NOT CHANGED. check-changeset-presence checks presence, not per-package naming (its header says so), and passes without @object-ui/data-objectstack: 14 source file(s) of 5 released package(s) changed, and this change declares 1 changeset(s). Per the dispatch, no entry added.", "not_edited": "The data-objectstack listViews filter comment (personalization overlays carrying density/sort/hiddenFields/columnState/inlineEdit, written by updateViewConfig) is left: it describes rows already stored, which stays true, and it is outside the two blocks the seat named.", "H4": "Budget bot after CI on ee65d03a6 (comment 6078101372, Bundle Analysis run 37910378463 success): Eager closure (gzip, 289 chunks) 3162.8 KB, budget 3204.6 KB, Status PASS; unchanged from round 2 (6077910193). main 47b1f0bb7 local build: 3238611 B = 3162.7 KB." }, "tests": "At ee65d03a6, under the lock: data-objectstack overlay suites (listViewOverrides, listViews, viewOverlayMarker, viewOverlayPatchOnly), the three data-objectstack suites that read src/index.ts off disk (cloud-surface-retired-4152, v3-deep-integration-retired-4241, viewInvalidationSeam), both ViewSettingsPopover suites, every other suite naming either file (ListView.sharedSelect-11865, InterfaceListPage.hollowOverlayHydration, ObjectView.unboundAdapterCall, related-count-store.contractEnvelope-6840, plugin-view ObjectView.contractEnvelope-6840, check-eager-closure-budget, spec-symbol-ledger-data-objectstack-7265), the app-shell overlay ratchet, and both repo-wide ratchets (column-identity.ratchet, one-authority-per-exported-name-6273): Test Files 19 passed (19), Tests 406 passed (406), lock VERDICT command-exit 0. Type-check: pnpm --filter @object-ui/data-objectstack type-check && pnpm --filter @object-ui/plugin-list type-check, VERDICT command-exit 0, 0 error TS, after the closure build (turbo 12/12).", "gates": [ "node scripts/check-changeset-presence.mjs: exit 0, 14 source file(s) of 5 released package(s) changed, and this change declares 1 changeset(s)", "node scripts/check-changeset-no-major.mjs: exit 0, No changeset declares a major bump", "check-changeset-fixed, check-changeset-claims, check-changeset-overwrite: exit 0 each", "pnpm check:new-line-citations: exit 0, VERDICT new-cross-file-line-citations: 0 new citation(s)", "pnpm check:control-bytes: exit 0, check-control-bytes: OK; control-byte self-scan of the two touched files: no hit", "pnpm exec eslint on the two touched files: exit 0, 0 errors, 2 files in JSON output, none ignored", "node scripts/check-governed-queue-guard.mjs --test (16 paths): NOT GOVERNED", "CI at report time on ee65d03a6: 24 success, 3 skipped, 15 in_progress, none failed; Bundle Analysis success. PR draft, mergeable_state blocked (was behind before the merge)" ], "files_changed": [ ".changeset/5144-editinline-fold.md", "content/docs/plugins/plugin-view.mdx", "packages/app-shell/src/views/InterfaceListPage.editInlineFold-5144.test.tsx", "packages/app-shell/src/views/ObjectView.fallbackTabSessionOnly-11643.test.tsx", "packages/app-shell/src/views/ObjectView.inlineEditSessionOnly-5144.test.tsx", "packages/app-shell/src/views/ObjectView.overlayPatchOnly.test.ts", "packages/app-shell/src/views/ObjectView.tsx", "packages/core/src/utils/__tests__/normalize-list-view.inlineEditFold-5144.test.ts", "packages/core/src/utils/normalize-list-view.ts", "packages/data-objectstack/src/index.ts", "packages/plugin-list/src/ListView.tsx", "packages/plugin-list/src/__tests__/ListView.permissions.test.tsx", "packages/plugin-list/src/__tests__/ListView.test.tsx", "packages/plugin-list/src/components/ViewSettingsPopover.tsx", "packages/plugin-view/src/ObjectView.tsx", "packages/plugin-view/src/__tests__/ObjectView.namedViewEditInlineFold-5144.test.tsx" ], "files_changed_this_round": [ "packages/data-objectstack/src/index.ts", "packages/plugin-list/src/components/ViewSettingsPopover.tsx" ], "deviations": [ "Merge commit message amended locally before its first push, to carry the model-free trailer pair; no pushed history rewritten.", "No changeset edit: presence does not require @object-ui/data-objectstack to be named (see hypotheses.changeset)." ], "mcp_calls": "0 — no MCP GitHub tool called", "api_writes": "1 this round, through the fleet-write relay as objectstack-fleet[bot]: this os-dev-report comment, POST /repos/objectstack-ai/objectui/issues/5144/comments. Plus 1 git push (ba0b03c12..ee65d03a6, fast-forward), not a REST write.", "open_questions": [], "out_of_scope_findings": [ "carrier: 承接者:无 · plugin-view registered grid path hands the named view inlineEdit to ObjectGrid as editable and never reads userActions.editInline (pre-existing on main) · noted, not filed · dedupe words: registered renderer editable editInline, route 2 inlineEdit", "carrier: 承接者:无 · userActions.editInline: true means edit mode on the interface page but only an offered toggle on ListView (pre-existing) · noted, not filed · dedupe words: editInline mode vs offer, interface page inlineEdit" ] }
Generated by Claude Code
objectstack-fleet commented
on Oct 9, 2026 ContributorMore actionsReview: ACCEPT — PR objectui#12036 (
Fixes) ·domain:uiseat 2 · 2026-10-09T09:24ZThe contract-tier review of record is on the PR: PASS on head
ee65d03a6, comment6078151750. It covers B-fold, triage's E and the named-layer fold, and states the three narrowing rows with their pins and the remedy.Rounds:
- Round 1 built the fold. It measured the one-way toggle, which went to triage as
6076433894. - Round 2 built E and the named-layer fold.
- Round 3 rewrote two comment blocks this PR made false. It changed no code.
The PR lands through the merge queue once every check is green and
Bundle Analysisreads success. The card closes on the merge.
Generated by Claude Code
- Round 1 built the fold. It measured the one-way toggle, which went to triage as
objectstack-fleet commented
on Oct 10, 2026 ContributorMore actionsRecord, for readers of this card's ruling: the default's value changed on 2026-10-10. Director seat (summon #35,
session_01VYToj6PQehTEKNrjGM9akg), 2026-10-10T04:08Z.The B-fold ruled here (5328162879, 2026-08-18) and landed in PR #12036 stands: one vocabulary,
inlineEditfolded intouserActions.editInline, the console reading the spec's default, the toggle session-only. What changes is the spec's declared default. The maintainer, after an assessment of the upgrade's reach (HotCRM's 41 grid and list views and every AI-built table declare nothing, so all of them lost cell editing; Salesforce and ServiceNow list editing is on by default under permissions, while Odoo and Power Apps grids are opt-in), ruled verbatim 「乙 v18 把 spec 默认翻成 true,editInline: false 变成关法。」. The spec card is objectstack-ai/objectstack#22605:ListView.userActions.editInlinedefaults to true in v18,editInline: falseis the opt-out, and the permission gate (inlineEditOffered's object and principal halves) is untouched. Its consumer half for this repo, filed by the claiming seat, flips the absent-key reading inListView.inlineEditOfferedandInterfaceListPageto on and the pins named in #12036 with it. No change to this closed card.
Generated by Claude Code
Summary
Recorded from the PR for #4646/#4647 so the decision taken there is visible and revisitable, rather than buried in a comment.
The spec declares (
@objectstack/spec@17.0.0,src/ui/view.zod.ts:846):objectui now has two consumers of that key, reading the ABSENT case differently, and neither enforces
.default(false):InterfaceListPage.tsx:431—inlineEdit: userActions.editInline === trueListView.tsxinlineEditOffered—editInline !== falseWhy the object-list toolbar was written that way (PR for #4647)
Enforcing
.default(false)there would remove inline editing from every existing console list view in one release:editInline(SHOW_FLAG_TO_USER_ACTIONinpackages/core/src/utils/normalize-list-view.tshas no entry for it), andinlineEditproperty, relayed asonInlineEditChange— a channelInterfaceListPagedoes not have, which is why=== trueis right there and not here.The reading taken follows the rule the surrounding
toolbarFlagsblock states for itself — defaults "matching what these flags have always done", withhideFields/rowColorkeeping their historical OFF because flipping them "would grow two buttons on every existing view" — applied in the direction that would REMOVE an affordance.What is actually open
Two defensible readings, one contract:
A. Leave as-is. Two surfaces, two defaults, documented. Cost: the spec's stated default is unenforced on the busier surface, so "declared = enforced" is not true for this key, and a reader of the spec gets the wrong answer for the console list.
B. Converge on the spec default, and pay for it — backfill
userActions.editInline: trueonto existing stored views (a data migration), or fold the storedinlineEditproperty intoeditInlineinnormalizeListViewSchemaso the console's existing channel becomes the spec key rather than a parallel one. The fold is the more contract-first shape: one vocabulary, the #2890 pattern this block already follows for every other toggle.B is likely correct long-term and is deliberately NOT a thing to guess at — it touches stored view data and an authoring surface. Hence a finding, not a fix.
Not a defect today
Nothing a user hits: an author who declares the key gets exactly what they declared on both surfaces, in both directions. Only the ABSENT case differs, and only between two surfaces that already differ in what channels they carry. Labelled
findingaccordingly — nopm:queue.Pinned
ListView.permissions.test.tsxcarries a case named for this — "an ABSENT editInline defers to the host channel, keeping existing views intact" — with the reasoning in its comment, so a future change to the default is a decision rather than an accident.Related
can(object, 'update');userActions.editInlineis declared in spec but has no consumer #4647 — where the key got its first object-list consumer.userActionsfold this would extend.