# MOBILE-COMPAT-SPEC.md â nightly cross-browser mobile-compat cron (for Code)
**FE:** `pure-responsive.html` (live) â deviceÃbrowser preview + a `pure_mobile_health` table it reads. **Backend/cron = Code.** This spec defines the nightly sweep that keeps mobile honest.

## Table
```sql
create table if not exists public.pure_mobile_health (
  id uuid primary key default gen_random_uuid(),
  page text not null,                 -- '/pure-home'
  browser text not null,              -- chromium | webkit | firefox
  device text not null,               -- 'iPhone 15' | 'Pixel 8' | 'iPad mini' | 'Desktop HD'
  viewport text,                      -- '390x844'
  status text not null default 'pass',-- pass | warn | fail
  issues jsonb default '[]',          -- [{type:'overflow'|'tap-target'|'font'|'mixed-content'|'console', detail}]
  lcp_ms int, cls numeric, inp_ms int,
  screenshot_url text, baseline_url text, diff_pct numeric,
  checked_at timestamptz default now(),
  unique(page, browser, device)
);
create index if not exists idx_mobile_health_status on public.pure_mobile_health(status);
```
FE reads a rolled-up worst-status per page for the health table; keep the latest row per (page,browser,device).

## Cron â `mobile_compat_sweep` (nightly, off-hours CT)
Gate with `mcp_cron_ct_window` (same pattern as `design_system_autobuild`). Per run:
1. Pull the page list from `pure_pages` (governance registry) where `enabled=true`.
2. Headless **Playwright** across **chromium Â· webkit Â· firefox** Ã devices: iPhone SE(375), iPhone 15(390), Pixel 8(412), iPad mini(768), Desktop(1440). (webkit â Safari; chromium â Chrome/Edge; firefox native.)
3. Per pageÃbrowserÃdevice capture:
   - **screenshot** â object storage; **visual-diff** vs stored baseline â `diff_pct` (flag > threshold, default 8%).
   - **checks:** horizontal overflow (scrollWidth>viewport), tap targets < 44px, body font < 16px on mobile, mixed-content, console errors, missing viewport meta.
   - **web-vitals:** LCP / CLS / INP.
4. Upsert `pure_mobile_health`. On any `fail` (or diff over threshold): open a `pure_board` ticket tagged `mobile-regression` with before/after screenshot URLs + the issue list (dedupe by page+issue so it doesn't re-file nightly).
5. Update baseline only on an approved pass (so diffs are meaningful).

## RUM pairing (already shipped FE)
`pure-monitor.js` streams real-device signals â a `pure_rum_events` (or existing monitor table): JS errors, CLS/LCP/INP, rage-clicks, bounces. The sweep is synthetic; RUM is real-user â cross-reference: a page failing synthetically **and** showing real bounces jumps the ticket priority.

## RPCs
| RPC | Args | Effect |
|---|---|---|
| `mcp_mobile_health` | `{page?}` | rolled-up status for the Responsive Lab table |
| `mcp_mobile_sweep_run` | `{page?}` | run the sweep now (admin; also the cron entry) |
| `mcp_mobile_baseline_set` | `{page,browser,device}` | promote current screenshot to baseline |

## Wiring
- Add `mobile_compat_sweep` to the cron registry + the **sweep-fold** 4 AM group (SHATTIQUE-BACKLOG A2).
- Results surface in `pure-responsive.html` (health table) and Shattique's Admin Console.
- Regression tickets flow to `pure_board` â Poppy triage.

## Change log
- 2026-06-30 â Lane A: Responsive Lab FE live; this hands the sweep cron + `pure_mobile_health` + RPCs to Code.
