Decision 4's never-nest rule destroys a filled-in form before the user confirms #235

Open
opened 2026-10-27 23:19:21 +00:00 by peterswimm · 1 comment
Owner

Split out from #231 decision 4, which is otherwise settled. The never-nest principle stands; only its sequencing needs a second look.

The rule as written

The #182 confirmation dialog never nests over a form dialog. The form presentation ends first. Then the confirmation step starts.

Never nesting a confirmation over a form is right. Stacked modals are the thing that makes a destructive confirmation feel routine, and #182's severity levels only mean something if the dialog that carries them is the only thing on screen.

The hazard

"The form presentation ends first" tears down a filled-in form before the person has confirmed. The rule says nothing about what happens to their input if they then cancel.

Three plausible readings, and they are very different products:

  1. The form is destroyed. Cancel returns to an empty form. For a multi-field form — and decision 4 reserves modals for "focused, complex" ones, so that is the case this applies to — the person loses everything they typed by using the confirm step as designed. A cancel button that costs you your work is not a cancel button.
  2. The form is closed but its state is held and restored on cancel. Correct outcome, but it is a real mechanism, not a free one: something has to own that state across the dismiss, and nothing in the client does today.
  3. The form stays alive and inert behind the confirmation. No nesting in the sense that matters — one interactive surface at a time, the confirmation unambiguously on top — and no state to preserve because nothing was destroyed.

(3) is the cheapest and the safest, and it satisfies the principle as stated: the confirmation is not nested in the form, it supersedes it. But that is a reading of the rule, not what the rule says, so it needs ratifying rather than assuming.

Why this is design's call and not engineering's

Either answer is buildable. The question is what the person should experience when they back out of a confirmation — whether the form is a thing they were in and returned to, or a thing that ended. That is an interaction decision, so it belongs here.

The engineering consequence follows from the answer: (2) needs form-state preservation across a dismiss, which is work that does not exist; (3) needs the focus and dismissal behaviour of FocusTrap (lib/utils/focus_trap.dart) to handle two stacked routes where the lower one is inert. (1) needs nothing, which is the tell.

Constraint that does not bend

Whichever is chosen, CLAUDE.md's escape-hatch rule still applies: any blocking state offers a way out — Escape, an X, or a visible Cancel. A confirmation that can only be dismissed by completing it is not an option here.

Acceptance

  • One reading ratified, and #231 decision 4 amended to say it rather than imply it.
  • If (2): the state-preservation mechanism has a ticket before any form-in-modal ships.
  • A cancelled confirmation never costs the person typed input — stated as a test, not as an intention.
Split out from #231 decision 4, which is otherwise settled. The never-nest principle stands; only its sequencing needs a second look. ## The rule as written > The #182 confirmation dialog never nests over a form dialog. The form presentation ends first. Then the confirmation step starts. Never nesting a confirmation over a form is right. Stacked modals are the thing that makes a destructive confirmation feel routine, and #182's severity levels only mean something if the dialog that carries them is the only thing on screen. ## The hazard "The form presentation ends first" tears down a filled-in form **before** the person has confirmed. The rule says nothing about what happens to their input if they then cancel. Three plausible readings, and they are very different products: 1. **The form is destroyed.** Cancel returns to an empty form. For a multi-field form — and decision 4 reserves modals for "focused, complex" ones, so that is the case this applies to — the person loses everything they typed by using the confirm step as designed. A cancel button that costs you your work is not a cancel button. 2. **The form is closed but its state is held and restored on cancel.** Correct outcome, but it is a real mechanism, not a free one: something has to own that state across the dismiss, and nothing in the client does today. 3. **The form stays alive and inert behind the confirmation.** No nesting in the sense that matters — one interactive surface at a time, the confirmation unambiguously on top — and no state to preserve because nothing was destroyed. (3) is the cheapest and the safest, and it satisfies the principle as stated: the confirmation is not *nested in* the form, it *supersedes* it. But that is a reading of the rule, not what the rule says, so it needs ratifying rather than assuming. ## Why this is design's call and not engineering's Either answer is buildable. The question is what the person should experience when they back out of a confirmation — whether the form is a thing they were in and returned to, or a thing that ended. That is an interaction decision, so it belongs here. The engineering consequence follows from the answer: (2) needs form-state preservation across a dismiss, which is work that does not exist; (3) needs the focus and dismissal behaviour of `FocusTrap` (`lib/utils/focus_trap.dart`) to handle two stacked routes where the lower one is inert. (1) needs nothing, which is the tell. ## Constraint that does not bend Whichever is chosen, `CLAUDE.md`'s escape-hatch rule still applies: any blocking state offers a way out — Escape, an X, or a visible Cancel. A confirmation that can only be dismissed by completing it is not an option here. ## Acceptance - [ ] One reading ratified, and #231 decision 4 amended to say it rather than imply it. - [ ] If (2): the state-preservation mechanism has a ticket before any form-in-modal ships. - [ ] A cancelled confirmation never costs the person typed input — stated as a test, not as an intention.
Member

Decision for #235: a confirmation over a form.

The confirmation is the only interactive surface. It is not the only visible surface. This supersedes the wording in #231 decision 4: "The #182 confirmation dialog never nests over a form dialog. The form presentation ends first. Then the confirmation step starts."

The rule

  • The form stays mounted and visible behind the confirmation, dimmed. It keeps all entered state.
  • While the confirmation is active, the form is inert to pointer, keyboard and assistive technology.
  • The confirmation owns focus. It is the only active accessibility surface.
  • Cancel, Escape and the visible cancel or close control dismiss only the confirmation. The person returns to the exact form state they left.
  • Confirm proceeds with the action. The form may be destroyed only after that action succeeds.
  • A failed submit keeps the form and its input (#580: a failed submit is an error state with retry).

What "never nest" means now
Two interactive dialogs at the same time is the thing to avoid. A dimmed, inert form behind one confirmation is not that. The test is one interactive surface at a time. It is not one visible surface. "The dialog is the only thing on screen" (this issue) is read the same way.

Scope

  • It applies to Review, Ceremony, Destructive and safety-override confirmations.
  • Simple stays as #182 says. A Simple confirmation with inputs has no second dialog. Submitting the completed form is the confirmation.
  • Closing a form that has unsaved input is a separate question. This decision does not cover it.

Constraints that stay (#182)

  • Escape and a visible way out always exist.
  • Initial focus follows the level. Review starts on Cancel or the first item, never on the confirming action.
  • When the confirmation closes, focus returns to the control that opened it.

Acceptance

  • This ratifies reading 3. #231 decision 4 reads as above.
  • Reading 2 is not chosen, so no state-preservation ticket is needed.
  • A cancelled confirmation never costs typed input. It is a test on both ports, not an intention. The test also covers: the form cannot be reached by pointer, keyboard or screen reader while the confirmation is up; Escape closes only the confirmation; the form is destroyed only after success.

Implementation, for the follow-up

  • The container shows the confirmation as a layer above the form. It is not a sibling inside the form.
  • Each port needs the behaviour: Flutter and macOS. A parity test holds them to one answer.
  • Flutter: the confirmation sets its own initial focus. Plain showDialog focus is not enough. In a probe, focus landed on the dialog itself, not on a control.
  • Peter's precedence rule applies to the shape of this mechanism.
**Decision for #235: a confirmation over a form.** The confirmation is the only interactive surface. It is not the only visible surface. This supersedes the wording in #231 decision 4: "The #182 confirmation dialog never nests over a form dialog. The form presentation ends first. Then the confirmation step starts." **The rule** - The form stays mounted and visible behind the confirmation, dimmed. It keeps all entered state. - While the confirmation is active, the form is inert to pointer, keyboard and assistive technology. - The confirmation owns focus. It is the only active accessibility surface. - Cancel, Escape and the visible cancel or close control dismiss only the confirmation. The person returns to the exact form state they left. - Confirm proceeds with the action. The form may be destroyed only after that action succeeds. - A failed submit keeps the form and its input (#580: a failed submit is an error state with retry). **What "never nest" means now** Two interactive dialogs at the same time is the thing to avoid. A dimmed, inert form behind one confirmation is not that. The test is one interactive surface at a time. It is not one visible surface. "The dialog is the only thing on screen" (this issue) is read the same way. **Scope** - It applies to Review, Ceremony, Destructive and safety-override confirmations. - Simple stays as #182 says. A Simple confirmation with inputs has no second dialog. Submitting the completed form is the confirmation. - Closing a form that has unsaved input is a separate question. This decision does not cover it. **Constraints that stay (#182)** - Escape and a visible way out always exist. - Initial focus follows the level. Review starts on Cancel or the first item, never on the confirming action. - When the confirmation closes, focus returns to the control that opened it. **Acceptance** - This ratifies reading 3. #231 decision 4 reads as above. - Reading 2 is not chosen, so no state-preservation ticket is needed. - A cancelled confirmation never costs typed input. It is a test on both ports, not an intention. The test also covers: the form cannot be reached by pointer, keyboard or screen reader while the confirmation is up; Escape closes only the confirmation; the form is destroyed only after success. **Implementation, for the follow-up** - The container shows the confirmation as a layer above the form. It is not a sibling inside the form. - Each port needs the behaviour: Flutter and macOS. A parity test holds them to one answer. - Flutter: the confirmation sets its own initial focus. Plain `showDialog` focus is not enough. In a probe, focus landed on the dialog itself, not on a control. - Peter's precedence rule applies to the shape of this mechanism.
Sign in to join this conversation.
No description provided.