# Preview/confirm CSRF release gate

Use for browser workflows where a read-only preview precedes a queued or persisted mutation.

## Contract

1. Establish the authenticated browser session before requesting action CSRF material.
2. Fetch CSRF from the endpoint for the **actual mutation domain**; do not reuse a generic page/form token merely because both appear in the same shell.
3. Normalize the payload server-side and compute a keyed, domain-separated preview revision over the complete payload plus current database context.
4. Preview validates but does not consume the one-time token. Freeze the exact normalized payload, preview revision, and that same token in client state.
5. Any form mutation clears all frozen state and forces a new token and preview.
6. Confirm consumes the token, recomputes the revision, uses constant-time comparison, and then enters the durable idempotency/replay boundary.

## Release verification

A dialog-opening test is insufficient. The browser smoke must:

- execute the real preview request and require HTTP 200;
- assert that the frozen preview state is shown;
- mutate nothing and never submit confirm in a read-only smoke;
- prove database row counts/digests and action-queue contents are unchanged;
- check console/page errors and ensure sensitive references are absent from visible URLs.

For deployment, distinguish service activation from reachability. Read the actual process environment or socket after startup because an EnvironmentFile may override the unit's nominal host. Probe only the observed bind address with an allowed Host and preserve auth/no-store/CSP gates.
