# UI Element Matrix Design

audience: AI coding agents first.

## Goal

Add data-driven Playwright UI regression coverage for unauthenticated Overdeck dashboard routes. Catch missing controls, incorrect enabled states, failed collector requests, and browser console errors.

## Scope

- Role axis: `dashboard` only. App has no user auth or role-specific routes; do NOT invent storage states.
- Layer 1: skip. No local shared-component gallery exists; upstream `deck-ui` contracts remain upstream responsibility.
- Layer 2: sweep every dashboard route using route-specific heading invariant, zero page-error/console-error, and zero failed `fetch`/`xhr` request assertions.
- Layer 3: manifest exact high-value states for Settings, Inbox, Decisions, and destructive-action confirmation dialog.
- Do NOT add visual baselines or axe-core: harness has neither dependency nor stable screenshot policy.

## Design

Create `apps/web/tests/ui-matrix.spec.ts` beside current Playwright specs.

`UI_SWEEP` declares `route`, accessible heading, and fixture requirement. Generic runner starts existing fixture collector, visits each route, waits for heading, then asserts no page errors, console errors, or failed API fetch/XHR requests.

`ELEMENT_MATRIX` declares page-specific entries. Each entry identifies a stable locator using existing `data-*` hooks or accessible role/name, an exact state (`present`, `enabled`, `disabled`, `editable`, `absent`), and optional `required` assertion. Generic runner resolves one entry and makes one exact assertion; it never conditionally skips a missing element.

Confirmation-dialog states run after opening existing `data-action-verb="reap"` control. Initial matrix asserts submit and cancel enabled. Busy state remains covered by action flow tests because it requires request timing control.

## Contracts

```ts
type UiState = 'present' | 'enabled' | 'disabled' | 'editable' | 'absent'

interface UiMatrixEntry {
  route: string
  name: string
  locator: (page: Page) => Locator
  state: UiState
  required?: boolean
}
```

## Acceptance

- Every route has route-specific heading invariant.
- Sweep fails for browser console/page errors and failed dashboard API requests.
- Matrix fails when Settings color input or save action changes state, Inbox non-gateway action becomes enabled, or confirmation controls disappear/change state.
- `pnpm exec playwright test apps/web/tests/ui-matrix.spec.ts` passes.
- `pnpm typecheck` passes without warnings.
