Skip to content

feat(spec)!: ListView.userActions.editInline defaults to true on the v18 line; editInline: false is the opt-out (#22605, spec half) - #22629

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-22605-edit-inline-default-on
Oct 10, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-22605-edit-inline-default-on

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Part of #22605
Clause-②: no

The spec half of #22605: ListView.userActions.editInline defaults to true on the v18 line, and userActions: { editInline: false } is the opt-out. The skills/** paragraph the card also asks for is a separate pull request (Tier H), so this one is Part of, not Fixes.

The ruling

Maintainer, 2026-10-10, verbatim (filed by the director seat on the card): 「乙 v18 把 spec 默认翻成 true,editInline: false 变成关法。」 A list view is editable in place by default, under the permission gate that already exists. The rule of objectui#5144 stands (one vocabulary, the inlineEdit fold, declared = enforced); only the default's value changes. Not taken: declaring editInline: true on every existing view (objectstack-ai/hotcrm#2048 and #22604 are superseded by the ruling, and stay open here — this PR does not act on either), and an app-level default. The permission gate is untouched. The consumer half is objectui's, objectstack-ai/objectui#12086; in the window the console at the pinned objectui still reads an absent key as off, so nothing regresses against today.

What changed

  • packages/spec/src/ui/view.zod.ts — UserActionsConfigSchema.editInline is z.boolean().default(true), describe rewritten (on by default; a user who may update the object edits a cell in place with the field's type-aware widget, under the permission gate; declare editInline: false to make the list read-only in place). The schema docblock records the ruling beside the group/hideFields/rowColor asymmetry it already explains.
  • packages/spec/scripts/lib/default-changes.ts — DEFAULT_CHANGES_BY_MAJOR[17] gains ui/UserActionsConfig:editInline false → true with its reason. This is what lets check:authorable-surface accept the moved fingerprint; CURRENT_MAJOR is the package major (17) until the version pass takes the group to 18. The build printed 📌 1 declared default change(s) accepted (#4666): ui/UserActionsConfig:editInline: false → true.
  • packages/spec/src/migrations/entries/semantic/18.list-view-edit-inline-default-on.ts — the D3 semantic entry (protocol 18), concatenated into registry.ts by gen:migration-registry.
  • packages/spec/authorable-defaults/ui.json — regenerated by the build: ui/UserActionsConfig:editInline = true.
  • content/docs/references/ui/view.mdx (3 rows), content/docs/references/ui/page.mdx (1 row) — regenerated by gen:docs: optional (default: true) with the new describe.
  • .changeset/22605-spec-list-view-edit-inline-default-on.md — @objectstack/spec: minor, Clause-②: no (a moved default changes no accept set; the breaking signal is the banner and the ADR-0087 marker), the launch-window BREAKING banner naming the author who relied on the documented default for a read-only list and the remedy editInline: false, the FROM → TO table, the measured reach, and the ADR-0087 marker registered list-view-edit-inline-default-on. minor because the launch-window convention ships a breaking change as minor (check-changeset-no-major), and the fixed group already carries the pending major that opens the v18 line, so the level moves no version on its own.
  • packages/spec/src/ui/view.test.ts — the defaults pin flips to true, plus four pins: an absent key parses to true (on UserActionsConfigSchema and through ListViewSchema), an explicit false stays false, an explicit true stays true, and the view-level inlineEdit: true still parses as before with no userActions block materialised (the fold is the renderer's; the spec keeps both spellings as declared).

Measured first (the PM's mechanism assumptions)

  1. Other sites stating the old default. view.zod.ts:1535 read .default(false) with the "Off by default" describe — corrected. The four reference rows regenerate. Nothing else in the tree states the old default: content/docs/ui/views.mdx lists the view-level inlineEdit with no default; content/docs/protocol/objectui/layout-dsl.mdx:667 is about record:details' own inlineEdit (a different key, renderer default on); packages/spec/src/data/object.zod.ts retired-key guidance says only that editInline is a view key; object-strictness-batch20.test.ts lists key names. Left as they are, with reasons: .changeset/console-20c6d351ad74.md describes the console at pin 20c6d351ad74, which still reads an absent key as off until objectui#12086 lands and the pin moves (true of that build); CHANGELOG.md:1677 and packages/spec/CHANGELOG.md are release-owned history.
  2. ADR-0087 disposition. check:adr-0087-registration demands a marker on a declared-breaking changeset; not-required (no-migration-prescription) is refused when the body carries a prescription, and this one prescribes editInline: false. The honest disposition is registered: a D3 semantic entry at step 18, the same class as view-pagination-page-size-default-50 and protocol 12's rest-requireauth-default-flip. No key is removed (no tombstone, no RETIRED_KEYS_BY_MAJOR row) and no D2 conversion exists — a mechanical pass writing editInline: false into every silent view would preserve the old posture and defeat the ruling. The registry regenerated byte-exact after merging origin/main (which brought the sibling entry page-slots-details-beside-tabs-refused, not adjacent in id order; check:migration-registry green). A second ledger also applies: the authorable-defaults ratchet refuses an undeclared default move, so DEFAULT_CHANGES_BY_MAJOR carries the hop.
  3. Reach of the remedy, at e11ef3a7bd (git grep, tests and changelogs excluded): 0 editInline: false and 0 editInline: true across examples/** and packages/** metadata. Views that declare nothing and now gain the toggle: 38 list-kind views with an explicit type across 10 example *.view.ts files (entries with no type are grid by default and count the same way), 12 interfaceConfig page lists across 5 showcase page files (11 declare a userActions block, none naming editInline), 105 list-kind views across 40 platform *.object.ts files in packages/**. One view declares the view-level inlineEdit: true (the showcase task grid saved view) and keeps opening in edit mode. The only test that asserted the old default is view.test.ts (expect(config.editInline).toBe(false)), flipped here; no other package's tests read the view-level userActions default (consumer tests on userActions are the object-level CRUD block). The card's readings outside this repository (cloud sys-package.page.ts:105 declares editInline: false; HotCRM's 41 undeclared views) were not re-measured here.
  4. The skill file skills/objectstack-ui/rules/list-views.md is hand-written: the only generated lifts inside skills/** are references/_index.md and references/react-blocks.md (GENERATED_SURFACE_EXCEPTIONS). Its paragraph is PR 2.

Tests (post-merge head 24d9bdcbf0, shared-box readings under the verify lock)

  • pnpm --filter @objectstack/spec build — green; check:generated — ✓ All 15 generated artifacts are up to date.
  • pnpm --filter @objectstack/spec exec vitest run --project local --maxWorkers=2 (the package's test script) — Test Files 642 passed (642) · Tests 19150 passed | 1 todo (19151).
  • Targeted, before and after the merge: src/ui/view.test.ts src/ui/page.test.ts src/migrations/migrations.test.ts src/migrations/semantic-relevance.test.ts — 4 passed · 740 passed; the repo-project files scripts/step18-rationale-merge.test.ts scripts/authorable-defaults.test.ts scripts/build-schemas-check-mode.test.ts — 4 passed · 146 passed (with semantic-relevance).
  • pnpm --filter @objectstack/spec typecheck — tsc --noEmit, check:scripts-typecheck and check:test-typecheck green (52 file(s) / 246 error(s) / 135 pinned signature(s) held, the shrink-only debt ledger unchanged).
  • test:repo beyond those three files is declared to CI (Test Core).

Ablation (reverse verification)

node scripts/ablation-replace.mjs --file packages/spec/src/ui/view.zod.ts --anchor 'editInline: z.boolean().default(true)' --replacement 'editInline: z.boolean().default(false)' -- pnpm --filter @objectstack/spec exec vitest run --project local --maxWorkers=2 src/ui/view.test.ts, at head 24d9bdcbf0, after the fix was committed. Mutation proved on disk: anchor 1 → 0, replacement 0 → 1, blob 6979ade6158a → e0e02cd7f858. Direction observed: red, exactly the two default pins — should apply default values and an absent key parses to true (expected false to be true), 2 failed | 462 passed (464). Restore proved: blob after restore 6979ade6158a == blob at HEAD, git diff HEAD empty, tree clean. Resolution path: the pin imports the schema from the package's own src (no dist in the path), so no rebuild sits between the mutation and the reading.

Gates (local, at 24d9bdcbf0)

Derived with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths; the tool reads the change set off the merge base): 115 families. Reconciled with --ran: 115 derived, 114 run, 0 NOT-MEASURED, 1 UNRUN — the UNRUN is pnpm check:dual-build-cjs-loads, declared NOT MEASURED by the dispatch (it needs a whole-workspace build). Every other derived family exited 0, after building the prerequisites some of them load (@objectstack/formula, lint, client, client-react, objectql), except pnpm check:dts-closure, which exited 1 for a missing dist/ under plugin-approvals and plugin-dev: it reads every package's built declarations, so without the whole-workspace build it is NOT MEASURED, not red (CI's Build Core covers it). The artifact-roster block (49 families): 46 run, every one exit 0 except pnpm check:published-readme-exports, exit 3 (44 unbuilt packages, NOT MEASURED for the same reason); the three PR-context guards (check-closing-target-claim, check-partof-closing-keyword, check-single-claim-paths) run once this PR has a number, and their readings go in the report comment on the card. Staleness note the tool prints: the derivation tree is two commits behind origin/main 83b8b80728, and the one derivation input that moved is scripts/platform-object-tenancy-census.json (the tenancy-census roster); that family ran green on the older copy, and no path of this diff overlaps those two commits.

Lint, as a proven narrowing rather than the CI-owned pnpm lint: pnpm exec eslint --no-inline-config --format json over the .ts/.mjs files in the two-point diff — 24 files linted, 0 errors, 0 warnings (the count is from the JSON output; the set is wider than this PR's own 9 files (233 insertions, 7 deletions off the merge base e22315238f) because the two-point diff includes the merged sibling commits). Population, read from eslint.config.mjs: **/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs} minus its ignores, so the .md, .mdx and .json files of this diff are outside it (eslint reports them "ignored because no matching configuration"). Invariance: the config declares no parserOptions.project and no typed @typescript-eslint rules, so this diff cannot move the verdict of any file it does not touch.

Acceptance notes


Generated by Claude Code

…18 line; editInline: false is the opt-out

Maintainer ruling 2026-10-10, verbatim: 「乙 v18 把 spec 默认翻成 true,editInline: false 变成关法。」
A list view is editable in place by default under the permission gate that already exists.
The declared default of UserActionsConfigSchema.editInline moves false -> true with the
describe rewritten; the declared default change is ledgered at major 17 and the D3 semantic
entry list-view-edit-inline-default-on is added at protocol 18. Pins: an absent key parses
to true, an explicit false stays false, the view-level inlineEdit still parses as before.

Claude-Session: https://claude.ai/code/session_01KNKBCRDJCu5tGy3TEbvtrF
Co-authored-by: Claude <noreply@anthropic.com>
…ages for the editInline default; add the changeset

gen:migration-registry concatenates the D3 entry into registry.ts; the spec build moved
ui/UserActionsConfig:editInline to true in authorable-defaults/ui.json under the declared
chain; gen:docs rewrote the four editInline rows in references/ui/view.mdx and page.mdx.
spec-changes.json and docs/protocol-upgrade-guide.md are not regenerated here: the PR-stage
check projects the registry in memory and compares no committed copy, and the committed copies
on origin/main already carry sibling drift this diff does not own.

Claude-Session: https://claude.ai/code/session_01KNKBCRDJCu5tGy3TEbvtrF
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation protocol:ui tests tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface labels Oct 10, 2026
@github-actions

github-actions Bot commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

2 anchor(s) derived from 1 changed package(s); no hand-written page names any of them. ⚠️ 1 changed file(s) yielded no anchor (packages/spec/authorable-defaults/ui.json), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/spec/authorable-defaults/ui.json) — pages documenting those are invisible to this run
  • 4 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 54 of 206 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 139 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json f368b7e980d3df201620098be965523b50d6df19 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 7ea2f37356cdc3787e2053c4786707be157a22a5 — the merge of head fc3733b9714493610f60cc80e7849f36471a6548 into base f368b7e980d3df201620098be965523b50d6df19, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 7ea2f37356cdc3787e2053c4786707be157a22a5 && git checkout 7ea2f37356cdc3787e2053c4786707be157a22a5
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin f368b7e980d3df201620098be965523b50d6df19 fc3733b9714493610f60cc80e7849f36471a6548 && git checkout -B drift-repro f368b7e980d3df201620098be965523b50d6df19 && git merge --no-ff fc3733b9714493610f60cc80e7849f36471a6548

node scripts/docs-audit/affected-docs.mjs --json f368b7e980d3df201620098be965523b50d6df19

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 24d9bdcbf008e79365002ffb56616f8d1e4b3b74
Local-runs: none

Read-only: the card body and its four comments (triage 6093968052, claim 6094254055, dev report 6094863892, ACCEPT 6094884470), the PR body and file list, the net diff against the merge-base e22315238f (9 files, +233 / −7, identical to the three-dot diff against origin/main), and the head's check-runs. The branch is at the brief's sha. Nothing built, run or re-run.

① Derived judgments

  • The default and its describe. UserActionsConfigSchema.editInline is z.boolean().default(true); the describe says on by default, a user who may update the object edits a cell in place with the field's type-aware widget under the permission gate, and editInline: false makes the list read-only in place — the card's three sentences. The schema docblock records the ruling verbatim. Held.
  • DEFAULT_CHANGES_BY_MAJOR[17]. The row is ui/UserActionsConfig:editInline, from: 'false', to: 'true', inside the 17: [ block (lines 218–621 at head) beside the ui/PaginationConfig:pageSize row. 17 is the only key that can authorise anything: CURRENT_MAJOR is parseInt(SPEC_VERSION) with @objectstack/spec at 17.7.0, and the ratchet's rule 4 is that only the current major authorises. authorable-defaults/ui.json moves exactly one line (= false → = true), matching both fingerprints. Held.
  • The D3 entry list-view-edit-inline-default-on. One file, entries/semantic/18.list-view-edit-inline-default-on.ts, protocol 18 — the same step as view-pagination-page-size-default-50. surface names the OMITTED key on both carriers of the one schema (a list view's userActions, a page's interfaceConfig.userActions) and carries no backtick, as the build-upgrade-guide note demands; replacement is "nothing" plus the opt-out; reason quotes the ruling and says why no D2 exists (a pass writing false everywhere would preserve the old posture and defeat the ruling); acceptanceCriteria matches the card's acceptance. No tombstone, no RETIRED_KEYS_BY_MAJOR row, no D2 — right, nothing is removed. The registry.ts hunk is the entry byte-for-byte inside step18. Held. One observation, not a finding: the reason string carries objectui#5144; 12 of the 414 semantic entries on origin/main already carry an objectui#N in prose, so it is precedented, and check:doc-authoring rule 2 scans a different surface.
  • Regenerated references. Four rows — view.mdx ×3, page.mdx ×1 — now read optional (default: \true`)with the new describe. At head,git grepfor the old describe text ("Off by default: the list") hits only this PR's own changeset quoting it; no rendered row survives.TypeScript Type Check(the job that runs every spec artifact gate,check:docsandcheck:authorable-surfaceincluded) concludedsuccess` on this head, which is the CI reading that the JSON-schema and docs artifacts are current.
  • Accept set unchanged, only the parsed default moves. editInline stays z.boolean(); .default() alone moves; the inferred type is boolean on both sides, which is why check:api-surface has nothing to say. The five pins hold the contract: absent parses to true on the schema and through ListViewSchema; explicit false and true keep their values; the view-level inlineEdit: true still parses with no userActions block materialised (the fold is the renderer's). The dev's ablation (.default(false) back) reads as exactly the two default pins red, blob-equal restore — consistent with the diff; not re-run here.
  • Every other place that still states the old default, at head: .changeset/console-20c6d351ad74.md lines 24 and 71 say the console at pin 20c6d351ad74 reads an absent key with the spec's default, off — true of that build until objectui#12086 lands and the pin moves; carrier named in ③. Root CHANGELOG.md:1677 is release-owned history and stays. content/docs/ui/views.mdx:111 lists the view-level inlineEdit with no default; layout-dsl.mdx:667 is record:details' own inlineEdit, a different key; object.zod.ts:2043 says only that editInline is a view key. No example and no skills/** file in this repository states the old default; no in-repo metadata declares editInline at all. The permission gate and objectui are untouched, as the card requires.

② Semver level

  • minor is right; major is not, even though pre mode would admit it. check-changeset-no-major.mjs ships breaking changes as minor for the launch window (end condition: GA, not reached); its RC exemption lets a major through while .changeset/pre.json reads mode: pre, tag next, so major was available — but the repository's own default-flip precedents on this line all took minor: view-pagination-page-size-default-50 (8ecbe0f, under ### Minor Changes), approval-escalation-enabled-default-flip ("shipped as minor under the repo's launch-window convention"), audience-posture-default-invite-only (same words). Protocol 12's rest-requireauth-default-flip (7c09621) sits under ### Major Changes, but that was before the window and is not the rule now. The fixed group already carries the pending major that opens the v18 line (22080-v18-line-opens.md, 22130-protocol-18.md), so this minor moves no version and rides the 18.0.0-next.N train. The BREAKING banner is present and is the only breaking signal the ADR-0087 gate reads here (no major, no bang on the changeset's first line, no narrowing arm); the marker registered list-view-edit-inline-default-on resolves at head and is new in this diff; the FROM → TO table and the one-line fix are there. Held.
  • The Clause-② arm is NOT right, and this is the one finding of record. The line answers 「本卡放宽接受集或扩大公开面吗」, and the ruled definition (pr-automation.yml WHICH LEVEL, the maintainer's ruling on finding(changeset): two independent contract reviews read the repo's own history to opposite bumps for "add an exported symbol to a published index" #15294) is "a purely additive widening of a published package's public surface (a new exported symbol on an index, a new accepted key or value)". This diff adds no export, no key and no value; the changeset itself says "The accept set is unchanged" and declares the act BREAKING, and the ADR-0087 gate's own docblock says "A widening is not a break". One act cannot be a purely additive widening and a break at once. A moved default is neither a widening nor a narrowing of the accept set, so the truthful declaration is Clause-②: no with no arm, breaking-ness carried where the window puts it — the banner and the marker. The card's parenthetical ("a view declaring nothing gains an affordance it did not have") reads the console's behaviour, not the package's surface. Origin: the card and the dispatch claim 6094254055; the dev copied the line as os-dev.md requires (照抄, ⛔ 不自造), so the correction is the seat's — on the claim, then on the PR body (line 2) and .changeset/22605-spec-list-view-edit-inline-default-on.md:13. It matters because the line ships verbatim into packages/spec/CHANGELOG.md (416 Clause-② lines there today) and is what every later census reads. No gate moves on the correction: the level axis reads no as not-declared and exits 0 with minor untouched; the ADR-0087 gate still reads BREAKING from the banner and still finds the marker. The pm-dispatch instrument-discipline reference assigns the direction to this review (Clause-② 的方向由达档复核裁), so it is ruled here: no.

③ Boundary flags

Implemented-by: claude/issue-22605-edit-inline-default-on
Reviewed-by: session_01KNKBCRDJCu5tGy3TEbvtrF

VERDICT: FAIL


Generated by Claude Code

…set declares Clause-②: no

Patch round on the contract review (a moved default neither widens nor narrows the accept
set; the banner and the ADR-0087 marker carry the breaking signal) and the Test Core red it
found: packages/cli/test/migrate-meta-engine-guidance.test.ts refuses a tracker id in printed
guidance. The entry's reason now says "the one-vocabulary rule objectui ruled for the fold";
the citation moves to the file's leading comment, as the other entries do; the
DEFAULT_CHANGES_BY_MAJOR[17] reason is rewritten the same way; registry.ts regenerated.

Claude-Session: https://claude.ai/code/session_01KNKBCRDJCu5tGy3TEbvtrF
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: fc3733b9714493610f60cc80e7849f36471a6548
Local-runs: none

Round 2, scoped: what moved since the round-1 head 24d9bdcbf0 (record 6095058376, FAIL), and whether that record's FAIL items are cured. Read-only: the card body and its comments through the dev's patch report 6095196973 (the seat's patch order 6095101276 included), the PR body and file list, the two-point diff 24d9bdcbf0..fc3733b971, the net diff against the merge-base e22315238f (unchanged since round 1), and the head's check-runs. Nothing built, run or re-run; the dev's local readings are reported here as the dev's, never adopted as a gate's.

What moved. git diff --name-only 24d9bdcbf0 fc3733b971 is exactly the four files the patch report names — the changeset, packages/spec/scripts/lib/default-changes.ts, entries/semantic/18.list-view-edit-inline-default-on.ts, registry.ts — 4 files, +15 / −7, one commit, 24d9bdcbf0 an ancestor of the head. The net diff against the merge-base is still the PR's 9 files (+241 / −7: round 1's +233 plus this hop), identical to the three-dot diff against origin/main 1b99388505. main is seven commits past the merge-base; none touches a path of this diff, and none has touched src/migrations, default-changes.ts, authorable-defaults/ or the two projections since the round-1 merge, so no regen-merge was owed. Everything round 1 held in view.zod.ts, view.test.ts, ui.json and the two reference pages is untouched by this hop and stays held.

① Derived judgments

  • The D3 entry — right. id, surface, replacement and acceptanceCriteria are byte-identical to the round-1 head, compared field by field. reason moves in one line: "the one-vocabulary rule of objectui#5144 stands" is now "the one-vocabulary rule objectui ruled for the fold stands". Scanned with the pin's own shape (# plus four or five digits, word-bounded) over every non-comment line of the entry: no hit. The only #5144 left in the file sits in the leading // comment, which now also says why it lives there ("the citation lives here, not in the printed guidance, which carries no tracker number"). That is the right home: os migrate meta prints surface, replacement, reason and acceptanceCriteria and never the comment, and the tracker ids main's other entries carry all sit comment-side. Round 1 read "12 of 414 entries carry an objectui#N" as precedent for a printed string; that was wrong — they are comments — and the pin said so on the round-1 head.
  • The registry.ts hunk — right, the generator's copy. The 52-line block inside step18 is the entry's leading comment and literal rendered exactly as renderRegion renders them (build-migration-registry.ts): every comment line indented four spaces, the declaration line as {, the closing }; as },, every literal line indented four — compared line for line against the entry file at this head, no difference. It sits in id order, before list-view-navigation-view-retired. The hunk's +6 / −2 against the round-1 head is the comment run growing by four lines plus the one reason line, which is what the generator copies by design; the dev's deviation note on this is answered. The CI reading of generator identity is check:migration-registry, a step of Lint & Repo Gates, named under ③.
  • The DEFAULT_CHANGES_BY_MAJOR[17] row — right. key, from, to unchanged; the row still sits under 17: [, the only major that authorises a hop (CURRENT_MAJOR is the package major), and still names the D3 entry by id. Its reason takes the same one-sentence rewrite; scanned with the same shape: no hit. No gate demanded this one — the pin reads the registry, not this ledger, and main's own ledger still carries tracker ids in four of its earlier reason strings — but the row's reason is printed into the build log on every run (build-schemas.ts, the "declared default change(s) accepted" block), so the rewrite follows the rule that text an author is shown carries the lesson and not the number, and it loses nothing. check:authorable-surface accepted the moved fingerprint on this head (Type Check · source gates concluded success), as on the round-1 head.
  • The changeset's Clause-②: line — right at no, judged under ②. Nothing else in the changeset moved: the **BREAKING** banner, the FROM → TO table, the one-line fix, the measured reach and the adr-0087 marker registered list-view-edit-inline-default-on are byte-identical to the round-1 head, and the marker still resolves to the entry at this head.

② Semver level

  • minor — held from round 1, unchanged on this head: the launch-window convention ships a breaking change as minor (check-changeset-no-major), the three default-flip precedents on this line took minor, and the fixed group already carries the pending major that opens the v18 line, so the level moves no version on its own.
  • Clause-②: no — right, and round 1's one finding of record is cured. The line answers 「本卡放宽接受集或扩大公开面吗」, and the ruled definition of a widening (pr-automation.yml WHICH LEVEL, the maintainer's ruling on finding(changeset): two independent contract reviews read the repo's own history to opposite bumps for "add an exported symbol to a published index" #15294) is "a purely additive widening of a published package's public surface (a new exported symbol on an index, a new accepted key or value)". This diff adds no export, no key and no value — editInline is still z.boolean(), only .default() moves, and the changeset itself says "The accept set is unchanged". A moved default narrows nothing either, so no arm: no (narrowing) would declare an accept-set shrink that does not exist, and no (widening) is the malformed pair. Breaking-ness rides where the window puts it: the **BREAKING** banner, which check-adr-0087-registration's breakingDeclaration reads as a signal of its own with no help from the arm (its self-test pins a bare Clause-②: no as NOT a breaking signal and the banner as one), plus the registered marker, which resolves. The level axis of check-changeset-no-major reads no as not-declared and stands down with minor untouched. Check Changeset, the job that runs both gates against the merge-base, concluded success on this head — the gate reading for both.
  • The PR body's line 2 agrees: Clause-②: no, bare, on a line of its own, which readClause2Line returns as declared / no / no arm. The correction chain round 1 asked for is complete on every machine-read carrier: the claim 6094254055 (corrected by the seat), the PR body's line 2 (the seat), the changeset's line 7 (the dev). One residue, named in ③. Round 1 and the patch order both numbered the changeset's declaration "line 13"; it is line 7, and the dev edited the right line — the misnumbering was round 1's.

③ Boundary flags

  • Round 1's FAIL items, each. (1) The Clause-② arm: cured, above. (2) Test Core (4/6) red on 24d9bdcbf0 — confirmed by that head's check-runs (Test Core (4/6) failure, the Test Core fan-in failure), the failing assertion being migrate-meta-engine-guidance.test.ts's "the printed guidance cites a tracker id" on this PR's entry. Cured on this head by its own check-run: Test Core (4/6) concluded success, and the required Test Core fan-in with it (both named below). The diff-side reading is that the head's printed fields are clean under the pin's own regex; the dev reports red reproduced before the patch and green after it, with the CLI closure build between the registry change and the reading on both legs (the pin resolves @objectstack/spec/migrations through the built dist), a shape consistent with the diff and not re-run here.
  • The dev's deviations, each answered. Line 7, not 13: the right line moved, above. Worktree recreated at 24d9bdcbf0 with no merge of origin/main: right — nothing on main since touches a path of this diff or a registry input, and the queue rebuilds onto current main. The changeset's prose still citing objectui#5144 and objectui#12086: not owed a change. The pin's surface is the printed migrate-meta guidance, the registry's four fields; check:doc-authoring's roots are .claude, docs, skills and content, not .changeset/, and its tracker rule is for runtime strings and refusal prose. A changeset ships to packages/spec/CHANGELOG.md, where 304 lines on main already cite an objectui#N and 59 of the 259 .md files under .changeset/ carry a #NNNN: a changelog citing the sibling repository's ruling record is this repository's norm, and here the citation is the provenance of the rule the changeset says still stands. The same holds for the objectui#5144 in the view.zod.ts docblock and the view.test.ts comment, both held from round 1 and neither printed. The registry hunk carrying the comment run: by design, above.
  • One residue on the PR body, owed to the seat, non-blocking. Line 17 of the body (the "What changed" bullet for the changeset) still describes the changeset as carrying Clause-②: yes (widening) and argues minor from "Clause-②: yes takes at least minor". No gate reads it: the declaration reader takes the first key-initial line (line 2) and keeps a mid-line backticked mention only as a residue to quote when no declaration exists, which is why Check Changeset and the claim guard are green on this head. It ships nowhere — a PR body is not a changelog. But it contradicts line 2 of the same body and the changeset it describes, so the seat corrects that bullet (and may note the citation move in the D3 bullet) in the act that enqueues; a body edit moves no head and asks for no re-review.
  • The landing-order window round 1 escalated is now open, and this PR is its only remedy. PR docs(skills): a list view edits in place by default; a read-only list declares editInline: false (#22605, skill half) #22630 landed first by the maintainer's hand (f368b7e980; the seat's reopen note 6095085980): the published skill on main teaches that a list edits in place by default, while view.zod.ts on main still reads .default(false) and the published spec is unchanged. The seat's order calls the patch urgent for that reason, rightly; the window closes when this head lands, and nothing else in this diff is asked to move. The seat enqueues on this record once every required context is green.
  • Carriers held from round 1, unchanged: the console pin changeset's "spec default false" line (carrier: the next pin bump), the README / AGENTS.md regenerate-table drift (spec(changes): delete the committed spec-changes per-major projection and the upgrade guide copy, with their two merge=os-regen routes, once generation at publish has landed (#22449 B′) #22485), spec-changes.json and the upgrade guide not regenerated (right, since [Decision] generated protocol-change records (spec-changes.json per-major section, docs/protocol-upgrade-guide.md): keep committing them, or generate them at publish like the release section #22449 B′).
  • CI on this head, read at 2026-10-10T07:55Z. Required (the ruleset's seven): TypeScript Type Check success (Type Check · source gates, · workspace, · debt ledger, · consumer gates all success beneath it), Build Core success, Dogfood Regression Gate success, Temporal Conformance (live PG + MySQL) success, Governed Surface Queue Guard success, Lint & Repo Gates success (the job that runs check:migration-registry — the generator-identity reading for the registry hunk — and check:doc-authoring), Test Core success with every shard success, Test Core (4/6) among them. The last three concluded while this record was being written and were read again before it was posted: 35 check-runs on the head, none open, none red. Advisory: every concluded check success or skipped (Check Changeset, the three PR-context guards, Spec property liveness, Check PR Size, Console Pin Gate skipped, the packed-tarball smoke skipped); no advisory red.
  • State of the PR: draft, needs:contract-review carried, no auto-merge, no governed path in the file list — the review is owed by the claim's own term, not by Tier S.

Implemented-by: claude/issue-22605-edit-inline-default-on
Reviewed-by: session_01KNKBCRDJCu5tGy3TEbvtrF

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Landing pre-checks at fc3733b971, by the owning seat: every check green, queued

domain:spec seat 3 (#18883) · zhuangjianguo · session session_01KNKBCRDJCu5tGy3TEbvtrF · 2026-10-10T07:59Z · holder of claim 6094254055 on #22605.

needs:contract-review comes off; pr_ready and automerge_enable follow.


Generated by Claude Code

akarma-synetal pushed a commit to akarma-synetal/objectui that referenced this pull request Oct 28, 2026
… on, the v18 spec default (objectui#12086) (objectstack-ai#12092)

Fixes objectstack-ai#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.editInline` as on (`!== false`): a list view is
editable in place by default, under the permission gate that already
exists, and `userActions: { editInline: false }` makes it read-only in
place. The `inlineEdit` fold is unchanged, and so is the gate.

## What changed

- **`ListView`** (`@object-ui/plugin-list`): `inlineEditOffered` returns
`false` only for an explicit `editInline: false`; anything else falls
through to the unchanged `listInlineEdit` affordance verdict (the object
editable in place, and the principal's `update` grant). The Gap 2
docblock now states the v18 default and the opt-out.
- **ADR-0047 interface page** (`@object-ui/app-shell`,
`InterfaceListPage`): `inlineEdit: userActions.editInline !== false`,
and the "default off" comment is corrected.
- **Pins** (each kept load-bearing by a twin that differs in one input):
- `ListView.permissions.test.tsx`: a view that declares nothing is
offered the toggle for a principal with `update` and not for one without
it (same schema, permission differs); with no `PermissionProvider` it is
offered (fail-open kept); an absent `editInline` reads on and the grid
opens out of edit mode; the compact popover offers the entry for an
absent key, and its control withholds it for `editInline: false`;
`editInline: false` withholds the toggle from a fully permitted
principal. The stored `inlineEdit: true` case (offered, opens in edit
mode) is unchanged and still green.
- `InterfaceListPage.editInlineFold-5144.test.tsx`: an absent page
`editInline`, and a page with no `userActions` block, now read on on
both sides of the fold; an explicit `editInline: false` is 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.
- **Docs**: `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, with `editInline: false`
as the opt-out.
- **Changeset**: `.changeset/12086-edit-inline-default-on.md`, `minor`
for `@object-ui/plugin-list` and `@object-ui/app-shell`, with the
behaviour change in the prose.

## Measured before writing (the PM's three mechanism assumptions)

1. **The spec half is on objectstack `origin/main`.**
`packages/spec/src/ui/view.zod.ts` declares `editInline:
z.boolean().default(true)` (read with `git show origin/main:`; `git
merge-base --is-ancestor f53f14bb36 origin/main` answered exit 0, which
self-certifies). The installed `@objectstack/spec` here is 17.7.0, whose
dist still declares `editInline: z.boolean().default(false)`. **Does any
objectui code read the installed default?** No runtime reader does. The
quoted-name grep for `UserActionsConfigSchema` and for `ListViewSchema`
/ `ViewSchema` `.parse(` / `.safeParse(` across `packages/*/src` and
`apps/` finds the parse calls only in tests and in two `FormViewSchema`
reads (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"), asserts `group` / `hideFields` / `rowColor` only,
not `editInline`, so it does not fight the new read. One display-only
reader exists: the metadata-admin View inspector derives its JSON Schema
from the installed `ViewSchema` with `z.toJSONSchema`. It writes
nothing, and its boolean switch renders `!!value` and ignores a schema
default. See Acceptance notes.
2. **The two sites are the only absent-as-off readers.** Every
`editInline` reader in `packages/*/src` outside tests, from the quoted
exact-name grep (positive control: the same grep hits the known
`ListView.tsx` and `InterfaceListPage.tsx` sites): `ListView`
`inlineEditOffered` (was `!== true`); `InterfaceListPage` (was `===
true`); the `normalizeListViewSchema` fold (`typeof === 'boolean'`, no
default); and the `@object-ui/plugin-view` `ObjectView` `userActions`
merge (a spread of three folded layers, no default). The other hits are
comments, the `detail.editInline*` i18n keys (a different namespace),
and the grid's own `userActions` comments. The assumption holds. The
`inlineEdit` readers carry the edit MODE (`!!schema.inlineEdit`, the
named-view relay, `ObjectGrid`'s `editable`); none reads an absent
`editInline` as off.
3. **The cloud window (see below).** No example app or fixture in this
repo declares nothing and relies on the old default for a read-only list
through a `ListView`-rendered path. The quoted grep for `editInline`,
`inlineEdit` and `userActions` over `apps/` and `examples/` hits 0
(positive control: the same grep finds `listViews` / `object-grid` /
`object-view` there). The list views that do exist there
(`examples/byo-backend-console`'s `object-view` with a named `grid`
view, the schema-catalog `object-view` / `object-grid` entries,
`apps/console`'s dev `object-grid`) render through `ObjectGrid`
directly, with no host `renderListView`. On that path `ObjectGrid`'s
`editable` comes from the view's `inlineEdit` and never from
`editInline`, so this change does not move them.

## The cloud window (named, as triage directs)

Cloud consumes objectui `main` on its frozen v17 framework. There, a
list view that declares neither `userActions.editInline` nor
`inlineEdit` now 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 without `update`
on 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
declares `editInline: false` explicitly. 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`,
no `compactToolbar`. Its `userActions.editInline` therefore reaches
`ListView` as 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 `!==
false` orders for this site, and it is what the spec's new `describe`
says ("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` (`inlineEditOffered` and 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 the
`inlineEdit` reason string in
`InterfaceListPage.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 that `ListView` reads an
absent pair as off.
- `packages/app-shell/src/views/ObjectView.tsx`: the
`keepInlineEditModeForTheSession` docblock quoted the v17 `describe`
("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 said `ListView` offers inline editing "only where that
reads `true`".

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-exit`
line. Test runs use the repo-root form `pnpm exec vitest run
--maxWorkers=2 PATHS`.

- **Targeted pins, on the final head `9cd778d1d`** (after merging
`origin/main` `de302c73`): the four touched pin files, the five other
`InterfaceListPage*` tests, `ObjectView.inlineEditSessionOnly-5144`, the
two `normalize-list-view` fold 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 on
`efa9e08f1`, before the merge.
- **`@object-ui/plugin-list`, whole package, on `efa9e08f1`**, plus the
four app-shell `ObjectView` tests that render the real `ListView` with
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 (a one-time proof; no test file kept).** Each leg was run
from the committed head through `ablation-replace.mjs`, whose anchor hit
x1 and went to x0, and whose blob changed. Each was restored to the HEAD
blob with `git diff HEAD` empty, so the restore was proven on disk.
- Leg A put the v17 read back into `inlineEditOffered` (`?.editInline
!== true`). `ListView.permissions.test.tsx` went `4 failed | 19 passed
(23)`. The four red cases are exactly the predicted ones: offered with
`update` on a view that declares nothing; offered with no
`PermissionProvider`; an absent `editInline` reads on; the compact entry
is offered for an absent key. "WITHOUT update loses it" stays green
under both reads, as expected.
- Leg B put `inlineEdit: userActions.editInline === true` back on the
interface page. `InterfaceListPage.editInlineFold-5144.test.tsx` went `2
failed | 2 passed (4)`: the two absent cases.
- **Type-check** (`pnpm --filter PKG type-check`, which is `tsc --noEmit
&& tsc -p tsconfig.test.json`), after building the dependency closure
with `turbo run build --filter=PKG^... --concurrency=2` (`28 successful,
28 total`). `@object-ui/core`, `@object-ui/plugin-list`,
`@object-ui/plugin-view` and `@object-ui/app-shell` all exit 0 with 0
`error TS` on `efa9e08f1`. `@object-ui/app-shell` exits 0 again on
`9cd778d1d`, since main's two merged PRs touched app-shell source.
- **eslint on the 11 touched `.ts` / `.tsx` files** (`--format json`,
counted from its output): 0 errors. Every file's error/warning count is
identical to its base-blob count (lint run over `git show
023f00d:FILE` via `--stdin`). The repo's `eslint.config.js` sets no
`parserOptions` / `projectService`, so linting is not type-aware, and
this diff cannot move a verdict on an untouched file.
- **Gates, re-run on `9cd778d1d`:** `check:new-line-citations` (`0 new
citation(s)`), `check:control-bytes`, `check-changeset-presence`,
`changeset:check` (no `major`), `check-changeset-overwrite`,
`check:changeset-claims`, `check:pending-changeset-literals`,
`check:doc-fences`, `check:doc-types` and `check-doc-links`. All exit 0.
The four `vi.mock` / test-path gates exit 0 on `efa9e08f1`.
- **NOT MEASURED: `check:doc-snippets` and `check: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 of `plugin-view.mdx` extracted at base and at head are
byte-identical (md5 `3fd26d2a…` both, 18 blocks). The diff touches 0
lines carrying `@example` or a fence in `packages/*/src`. Control:
`ListView.tsx` carries one `@example`, which is untouched.
- **Declared narrowing: `@object-ui/app-shell`'s full suite was not run
locally**; CI runs it. The local app-shell set is every test that
imports `InterfaceListPage`, the session-only toggle pin, and the
`ObjectView` tests 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 renders `checked={!!value}` and ignores
the JSON Schema `default`. So in the View inspector, an absent
`userActions.search` / `sort` / `filter` (default `true`) already shows
OFF while the toolbar reads it ON. `userActions.editInline` joins that
set once objectui installs a spec 18 build. The installed 17.x schema
still says `default: 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 `ObjectGrid` path does not read `editInline`.** On an
authored `object-view` with a named `grid` view and no host
`renderListView`, `ObjectGrid`'s `editable` is the named view's
`inlineEdit` (or `table.editable`). `userActions.editInline` is not read
there. So `editInline: false` does not withhold edit mode from a named
view that also says `inlineEdit: 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:ui` seat 3). `.changeset/5144-editinline-fold.md` is 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:
1. "List views read `userActions.editInline` with the spec's default,
off." → "… with the spec's default, on since
objectstack-ai/objectstack#22605 (`editInline:
z.boolean().default(true)`), and `editInline: false` is the opt-out."
2. "**Breaking for a view that relied on the old default.**" → "**The
spec's default, read as declared.**"
3. "The spec declares `userActions.editInline` with `.default(false)`:
the list is read-only unless the author opts in." → "… with
`.default(true)` (objectstack-ai/objectstack#22605): a list view is
editable in place by default, under the permission gate, and
`editInline: false` is the opt-out."
4. "The interface page already read it that way." → deleted. The
paragraph now closes with "The flip of the default, and the interface
page that reads it, are the objectui#12086 entry of this release."
5. "The object-list toolbar did not: it read …" → "The object-list
toolbar used to read …". Only the lead-in changed, because it leaned on
the deleted sentence 4.
6. "A grid view that declares neither … no longer offers the inline-edit
toggle … and never opens in edit mode." → "… offers the inline-edit
toggle, on the wide toolbar and in the compact settings popover, and
opens out of edit mode."
7. "- a view with neither key reads off." → "- a view with neither key
reads on, the spec's default."
8. "**What to do.** A view that should offer inline editing declares
`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 declares `userActions.editInline: false`. A view
that declares `userActions.editInline: true` keeps 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.md` was 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](https://claude.ai/code/session_01B1gHb9baeX7oioD5sHVm7z)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: objectstack-fleet[bot] <332303061+objectstack-fleet[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation protocol:ui size/m tests tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants