Repository navigation
feat(spec,plugin-form)!: a form view's buttons hold submit and cancel only — buttons.reset is retired, because no form ever drew a reset button - #27269
Conversation
…t button WIP: tombstone, D2 conversion form-view-buttons-reset-removed, D3 entry ui-form-view-buttons-reset-retired, liveness note, ObjectForm fold and ui mirror drop reset; artifacts not yet regenerated. Claude-Session: https://claude.ai/code/session_01WGufzg7PvSmSGxVnCGiGfZ Co-authored-by: Claude <noreply@anthropic.com>
…tombstone Claude-Session: https://claude.ai/code/session_01WGufzg7PvSmSGxVnCGiGfZ Co-authored-by: Claude <noreply@anthropic.com>
…el only Claude-Session: https://claude.ai/code/session_01WGufzg7PvSmSGxVnCGiGfZ Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGufzg7PvSmSGxVnCGiGfZ Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 3 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 2 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 165 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 fdbcee1d3aa9f031d715c9bcda218405c62a6f95 && git checkout fdbcee1d3aa9f031d715c9bcda218405c62a6f95
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin d4427aedcf4c490637bdd40d850ce8344c4da4a1 a443f122897f70ce11d516a5c9dab7905fecf236 && git checkout -B drift-repro d4427aedcf4c490637bdd40d850ce8344c4da4a1 && git merge --no-ff a443f122897f70ce11d516a5c9dab7905fecf236
node scripts/docs-audit/affected-docs.mjs --json d4427aedcf4c490637bdd40d850ce8344c4da4a1
|
Contract reviewServed-tier: Inputs read: card #27153 body and all five comments (6464317022, 6464891999, 6465263085, the claim 6469111181, the dev report 6471072004); PR #27269 body, its 20-file list, the net diff against ① Derived judgmentsEach accept-set or public-surface change the diff implies, read in the tree at the head.
② Semver levelChangeset Clause-②: no (narrowing) — matches what the diff publishes. Level: right. The changeset's prose has one must-fix sentence (④ M1). ③ Boundary flags
④ Design judgmentThe narrowing against the published spec on The retirement itself holds. Where it breaks — M1 (must-fix): the migration text misstates the replacement, and the behaviour change is undisclosed. Today a stored or authored form view with
These are the texts an upgrading agent greps ( S1 (should-fix): the hotcrm census, as in ③. S2 (should-fix): Tried and holding: a Implemented-by: VERDICT: FAIL |
…ts conversion as the registry asks
Review 6471309095 M1: the prescription, the D3 replacement and reason, the
conversion docblock and summary, the STEP18 rationale fragment and the
changeset's FROM -> TO line now say that `reset.show: true` used to clear
the form after each save (the ObjectForm fold that ObjectView and the
record form page render), that a converted form no longer clears after a
save, and that `submitBehavior: { kind: 'continue' }` declares that effect.
The D2 conversion still only strips the key.
S2: the ObjectForm fold comment no longer lists `reset` among the
structured `buttons` keys.
CI (conversions-major18-merge placement pin): formViewButtonsResetRemoved
is now defined directly above formViewOptionDefaultRemoved, the entry that
follows it in MAJOR_18_CONVERSIONS.
Refs #27153
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGufzg7PvSmSGxVnCGiGfZ
Refs #27153 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzg7PvSmSGxVnCGiGfZ
席位核对 · ACCEPT ·
|
Requested by Yibo Wang · project thread
Refs #27153
Ruling-ref: 6469111181
Clause-②: no (narrowing)
Metadata-protocol: narrowed
Skills-docs: none — no
skills/**file or hand-written docs page authors or teachesbuttons.reset(0 hits at base); only the generated references move维护者速读
buttons里的reset退役,写了会被拒并附改法。buttons只剩submit和cancel。ObjectForm 不再读buttons.reset.show,ui 的ObjectFormSchema.buttons镜像同步去掉reset。reset.label无人读取;唯一读reset.show的地方把它当成"保存后清空表单",与"重置按钮"的含义不符。buttons.reset的元数据会被拒。本仓除两个测试夹具外没有任何生产者;已存的sys_metadata行读取时自动去掉该键,os migrate meta --from 17改写源码。回滚就是 revert 本 PR。packages/spec/src/ui/view.zod.ts的FORM_VIEW_BUTTONS_RESET_RETIRED改法文案;②packages/spec/src/conversions/registry.ts的formViewButtonsResetRemoved;③ui/packages/plugin-form/src/ObjectForm.tsx删掉的那一行折叠。pnpm --filter @objectstack/spec exec vitest run --project repo src/ui/form-view-buttons-reset-retirement.test.ts,预期 22 个测试全部通过。What changes
Spec (
@objectstack/spec)FormViewSchema.buttons.resetis aretiredKey()tombstone inside the live, strictbuttonsblock. Its prescription: "view.form.buttons.resetwas removed in @objectstack/spec 18.3.0 (ADR-0049) — no form ever drew a reset button, and its label was never read. Delete the key: a form hassubmitandcancelbuttons only, and Cancel leaves the form without saving.reset.show: trueused to clear the form after each save (the ObjectForm fold that ObjectView and the record form page render); a form converted by this release no longer clears after a save, and a form that should declaressubmitBehavior: { kind: 'continue' }." followed by theos migrate meta --from 17sentence.buttons.submitandbuttons.cancelare unchanged.reset.show: trueused to clear the form after each save, through the ObjectForm fold that ObjectView and the record form page render. A converted stored row no longer clears after a save. The D2 conversion does not map the key ontosubmitBehavior, because the row cannot say whether the author wanted the clear. The prescription, the D3replacementandreason, the conversion docblock and summary, the STEP18 rationale fragment and the changeset's FROM → TO line now all say this. They namesubmitBehavior: { kind: 'continue' }, which ObjectForm and the consoleFormPagehonour, for an author who wants the clear.spec-property-retirement, key-tombstone route):resetthrough 18.2.0 andPUT /meta/viewpersists form views, so a storedviewrow can carry the key. Conversionform-view-buttons-reset-removed(retiredFromLoadPath: true,retiredAfter: '18.2.0', MAJOR_18 order 79) stripsresetfrom every form payload'sbuttons: a container'sformandformViews.*, a form view item'sconfig, a flattened form overlay, and the assembledviewItemschannel. A block that held onlyresetstays an empty block. Its fixture has 4 notices.ui-form-view-buttons-reset-retired(itsconversionIdsnames the conversion), plus a STEP18_RATIONALE fragment.RETIRED_KEYS_BY_MAJORrow:ui/FormView:buttons.reset(a nested key of an inline block, so noauthorable-surface/line of its own).liveness/view.json): theprops/form/children/buttonsrow staysliveforsubmit/cancel, and its note no longer claimsresetfolds. It records the removal and the measurement, because sub-keys cannot be drilled.content/docs/references/ui/view.mdxandreferences/api/protocol.mdx.authorable-surface,api-surface,react-blocks.mdandskills/**are byte-identical (buttonsis not in the ReactObjectFormblock'sdataProps).Renderer (
@object-ui/plugin-form,@object-ui/types): the reader of the refused key, in the same PRObjectForm.foldFormButtonsno longer foldsbuttons.reset.showontoshowReset. That fold was the key's only reader, and it landed onresetOnSubmit(clear the form after a save), not on a button. The fold's comment no longer listsresetamong the structuredbuttonskeys.ObjectFormSchema.buttonsmirror dropsresetin both the TypeScript type (types/src/objectql.ts) and the zod mirror (types/src/zod/objectql.zod.ts), so the ui side no longer offers a key nothing reads.object-form-unmirrored-members-6152.test.tsnow usescancelwhere it usedreset.FormPage.readFormButton,resolveFormViewChromeand the plugin-form fold test header no longer describeresetas an unread key.showResetprop and itsresetOnSubmitmapping. That is the block contract's own defect (component.zod.tsandreact-blocks.tsdescribe it as "Show the reset button"), filed by the seat as [finding] the ObjectForm block'sshowResetis described as "Show the reset button" but the renderer maps it toresetOnSubmit, sotrueclears the form after a save andfalsedoes nothing #27247.Why
#27153 asked for enforce-or-remove on
buttons.resetunder ADR-0049. Measured atorigin/mainfbe344b3, six separate button bars draw a form's submit and cancel: the components form action bar (simple, sectioned, tabbed and split ObjectForm), consoleFormPage, theModalFormandDrawerFormfooters,WizardFormandMasterDetailForm. None of them draws a reset button. Two of them would need a semantic decision before one could (whether the wizard resets the step or the whole wizard, and whether master-detail resets line items). In-repo producers: 0 outside two test fixtures. Seat 1 ruled retire (claim 6469111181).Tests
packages/spec/src/ui/form-view-buttons-reset-retirement.test.ts(22 tests,repoproject, added tovitest.repo-tests.json):buttons.reset(withshow: true,show: false, a label, and empty) at…buttons.reset, with the prescription's first sentence and the migrate sentence. The doors areFormViewSchema,view.form,view.formViews.*, a ViewItem form record and the flattened form overlay;submitandcancel;unrecognized_keys, not "was removed";defineStackrefuses withSTACK_SCHEMA_INVALID/ 422 atviews.0.formViews.quick.buttons.reset;@ts-expect-errorat the authoring site;packages/spec/src/ui/zz-probe-27153.tsauthoringbuttons: { submit: {}, reset: { show: true } }; the walk named it (1 failed), and the probe was removed with a trap.view.test.ts: the buttons block test dropsreset, and a new case pins the tombstone.retired-key-removal-version.pin.test.ts: JOIN row.Acceptance notes
fbe344b3:buttons.resetwas authored by 0 files inexamples/, platform sources,skills/**, Studio*.form.tsand ui examples. Two test fixtures authored it: specview.test.ts:3222and ui typesobject-form-unmirrored-members-6152.test.ts:112, both moved here. hotcrm, measured on a public shallow clone at353dace(1055 tracked files, at 2026-10-28T08:39Z): 0 files author abuttons: {block at all, and noreset:key appears outside apackage.jsonscript name. If a hotcrm source authored after that commit carries the key, it is refused at parse with the prescription,os migrate meta --from 17 --writedeletes it, and a stored row is converted on read.drawerSideanddrawerWidthstay. They retire with ui(plugin-form):ObjectFormdrops thesplit/drawer/modalbranches andSplitFormretires; showcasetaskviews re-spelled (ADR-0050 cutover, renderer half of #27155) #27159, which owns the ReactObjectFormblock contract; henceRefs #27153, notFixes.--ignore-scripts, because thebetter-sqlite3header download from nodejs.org was cut off twice. Its shippedprebuilds/linux-x64.nodeloads (select 1answered), so nothing measured here depended on the skipped script.Verification
Head:
a443f1228. It isf101f23ddplus3684cdf07(review 6471309095 round 2: M1, S2, and theconversions-major18-mergeplacement fix, which movesformViewButtonsResetRemoveddirectly aboveformViewOptionDefaultRemoved), a merge oforigin/mainat696ee79f5(made withos-regen-merge.sh), and theprotocol.mdxregeneration it owed. On the merged tree: the spec build,check:generated(14/14), the spec suite (749 files, 22381 tests passed), andtest:repoat 1376 of 1377. The one failure isdef-key-collisions.test.ts: its sandbox copy cannot find tsx'scli.mjsbecause this worktree was installed with--ignore-scripts; it passed in CI onf101f23dd. Full dogfood ran on5026fd569. The round-1 notes below were measured onf101f23dd.Spec build, generated artifacts and source audits
pnpm --filter @objectstack/spec build(under os-verify-lock):VERDICT command-exit 0.check:generated: 1 of 14 stale (check:docs), fixed with--fix; re-run: "All 14 generated artifacts are up to date".check:liveness(exit 0, 1209 classified),check:empty-state,check:exported-any,check:dual-source-exports,check:variant-docs: exit 0 each.pnpm --filter @objectstack/spec typecheck: exit 0;check:test-typecheckOK, 132 pinned signatures held.Tests
@objectstack/specpnpm test: 744 files and 22314 tests passed, 1 todo (5026fd569); after the merge, 748 files and 22353 tests passed, 1 todo (f101f23dd).--project repo): 22/22.retired-key-removal-version.pin.test.tsandretired-key-migrate-sentence.test.ts: 70/70.@object-ui/types:type-checkexit 0;object-form-unmirrored-members-6152,zod-mirror-parityandobject-view-slot-key-lists: 165/165.@object-ui/plugin-form:type-checkexit 0;formButtonsDefaults,formViewTabKeysAndButtons-26843andObjectForm.test: 19/19.'@objectstack/dogfood^...'closure build, thenpnpm --filter @objectstack/dogfood test, under os-verify-lock, on5026fd569):VERDICT command-exit 0; 348 test files passed and 3 skipped (351); 2804 tests passed and 20 skipped.Derived gates
node scripts/pm/dispatch-gates.mjs --commands(treeobjectstack-ai/objectstack, merge basefbe344b3c, 20 paths, 589 changed lines): all 32node scripts/…commands exit 0 on both5026fd569andf101f23dd,check-adr-0087-registration --base origin/mainincluded.pnpm --dir ui exec vitest run scripts/: 175 files passed, 2 skipped; 5020 tests passed. Every other family is CI's.Human Minimum
packages/specholds no runtime logic.pnpm lintis CI's run (not run locally).main, one pull request.packages/spectouched: its generated artifacts are regenerated and committed.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.Generated by Claude Code