diff --git a/CLAUDE.md b/CLAUDE.md index f9a4bd2..c05a841 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -12,7 +12,7 @@ Phase 5 is complete — updates and distribution. See `dev_docs/MASTER-PLAN.md` - **Installer** — `npx pixelslop install` is interactive by default. It detects Claude Code and Codex CLI, lets the user pick runtimes and scope, supports project-local Codex installs in `.codex/`, rewrites paths, configures MCP, and installs skills via symlink or copy. `npx pixelslop@latest update` upgrades the installed runtime set with backup + diff. - **CI/CD** — GitHub Actions for CI (Node 18/20/22) and automated releases via release-please + npm publish with OIDC provenance. - **Orchestrator** — coordinates the full scan→fix→verify workflow. Spawns subagents, manages user interaction, groups findings by category, handles PARTIAL results. Supports `--personas` and `--thorough` flags. -- **Scanner** — evaluates pages across 3 viewports, scores 5 pillars, detects 25 slop patterns, runs persona evaluation from 8 user perspectives. Tested on 7 pages, scores stable within ±1. +- **Scanner** — evaluates pages across 3 viewports, scores 5 pillars, detects 26 slop patterns, runs vision-first persona evaluation (the page-relevant subset of 8 built-ins, plus any project persona). Tested on 7 pages, scores stable within ±1. - **Persona evaluation** — 8 built-in personas (screen-reader-user, low-vision-user, keyboard-user, rushed-mobile-user, slow-connection-user, non-native-english, design-critic, first-time-visitor). Extensible JSON format supports custom personas. - **Fixer** — takes a scanner finding, locates the source code, creates a checkpoint via `pixelslop-tools`, applies the smallest viable fix. - **Checker** — re-measures the targeted metric after a fix, compares before/after, returns PASS/FAIL/PARTIAL. Updates plan via `pixelslop-tools`. @@ -137,7 +137,7 @@ Agents use `pixelslop-tools` (bin/pixelslop-tools.cjs) for all state operations. - **`scan trend`** reports the score progression across runs. `scan save-results` now appends each run's /20 total (plus per-pillar scores) to `.pixelslop/scan-history.json`; `scan trend [--target ] [--last ]` reads it back (`11 -> 13 -> 14 (+3)`). History is best-effort — a corrupt history file self-heals and never blocks the actual save. The orchestrator surfaces the trend in its scan summary. - **`personas write` / `personas list`** manage project-specific personas. `write --json ''` validates (required fields, slug-only id, no built-in collision, no path traversal) and saves to `.pixelslop/personas/.json`; `list` returns the 8 built-ins plus any custom ones. The orchestrator generates 1-2 personas from the project's audience/brand and evaluates them alongside the built-ins, so persona findings fit the real users instead of only the generic profiles. - **`doctor`** self-checks the install: reports the version, confirms `pixelslop-tools.cjs` is reachable, and flags when a newer version is published (a throttled npm check, cached 24h in `.pixelslop-doctor-cache.json`, fail-soft offline). The skill runs it at preflight — if it can't run, the install is broken/stale and the skill tells the user to `npx pixelslop@latest update`; if it reports `stale`, the skill surfaces the update once and continues. This is what makes a stale/broken install self-diagnose instead of failing opaquely. -- **`config write --register brand|product`** stores the project's **register** — a `## Register` section in `.pixelslop.md`. Register frames the whole review: a `brand` surface (landing, marketing, campaign) is judged on distinctiveness and emotional pull; a `product` surface (app, dashboard, tool) on clarity and low friction. `config write` validates it (bare `brand`/`product`, junk is dropped) and `config read` round-trips it. It calibrates **only** the design-director's judgment pass — the 6 measured pillars stay register-blind, because a 90-char line or a 3:1 contrast ratio is a defect on any surface. The setup agent forms a register hypothesis from route/component signals and confirms it with a leading question. +- **`config write --register brand|product`** stores the project's **register** — a `## Register` section in `.pixelslop.md`. Register frames the whole review: a `brand` surface (landing, marketing, campaign) is judged on distinctiveness and emotional pull; a `product` surface (app, dashboard, tool) on clarity and low friction. `config write` validates it (bare `brand`/`product`, junk is dropped) and `config read` round-trips it. It calibrates **only** the design-director's judgment pass — the 5 measured pillars stay register-blind, because a 90-char line or a 3:1 contrast ratio is a defect on any surface. The setup agent forms a register hypothesis from route/component signals and confirms it with a leading question. ## Design Detectors & Report Provenance @@ -153,7 +153,7 @@ The measured /20 is the objective backbone; the perceptual layer is how the page - **Personas ground in behavior, not just the still.** Beyond the three above-fold viewport shots, the persona evaluator reads `scroll.foldScreenshots` (the whole scrolled page) and the interaction evidence the collector already captured — `interactivePromises.results` (did the mobile menu open, did the anchor jump), `focusPass` (keyboard reachability + focus rings), `viewports.mobile.touchTargets`, `hoverStates`. So "would I bounce" is grounded in whether the flow *works*, not only how the hero looks. Each persona pulls the evidence its `designPriorities` care about; a null pass means it didn't run and must not be invented. All deterministic — it's evidence collected once, not the persona re-driving the browser. - **Project persona sourcing (in priority order).** The tailored persona comes from the best available signal: (1) an explicit audience/brand description in `.pixelslop.md` (setup) — always wins; (2) failing that, a **hero-inference fallback** in Step 6a — if the desktop hero pitches a specific, nameable audience ("The product development system for teams and agents"), infer one persona from it, tagged as an unconfirmed hypothesis; (3) failing that, the built-ins. The fallback self-gates: a bare search box, app shell, or generic splash produces nothing (verified against Linear/Stripe/Airbnb heroes — sharp on the first two, correctly silent on Airbnb's search box). Text about the audience always beats a guess from pixels, so the fallback only fires when there was no text to begin with. - **The Read co-headlines.** The design-director's verdict + the sharpest persona reactions lead the report: a `### The Read` section above the Scores, a `Reads as:` header line, a co-led scan summary (`Measured: X/20` **and** `Reads as: …`), and an HTML card next to the /20 (`{{PERCEPTUAL_READ}}`, from `scan.perceptualRead`). It's prose grounded in what was seen — **never a competing number.** A second "/10" would be judgment masquerading as measurement, the exact failure the measured/judgment split prevents. -- **The internal evaluator count is now 8** (6 pillars + design-director + persona). `evaluator.test.js` pins it. +- **The internal evaluator count is now 8** (5 measured pillars + slop classifier + design-director + persona). `evaluator.test.js` pins it. The slop evaluator returns a severity band, not a pillar score, so it never counts toward the /20 — that stays 5 pillars × 4. ## Voice & Persona