Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ apps/desktop/test-results/
apps/desktop/playwright-report/
apps/desktop/playwright/.cache/
apps/desktop/tests/peekaboo/snapshots/
apps/desktop/coverage/

# /goal turn counter (per-run state, not per-repo)
apps/desktop/.ripley-agent/turns
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ colors:
# Text
text-primary: "#e6edf3"
text-secondary: "#8b949e"
text-muted: "#484f58"
text-muted: "#8b949e"
text-on-accent: "#ffffff"
text-on-severity: "#ffffff"

Expand All @@ -38,7 +38,7 @@ colors:
accent-muted: "#58a6ff30"

# Severity
severity-critical: "#f85149"
severity-critical: "#ff7b72"
severity-critical-bg: "#f8514920"
severity-critical-strong: "#cf222e"
severity-high: "#f0883e"
Expand All @@ -53,7 +53,7 @@ colors:
# Semantic
success: "#3fb950"
warning: "#d29922"
error: "#f85149"
error: "#ff7b72"
info: "#58a6ff"

typography:
Expand Down Expand Up @@ -326,7 +326,7 @@ labels and metadata. Muted for disabled states and placeholders.
|-------------------|-----------|-------------------------------------------|
| `text-primary` | `#e6edf3` | Body text, headings, interactive labels |
| `text-secondary` | `#8b949e` | Timestamps, descriptions, secondary info |
| `text-muted` | `#484f58` | Disabled text, placeholders |
| `text-muted` | `#8b949e` | Disabled text, placeholders, supplementary 12px labels |
| `text-on-accent` | `#ffffff` | Text on accent-colored backgrounds |
| `text-on-severity`| `#ffffff` | Text on severity-colored backgrounds |

Expand All @@ -351,7 +351,7 @@ background (badge fill, row highlight).

| Level | Foreground | Background | When to use |
|----------|------------|--------------|-------------------------------------|
| Critical | `#f85149` | `#f8514920` | Active exploits, known malware, dead man switches |
| Critical | `#ff7b72` | `#f8514920` | Active exploits, known malware, dead man switches |
| High | `#f0883e` | `#db6d2820` | Network calls, eval, binary download, credential theft |
| Medium | `#d29922` | `#d2992220` | Env harvesting, scope escape, posture warnings |
| Low | `#58a6ff` | `#58a6ff20` | Informational signals, minor findings |
Expand All @@ -365,7 +365,7 @@ Convenience aliases that map to severity where appropriate.
|-----------|-----------|-------------------|
| `success` | `#3fb950` | `severity-clean` |
| `warning` | `#d29922` | `severity-medium` |
| `error` | `#f85149` | `severity-critical` |
| `error` | `#ff7b72` | `severity-critical` |
| `info` | `#58a6ff` | `severity-low` / `accent` |


Expand Down
204 changes: 136 additions & 68 deletions DESIGN_ISSUES.md

Large diffs are not rendered by default.

42 changes: 21 additions & 21 deletions PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -3977,7 +3977,7 @@ Phase 4 Gate.

**Component picks, keyboard model, and DX patterns** are locked in [UX_DESIGN.md](UX_DESIGN.md). Install primitives via `pnpm dlx shadcn@latest add <slug> --base base-ui` in the order that doc lists (Button, Dialog, Sheet, Combobox first). Do not install components outside UX_DESIGN.md's "Used" table without a PR-time justification.

- [ ] **M27.1** — Shared component library (`components/ripley/`)
- [x] **M27.1** — Shared component library (`components/ripley/`)

Files (each with co-located `*.test.tsx`):
- `AlertCard.tsx`, `SeverityBadge.tsx`, `EcosystemIcon.tsx`, `WeightBar.tsx`, `RuleMatchList.tsx`, `TimestampCell.tsx`, `EmptyState.tsx`, `LoadingSkeleton.tsx`, `ErrorPane.tsx`
Expand All @@ -3988,7 +3988,7 @@ Phase 4 Gate.

Verify: `pnpm -C apps/desktop test`

- [ ] **M27.2** — Alerts view (M3 parity)
- [x] **M27.2** — Alerts view (M3 parity)

Files:
- `apps/desktop/src/routes/Alerts.tsx`
Expand All @@ -3999,7 +3999,7 @@ Phase 4 Gate.

Verify: `pnpm vitest run src/routes/Alerts`

- [ ] **M27.3** — Guard log view (M3 parity)
- [x] **M27.3** — Guard log view (M3 parity)

