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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
173 changes: 173 additions & 0 deletions .claude/skills/current-ui-qa/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
---
name: current-ui-qa
description: Use when a human or agent needs to do exploratory QA on existing Itervox UI before/after a UI change. Drives both the route-mocked Playwright lane and the real-daemon lane, then captures qualitative issues (visual hierarchy, copy, accessibility) automated tests cannot. Produces a structured report under `docs/qa-reports/`.
---

# Current Itervox UI QA

This skill drives an exploratory QA pass over the **existing** Itervox dashboard, focused on locking the regression baseline before a UI change. It complements `make qa-current` (which catches programmatic regressions) by capturing the qualitative issues humans or agents notice when they actually drive the app.

## Required reading

Read `CLAUDE.md` (project root) for the project invariants — auth boundaries, SSE wiring, Zustand store rules. Everything else this skill needs is inlined below.

## Pre-flight

```bash
git status # confirm clean working tree
git rev-parse HEAD # capture commit
make qa-current # baseline must be green before exploratory pass
pnpm exec playwright install chromium # one-time per contributor
```

If `make qa-current` fails, do **not** proceed — fix the regression first.

## Setup

Pick a lane:

- **Route-mocked (faster, deterministic):**
```bash
cd web && pnpm test:ui-current --ui # opens Playwright UI; navigate scenario by scenario
```
- **Real-daemon (catches embed/build/auth drift):**
```bash
make build
./itervox -workflow path/to/WORKFLOW.md # in another terminal
open "http://127.0.0.1:8090/?token=$ITERVOX_API_TOKEN"
```

## Viewport matrix

For each scenario, exercise:

| Viewport | Width × Height | Why |
|---|---|---|
| Desktop | 1440 × 900 | primary target |
| Tablet | 1024 × 768 | layout breakpoint check |
| Mobile | 390 × 844 | iPhone 14 — drawer/responsive |

## Per-route checklist

Run for `/`, `/timeline`, `/logs`, `/agents`, `/automations`, `/settings`:

- [ ] Page loads under 2s; no skeletons stuck > 500ms after data arrives.
- [ ] Primary action (Save, Submit, Refresh) is visible without scrolling.
- [ ] Empty state is intentional copy (not "undefined" or blank).
- [ ] Keyboard focus is not trapped — Tab reaches every interactive element.
- [ ] Esc closes any open dialog / slide / dropdown.
- [ ] No horizontal scroll at the smallest supported viewport.
- [ ] Mobile drawer opens, closes, doesn't push body content offscreen.
- [ ] Status / state is conveyed by text or shape, not color alone.
- [ ] No console errors after hydration (`Cmd+Opt+I` → Console tab).
- [ ] Network tab shows zero unexpected `/api/v1/*` failures.

## Required scenarios

Drive every named scenario shipped in the fixture library. Each is exported from `web/src/test/fixtures/scenarios.ts`:

- `emptyScenario` — empty state across every route.
- `quickstartScenario` — memory-tracker default (most common case).
- `activeRunScenario` — running rows present, hero counts non-zero.
- `inputRequiredScenario` — input_required + pending_input_resume rows.
- `retryAndPausedScenario` — retry queue + paused issues + pausedWithPR.
- `configInvalidScenario` — `configInvalid` populated; banner visible.
- `timelineLogsScenario` — every history status + every log event variant.
- `settingsMatrixScenario` — multi-profile, automations, SSH hosts, dispatch strategy.
- `mobileShellScenario` — quickstart + long-title issue for mobile responsiveness.

Use the route-mocked Playwright UI to switch scenarios without restarting the daemon.

## Screenshots

Capture per `(route, viewport, scenario)` triple. Filename pattern:

```
<route>-<viewport>-<scenario>.png
e.g. dashboard-desktop-quickstart.png
timeline-mobile-empty.png
```

Save under `docs/qa-reports/screenshots/<report-date>/`.

## Severity rubric

| Severity | Definition |
|---|---|
| **P0** | Blocks release. Crash, data loss, auth bypass, ARIA blocker. |
| **P1** | Must-fix before merge. Wrong copy on a primary CTA, infinite spinner, console error in happy path. |
| **P2** | Should-fix. Layout glitch, sub-optimal empty state, console warning. |
| **P3** | Nice-to-have. Minor copy polish, inconsistent spacing, focus ring on uncommon path. |
| **P4** | Subjective polish. Aesthetic preference, naming opinion, fully optional. |

## Promotion rule

If the **same qualitative finding** appears in **two consecutive QA runs**, promote it to an automated test before the third run. Track the promotion target file (e.g. `web/e2e/ui-current-<area>-smoke.spec.ts`) inline in the next report.

## Report path

Write the report to:

```
docs/qa-reports/YYYY-MM-DD-current-ui-qa-<short-scope>.md
```

## Report template

Use this exact structure (inline so the skill stays self-contained — no external template files):

