Uh oh!
There was an error while loading. Please reload this page.
feat(spec): retire the element:form element at element grain (#9249, ADR-0049) - #11244
Conversation
…ADR-0049) No renderer or reader anywhere — measured objectstack c684d00, objectui 76ceb1e, cloud 5f1bf23f/a11458b (thread readings). All six ElementFormProps keys are retiredKey tombstones behind the kept ComponentPropsMap row; D2 strip conversion element-form-removed under protocol 18; enum value dropped; lint COMPONENT_FIELD_SPECS entry dropped; three conversion fixtures re-seated off the retired neighbor; docs and baselines regenerated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B4h3medzvhB9rpfoja9jcw
…generate The withdrawal audit found the WIP's measurement was never written down; the verdict is re-taken on today's merged refs (objectstack dd84ddd, objectui 3ece13e33 — zero element:form readers, positive controls passing; cloud stays settled per the card's two recorded readings) and the six retired-key entries, the D2 conversion comment and the changeset now cite those refs. Regenerated: migration-registry concat, authorable surface/defaults, reference docs, openapi restore.
Retiring element:form removed the last ExpressionInputSchema member the cel-ui row's 'submit predicates' half covered; the ADR-0060 ratchet correctly reported STALE covers. Deleted rather than re-pointed, the mapping.zod.ts:expression (#5552) way; the summary drops the dead half.
📓 Docs Drift CheckThis PR changes 3 package(s): 3 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 1 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 127 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 f7e692ce739b64538e2067d6c681fb8f75ecf38b && git checkout f7e692ce739b64538e2067d6c681fb8f75ecf38b
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 3ece7704a338e1cb954796c35fb41f7a6e1d8bc4 72f5cab986e68e4bfccb18c1b9072137429c04b9 && git checkout -B drift-repro 3ece7704a338e1cb954796c35fb41f7a6e1d8bc4 && git merge --no-ff 72f5cab986e68e4bfccb18c1b9072137429c04b9
node scripts/docs-audit/affected-docs.mjs --json 3ece7704a338e1cb954796c35fb41f7a6e1d8bc4
|
Uh oh!
There was an error while loading. Please reload this page.
Fixes#9249
ADR-0049 enforce-or-remove verdict and retirement for
element:form, at ELEMENT grain, per the #9220 / PR #9250 mechanism (keptComponentPropsMaprow, D2 strip conversion, all-repo verdict recording). Clause-② applies (the strip changes the accepted set) —needs:contract-reviewexpected.Element-grain verdict — re-taken 2026-08-23, recorded verbatim
The prior WIP's verdict was never written down (withdrawal audit on the card); it is re-taken here on today's merged refs, per the dispatch.
objectstack — origin/main @
dd84ddd796d32a1deb9b8b71165c9bce5ddac30aRuntime-reader closure — zero hits in every runtime/consumer package:
Positive control (same query space, live block type — must be non-zero for the zero to count):
Full-tree enumeration: 16 files contain
element:form; every one is (a) the spec declaration itself and its generated artifacts (component.zod.ts,page.zod.ts,translation.zod.tsdescribe strings,component.test.ts,format-type.test.ts,i18n-resolver.test.ts), (b) thepackages/lintvalidator halves this PR retires (validate-page-field-bindings.ts:200binding row,validate-react-page-props.tscomments), (c) docs/audit/CHANGELOG prose — the 2026-06 page-liveness audit itself listselement:formunder "Aspirational (render 'Unknown component type')" — or (d) untouched neighbor fixtures inside other retirements' conversion fixtures.Reader-closure reasoning: page components are rendered by objectui, never by this repo's runtime; the only programmatic readers of the component-type vocabulary are the
packages/lintvalidators, whose dispatch is viaComponentPropsMap—git grep -ln "ComponentPropsMap" origin/mainoutsidepackages/spec/returns onlypackages/lint/*sources plus docs/CHANGELOG prose, andElementFormPropsoutside spec's own generated artifacts appears only in generated reference docs. No runtime package reads the element; the lint rows are declaration-driven validation, not consumption.objectui — origin/main @
3ece13e331b65e31b0cadbfb9feeb2fa50a3fd4a(fetched 2026-08-23)Renderer-registry check — zero, with a passing positive control:
cloud — SETTLED on the card (not re-taken, per the standing ruling)
Two independent zero-readings with passing positive controls at cloud refs
5f1bf23fanda11458b(issue #9249, comments of 2026-08-20 and 2026-08-21).Verdict: dead at element grain. Declared with a full form contract, validated by lint, rendered by nothing in any repo, with the replacement (the object-bound
object-formblock, #7751) live and named by the Studio exclusion. Premise valid; retirement proceeds.What this PR does
ElementFormPropskeys (object,fields,mode,submitLabel,onSubmit,aria) becomeretiredKey()tombstones carrying the element-grain prescription; theComponentPropsMaprow is KEPT so the SDUI 组件 props 没有解析闸门:PageComponent.properties是开放 record,ComponentPropsMap的 29 个站点从不被 parse(#4001 批 17 的 no gate 判定) #5068 props gate keeps dispatching and refusing loudly;PageComponentTypedrops the enum value (de-advertisement — the open string arm still accepts the bare migrated node).ui/ElementFormProps:{aria,fields,mode,object,onSubmit,submitLabel}under major 18 plus the D2 conversionelement-form-removed(strips all six keys, leaves the bare inert node), wired into the step-18 chain.retiredFromLoadPath: true(no alias window, deliberate).element:formas an untouched neighbor are re-anchored on types no conversion dispatches on (element:text,element:record_picker) — the whole-table replay contract.COMPONENT_FIELD_SPECS['element:form']binding row drops (residue class, own patch changeset); react-page-props escape-hatch pins re-anchored onelement:number.element:formassubmitLabel's carrier are corrected; the orphaned-key decision is i18n: component-translationsubmitLabelcopy key lost its only declared carrier whenelement:formretired (#9249) — decide retire vs re-anchor #10926 (already filed, pm:queue) — deliberately NOT expanded into here.i18n-resolver.test.tsrides a bespoke component type (documented legal route), pending i18n: component-translationsubmitLabelcopy key lost its only declared carrier whenelement:formretired (#9249) — decide retire vs re-anchor #10926.ui/component.zod.ts:onSubmitcover is deleted (the mapping.zod.ts:expression shared/mapping.zod.ts 的 javascript 变换 describe 推荐 dialect="js",而 ExpressionDialect 只有 cel/cron/template —— 照着写会被拒 #5552 way) — the ratchet correctly reported it STALE once the lastExpressionInputSchemamember left source. This file is outside the dispatch's declared surface; it is the playbook's own mandated consumption-radius face for retirements with an expression key, and is flagged in the report.[RETIRED]rows,modedefault row dropped), reference docs, migration-registry concat — regenerated with the repo tooling only.spec-changes.jsonand the upgrade guide project only up to protocol 17 and are unchanged, exactly as the merged ADR-0049 candidate:element:filterdeclarestargetVariable(and possibly the whole element) with no renderer or reader in any repo #9220 precedent left them.@objectstack/specminor (launch-window convention, the ADR-0049 candidate:element:filterdeclarestargetVariable(and possibly the whole element) with no renderer or reader in any repo #9220/feat(spec): refuse${…}placeholder syntax in memory persistence.path / persistence.key at publish (#8495) #8666 precedent; carries the FROM→TO mapping andadr-0087: registered element-form-removed) +@objectstack/lintpatch.WIP audit trail
The branch's pre-existing WIP commit
65402414(audit input per the withdrawal comment) was audited file-by-file against.claude/skills/spec-property-retirementand the #9220 / PR #9250 precedent. Audit outcome: kept, with one correction — its measurement refs (objectstack @c684d00cfc, objectui @76ceb1e) named a verdict that was never recorded anywhere; all citations (six entry files, the conversion comment, the changeset) now carry the re-taken, recorded readings above. Liveness ledger: no entries exist for either element's props (matches the merged element:filter precedent) — nothing owed.Reverse verification (from committed state
712b269f)Predicted direction, stated before running: exactly 3 failures in
component.test.ts— the six-key refusal pin, the bare-node materializes-nothing pin, the kept-map-row refusal pin; the bare-node PageComponent pin stays green (node-level parse never dispatches into the props schema); everything else stays green.Mutation: the six tombstones swapped back to the pre-retirement declarations via an anchored single-occurrence replace; confirmed on disk (injected-anchor grep = 1, deleted-anchor grep = 0) before running. The spec suite resolves these tests through relative src imports (same package), so no dist rebuild is required for this leg; both legs still ran the disk-confirmation step. Restore leg via git checkout from HEAD, script carried a restore trap for EXIT/INT/TERM; restore confirmed on disk (injected-anchor = 0, restored-anchor = 1).
Observed: mutated tree —
Tests 3 failed | 196 passed (199), exactly the three predicted pins, zero collateral. Restored tree —Tests 199 passed (199). Direction matches prediction exactly.Test and gate readouts (head
72f5cab9)All heavy runs were serialized through
scripts/pm/os-verify-lock.sh; verdicts below quote each runner's own printed result line, with exits captured before any pipe.@objectstack/specbuild + suite:Test Files 417 passed (417)/Tests 11098 passed (11098); verify-lockVERDICT command-exit 0.Done; verify-lockVERDICT command-exit 0(spec's gate line:check:test-typecheck: OK — 55 file(s) / 263 error(s) held in test-typecheck-debt.json (shrink-only)).@objectstack/linttests:Test Files 80 passed (80)/Tests 2251 passed (2251).@objectstack/platform-objectstests:Test Files 27 passed (27)/Tests 432 passed (432).@objectstack/dogfoodtests: first full run1 failed | 893 passed | 3 skipped (897)— the one red was the STALE-covers finding above; after the ledger fix,test/expression-conformance.test.tsre-ran green (Test Files 1 passed (1)/Tests 3 passed (3)). Declared narrowing for the re-run: the fix touches onlyexpression-conformance.ledger.ts, whose sole importer (measured by grep across packages/) is that one test file, and the rest of the suite had just passed at the same tree minus a comment-only ledger edit.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(provenance line: derived at commit72f5cab9in this checkout; --repo assertion holds). All 36 path-derived + convention-triggered families ran locally: PASS across the board — includingcheck:adr-0087-registration,check:variant-docs,check:liveness,check:engine-double-contract,check:where-matcher,check:type-check-coverage,check:nul-bytes— exceptcheck:dev-prereqs, which failed on a workspace-build precondition (eight packages this worktree had never built; its own text: "not a list of problems"), cleared by building those packages' closures — re-run green (67 package build artifacts present).check:type-check-debt --re-measurereadout:OK — 33 ledger entr(ies) re-measured in 630.6s, 1896 raw tsc error(s) total, none above its recorded number(the lower-able surplus notes are pre-existing and informational).pnpm --filter @objectstack/spec check:generated: all 14 artifact gates green after regeneration (check:api-surface's earlier "stale" was the documented stale-dist phantom, cleared by rebuild).pnpm lint(eslint, repo-wide) is CI-owned and was not run locally; no lint-rule surface is touched by this diff.Fences honored
elements.tsx:18comment, Studio palette exclusion table, objectui lint binding map): READ-ONLY — read for the verdict, not touched.element:formsubsumption note is a PM-side landing step. That card remains open.content/docs/releases/: untouched.submitLabelcopy key lost its only declared carrier whenelement:formretired (#9249) — decide retire vs re-anchor #10926 (translationsubmitLabelcarrier decision) — already filed and queued; this PR only corrects the two describes that advertised the dead carrier.Generated by Claude Code