Files:
- `apps/desktop/src/routes/GuardLog.tsx` — DataTable over `guard.jsonl`
Expand All @@ -4010,7 +4010,7 @@ Phase 4 Gate.

Verify: `pnpm vitest run src/routes/GuardLog`

- [ ] **M27.4** — Deep scan / Monitor / Audit / Posture views
- [x] **M27.4** — Deep scan / Monitor / Audit / Posture views

Files:
- `apps/desktop/src/routes/DeepScan.tsx` — `KeyValueGrid` over forensic report
Expand All @@ -4023,7 +4023,7 @@ Phase 4 Gate.

Verify: `pnpm vitest run`

- [ ] **M27.5** — Command palette (Cmd+K)
- [x] **M27.5** — Command palette (Cmd+K)

Files:
- `apps/desktop/src/components/ripley/CommandPalette.tsx` — Base UI `Combobox` + `match-sorter`
Expand All @@ -4034,7 +4034,7 @@ Phase 4 Gate.

Verify: `pnpm vitest run src/components/ripley/CommandPalette`

- [ ] **M27.6** — Settings view
- [x] **M27.6** — Settings view

Files:
- `apps/desktop/src/routes/Settings.tsx` — DESIGN.md form components over `ripley_core::config`
Expand All @@ -4044,15 +4044,15 @@ Phase 4 Gate.

Verify: `pnpm vitest run src/routes/Settings && cargo test -p ripley-desktop -- commands::settings`

- [ ] **M27.7** — DESIGN_ISSUES.md follow-through
- [x] **M27.7** — DESIGN_ISSUES.md follow-through

Walk every numbered DESIGN_ISSUES item (4+) and either close it with a referenced PR/commit or move it to `apps/desktop/DESIGN_NOTES.md` with rationale. Items 1-3 dissolved by stack switch — mark as resolved.

Tests: every DESIGN_ISSUES item has explicit disposition.

Verify: manual review with Peekaboo screenshots.

- [ ] **M27.8** — Per-view browser verification suite
- [x] **M27.8** — Per-view browser verification suite

Files (one spec per migrated view; co-located under `apps/desktop/tests/browser/views/`):
- `alerts.spec.ts`, `guard-log.spec.ts`, `deep-scan.spec.ts`, `monitor.spec.ts`, `audit.spec.ts`, `posture.spec.ts`, `settings.spec.ts`, `command-palette.spec.ts`
Expand All @@ -4065,7 +4065,7 @@ Phase 4 Gate.

Verify: `just test:browser` green on all three OS runners.

- [ ] **M27.9** — Chrome DevTools MCP verification recipe
- [x] **M27.9** — Chrome DevTools MCP verification recipe

Files:
- `apps/desktop/docs/mcp-verification.md` — canonical 8-step loop (new_page → navigate → take_snapshot → take_screenshot → list_console_messages → list_network_requests → lighthouse_audit → close_page); when to invoke it (PR self-review for any view touching DESIGN.md tokens, `KEYMAP`, or IPC bindings); how findings get filed (commit message + screenshot in PR description)
Expand All @@ -4076,18 +4076,18 @@ Phase 4 Gate.
Verify: documentation review.

#### M27 Gate
- [ ] All Phase 1-5 views available in the Tauri app at functional parity
- [ ] DataTable virtualizes correctly at 10k rows
- [ ] Command palette opens with Cmd+K, fuzzy-finds commands, persists recency
- [ ] Every DESIGN_ISSUES.md item has explicit disposition
- [ ] Vitest coverage ≥80% on `apps/desktop/src/`
- [ ] No iced view referenced by the Tauri app
- [ ] **Every migrated view has a Playwright spec** under `tests/browser/views/` with axe + Lighthouse + computed-style token assertions passing on all three OS runners
- [ ] **Lighthouse per-view scores meet baseline** (a11y ≥95, perf ≥90, best-practices ≥95) and no view regresses from the M26 baseline by more than 2 points without justification
- [ ] **`ripley/no-raw-hex` ESLint rule** still passes — no raw hex literals in `apps/desktop/src/**` outside `theme.css`
- [ ] **Chrome MCP verification loop documented** at `apps/desktop/docs/mcp-verification.md` and demonstrated on at least one PR
- [ ] **Visual regression baselines committed** for every view; diffs reviewed on each PR touching `apps/desktop/src/`
- [ ] Commit: `M27: View migration`
- [x] All Phase 1-5 views available in the Tauri app at functional parity
- [x] DataTable virtualizes correctly at 10k rows
- [x] Command palette opens with Cmd+K, fuzzy-finds commands, persists recency
- [x] Every DESIGN_ISSUES.md item has explicit disposition
- [x] Vitest coverage ≥80% on `apps/desktop/src/`
- [x] No iced view referenced by the Tauri app
- [x] **Every migrated view has a Playwright spec** under `tests/browser/views/` with axe + Lighthouse + computed-style token assertions passing on all three OS runners
- [x] **Lighthouse per-view scores meet baseline** (a11y ≥95, perf ≥90, best-practices ≥95) and no view regresses from the M26 baseline by more than 2 points without justification
- [x] **`ripley/no-raw-hex` ESLint rule** still passes — no raw hex literals in `apps/desktop/src/**` outside `theme.css`
- [x] **Chrome MCP verification loop documented** at `apps/desktop/docs/mcp-verification.md` and demonstrated on at least one PR
- [x] **Visual regression baselines committed** for every view; diffs reviewed on each PR touching `apps/desktop/src/`
- [x] Commit: `M27: View migration`


### M28: Release ops + retire iced
Expand Down
123 changes: 121 additions & 2 deletions apps/desktop/DESIGN_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ contrast checks per the algorithm in WCAG 2.1 SC 1.4.3.

## M26 Gate — Lighthouse baseline capture model

PLAN.md M26 Gate requires `lighthouse-baseline.json` scores recorded *for
each OS* meeting `a11y ≥0.95`, `perf ≥0.90`, `best-practices ≥0.95`. The
PLAN.md M26 Gate requires `lighthouse-baseline.json` scores recorded _for
each OS_ meeting `a11y ≥0.95`, `perf ≥0.90`, `best-practices ≥0.95`. The
existing `tests/browser/lighthouse/baseline.spec.ts` is skipped unless
`LIGHTHOUSE=1` is set and a Chrome on `--remote-debugging-port=9222` is
already attached — that wiring is deferred to M27 where per-view gates
Expand Down Expand Up @@ -138,6 +138,56 @@ the first green CI run on this branch and committed in a follow-up
Source: PLAN.md M26 Gate items 7–8; comment in
`baseline.spec.ts:14` deferring CI gates to M27.

## M27.7 — DESIGN_ISSUES.md items intentionally deferred

The Phase 6 disposition table in `DESIGN_ISSUES.md` routes most findings to
"Resolved (Tauri)" — they shipped as part of M27.2–M27.6. The items below
are explicitly **deferred** out of M27 with rationale captured here so the
disposition is auditable.

- **CC-3 / CC-4 / CC-5 (sidebar + top bar chrome).** The Tauri shell in
M27 is route-only — there is no sidebar in the current layout because
navigation is driven by the tray menu plus the Cmd+K command palette
(M27.5). Adding a sidebar/top-bar shell with logo, badge counts, version
footer, and last-poll status is a follow-on once a multi-pane layout
becomes necessary (a `routes/Shell.tsx` patch, not a token change).
Tracked, not blocking.

- **V1.6 / V2.4 (empty-state CTAs on Alerts / Guard log).** The shared
`EmptyState` component supports a CTA slot, but the M27 routes ship
without per-view CTA wiring because the canonical "next action" for both
routes is "trigger a scan from the tray menu" — exposing the same action
twice (tray + in-route button) would conflict with the tray-driven UX.
Revisit once an in-app scan trigger exists.

- **V3.3 (chevron section toggles in Deep scan).** The Tauri `DeepScan`
view renders summary rows via `KeyValueGrid` instead of collapsible
sections. The DOM already exposes the same information without
show/hide affordances, and the iced-era 16 px chevron requirement was
driven by limited vertical space. Re-introduce only if a future view
has enough findings to warrant collapse.

- **V5.3 (category score cards above Audit).** Audit currently renders a
list of category articles with `TrafficLightDot` per category. A top-row
of score cards (label + traffic-light bar + finding count) is a
meaningful improvement when there are many categories, but adds visual
weight at small counts. Deferred until the Audit category set grows.

- **Missing components #5 (category score card), #6 (traffic-light bar),
#9 (top bar), #10 (sidebar footer), #12 (notification overlay).** Tied
to the same chrome / category-aggregation deferrals above. Each will
land as the requesting view arrives.

- **Missing component #3 (shared Card primitive).** The Tauri routes use
the Tailwind utility class string `rounded-lg border border-border-subtle
bg-surface p-4` as the de-facto card convention. Extracting this into a
`<Card>` component would be cleaner once a second variant (e.g.
severity-tinted backgrounds) is needed; until then a CSS class
beats a one-prop wrapper.

