Skip to content

[finding] A THIRD hand-written FormViewSchema mirror survives in packages/react's spec bridge, and it has drifted on three keys #5596 just measured #5652

Description

@os-sales

Found while implementing #5596. Filed unassigned as an observation, for PM triage — #5596's
declared surface was the app-shell / apps/console pair only, and this is deliberately not
widened into it.

Mechanism

#5040 / #5542 / #5596 are one contract described several times, each description only ever
checked against itself. #5542 converged the leaf (FormFieldSpec); #5596 converged the two
containers (FormSectionSpec / FormViewSpec) across packages/app-shell and
apps/console. A third hand-written description of the same FormViewSchema contract
survives in a different package and was outside both scopes:

packages/react/src/spec-bridge/bridges/form-view.ts declares its own FormViewSpec
(line 54), FormSection (line 34) and FormField (line 12), and says so in its own docstring:

The subset of @objectstack/spec FormViewSchema the bridge consumes. Every serializable
spec key is either mapped onto the object-form node or listed here with an explicit
reason for being ignored — the bridge must never silently drop spec configuration (#2545).

That is the mirror shape scripts/check-spec-symbol-derivation.mjs exists to catch: a mirror
nothing checks is one spec release from being a fork.

It has already drifted — on the exact keys #5596 measured

This is not a hypothetical. Three of its keys disagree with what the contract accepts, and in
each case #5596 measured the contract's answer while converging the other two copies:

keybridge declaresthe contract admits
FormSection.columns (l.42) and FormViewSpec.columns (l.57)numberthe string arm too — FormSectionSchema.columns unions z.enum(['1','2','3','4']) with the four numeric literals
FormField.dependsOn (l.28)string[]string | string[] — the bare-string arm is the one that makes field-selector work (#5040)
FormField.visibleWhen (l.30), FormSection.visibleWhen (l.44)stringstring | { dialect?, source } — the object arm is what evalFieldPredicate takes (ADR-0089)

columns is the same numbers-only narrowing #5596 found in app-shell's copy and removed as
"rejecting metadata the platform accepts, not a deliberate narrowing". The bridge still has it.

Why file it rather than fold it into #5596

#5596's fence was the app-shellconsole pair, and its ruling was explicitly conditional
on the shape staying derived from spec symbols. This bridge is a different call with its own
architecture behind it, not a mechanical repeat:

That is a triage decision, which is why this is a finding and not a queued card.

Severity note

No user-reachable failure proven from this repo's tests. The reachable consequence is the
#5040 shape: a spec-authored form that spells columns: '3', dependsOn: 'objectName', or an
object-form visibleWhen is legal metadata the bridge's type refuses to describe. Severity is
triage's call.

Boundary

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatfinding

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions