You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
finding(react): the form-view bridge's #2545 "never silently drop spec configuration" promise is false — 18 spec keys are neither mapped nor explained #5898
Found while implementing #5652 (the three drifted key TYPES). Filed unassigned as an
observation, for PM triage — #5652's fence was the drifted arms, and this is deliberately not
folded into it.
The promise
packages/react/src/spec-bridge/bridges/form-view.ts carries this docstring, and FormViewSpecConformance.test.ts exists to enforce it:
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).
Deriving the drifted keys in #5652 made the contract's full key set visible next to the
declaration, and the promise does not hold: 18 spec keys are neither mapped nor explained.
The conformance test does not catch them because its fixture is a hand-written list of keys
someone remembered, not the contract's key set — a key absent from the fixture is a key the
completeness loop never asks about.
Measured against the installed @objectstack/spec
Key sets read through the TypeScript checker off the spec's own .d.ts (keyof FormView, keyof FormSection, keyof FormFieldInput), then diffed against what the bridge declares.
FormView — 2 dropped:buttons, defaults.
(defaultSort and aria are correctly absent AND explained — they are retired-key tombstones,
pinned by FormViewRetiredKeys.test.ts. They are the shape the other 18 should have.)
Most of them are dropped configuration, not harmless omissions
This is what makes it worth filing rather than noting. The receiving layer already reads them:
FormSection.pane is read at plugin-form/src/ObjectForm.tsx:302 (pane: s.pane) and is
the whole subject of SplitForm.tsx's per-section placement. A spec-authored split form loses
its explicit pane placement at this bridge and silently falls back to the legacy positional
rule (first section primary, the rest secondary) — so reordering sections moves them across
the divider, which is the exact failure pane was added to prevent.
13 of the 14 field keys are copied onto the runtime field by normalizeSectionField
(plugin-form/src/sectionFields.ts): maxLength, minLength, min, max, precision, scale, multiple, immutable, span, language, keyField, disclosure, fields. The
bridge is the only thing between the authored document and that reader, so an authored maxLength / precision / composite fields never arrives. publicPicker is the one with
no reader found here.
FormSection.visibleOn — the field path already reads visibleWhen ?? visibleOn; the
section path reads only visibleWhen, so the deprecated section spelling is dropped on a
document that has not been through the spec's normaliser (the same never-parsed input class
the bridge keeps reading groups and field visibleOn for).
buttons and defaults need a triage answer rather than a mechanical copy — there may be no
node slot for either, in which case the honest fix is an entry in the ignore list with the
reason, not a passthrough.
Why this is a finding and not a queued card
Two decisions sit above the mechanical part, and both belong to triage:
Where the completeness check should get its key set. Pinning the fixture against the
contract's keyof (so a new spec key fails the suite until it is mapped or explained) is a
different instrument from the current hand-listed fixture, and it will fail immediately on
all 18 — the ordering of "build the guard" and "close the gap" is a call.
declared = enforced vs. passthrough. Some of these are simply un-copied; buttons / defaults / publicPicker may have no consumer at all, in which case ADR-0049's
enforce-or-remove applies to the ignore-list entry rather than to a copy.
Found while implementing #5652 (the three drifted key TYPES). Filed unassigned as an
observation, for PM triage — #5652's fence was the drifted arms, and this is deliberately not
folded into it.
The promise
packages/react/src/spec-bridge/bridges/form-view.tscarries this docstring, andFormViewSpecConformance.test.tsexists to enforce it:Deriving the drifted keys in #5652 made the contract's full key set visible next to the
declaration, and the promise does not hold: 18 spec keys are neither mapped nor explained.
The conformance test does not catch them because its fixture is a hand-written list of keys
someone remembered, not the contract's key set — a key absent from the fixture is a key the
completeness loop never asks about.
Measured against the installed
@objectstack/specKey sets read through the TypeScript checker off the spec's own
.d.ts(keyof FormView,keyof FormSection,keyof FormFieldInput), then diffed against what the bridge declares.FormView— 2 dropped:buttons,defaults.(
defaultSortandariaare correctly absent AND explained — they are retired-key tombstones,pinned by
FormViewRetiredKeys.test.ts. They are the shape the other 18 should have.)FormSection— 2 dropped:visibleOn,pane.FormFieldInput— 14 dropped:publicPicker,maxLength,minLength,min,max,precision,scale,multiple,immutable,span,language,keyField,disclosure,fields.Most of them are dropped configuration, not harmless omissions
This is what makes it worth filing rather than noting. The receiving layer already reads them:
FormSection.paneis read atplugin-form/src/ObjectForm.tsx:302(pane: s.pane) and isthe whole subject of
SplitForm.tsx's per-section placement. A spec-authored split form losesits explicit pane placement at this bridge and silently falls back to the legacy positional
rule (first section primary, the rest secondary) — so reordering sections moves them across
the divider, which is the exact failure
panewas added to prevent.normalizeSectionField(
plugin-form/src/sectionFields.ts):maxLength,minLength,min,max,precision,scale,multiple,immutable,span,language,keyField,disclosure,fields. Thebridge is the only thing between the authored document and that reader, so an authored
maxLength/precision/ compositefieldsnever arrives.publicPickeris the one withno reader found here.
FormSection.visibleOn— the field path already readsvisibleWhen ?? visibleOn; thesection path reads only
visibleWhen, so the deprecated section spelling is dropped on adocument that has not been through the spec's normaliser (the same never-parsed input class
the bridge keeps reading
groupsand fieldvisibleOnfor).buttonsanddefaultsneed a triage answer rather than a mechanical copy — there may be nonode slot for either, in which case the honest fix is an entry in the ignore list with the
reason, not a passthrough.
Why this is a finding and not a queued card
Two decisions sit above the mechanical part, and both belong to triage:
contract's
keyof(so a new spec key fails the suite until it is mapped or explained) is adifferent instrument from the current hand-listed fixture, and it will fail immediately on
all 18 — the ordering of "build the guard" and "close the gap" is a call.
declared = enforcedvs. passthrough. Some of these are simply un-copied;buttons/defaults/publicPickermay have no consumer at all, in which case ADR-0049'senforce-or-remove applies to the ignore-list entry rather than to a copy.
Boundary
FormSection / FormField / drop / silent / pane / shorthand phrasings, over all 231 open
issues — this session cannot reach the search API, so the list was fetched and filtered
locally). Nothing open covers it. Console FormPage still drops the other three conditional-rule surfaces after #5594: section-level visibleWhen/visibleOn, and the object-level field rules visibleWhen/readonlyWhen/requiredWhen #5627 is the nearest neighbour and is closed, and it was
the console
FormPagerenderer's own section-rule drops, not this bridge's declaration.packages/react's spec bridge, and it has drifted on three keys #5596 just measured #5652 (thethree drifted arms — the card this was found under).
fields: ['name']becoming{ name: undefined }) was in-fence and is fixed in [finding] A THIRD hand-written FormViewSchema mirror survives inpackages/react's spec bridge, and it has drifted on three keys #5596 just measured #5652's PR; it is not part of this.Generated by Claude Code