diff --git a/AGENTS.md b/AGENTS.md index 475c26e..7d2c40a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -98,8 +98,9 @@ Use `bun run ui:check` as the fast static guardrail for source CSS drift. Use - Baseline target: Baseline Widely Available. Before frontend, UI, CSS, accessibility, browser proof, or web-design changes in `packages/website`, run repo-installed Modern Web Guidance with `bun run agentic:guidance`, then apply `packages/website/DESIGN.md` and the website token system. - Prefer semantic HTML, native controls, platform CSS, and browser primitives before custom JavaScript. Keep landmarks, headings, links, forms, accessible names, focus states, touch targets, empty/error/loading states, and reduced-motion behavior clear in the rendered DOM and accessibility tree. -- Run `bun run agentic:check` for the hard guidance-readiness and advisory source proof path (`agentic:guidance`, `plans:validate`, plus `ui:check`). Use `bun run agentic:browser-proof ` (same rendered lane as `agentic:verify`) when layout, interaction, motion, or public routes need browser proof at the repo's 375 / 1024 / 1440 viewport loop. `dev-surfaces` remains the cross-repo/global doctor for shared Modern Web Guidance cache refresh, Brave, and MCP readiness. -- For local human/agent browser walkthroughs, WebMCP validation, and DevTools MCP proof, prefer Brave with an isolated/non-default profile. Keep the repo commands Chrome/Chromium-compatible for contributors and CI unless a task explicitly requires Brave-only WebMCP validation. +- Run `bun run agentic:check` for the hard guidance-readiness and advisory source proof path (`agentic:guidance`, `plans:validate`, plus `ui:check`). Treat `bun run agentic:browser-proof ` as CI/clean-room proof only. `dev-surfaces` remains the cross-repo/global doctor for shared Modern Web Guidance cache refresh, Brave, and MCP readiness. +- Local agentic browser QA must use the authenticated Brave QA profile. Codex: use the Codex browser-extension path and claim the already-open Brave tab/window. Claude Code: use the Claude Code Chrome/Chromium extension path (`claude --chrome` or `/chrome`) and select the authenticated Brave profile/tab when it is installed, connected, and able to control the already-open Brave window. Do not fall back merely because the extension is branded Chrome. If the Brave extension path is unavailable or not connected, use Claude computer-use/visible desktop control of the already-open Brave window; if neither can reach authenticated Brave, report QA as blocked. Use this for admin, PWA, extension, wallet/passkey, staging-session, installed-app, and profile-dependent verification. +- Do not use isolated Browser, Playwright, or DevTools MCP profiles for local QA. Existing isolated browser-proof commands are CI/clean-room checks only and must not be reported as authenticated verification. If authenticated Brave access is blocked, stop and report QA as blocked. - WebMCP has an explicitly approved public read-only runtime pilot in `packages/website/src/scripts/webmcp.ts`. Keep tools visible, page-scoped, and public-safe; do not expose Directus private state, database credentials, pending intake, steward notes, hidden admin actions, destructive operations, or background-only actions. - For June website work and MCP/tool selection, use `docs/agentic-mcp-tooling-runbook.md` as the role map before adding tools, changing proof lanes, or expanding WebMCP. diff --git a/CLAUDE.md b/CLAUDE.md index aec9f26..58b8348 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -63,8 +63,9 @@ Website source and config live under `packages/website`: - Baseline target: Baseline Widely Available. Before frontend, UI, CSS, accessibility, browser proof, or web-design changes in `packages/website`, run repo-installed Modern Web Guidance with `bun run agentic:guidance`, then apply `packages/website/DESIGN.md` and the website token system. - Prefer semantic HTML, native controls, platform CSS, and browser primitives before custom JavaScript. Keep landmarks, headings, links, forms, accessible names, focus states, touch targets, empty/error/loading states, and reduced-motion behavior clear in the rendered DOM and accessibility tree. -- Run `bun run agentic:check` for the hard guidance-readiness and advisory source proof path (`agentic:guidance`, `plans:validate`, plus `ui:check`). Use `bun run agentic:browser-proof ` (same rendered lane as `agentic:verify`) when layout, interaction, motion, or public routes need browser proof at the repo's 375 / 1024 / 1440 viewport loop. `dev-surfaces` remains the cross-repo/global doctor for shared Modern Web Guidance cache refresh, Brave, and MCP readiness. -- For local human/agent browser walkthroughs, WebMCP validation, and DevTools MCP proof, prefer Brave with an isolated/non-default profile. Keep the repo commands Chrome/Chromium-compatible for contributors and CI unless a task explicitly requires Brave-only WebMCP validation. +- Run `bun run agentic:check` for the hard guidance-readiness and advisory source proof path (`agentic:guidance`, `plans:validate`, plus `ui:check`). Treat `bun run agentic:browser-proof ` as CI/clean-room proof only. `dev-surfaces` remains the cross-repo/global doctor for shared Modern Web Guidance cache refresh, Brave, and MCP readiness. +- Local agentic browser QA must use the authenticated Brave QA profile. Codex: use the Codex browser-extension path and claim the already-open Brave tab/window. Claude Code: use the Claude Code Chrome/Chromium extension path (`claude --chrome` or `/chrome`) and select the authenticated Brave profile/tab when it is installed, connected, and able to control the already-open Brave window. Do not fall back merely because the extension is branded Chrome. If the Brave extension path is unavailable or not connected, use Claude computer-use/visible desktop control of the already-open Brave window; if neither can reach authenticated Brave, report QA as blocked. Use this for admin, PWA, extension, wallet/passkey, staging-session, installed-app, and profile-dependent verification. +- Do not use isolated Browser, Playwright, or DevTools MCP profiles for local QA. Existing isolated browser-proof commands are CI/clean-room checks only and must not be reported as authenticated verification. If authenticated Brave access is blocked, stop and report QA as blocked. - WebMCP has an explicitly approved public read-only runtime pilot in `packages/website/src/scripts/webmcp.ts`. Keep tools visible, page-scoped, and public-safe; do not expose Directus private state, database credentials, pending intake, steward notes, hidden admin actions, destructive operations, or background-only actions. - For June website work and MCP/tool selection, use `docs/agentic-mcp-tooling-runbook.md` as the role map before adding tools, changing proof lanes, or expanding WebMCP. diff --git a/package.json b/package.json index b976df3..2dd2f60 100644 --- a/package.json +++ b/package.json @@ -41,9 +41,9 @@ "plans:scaffold": "bun --no-env-file scripts/plan-hub.ts scaffold", "plans:validate": "bun --no-env-file scripts/plan-hub.ts validate", "agentic:guidance": "DISABLE_TELEMETRY=1 bun --bun modern-web-guidance search \"agentic frontend CSS accessibility browser validation DevTools MCP\" && DISABLE_TELEMETRY=1 bun --bun modern-web-guidance retrieve accessibility", - "agentic:check": "bun run agentic:guidance && bun run plans:validate && bun run ui:check", - "agentic:browser-proof": "bun run ui:verify", - "agentic:verify": "bun run ui:verify", + "agentic:check": "bun run agentic:guidance && bun run check:browser-verification-policy && bun run plans:validate && bun run ui:check", + "agentic:browser-proof": "bun scripts/require-authenticated-browser-qa.mjs && bun run ui:verify", + "agentic:verify": "bun scripts/require-authenticated-browser-qa.mjs && bun run ui:verify", "test:agent": "bun run build:packages && bun test scripts/agent-contract.test.ts", "test:chapter-impact": "bun run build:packages && bun test scripts/chapter-impact-contract.test.ts", "test:content": "bun run build:packages && bun test scripts/public-content-contract.test.ts", @@ -57,7 +57,8 @@ "test:plans": "bun test scripts/plan-hub.test.ts", "ui:check": "UI_VERIFY_SOURCE_ONLY=1 bun --no-env-file scripts/ui-verify.ts", "ui:verify": "bun run build:website && bun --no-env-file scripts/ui-verify.ts", - "ui:verify:required": "UI_VERIFY_REQUIRED=1 bun run ui:verify" + "ui:verify:required": "UI_VERIFY_REQUIRED=1 bun run ui:verify", + "check:browser-verification-policy": "bun scripts/check-browser-verification-policy.mjs" }, "author": "", "license": "ISC", diff --git a/packages/website/CLAUDE.md b/packages/website/CLAUDE.md index 85fca75..d35e600 100644 --- a/packages/website/CLAUDE.md +++ b/packages/website/CLAUDE.md @@ -46,7 +46,9 @@ bun run ui:verify /your-route `ui:check` is static/source-only and catches CSS standard drift without building or opening a browser. `ui:verify` renders at 375/1024/1440 and runs four channels — layout (overflow / wrapped pills / 44px targets), accessibility tree, axe-core, and CLS + semantic lint — writing screenshots + `report.json` to `.ui-verify/`. **Read the 375px PNG first.** Fix every HARD violation. Never declare UI work done on code review alone — responsiveness and a11y bugs are invisible in source. -For local human/agent walkthroughs, WebMCP validation, and DevTools MCP proof, prefer Brave with an isolated/non-default profile. Keep `ui:check` / `ui:verify` Chrome/Chromium-compatible for contributors and CI unless a task explicitly requires Brave-only WebMCP validation. +Local agentic browser QA must use the authenticated Brave QA profile. +- Codex: use the Codex browser-extension path and claim the already-open Brave tab. Claude Code: use the Claude Code Chrome/Chromium extension path (`claude --chrome` or `/chrome`) and select the authenticated Brave profile/tab when it is installed, connected, and able to control the already-open Brave window. Do not fall back merely because the extension is branded Chrome. If the Brave extension path is unavailable or not connected, use Claude computer-use/visible desktop control of the already-open Brave window; if neither can reach authenticated Brave, report QA as blocked. Use this for Directus-backed, future workspace/session, staging, and profile-dependent verification. +- Do not use isolated Browser, Playwright, or DevTools MCP profiles for local QA. Existing `ui:verify` / browser-proof commands are CI/clean-room checks only and must not be reported as authenticated verification. If authenticated Brave access is blocked, stop and report QA as blocked. Runtime WebMCP is approved only for the public read-only pilot in `src/scripts/webmcp.ts`. Keep tools scoped to visible public page/map state and do not expose private Directus data, pending intake, steward notes, edit links, emails, credentials, writes, or background-only actions. @@ -63,3 +65,9 @@ Tailwind is being retired from this package (its utilities are unused; `@apply` ## Canonical references web.dev [Learn CSS](https://web.dev/learn/css) · [Learn Accessibility](https://web.dev/learn/accessibility) · [Responsive design](https://web.dev/articles/responsive-web-design-basics) · [Building agent-friendly UX](https://web.dev/articles/ai-agent-site-ux) · Chrome [CSS & UI](https://developer.chrome.com/docs/css-ui). + +## Agentic Browser QA + +Local agentic browser QA must use the authenticated Brave QA profile. +- Codex: use the Codex browser-extension path and claim the already-open Brave tab. Claude Code: use the Claude Code Chrome/Chromium extension path (`claude --chrome` or `/chrome`) and select the authenticated Brave profile/tab when it is installed, connected, and able to control the already-open Brave window. Do not fall back merely because the extension is branded Chrome. If the Brave extension path is unavailable or not connected, use Claude computer-use/visible desktop control of the already-open Brave window; if neither can reach authenticated Brave, report QA as blocked. Use this for Directus-backed, future workspace/session, staging, and profile-dependent verification. +- Do not use isolated Browser, Playwright, or DevTools MCP profiles for local QA. Existing `ui:verify` / browser-proof commands are CI/clean-room checks only and must not be reported as authenticated verification. If authenticated Brave access is blocked, stop and report QA as blocked. diff --git a/scripts/check-browser-verification-policy.mjs b/scripts/check-browser-verification-policy.mjs new file mode 100644 index 0000000..c676c0a --- /dev/null +++ b/scripts/check-browser-verification-policy.mjs @@ -0,0 +1,144 @@ +#!/usr/bin/env bun + +import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs'; +import { join, relative } from 'node:path'; + +const repoRoot = process.cwd(); +const requiredPolicyFiles = ["AGENTS.md", "CLAUDE.md", "packages/website/CLAUDE.md"]; + +const failures = []; + +function fail(message) { + failures.push(message); +} + +function read(relPath) { + return readFileSync(join(repoRoot, relPath), 'utf8'); +} + +function walk(dir, result = []) { + if (!existsSync(dir)) return result; + for (const entry of readdirSync(dir)) { + if ( + [ + '.git', + '.cache', + '.claude', + '.next', + 'node_modules', + 'dist', + 'build', + 'build-storybook', + 'output', + ].includes(entry) + ) { + continue; + } + const fullPath = join(dir, entry); + let stat; + try { + stat = statSync(fullPath); + } catch { + continue; + } + if (stat.isDirectory()) { + walk(fullPath, result); + } else if (entry === 'AGENTS.md' || entry === 'CLAUDE.md') { + result.push(fullPath); + } + } + return result; +} + +for (const relPath of requiredPolicyFiles) { + if (!existsSync(join(repoRoot, relPath))) { + fail(`${relPath}: missing required authenticated-browser QA policy file`); + continue; + } + + const text = read(relPath); + for (const phrase of [ + 'authenticated Brave QA profile', + 'Codex browser-extension path', + 'Claude Code Chrome/Chromium extension path', + 'authenticated Brave profile/tab', + 'Do not use isolated Browser, Playwright, or DevTools MCP profiles for local QA', + 'If authenticated Brave access is blocked, stop and report QA as blocked', + ]) { + if (!text.includes(phrase)) { + fail(`${relPath}: missing required authenticated-browser QA phrase "${phrase}"`); + } + } +} + +const stalePatterns = [ + /Browser verification has two lanes/i, + /Use isolated browser proof/i, + /deterministic public[-/ ](route|website|app|login)/i, + /For local human\/agent browser walkthroughs[^\n]*isolated/i, + /prefer Brave with an isolated/i, + /use Brave with an\s+isolated/i, + /shared posture Brave-first/i, + /Use `bun run agentic:browser-proof/i, + /Build-backed browser proof:\s*`bun run agentic:browser-proof`/i, + /Brave MCP live DOM/i, + /Brave-backed browser MCP/i, + /DevTools MCP path for live browser debugging/i, + /isolated\/public proof lane/i, + /browser proof still runs in Brave/i, + /only when the authenticated QA browser is Chrome\/Edge/i, + /Brave-only QA/i, + /Chrome\/Edge QA profiles/i, + /for Brave-only QA/i, +]; + +for (const filePath of walk(repoRoot)) { + const relPath = relative(repoRoot, filePath); + const text = readFileSync(filePath, 'utf8'); + for (const pattern of stalePatterns) { + if (pattern.test(text)) { + fail(`${relPath}: stale isolated-browser QA guidance matched ${pattern}`); + } + } +} + +const packageJsonPath = join(repoRoot, 'package.json'); +if (existsSync(packageJsonPath)) { + const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8')); + const scripts = packageJson.scripts ?? {}; + + if (scripts['check:browser-verification-policy'] !== 'bun scripts/check-browser-verification-policy.mjs') { + fail('package.json: missing check:browser-verification-policy script'); + } + + if (!scripts['agentic:check']?.includes('check:browser-verification-policy')) { + fail('package.json: agentic:check must run check:browser-verification-policy'); + } + + if ( + scripts['agentic:browser-proof'] && + !scripts['agentic:browser-proof'].startsWith('bun scripts/require-authenticated-browser-qa.mjs') + ) { + fail('package.json: local agentic:browser-proof must be guarded by require-authenticated-browser-qa.mjs'); + } + + if ( + scripts['agentic:verify'] && + scripts['agentic:verify'].includes('ui:verify') && + !scripts['agentic:verify'].startsWith('bun scripts/require-authenticated-browser-qa.mjs') + ) { + fail('package.json: local agentic:verify browser lane must be guarded by require-authenticated-browser-qa.mjs'); + } +} + +if (failures.length > 0) { + console.error('Authenticated browser QA policy check failed:'); + for (const failure of failures) { + console.error(`- ${failure}`); + } + process.exit(1); +} + +console.log( + `Authenticated browser QA policy check passed for ${requiredPolicyFiles.length} guidance file(s).`, +); diff --git a/scripts/require-authenticated-browser-qa.mjs b/scripts/require-authenticated-browser-qa.mjs new file mode 100644 index 0000000..18833a2 --- /dev/null +++ b/scripts/require-authenticated-browser-qa.mjs @@ -0,0 +1,20 @@ +#!/usr/bin/env bun + +if (process.env.CI === 'true') { + console.warn( + '[browser-qa] CI=true: allowing clean-room browser proof. Do not report this as authenticated local QA.', + ); + process.exit(0); +} + +console.error( + [ + '[browser-qa] Local agentic browser QA must use the authenticated Brave QA profile.', + '[browser-qa] Codex: use the Codex browser-extension path and claim the already-open Brave tab/window.', + '[browser-qa] Claude Code: use the Claude Code Chrome/Chromium extension path (`claude --chrome` or `/chrome`) and select the authenticated Brave profile/tab when connected.', + '[browser-qa] Claude fallback: if the Brave extension path is unavailable, use computer-use/visible desktop control of the already-open Brave window.', + '[browser-qa] Do not run isolated Browser, Playwright, or DevTools MCP profiles for local QA.', + '[browser-qa] If authenticated Brave access is blocked, report QA as blocked.', + ].join('\n'), +); +process.exit(1);