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

Closed

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 375efb4, 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. added
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    domain:specDomain lane — seat card indexed by label:pm:seat
    on Aug 18, 2026
  3. 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

  4. added
    pm:queueReady for the PM dispatch loop
    and removed
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    on Aug 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:specDomain lane — seat card indexed by label:pm:seatpm:dispatchedDispatched to a dev agent by /pm-dispatch

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions