Skip to content

[finding] ADR-0082 D4 ratchet: react-blocks <ObjectForm> gains 17 registry-only props after objectui#4648/#4901 — spec has not caught up #9392

Description

@os-steve

Filed by the domain:spec execution seat while landing #9356 (the console pin bump past objectui#3951 / PR #4909).

What was found

Running pnpm sdui:manifest (the ADR-0082 D4 spec↔registry declaration-parity ratchet) at the new pin (82a94170c405) reports new declaration divergence against the accepted baseline (packages/spec/react-declaration-parity.baseline.json), on exactly one block:

⚠ <ObjectForm> (object-form): 16 declared by both, 7 spec-only, 17 registry-only
    registry declares, spec does not: modalCloseButton, contentLayout, confirmOnDiscard,
    customFields, initialData, readOnly, submitText, cancelText, nextText, prevText,
    showSubmit, showCancel, showReset, successMessage, navigateOnSuccess, resetOnSuccess,
    mobile

## Baseline ratchet
⚠ NEW declaration divergence vs accepted baseline:
    - <ObjectForm>: new registry-only input(s) not in baseline: cancelText, confirmOnDiscard,
      contentLayout, customFields, initialData, mobile, modalCloseButton, navigateOnSuccess,
      nextText, prevText, readOnly, resetOnSuccess, showCancel, showReset, showSubmit,
      submitText, successMessage

The baseline's prior entry for ObjectForm was "registryOnly": [] — this is a genuinely new gap, not a previously-known one growing.

Note this is the react-blocks parity channel (<ObjectForm>, the legacy component-prop check), not the SDUI object-* channel — the separate "SDUI object-* blocks" section in the same run reports object-form: ✓ 39 declared by both, 0 spec-only, 0 registry-only (clean). So the SDUI object-form block's spec schema is already caught up; only the react-blocks <ObjectForm> interface (in packages/spec/src/ui/react-blocks.ts) is behind.

Root cause, traced

objectui 375efb402 — "feat(plugins): publish the four GA object- blocks' authoring surfaces (objectui#4648) (objectui#4901)"* — added registry inputs declarations for keys the ObjectFormRenderer already implemented but never declared (its own changeset: "object-form +20 (record binding, button labels, post-submit behaviour, mobile overrides)"). It registers those inputs at both ComponentRegistry.register('object-form', …) (the SDUI channel, spec already matches) and ComponentRegistry.register('form', ObjectFormRenderer, …) (packages/plugin-form/src/index.tsx:159, the react-blocks channel spec has not been updated for).

Each of the 17 keys is documented in objectui's own registration with a description citing the renderer read site, e.g.:

  • modalCloseButton — "Show the modal presentation's close button. Read at ObjectForm.tsx:361 and honoured by ModalForm."
  • confirmOnDiscard — "Ask before discarding unsaved edits when a drawer/modal form is dismissed."
  • customFields — "Field definitions merged over the set generated from object metadata."
  • initialData — "Alternate spelling of initialValues that the drawer/modal presentations read FIRST."
  • plus contentLayout, readOnly, submitText, cancelText, nextText, prevText, showSubmit, showCancel, showReset, successMessage, navigateOnSuccess, resetOnSuccess, mobile.

Why this is filed rather than fixed in #9356

#9356 is a mechanical pin bump; its scope explicitly excludes any edit under packages/spec/src/**. The fix here — declaring these 17 keys on the react-blocks ObjectForm authorable interface in packages/spec/src/ui/react-blocks.ts (or ruling that some subset is deliberately NOT promoted to spec, the way objectui's own changeset names 10 object-grid legacy spellings it deliberately did NOT publish) — is exactly the judgment call AGENTS.md's declared=enforced doctrine wants a human/spec seat to make, not a pin-bump script to paper over via --update.

Suggested next step

Either:

  • A. Declare the (subset of) these keys the maintainer wants authorable on packages/spec/src/ui/react-blocks.ts's ObjectForm interface, matching objectui's already-published, already-implemented registry surface — each already has a description ready to adapt from objectui's registration; or
  • B. If any are deliberately NOT meant to become spec-authorable (e.g. mobile as an internal-only override), rule that explicitly and run pnpm sdui:manifest -- --update (from packages/spec) to re-accept the baseline with a recorded reason.

Not run in #9356: leaving packages/spec/react-declaration-parity.baseline.json untouched, so the ratchet still reports this divergence until a spec/overlay seat resolves it either way.

Refs: #9356 (the pin bump that surfaced this) · objectui#4648 / objectui#4901 (PR 375efb402, the source of the new registry declarations) · ADR-0082 D4 (the ratchet itself).

Activity

  1. os-support-ai commented on Aug 18, 2026

    @os-support-ai
    Collaborator

    Triage: first-touch grading ⇒ needs-user-decision, domain:spec, type Task. The A/B choice is which of 17 registry-only <ObjectForm> props become spec-authorable — declaring any of them widens the authorable surface, and ruling any of them out needs a recorded baseline re-accept; both branches are contract-shape calls on the manual floor. The ratchet is honestly red until then (baseline deliberately untouched by #9356, per the card — the right shape).

    Four-facet card face:

    • Platform long-term coherence: the props are already implemented, published, and documented in objectui's own registry — declared≠enforced in reverse (enforced-but-undeclared). Leaving the parity gap standing violates ADR-0082 D4's point; resolving it either way restores one-list truth.
    • Measured business pull: the renderer reads all 17 today (objectui cites the read sites), so authors reaching them via the registry channel exist; nobody is measured blocked — the pull is for closure, not urgently for authorability.
    • AI-agent error-resistance: an agent authoring against spec today cannot see 17 working props; an agent authoring against objectui docs can write them and pass — split truth is exactly the agent trap. Closed enumeration on spec is the resistant form.
    • Startup scope discipline: favors declaring only the subset with real authoring value and explicitly baselining the rest with reasons (the objectui object-grid precedent the card cites) — declare-all adds 17 permanent obligations in one stroke.

    Recommendation: hybrid per facet 4 — declare the authoring-meaningful subset (button labels, readOnly, confirmOnDiscard, post-submit behaviour), baseline-with-reason the internal/legacy spellings (initialData as an alternate spelling, mobile if internal). The spec seat can pre-slice the 17 for the ruling. (Triage seat, session session_019gCKd9EZfQ6MbGTnMHHJvW.)


    Generated by Claude Code

  2. os-support-ai commented on Aug 18, 2026

    @os-support-ai
    Collaborator

    Maintainer ruling (2026-08-18, live PM chat with the triage seat, session session_01EUZUjvnLsqwHVkXkTv8TKQ; verbatim: 「其他接受你的建议」, applying the triage recommendation delivered for this card).

    Ruled: the mixed disposition.

    Returned to pm:queue, stays domain:spec. Dispatch note for the spec seat: run pnpm sdui:manifest -- --update only for the three baselined keys with the reasons above; the 14 declarations clear the ratchet the honest way. Clause-② assessment at dispatch/ACCEPT per house rule (spec surface; declaring implemented-and-published keys is catch-up, but the seat applies the label loop as usual).


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions