Make the uncertain state explicit

Use action states that distinguish a failed identity check from a denied business action or an interrupted request:

ready → pending → session_expired → reconfirmation_required → pending
                     ├────────────→ already_processed
                     └────────────→ denied
pending → accepted | denied | unknown_outcome

MDN's 401 response reference describes an authentication challenge. It does not say whether the original business action ran. The API needs a documented way to inspect the record or a request identifier after authentication is restored.

Preserve intent, not an automatic replay

Retain the displayed decision, record identity, and record version long enough to explain what happened. Do not make those local values permission to send another approval. After reauthentication:

  1. Fetch the current record and server-reported outcome.
  2. If the server says the action already completed, show that result and stop.
  3. If the record is no longer eligible or the current authorization denies the action, show that result and stop.
  4. If it is still eligible, show the current facts and ask the person to confirm again.
  5. Submit a new request only after that explicit confirmation and under the server's current authorization and version rules.

React's useOptimistic can render a temporary pending state during an Action. It cannot authenticate a session, determine whether a previous request committed, or authorize the next one.

Test the decision path before the component

The P99 model checks that session expiry retains intent without accepting it, reauthentication blocks a new send until reconfirmation, a processed outcome cannot be reconfirmed, and denial remains distinct from an unknown outcome. The model is not an authentication-provider, idempotency-key, browser, or accessibility test.

Leave trusted work to the server

The backend owns authentication, authorization, anti-replay rules, durable approval evidence, request identity, and the final decision record. A disabled button, a session-expiry message, or a React state transition cannot supply any of them. Stop before shipping if reauthentication automatically repeats a consequential action or the product cannot determine what happened to the first request.