```markdown
# Itervox UI QA — <date> — <scope>

## Summary

- **Commit:** `<sha>`
- **Branch:** `<name>`
- **Lane:** route-mocked / real-daemon / both
- **Viewports:** desktop 1440×900, tablet 1024×768, mobile 390×844
- **Scenarios driven:** <list>
- **`make qa-current` baseline:** PASS / FAIL (sha:X / commit:Y)

## Findings

### P0 — release-blockers
*(none, or list — each finding: short title; affected route + viewport + scenario; reproduction; expected vs actual; issue link or "no GitHub yet — captured here")*

### P1 — must-fix
*(same shape as P0)*

### P2 — should-fix
*(same shape)*

### P3 — nice-to-have

### P4 — subjective polish

## Repeated findings (promotion candidates)

Findings that appeared in the previous report AND in this one. Each row must include the promotion target (test file or refactor target) before the next QA run.

| Finding | First seen | Promotion target |
|---|---|---|

## Screenshots

Stored under `docs/qa-reports/screenshots/<date>/`. Naming: `<route>-<viewport>-<scenario>.png`.

## Notes

Any free-form observations, hypotheses, or open questions for the next iteration.
```

### Where findings go from here

- **P0/P1** — file a GitHub issue immediately, link from the report row.
- **P2** — capture in the report; pick up in the next iteration.
- **P3/P4** — track in the report; revisit when the area is touched.

## Done criteria

- [ ] All 9 scenarios driven across 3 viewports = 27 checkpoints.
- [ ] One report file written at `docs/qa-reports/YYYY-MM-DD-current-ui-qa-<short-scope>.md`.
- [ ] Every P0/P1 finding has an issue link (or a one-line "no GitHub yet — captured here").
- [ ] Two-run rule applied: list any qualitative finding that appeared in the prior report — if matched, document the promotion target.
4 changes: 2 additions & 2 deletions .claude/skills/go-toolchain-sync/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ itervox pins the Go toolchain in **two** places. They MUST match byte-for-byte.

| File | Line | Current |
|---|---|---|
| `/Users/vladimirnovick/dev/oss/itervox/go.mod` | 3 | `go 1.25.9` |
| `/Users/vladimirnovick/dev/oss/itervox/Makefile` | 6 | `export GOTOOLCHAIN := go1.25.9` |
| `go.mod` | 3 | `go 1.25.9` |
| `Makefile` | 6 | `export GOTOOLCHAIN := go1.25.9` |

CI is the single-source-of-truth pattern: `.github/workflows/ci-go.yml` and `release.yml` use `actions/setup-go@v6` with `go-version-file: go.mod`. **Never** hardcode `go-version:` in workflow YAML.

Expand Down
15 changes: 12 additions & 3 deletions .claude/skills/orchestrator-invariants/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,33 @@ Itervox's orchestrator is a single-goroutine state machine. Violating these rule

These `Orchestrator.cfg` fields can be mutated at runtime by HTTP handler goroutines and MUST be accessed under `cfgMu`:

- `cfg.Agent.AgentMode`
- `cfg.Agent.MaxConcurrentAgents`
- `cfg.Agent.MaxRetries`
- `cfg.Agent.MaxSwitchesPerIssuePerWindow`
- `cfg.Agent.SwitchWindowHours`
- `cfg.Agent.SwitchRevertHours`
- `cfg.Agent.RateLimitErrorPatterns`
- `cfg.Agent.Profiles`
- `cfg.Agent.SSHHosts`
- `cfg.Agent.SSHHostDescriptions`
- `cfg.Agent.DispatchStrategy`
- `cfg.Agent.ReviewerProfile`
- `cfg.Agent.AutoReview`
- `cfg.Agent.InlineInput`
- `cfg.Tracker.ActiveStates`
- `cfg.Tracker.TerminalStates`
- `cfg.Tracker.CompletionState`
- `cfg.Tracker.FailedState`
- `cfg.Workspace.AutoClearWorkspace`
- `cfg.Automations`

All OTHER `cfg.*` fields are read-only after startup. Do NOT add locks defensively to read-only fields. If a static-analysis pass flags one, verify there is a runtime setter (HTTP handler) before believing the claim — no setter means no race.
The canonical allowlist is `internal/orchestrator/cfg_mu_audit_test.go::AllowedMutableCfgFields`. All OTHER `cfg.*` fields are read-only after startup. Do NOT add locks defensively to read-only fields. If a static-analysis pass flags one, verify there is a runtime setter (HTTP handler) before believing the claim — no setter means no race.

## 3. Adding a new runtime-mutable `cfg.*` field

If you make a `cfg.*` field mutable at runtime, you MUST do all three:

1. Add it to the cfgMu guard list in `/Users/vladimirnovick/dev/oss/itervox/CLAUDE.md`.
1. Add it to the cfgMu guard list in `CLAUDE.md`.
2. Ensure the HTTP handler that mutates it acquires `o.cfgMu.Lock()`.
3. Ensure every read of it acquires `o.cfgMu.RLock()`.

Expand Down
25 changes: 12 additions & 13 deletions .claude/skills/verify-before-done/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,22 @@ Run from the repo root:
make verify
```

This runs, in order: `fmt` -> `vet` -> `lint-go` (golangci-lint) -> `test` (`go test -race ./... -count=1`) -> `web-test` (`pnpm install --frozen-lockfile && pnpm test` in `web/`) -> `web-spelling` (guards against the old "Symphony" name in user-visible strings).
This runs, in order: `fmt` -> `vet` -> `lint-go` (golangci-lint) -> `test` (`go test -race ./cmd/... ./internal/... -count=1`) -> `web-coverage` (`pnpm test:coverage` in `web/`) -> `web-build` -> `web-spelling` (guards against the old "Symphony" name in user-visible strings) -> `size-budget` -> `no-os-exit`.

`go test ./...` alone is NOT sufficient. It misses:
- golangci-lint failures (CI lint job will fail)
- race conditions hidden by the test cache (no `-count=1`)
- frontend regressions (`pnpm test`)
- frontend regressions and coverage drops (`pnpm test:coverage`)
- the spelling guard

`make verify` must exit 0. Show the tail of the output as evidence.

## 2. Frontend coverage gate (when touching `web/`)
## 2. Frontend coverage gate

`pnpm test` does NOT enforce coverage. Only `pnpm test:coverage` does, with a 70% threshold on **statements, branches, functions, and lines** (all four).
`make verify` now runs `pnpm test:coverage`, with a 70% threshold on **statements, branches, functions, and lines** (all four). For faster frontend-only iteration, run the target directly:

```bash
cd web && pnpm test:coverage
make web-coverage
```

Read the summary. Confirm every one of the four axes is at or above 70%. A green `pnpm test` says nothing about whether the coverage gate will pass in CI. New files showing 0% mean you forgot the test - write it before claiming done.
Expand All @@ -50,7 +50,7 @@ If a race appears intermittently, that is a real race, not flakiness. Rerun with
If you touched `go.mod`, `go.sum`, or any Go dependency, run:

```bash
govulncheck -tags dev ./...
govulncheck -tags dev ./cmd/... ./internal/...
```

The `-tags dev` flag matches what the CI `govulncheck` job in `.github/workflows/ci-go.yml` uses. CI will fail the PR on new vulnerabilities.
Expand All @@ -59,11 +59,10 @@ The `-tags dev` flag matches what the CI `govulncheck` job in `.github/workflows

Run sequentially. Do not skip steps.

a. `make verify` - exits 0, output captured
b. `cd web && pnpm test:coverage` - if you touched frontend code; all four axes >= 70%
c. `govulncheck -tags dev ./...` - if you touched `go.mod` or Go deps
d. `git status` - review staged files; watch for `.env`, credentials, accidental binaries
e. Only THEN `git commit`
a. `make verify` - exits 0, output captured, including frontend coverage
b. `govulncheck -tags dev ./cmd/... ./internal/...` - if you touched `go.mod` or Go deps
c. `git status` - review staged files; watch for `.env`, credentials, accidental binaries
d. Only THEN `git commit`

## 6. Never claim "tests pass" without evidence

Expand All @@ -80,6 +79,6 @@ Show the exact command and a trimmed tail of its output. Claiming green based on

You may claim "done" only when:
- `make verify` exited 0 in the current session, output shown
- (if frontend touched) `pnpm test:coverage` shows all four axes >= 70%, output shown
- (if Go deps touched) `govulncheck -tags dev ./...` exited 0, output shown
- frontend coverage in `make verify` shows all four axes >= 70%, output shown
- (if Go deps touched) `govulncheck -tags dev ./cmd/... ./internal/...` exited 0, output shown
- `git status` reviewed, no secrets staged
2 changes: 2 additions & 0 deletions .codex/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[features]
goals = true
63 changes: 0 additions & 63 deletions .github/dependabot.yml

This file was deleted.

11 changes: 6 additions & 5 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@

## Checklist

- [ ] `go build ./...` passes
- [ ] `go test -race ./...` passes (or `make test` if touching Go)
- [ ] `cd web && pnpm test` passes (or `make web-test` if touching frontend)
- [ ] `golangci-lint run ./...` passes (if touching Go)
- [ ] `cd web && pnpm lint` passes (if touching frontend)
- [ ] `make verify` passes locally
- [ ] New behaviour is covered by tests
- [ ] Frontend coverage gate remains green (`make web-coverage` or `make verify`)
- [ ] Go/package changes use the repo-owned package scope (`./cmd/... ./internal/...`)
- [ ] Go dependency or toolchain changes ran `govulncheck -tags dev ./cmd/... ./internal/...`
- [ ] Large-file changes stay within `make size-budget`
- [ ] No new direct `os.Exit()` outside `cmd/itervox/exit.go`
- [ ] No API tokens, secrets, or credentials in the diff
- [ ] Exported Go symbols have doc comments

Expand Down
Loading