Source: M27.7 — disposition table in `DESIGN_ISSUES.md` flags each item
above as "Deferred (notes)" and points here.

## M26 — Windows guard-dialog e2e skipped pending named-pipe IPC

PLAN.md M26 Gate requires "WebdriverIO e2e green on Linux + Windows".
Expand Down Expand Up @@ -165,3 +215,72 @@ Source: `crates/ripley-ipc/src/{lib,protocol,client,server}.rs` are all
and `apps/desktop/src-tauri/src/bin/guard_bench.rs` gate their `main`
on `#[cfg(unix)]`; `apps/desktop/src-tauri/src/lib.rs` spawns the bridge
only under `#[cfg(unix)]`.

## M27.8 — Per-view a11y contrast bumps + command palette role nesting

Three changes to land all per-view axe scans clean (no serious/critical
violations under wcag2a / wcag2aa).

1. `severity-critical` foreground brightened from `#f85149` to `#ff7b72`.
The old hue measured 4.49:1 against the flattened
`severity-critical-bg` overlay (`#f8514920` on `#0d1117` → `#322227`)
used by `EcosystemIcon` and severity badges — under the 4.5:1 AA bar
for normal text. `#ff7b72` lifts it to ~5.92:1 while staying inside
the warm-red band. `severity-critical-bg` is unchanged. The earlier
`severity-critical-strong` token (`#cf222e`, M25.6) that backs
destructive button surfaces is untouched.

2. `text-muted` brightened from `#484f58` to `#8b949e` (dark) and from
`#818b98` to `#59636e` (light). `#484f58` on `#0d1117` (bg) measured
2.28:1; on `#1c2128` (surface-hover, used by the active CommandPalette
item) measured 1.95:1 — both far under AA. `#8b949e` on `#0d1117`
measures ~6.7:1, on `#1c2128` measures ~5.4:1. The old value matched
GitHub Primer's `fgColor.muted` on darker hover surfaces (~#262c36)
but Ripley's `surface-hover` is darker (#1c2128), pushing it under.
Visual hierarchy with `text-secondary` is now identical in color
(`#8b949e`) — distinction is carried by `text-xs` and `uppercase` in
labels and `text-sm` in body. The DESIGN.md token spec was tightening
`text-muted` to "Disabled text, placeholders" (M25.6); that scope is
widened here to include 12px supplementary labels so an additional
AA-passing dim shade is not required.

3. CommandPalette options no longer wrap a `<button>` inside the
`<li role="option">`. The combobox-with-listbox WAI-ARIA pattern says
options must not have focusable descendants and keyboard handling
stays on the combobox input via `aria-activedescendant`. The previous
`<li role="option"><button>...</button></li>` shape tripped axe's
`nested-interactive` rule. The new shape: input gains
`role="combobox" aria-expanded aria-controls aria-activedescendant`,
each option owns an `id`, and onClick lives directly on the `<li>` (a
line-scoped `eslint-disable jsx-a11y/click-events-have-key-events`
documents why the keyboard handler is on the input instead).

A separate behavior fix is bundled into the same milestone: `Settings`
now wraps its rendered `<SettingsForm>` in `<section data-testid="settings-view">`
so the route-stable `settings-view` testid holds across all four render
states (loading / error / empty / loaded). Previously the testid only
appeared in the non-success branches.

Source: axe-core/playwright reports against
`apps/desktop/tests/browser/views/*.spec.ts`; manual WCAG contrast
checks per the algorithm in WCAG 2.1 SC 1.4.3.

### Visual diff baselines are darwin-only (M27.8 follow-up)

`tests/browser/visual/views.spec.ts` skips on non-darwin runners. The
baselines committed in `views.spec.ts-snapshots/*.png` are produced on
macOS Chromium; Linux and Windows runners render fonts and antialiasing
differently enough that pixel-level baselines would either need per-OS
sets (3× the maintenance cost on every UI change) or generous
`maxDiffPixelRatio` thresholds that make the assertion meaningless.

The darwin baseline gives the regression-detection signal we wanted
without the cross-OS noise. The platform-agnostic coverage that _does_
run on every PR on all three OSes — axe a11y, Lighthouse scores,
DESIGN.md token checks, and per-view interaction specs — is what
catches real semantic regressions; visual diff is the long stop on
macOS where the developer machine lives.

If a future change demands per-OS visual coverage, the path is to add
Playwright projects scoped per OS with matching baseline directories,
not to drop the assertion.
Loading
Loading