Repository navigation
feat(spec)!: ListView.userActions.editInline defaults to true on the v18 line; editInline: false is the opt-out (#22605, spec half) - #22629
Conversation
…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>
…it-inline-default-on
📓 Docs Drift Check2 anchor(s) derived from 1 changed package(s); no hand-written page names any of them. What this run could not see
Coarse fallback — 139 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # 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 |
Contract reviewServed-tier: Read-only: the card body and its four comments (triage ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: 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>
Contract reviewServed-tier: Round 2, scoped: what moved since the round-1 head What moved. ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
Landing pre-checks at
|
Part of #22605
Clause-②: no
The spec half of #22605:
ListView.userActions.editInlinedefaults totrueon the v18 line, anduserActions: { editInline: false }is the opt-out. Theskills/**paragraph the card also asks for is a separate pull request (Tier H), so this one isPart of, notFixes.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
inlineEditfold, declared = enforced); only the default's value changes. Not taken: declaringeditInline: trueon 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.editInlineisz.boolean().default(true),describerewritten (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; declareeditInline: falseto 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]gainsui/UserActionsConfig:editInlinefalse→truewith its reason. This is what letscheck:authorable-surfaceaccept the moved fingerprint;CURRENT_MAJORis 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 intoregistry.tsbygen: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 bygen: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 remedyeditInline: false, the FROM → TO table, the measured reach, and the ADR-0087 markerregistered list-view-edit-inline-default-on.minorbecause the launch-window convention ships a breaking change asminor(check-changeset-no-major), and the fixed group already carries the pendingmajorthat opens the v18 line, so the level moves no version on its own.packages/spec/src/ui/view.test.ts— the defaults pin flips totrue, plus four pins: an absent key parses totrue(onUserActionsConfigSchemaand throughListViewSchema), an explicitfalsestaysfalse, an explicittruestaystrue, and the view-levelinlineEdit: truestill parses as before with nouserActionsblock materialised (the fold is the renderer's; the spec keeps both spellings as declared).Measured first (the PM's mechanism assumptions)
view.zod.ts:1535read.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.mdxlists the view-levelinlineEditwith no default;content/docs/protocol/objectui/layout-dsl.mdx:667is aboutrecord:details' owninlineEdit(a different key, renderer default on);packages/spec/src/data/object.zod.tsretired-key guidance says only thateditInlineis a view key;object-strictness-batch20.test.tslists key names. Left as they are, with reasons:.changeset/console-20c6d351ad74.mddescribes the console at pin20c6d351ad74, which still reads an absent key as off until objectui#12086 lands and the pin moves (true of that build);CHANGELOG.md:1677andpackages/spec/CHANGELOG.mdare release-owned history.check:adr-0087-registrationdemands a marker on a declared-breaking changeset;not-required (no-migration-prescription)is refused when the body carries a prescription, and this one prescribeseditInline: false. The honest disposition isregistered: a D3 semantic entry at step 18, the same class asview-pagination-page-size-default-50and protocol 12'srest-requireauth-default-flip. No key is removed (no tombstone, noRETIRED_KEYS_BY_MAJORrow) and no D2 conversion exists — a mechanical pass writingeditInline: falseinto every silent view would preserve the old posture and defeat the ruling. The registry regenerated byte-exact after mergingorigin/main(which brought the sibling entrypage-slots-details-beside-tabs-refused, not adjacent in id order;check:migration-registrygreen). A second ledger also applies: the authorable-defaults ratchet refuses an undeclared default move, soDEFAULT_CHANGES_BY_MAJORcarries the hop.e11ef3a7bd(git grep, tests and changelogs excluded): 0editInline: falseand 0editInline: trueacrossexamples/**andpackages/**metadata. Views that declare nothing and now gain the toggle: 38 list-kind views with an explicittypeacross 10 example*.view.tsfiles (entries with notypeare grid by default and count the same way), 12interfaceConfigpage lists across 5 showcase page files (11 declare auserActionsblock, none namingeditInline), 105 list-kind views across 40 platform*.object.tsfiles inpackages/**. One view declares the view-levelinlineEdit: true(the showcasetaskgrid saved view) and keeps opening in edit mode. The only test that asserted the old default isview.test.ts(expect(config.editInline).toBe(false)), flipped here; no other package's tests read the view-leveluserActionsdefault (consumer tests onuserActionsare the object-level CRUD block). The card's readings outside this repository (cloudsys-package.page.ts:105declareseditInline: false; HotCRM's 41 undeclared views) were not re-measured here.skills/objectstack-ui/rules/list-views.mdis hand-written: the only generated lifts insideskills/**arereferences/_index.mdandreferences/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'stestscript) —Test Files 642 passed (642) · Tests 19150 passed | 1 todo (19151).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; therepo-project filesscripts/step18-rationale-merge.test.ts scripts/authorable-defaults.test.ts scripts/build-schemas-check-mode.test.ts—4 passed · 146 passed(withsemantic-relevance).pnpm --filter @objectstack/spec typecheck—tsc --noEmit,check:scripts-typecheckandcheck:test-typecheckgreen (52 file(s) / 246 error(s) / 135 pinned signature(s) held, the shrink-only debt ledger unchanged).test:repobeyond 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 head24d9bdcbf0, after the fix was committed. Mutation proved on disk: anchor 1 → 0, replacement 0 → 1, blob6979ade6158a→e0e02cd7f858. Direction observed: red, exactly the two default pins —should apply default valuesandan absent key parses to true(expected false to be true),2 failed | 462 passed (464). Restore proved: blob after restore6979ade6158a== blob at HEAD,git diff HEADempty, tree clean. Resolution path: the pin imports the schema from the package's ownsrc(nodistin 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 ispnpm 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), exceptpnpm check:dts-closure, which exited 1 for a missingdist/underplugin-approvalsandplugin-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 exceptpnpm 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 behindorigin/main83b8b80728, and the one derivation input that moved isscripts/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 jsonover the.ts/.mjsfiles 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 basee22315238f) because the two-point diff includes the merged sibling commits). Population, read fromeslint.config.mjs:**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}minus itsignores, so the.md,.mdxand.jsonfiles of this diff are outside it (eslint reports them "ignored because no matching configuration"). Invariance: the config declares noparserOptions.projectand no typed@typescript-eslintrules, so this diff cannot move the verdict of any file it does not touch.Acceptance notes
packages/spec/spec-changes.jsonanddocs/protocol-upgrade-guide.mdare not regenerated here. Since [Decision] generated protocol-change records (spec-changes.jsonper-major section,docs/protocol-upgrade-guide.md): keep committing them, or generate them at publish like thereleasesection #22449 B′ the PR-stagecheck:spec-changesandcheck:upgrade-guideproject the registry in memory and compare no committed copy (the publish lane generates the shipped one), andorigin/mainturned the upgrade guide into a pointer stub while this branch was open; a regeneration on the pre-merge tree carried 30-odd lines of sibling drift this diff does not own, so it was reverted. The entries README still says to regenerate both; the generator header is the newer authority. Noted, not filed.editInline !== falseinListView.tsxandInterfaceListPage.tsx, theplugin-view.mdxrow, the flipped pins) is list views: read an absentuserActions.editInlineas on (editInline !== false), the consumer half of objectstack-ai/objectstack#22605 (the v18 default flip) objectui#12086, filed by the claiming seat; nothing in objectui moves here.Generated by Claude Code