# Review-separated health dashboard access and release gates

Use this pattern when a private health dashboard exposes originals, machine-extracted text, nutrition mappings, verified search, or doctor-report content.

## Independent document states

Keep these fields and decisions separate:

- **Technical original:** `available | missing | unsupported | blocked | too_large`.
- **Extraction:** `extracted | not_extracted | extraction_failed | unknown`.
- **Human review:** domain-defined review state; technical access never changes it.
- **Verified search:** `reviewed_searchable | extracted_not_reviewed | not_searchable`.

A safe unreviewed original or extracted preview may be viewable without becoming verified. Verified detail, FTS, doctor reports, and appointment packages must re-check the current reviewed state at read time; never trust stale index membership alone.

## Original and extracted-preview routes

- Keep opaque IDs, root containment, component-wise `openat`/`O_NOFOLLOW`, descriptor `fstat`, magic-byte MIME, size caps, generic names, no-store/nosniff/no-referrer, and a pinned descriptor through streaming.
- Give machine-extracted previews a distinct route-state discriminator. Reload, Back, and Forward must restore the preview rather than invoking the reviewed-detail endpoint.
- Never log or return raw paths, source URLs, numeric DB IDs, raw OCR payloads, or document names in release evidence.

## Auth principal versus CSRF

Same-origin, SameSite, CSP, and CSRF prove request context, not user authorization. Before minting a browser API session, require an authenticated principal at both the V5 HTML bootstrap and session endpoint. Reuse an existing private token-backed Basic/Bearer boundary; never embed credentials in HTML, JavaScript, URLs, browser storage, logs, or evidence. Test that an unauthenticated page visitor receives 401 and cannot mint a session.

## Exact nutrition queue links

Emit an opaque mapping deep link only after an exact unique match to a currently open review-queue row. Do not hash a display name and assume the queue entry exists. Missing, closed, ambiguous, or unmatched rows must expose no action. Malformed or unknown route keys are removed fail-closed.

## URL and accessibility parity

Pointer and roving-tab keyboard navigation must use the same URL/history writer. Acceptance tests should cover immediate navigation, focus, reload, Back, Forward, malformed parameters, and 390-pixel overflow. Programmatic focus targets need an actual focus contract (`tabindex=-1` where appropriate).

For `<details>` review cards, restoration is a four-part contract: exact card selected, `open === true`, card scrolled into view, and focus on its interactive `<summary>` (not the `<details>` container). Test all four after click, reload, Back, and Forward. A `data-selected` marker plus container focus is insufficient and can hide a Forward-only regression where the route is correct but the card is closed.

## Release sequencing after asynchronous reviews

A delegated gate remains pending until its result is consumed. If a blocking review arrives after a local commit, do not amend: remediate in a separate fix commit, invalidate affected full gates, rerun focused tests, then rerun each affected full matrix once at the new stable RC. Keep automated results and manual/independent review verdicts separate in evidence; never mark a re-review passed before it returns.

If the user explicitly accepts a known non-security/non-medical release exception, preserve the failing result verbatim: use a status such as `failed_exception_accepted`, record the narrow behavior and authorization, and label any earlier full matrix as belonging to the previous candidate. Never convert the failed review or test to `passed`. Security, authentication, privacy, review-boundary, or medical-trust failures remain blockers unless the governing policy itself is deliberately changed.
