FuzeFront
▦
SO
Selection Lists · Priority · Translations · fr

A change to a common list is refused — and turned into a way forward

The detail page never offers edit controls on a common list (editable: false), so this is reached through a deep link, a stale page, or a role revoked mid-session. Here: Sam opened the French translation editor of Priority from a bookmark and pressed Save.

Kept exactly as typed — never cleared by the refusal. Copy it before you leave.

403 vs 409 — the difference is whether you may fork

The service decides, in this order (design record D7): unreadable → 404; readable but not writable → 409 fork_required if you hold SelectionListCatalog:create, else 403. The UI branches on code + reason only — never on its own guess of your role.

409 CONFLICT · reason fork_required

Not saved — fork it to change it

Offers Fork to edit… (above). The typed change is preserved.

403 FORBIDDEN — no create (e.g. a viewer)

403 FORBIDDEN — access management on a common list

Access to common lists is managed by the platform

Access operations on a common list are always 403 — they are not forkable, so the 409 path never applies.

404 NOT_FOUND — not readable at all

List not found

Another customer organization's list, or no shared read. Same message as a list that never existed.

Fail-closed rules

  • A 409 without reason (key taken, last owner, …) is the ordinary conflict message from the 4.0.0 frames — the fork banner renders only for reason: fork_required.
  • The Fork CTA uses source_list_id from the error body, not the id in the page URL — the 409 names the list the service refused.
  • fork_url is relative (/v1/…) and is resolved against the same-origin API base. A body carrying an absolute URL is ignored and the client's own forkList(sourceListId) is used.
  • The same ForkRequiredBanner renders wherever a mutation can be refused: the value editor, the reorder save, the list settings, the translation workbench and auto-fill. It sits next to the control that was refused, not in a global toast.
  • The refusal never auto-forks. Forking creates a list in the organization and costs quota — it is always an explicit choice in the next dialog.
  • Flag OFF: the service answers 4.0.0 behaviour and no common list is reachable, so this banner cannot appear; the UI does not render it even if a stray reason arrives.

Test hooks: [data-frame='04-fork-required'] · [data-panel='mutation-attempt'] · [data-unsaved='true'] · [data-error='CONFLICT'][data-reason='fork_required'] · [data-action='fork-to-edit'] · [data-fork-url] · [data-action='back-to-list'] · [data-error='FORBIDDEN'][data-case='common-no-create'] · [data-error='FORBIDDEN'][data-case='common-access'] · [data-error='NOT_FOUND']
Contract: any per-list mutation (list update/delete/archive, item create/update/reorder/delete/archive, translation upsert/delete/autofill) → 409 Error{code: CONFLICT, reason: fork_required, source_list_id, fork_url} or 403 FORBIDDEN.
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