Stored values keep rendering across a fork

A record saved last month holds a common item id. Acme has since forked the list.

Resolve follows the fork; the picker shows the fork's answer

Forked items get new ids. POST /v1/resolve resolves common ids from every organization and, when the caller's organization holds an organization-visible, active fork with an item whose origin_item_id is that id, returns the fork item's label and names it in effective_item_id. The picker renders that label and selects the matching fork option. One request, as before.

Ticket #4182

Helpdesk · editing a record saved before Acme forked Priority

Shows the fork's label (“Medium”, renamed by Acme from the common “Normal”) and, when opened, the menu marks the fork's “Medium” option as selected. No visible change beyond the label Acme chose: no badge, no notice, no flicker, no dirty-form marker — to the user it is simply the current value.

Stored vs submitted
stored: front_sli_01jf8k2m3n4p5q6r7s8t9v0wa2 (common “Normal”)
effective: front_sli_01jfq3w8z6y5x4c3b2a1n9m8b2 (fork “Medium”)
submits: front_sli_01jf8k2m3n4p5q6r7s8t9v0wa2 (unchanged unless the user picks)

The picker's value is not rewritten: the host gave it the stored id and gets the same id back unless the user picks something else (the picker's contract with its host is unchanged). Both ids keep resolving, so that is always correct. A host that wants to migrate stored values passes onEffectiveValue(stored, effective); the picker calls it once per redirected id after a successful resolve, and the host may write the effective id on its own next save — lazily, as the contract intends. If the user picks a value, the picker emits that option's (fork) id, as for any pick.

Every resolve outcome a stored value can have

Each id renders independently. A batch with a mix of outcomes (some redirected, some missing) is a normal response, not a partial failure.

Stored idSituationResolve answersPicker renders
front_sli_…v0wa2 Common item; Acme has an org fork fork label + effective_item_id Medium
front_sli_…v0wa2 Common item; Acme's fork is private (draft) common label, no redirect Normal
front_sli_…v0wa3 Common item; the fork's copy was deleted falls back to the common item High
front_sli_…m8b6 Fork-only item (added by Acme); the fork was archived (reverted) Acme's own item — still resolves, with the item's own status Blocker (styled by the returned status; archived → greyed + badge)
front_sli_…v0wa4 Common item archived by the platform after Acme forked; Acme's active org fork still holds its copy redirected: fork item's label + fork item's status + effective_item_id Urgent (fork copy still active — the source's archive does not reach it)
front_sli_…v0wa5 Common item archived by the platform; no redirect applies (no active org fork, or the fork has no non-purged copy of it) status: archived Critical (legacy) archived
front_sli_…zz09 Another customer organization's item, or purged in missing Unknown value

Archived and missing rendering is unchanged from the approved 4.0.0 picker frame selection-lists/14-picker-archived: read but not newly selectable; “Unknown value” keeps the id in the form.

States

Resolving a stored value

The stored id is never shown as a label placeholder, and the control is not editable until resolve settles — choosing a value mid-resolve would race the label (and the host's onEffectiveValue) against the user's pick.

Resolve failed

Couldn't load the saved value

The stored id stays in the form untouched — onEffectiveValue is only ever called from a successful resolve. Saving the form re-submits the original id.

Test hooks: [data-frame='10-picker-stored-values'] · [data-panel='picker'][data-state='redirected'] · [data-selected-label][data-redirected='true'] · [data-migration='host-opt-in'] · [data-persisted] · [data-panel='resolve-matrix'] · [data-resolve-case='redirect'] · [data-resolve-case='private-fork'] · [data-resolve-case='fork-item-purged'] · [data-resolve-case='fork-archived'] · [data-resolve-case='common-archived-redirect'] · [data-resolve-case='common-archived'] · [data-resolve-case='missing'] · [data-missing='true'] · [data-state='resolving'] · [data-state='resolve-error'] · [data-error='resolve-failed'] · [data-action='retry']
Contract: POST /v1/resolve (ResolvedSelectionListItem.effective_item_id, 4.1.0) · SelectionListItem.origin_item_id.
Tokens only — no raw hex, spacing or type outside tokens.css / frame.css.

Review · selection-lists-shared approve or reject each flow ↓
shared-readapproved · izzywdev
forkapproved · izzywdev
fork-provenanceapproved · izzywdev
visibilityapproved · izzywdev
effective-pickerapproved · izzywdev