From 6f4569330ce13e8491227a5da83d80731cbdabfd Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 12 Jul 2026 21:51:29 +0000 Subject: [PATCH] feat(uicheck): add the Playwright interaction loop (forge uicheck interact) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements the ROADMAP "Next" item "Playwright loop": where `uicheck visual` fingerprints what the browser PAINTS, `uicheck interact` checks what it DOES, headless under prefers-reduced-motion — console-clean, keyboard-reachable, focus-visible (WCAG 2.4.7), and reduced-motion honesty. The verdict is expressed in the ledger's own evidence vocabulary and recorded through the cross-family-gated `behavioral` oracle, so it is advisory by default (a lone interaction run can never move a claim — overview §4 honesty register): - --record appends the verdict as evidence on the project `fingerprint` claim - --enforce (or FORGE_ENFORCE=1) turns a fail into a non-zero exit Reuses the visual gate's Playwright resolver and loopback-only target guard; Playwright stays an optional tier (ADR-0005) with a graceful "skipped (no browser runtime)" fallback. New src/uiinteract.js with a browser-free test suite (the skip/refusal/verdict/outcome logic is unit-tested; the browser path mirrors the proven visualGate orchestration). Docs: GUIDE uicheck section + CHANGELOG. Verified: npm test (683 pass), npm run check, npm run typecheck, forge docs check. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01WTc41NYip9GZLu4n9a5vLs --- CHANGELOG.md | 13 +++ docs/GUIDE.md | 31 ++++++- src/cli.js | 57 ++++++++++++ src/uiinteract.js | 201 ++++++++++++++++++++++++++++++++++++++++ test/uiinteract.test.js | 87 +++++++++++++++++ 5 files changed, 387 insertions(+), 2 deletions(-) create mode 100644 src/uiinteract.js create mode 100644 test/uiinteract.test.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 3376992..2422ecc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,19 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added + +- **Playwright interaction loop** — `forge uicheck interact ` drives the + page headless under `prefers-reduced-motion` and checks what it *does* + (console-clean, keyboard-reachable, focus-visible, reduced-motion), where + `uicheck visual` only fingerprints what it paints. The verdict is recorded through + the ledger's cross-family-gated `behavioral` oracle (advisory by default; + `--record` appends it as evidence on the project `fingerprint` claim, `--enforce` + gates). Reuses the visual gate's Playwright resolver + loopback-only target guard; + Playwright stays an optional tier (ADR-0005) with a graceful skip. New + `src/uiinteract.js` (`runInteractions`, `summarizeVerdict`, `verdictOutcome`, + `recordInteraction`) with a browser-free test suite. + ## [0.12.4] - 2026-07-11 ### Fixed diff --git a/docs/GUIDE.md b/docs/GUIDE.md index 4010137..245ace3 100644 --- a/docs/GUIDE.md +++ b/docs/GUIDE.md @@ -615,8 +615,8 @@ tree (your uncommitted changes wouldn't be in the run); commit/stash first or pa ### `forge uicheck` — deterministic UI checks -Four subcommands: three are static parsing — no LLM, no screenshots — and `visual` -optionally drives a real browser. +Five subcommands: three are static parsing — no LLM, no screenshots — and `visual` +and `interact` optionally drive a real browser. **`contrast `** — exact WCAG math, asserted, never guessed (bare `forge uicheck ` still works): @@ -675,6 +675,33 @@ Forge uicheck visual — rendered fingerprint + design gate ✓ PASS ``` +**`interact [--record] [--enforce] [--json] [--remote]`** — the Playwright +_interaction_ loop: where `visual` fingerprints what the page **paints**, `interact` +checks what it **does**, headless under `prefers-reduced-motion`. Four checks: +`console-clean` (no console errors on load), `keyboard-reachable` (Tab lands on an +interactive control), `focus-visible` (the focused control shows a visible focus ring — +WCAG 2.4.7), and `reduced-motion` (nothing animates when reduced motion is requested). +The verdict is **advisory** by default — it is recorded through the ledger's weakest, +cross-family-gated `behavioral` oracle, so a lone interaction run can never move a claim +on its own (overview §4 honesty register). `--record` appends the verdict as evidence on +your minted project `fingerprint` claim; `--enforce` (or `FORGE_ENFORCE=1`) turns a fail +into a non-zero exit. Playwright and the loopback-only target guard are shared with +`visual` (same _optional tier_, same `--remote` rule). + +```console +$ forge uicheck interact src/dash.html --record +Forge uicheck interact — browser interaction checks + + driven: file:///…/src/dash.html (headless, prefers-reduced-motion) + ✓ console-clean: no console errors on load + ✓ keyboard-reachable: Tab reached