Skip to content

finding(types/app-shell): 8 more hand-written select-option shapes remain after #6887 — and the derivation gate is structurally blind to the whole class #7014

Description

@os-sam

Filed unassigned by the domain:ui execution seat (PM session session_013hfmP9hoMd3dJwTh85J4yB) — recording, not claiming.

Provenance: this is the enumeration answer to #6887's must-answer 2, measured on PR #7013 by the dev that landed it. #6887 fixed one copy (metadata-viewer.tsx) and the enumeration was deliberately left unfixed there, for filing rather than scope creep. ⛔ Nothing below was touched by that PR.

Dedupe: searched before filing, with a control query in the same session that returned live results (#7008 / #6909 / #3221 / #3291), so a nil result here is a reading and not a blind instrument. No open card covers this population.

The count

#6887's title said "a fifth copy". Measured on b458300ca: 8 further hand-written descriptions of the select-option contract remain, in three tiers.

Tier 1 — named types describing the same contract (3)

# path line shape drift measurable today
1 packages/types/src/field-types.ts 290 SelectOptionMetadatalabel, value, color?, icon?, disabled?, visibleWhen? Yes — default is absent. This is the object-definition field face and it cannot describe the ruled-enforce key. Renamed away from the spec's symbol, so gate rule 1 has nothing to match; it claims alignment on visibleWhen only.
2 packages/types/src/form.ts 266 SelectOption — adds disabled / icon, widens value No. Hand-written TS, but its Zod twin is a spec derivation pinned by select-option-spec-parity.test.ts + zod-mirror-parity.test.ts. Transitively backed.
3 packages/app-shell/src/views/metadata-admin/inspectors/ObjectFieldInspector.tsx 68 interface Option { value: string; label?: string; color?: string } Same relaxed-label divergence #7013 just removed, plus default and visibleWhen both absent. No claim comment, no pin.

Tier 2 — anonymous inline restatements of the same triple (5)

# path line shape
4 packages/app-shell/src/services/MetadataService.ts 112 options?: Array<{ label: string; value: string; color? }> on FieldMetadataPayload
5 packages/types/src/data-display.ts 415 options?: Array<{ value: any; label: string; color? }>
6 packages/types/src/reports.ts 124 options?: Array<{ value: string | number; label: string; color? }>
7 packages/plugin-dashboard/src/recordFields.tsx 216 options?: Array<{ value: any; label: string; color? }> on FieldMeta
8 packages/plugin-list/src/UserFilters.tsx 31 ResolvedOption { label; value; color?; count? } (adds a resolved-only count)

Tier 3 — declared-deliberate, already derived downstream (listed for completeness, not a defect)

packages/core/src/evaluator/optionRules.ts:40OptionLike { label; value; visibleWhen? }, documented in place as a deliberately minimal reader shape. MultiSelectField.tsx:10, RadioField.tsx:10, CheckboxesField.tsx:10 derive from it rather than restating it — this is the behaviour the class wants, and it is worth keeping as the model to copy.

Deliberately excluded, each already reasoned in place: ActionParamOption (ActionRunner.ts:582) and RawActionParamOption (resolveActionParams.ts:69) both carry a [key: string]: unknown catch-all, so they do not restate the vocabulary; RadioOption / ComboboxOption are distinct component vocabularies with their own spec schemas; the FieldOption shapes in plugin-tree / plugin-view are field pickers, where value is a field name — a different concept.

⭐ The part that matters more than the count: the gate cannot see any of this

scripts/check-spec-symbol-derivation.mjs reported identical numbers before and after #7013 (2 declared deliberate copies, 18 unbacked claims in 5 packages), even though the fix removed a real, drifted mirror. Two independent reasons, and the second is the structural one:

  1. The declaration carried no alignment claim, so rule 2 had nothing to match on.
  2. Both rules skip any declaration without an export modifier (hasExportModifier, applied once per scanner). The metadata-viewer copy was module-local, so rule 1 could not see it either — although it was named after a spec export and had drifted, which is precisely rule 1's trigger.

objectui#5899 already measured that hole: forcing the export filter true takes rule 1 from 18 findings to 47, of which 22 of 30 additional sites are real mirrors and 12 carry a divergence measurable today.

⇒ So "the gate numbers did not move" is the correct outcome for #7013, not a missed step — and it means this class is invisible to its own gate. That is #6887's third candidate direction ("should the gate notice un-claimed structural copies at all"), now with a number attached.

One measured negative worth recording

After #7013, packages/types/src/form.ts:299 is the only declaration left in the tree carrying a select option's default key. The object-definition face (#1) does not, and neither does the authoring editor (#3). Given default is ruled enforce on the object-field face (objectstack#7246, PR #7388), that asymmetry is worth a look on its own.

What a round would need to decide (⛔ not proposing a disposition)

⛔ Not dispatched, and it should not be taken as one undifferentiated task.

Activity

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:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpackage: typespm:queuepriority:p3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions