Design-first gate · UX approval · SL9 · contract 4.1.0 · design-record task 13

Selection Lists — shared & common lists, copy-on-write fork

Fifteen navigable frames — every flow at desktop and at 375 px, in English and right-to-left Hebrew / Arabic — for what a member sees when their organization reads lists it doesn't own: the common-list badge and read-only detail, the “Fork to edit” path from a 409 fork_required, the fork confirmation and every answer it can get, the fork's provenance and “behind source” indicator, the owner's visibility control, and the picker resolving the effective list by key. Every state is contract — loading, empty, error, the fail-closed refusals, and the flag-OFF absence. Built in the fuse-seam design system (tokens only). Requirement: docs/planning/selection-lists-shared-and-fork.md.

Approval is per flow — five flows, approved independently

Approving one flow unblocks its implementation (its implementation.paths below) while the others iterate. Each flow's component directory is claimed by that flow alone, so approving one never unlocks a sibling's components; only the shared infrastructure in shared-lists/core/** (types, api, hooks, provider — no rendering components) unlocks with any approval. Flow 3 renders an honest fallback today and carries a named contract dependency (SelectionList.revision); it does not hold any sibling back.

Flow 1 · Shared read — browse, badge, read-only detail

● Awaiting approval
SelectionListManagementFlow (extended) → /settings/selection-lists · any member

A member reads and picks from lists the organization is given without owning them. Common lists are grouped and badged; a fork hides the common list with the same key unless a visibility filter is set; a list read only through visibility is read-only — no mutation affordances at all.

Flow 2 · Fork to edit

● Awaiting approval
ForkListFlow → /settings/selection-lists/:listId (dialog; no new route) · members who can create lists

A refused change to a common list becomes a way forward; the fork is always an explicit choice with a visibility (organization or private draft), keeps the key, and replaces the common list for the organization. Every answer — 201, 200, the three 409s, quota, the 5,000-value cap, 403, 404, network — has its own state.

Flow 3 · Your fork — provenance & behind source

● Awaiting approval
ForkProvenancePanel → /settings/selection-lists/:listId · fork owners and editors

Where the fork came from, which version it copied, and whether the common list has moved on — informational only, no merge. Revert to common = archive the fork — offered only while an active common list exists; otherwise “Archive fork…” states that forms will have no list.

Flow 4 · Visibility control

● Awaiting approval
VisibilityControl in SelectionListAccessFlow → /settings/selection-lists/:listId/access · list owners; platform operators

Owners switch private ↔ organization with the consequence spelled out. Publishing as a common list exists only for platform operators in the platform organization, behind a typed confirmation; a common list is locked (visibility_locked).

Flow 5 · Picker — the effective list

● Awaiting approval
SelectionListPicker (extended) → /embed/selection-list-picker (harness) · embedded in consuming forms

Unchanged for the host form, except that a key now means the effective list: the organization's fork if it has one, else the common list. Stored common ids render the fork's label through the resolve redirect, with no visible change.

Build inventory

Approving these frames approves this inventory. The implementation (design-record task 14, frontend-engineer) builds exactly these, inside the existing package — no new package, no new host route.

Flows (5 — approved independently)
shared-read → SelectionListManagementFlow (extended) · /settings/selection-lists fork → ForkListFlow · /settings/selection-lists/:listId fork-provenance → ForkProvenancePanel · /settings/selection-lists/:listId visibility → VisibilityControl · /settings/selection-lists/:listId/access effective-picker → SelectionListPicker (extended) · /embed/selection-list-picker
New components — packages/selection-lists-ui/src/shared-lists/<flow dir>/** (each directory claimed by its flow ONLY)
browse/VisibilityBadgebrowse/ForkBadgebrowse/EditableHint browse/SharedListsTogglebrowse/VisibilityFilterbrowse/ListSourceGroups browse/ReadOnlyListNotice fork/ForkListFlowfork/ForkToEditButtonfork/ForkRequiredBanner fork/ForkListDialogfork/ForkResultNotice provenance/ForkProvenancePanelprovenance/BehindSourceIndicatorprovenance/RevertToCommonConfirm visibility/VisibilityControlvisibility/PublishPlatformConfirm picker/EffectiveListSource
Shared infrastructure — shared-lists/core/** (claimed by every flow; no rendering components)
core/useEffectiveList core/SharedListsFeatureProvider + useSharedLists (flag, isPlatformOrg) core/api: getEffectiveList · forkList · error.reason / sourceListId / forkUrl core/types + unit tests of the above
Existing components extended (wiring only)
SelectionListIndexSelectionListDetailValueEditor TranslationWorkbench (read-only mode: locale index + read-only locale view; ForkRequiredBanner)AccessPanel SelectionListPicker (getEffectiveList, onEffectiveValue, showSource)
Viewports — every flow is frozen at desktop and at 375 px (manifest build.flows[].responsive)
shared-read → 11-rtl-mobile-detail fork → 12-rtl-mobile-fork fork-provenance → 13-rtl-mobile-provenance visibility → 14-rtl-mobile-visibility effective-picker → 15-rtl-mobile-picker same components at both widths · reuse BottomSheet, Drawer, --touch-target
Packages
@fuzeone/selection-lists-ui — extended, 0.3.0 → 0.4.0 (MINOR) @fuzeone/selection-list-client 2.1.0 — semantics followed (getEffectiveList, forkList, isForkRequired)
Host mounting (frontend/src/App.tsx — no new routes)
existing /settings/selection-lists/** routes pass sharedLists = flag fuzefront.selection-lists.shared-lists … and isPlatformOrg from the active organization's type /embed/selection-list-picker harness reads the same flag
Design-system additions (frontend-engineer, foundation PR)
RadioCardGroup — fork visibility + visibility control SegmentedControl — visibility filter reuse: Badge · StatusPill · Alert · Modal · BottomSheet · Toggle · Toast · Skeleton · Spinner · ProgressMeter · Tabs · DataTable
Contract dependency (contract-designer)
SelectionList.revision (read-only, additive MINOR) — needed by Flow 3's behind / up-to-date states
Manifest: design/frames/selection-lists-shared/manifest.json · Contract: services/selection-list-service/openapi.yaml 4.1.0 · Flag: fuzefront.selection-lists.shared-lists (default OFF) · Builds on the approved 4.0.0 frames in selection-lists.
Re-stamp after any edit: node scripts/stamp-frames.mjs --write --feature selection-lists-shared.
Review · selection-lists-shared approve or reject each flow ↓
shared-readapproved · izzywdev
forkapproved · izzywdev
fork-provenanceapproved · izzywdev
visibilityapproved · izzywdev
effective-pickerapproved · izzywdev