Skip to content

ExperimentalFeaturesPanel: derive client toggles from ClientCapabilities['experimental'] #1240

@cliffhall

Description

@cliffhall

Background

Documented as a Phase 5 audit partial in specification/v2_ux_interfaces.md (PR #1236). ExperimentalFeaturesPanel accepts a local clientToggles: ClientExperimentalToggle[] prop that bundles per-toggle UI metadata (label, description). The spec target is clientExperimental: ClientCapabilities['experimental'] — the freeform Record<string, object> from the SDK schema — iterated in-component.

The current local-toggle shape was retained because the panel needs a human-readable label and description for each toggle, and the bare capabilities record doesn't carry that. The reconciliation needs a design call before implementation.

Design question (resolve first)

Two viable approaches:

A. Keep clientToggles as a UI metadata wrapper but populate its enabled field from the live ClientCapabilities['experimental'] record. Adds a clientExperimental: ClientCapabilities['experimental'] prop alongside clientToggles; the component zips them. Spec entry needs minor revision.

B. Drop clientToggles entirely; iterate the freeform record and look up labels/descriptions from a static map inside the component (or a peer config file). Toggles with no entry in the map render with the bare capability key as the label.

Recommendation: B, because the toggle list is small and stable, and a static lookup keeps the "what's available" source of truth in the SDK schema rather than in caller-supplied metadata. But A is reasonable if dynamic toggle definitions are anticipated.

Acceptance criteria (assuming B)

  • ExperimentalFeaturesPanelProps drops clientToggles: ClientExperimentalToggle[] and adds clientExperimental: ClientCapabilities['experimental'] (already present today; just stop accepting the parallel clientToggles).
  • A static CLIENT_EXPERIMENTAL_TOGGLE_METADATA: Record<string, { label: string; description: string }> lives in the same file (or a peer module).
  • Component iterates Object.keys(clientExperimental ?? {}), looks up metadata, and renders a row per key. Unknown keys render with the raw key as the label and no description.
  • onToggleClientCapability callback signature unchanged: (name: string, enabled: boolean) => void.
  • Existing local ClientExperimentalToggle type is removed from the component file.
  • Stories cover: (a) empty clientExperimental, (b) all known toggles enabled, (c) mixed known + unknown keys.

Test plan

  • npm run format && npm run lint && npm run build clean.
  • No leftover references to ClientExperimentalToggle in the web client (git grep ClientExperimentalToggle returns zero).
  • Stories render correctly in Storybook; toggles fire onToggleClientCapability with the right (name, enabled) payload.
  • If an upstream consumer (currently none in app code, but check stories of larger surfaces) was passing clientToggles, it now passes clientExperimental instead.

Out of scope

  • Server-side experimental capability rendering — that's a separate serverExperimental prop already typed correctly.
  • Changing the JSON-RPC tester portion of the panel.
  • Adding new toggle metadata for capabilities that aren't already in the static map.

Related

Metadata

Metadata

Assignees

Labels

v2Issues and PRs for v2

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions