ccqa 0.10.2 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,10 +4,8 @@
4
4
 
5
5
  ccqa turns Claude Code into a browser test recorder. Write a spec in YAML, declare in the spec whether it should run **deterministic** or **live**, then `ccqa run` does the right thing per spec:
6
6
 
7
- - **Deterministic** (`mode: deterministic`, default): record once with `ccqa record`. Claude drives the browser, ccqa compiles every action into a `test.spec.ts` you can replay in CI under vitest no LLM at run time. Cheapest and most stable.
8
- - **Live** (`mode: live`): no codegen. `ccqa run` sends each step to Claude every time, Claude drives `agent-browser` directly, judges pass/fail against the step's `expected`, and saves a before/after screenshot. More flexible for fragile UIs.
9
-
10
- A single project mixes both: each spec.yaml picks its own mode, and `ccqa run` reads the field and dispatches. The HTML report covers both in one page.
7
+ - **Deterministic** (`mode: deterministic`, default): record once with `ccqa record` Claude drives the browser and ccqa compiles every action into a `test.spec.ts` you replay in CI under vitest, no LLM at run time. Cheapest and most stable.
8
+ - **Live** (`mode: live`): no codegen. `ccqa run` sends each step to Claude every time; Claude drives `agent-browser`, judges pass/fail against the step's `expected`, and saves a before/after screenshot. More flexible for fragile UIs.
11
9
 
12
10
  No extra API key. Just `claude`.
13
11
 
@@ -15,6 +13,8 @@ No extra API key. Just `claude`.
15
13
 
16
14
  ## How it works
17
15
 
16
+ Each spec picks its own mode; `ccqa run` reads the field and dispatches. One project mixes both, and one report covers both.
17
+
18
18
  ```mermaid
19
19
  flowchart LR
20
20
  A["Write spec\n(spec.yaml + mode:)"] --> B{mode}
@@ -23,10 +23,6 @@ flowchart LR
23
23
  B -- live --> E["ccqa run\n(Claude drives every time,\nper-step pass/fail)"]
24
24
  ```
25
25
 
26
- For deterministic specs, `record` invokes Claude Code with your spec, Claude drives the browser step by step, every action is recorded, and a vitest-compatible script is generated. `run` then replays it without involving an LLM.
27
-
28
- For live specs, `record` is not needed. `run` directly sends each step to Claude, which drives the browser through `agent-browser`, judges whether the step's `expected` clause holds, and writes a PNG before and after each step. Useful when codegen is fragile (timing-dependent UIs, rich-text editors, dynamic selectors).
29
-
30
26
  ## Install
31
27
 
32
28
  ```bash
@@ -69,11 +65,9 @@ ccqa run tasks/create-and-complete # vitest replays test.spec.ts; no LLM
69
65
  ccqa run tasks/create-and-complete # Claude drives the browser every time
70
66
  ```
71
67
 
72
- Live specs can start already-signed-in by naming a saved session with `session:`. Create it once with `ccqa session bootstrap <name>` (log in by hand, ccqa saves the cookies + localStorage), then specs restore it — see [Saved sessions](#saved-sessions-session) below for the bootstrap and the CI restore pattern.
73
-
74
- By default deterministic runs write step-boundary screenshots and metadata to `ccqa-report/evidence/<feature>/<spec>/` so a reviewer can confirm a passing spec actually reached the states its `expected` clauses describe. Disable with `--no-evidence`.
68
+ Live specs can start already-signed-in by naming a saved session with `session:` — see [Saved sessions](./docs/sessions.md). Deterministic runs also write step-boundary screenshots to `ccqa-report/evidence/` (disable with `--no-evidence`).
75
69
 
76
- In CI you can opt in to an HTML run report by passing `--report` every failing spec gets a drift audit plus a root-cause call (TEST_DRIFT / SPEC_CHANGE / PRODUCT_BUG) using the branch's git diff as context, and the report lets a human grade those calls to measure their accuracy. Requires `ANTHROPIC_API_KEY` or a local Claude login for the analysis part. Opt out with `--no-failure-analysis` (which also implicitly skips the drift audit — the audit is rendered as evidence under the classification, so without the classification the cost has nowhere to land). Use `--no-drift-audit` to keep the classification but skip the audit. See [Run report](./docs/report.md).
70
+ In CI, add `--report` to write a `report.json` (+ evidence PNGs) you push to the [ccqa hub](./docs/hub.md) and view in its UI; each failing spec gets a root-cause call (TEST_DRIFT / SPEC_CHANGE / PRODUCT_BUG) you can grade for accuracy. Needs `ANTHROPIC_API_KEY` or a local Claude login. See [Run report](./docs/report.md).
77
71
 
78
72
  ```bash
79
73
  ccqa run tasks/create-and-complete --report --base origin/main
@@ -85,6 +79,8 @@ ccqa run --changed --report # only specs whose relatedPaths t
85
79
  | Feature | Docs |
86
80
  |---|---|
87
81
  | Write specs interactively with Claude | [Draft](./docs/draft.md) |
82
+ | Run specs live (no codegen), with per-project guidance | [Live specs](./docs/live.md) |
83
+ | Restore a saved login to skip device-trust gates | [Saved sessions](./docs/sessions.md) |
88
84
  | Reuse login and other shared step sequences | [Blocks](./docs/blocks.md) |
89
85
  | Drive `<input type="file">` without an OS picker | [File upload](./docs/file-upload.md) |
90
86
  | Assertion helper functions | [Assertions](./docs/assertions.md) |
@@ -93,6 +89,7 @@ ccqa run --changed --report # only specs whose relatedPaths t
93
89
  | HTML run report with failure root-cause calls | [Run report](./docs/report.md) |
94
90
  | Inventory existing test coverage | [Perspectives](./docs/perspectives.md) |
95
91
  | Architecture decision records (why it is built this way) | [ADR](./docs/adr/README.md) |
92
+ | Aggregate CI run results, sessions, and variables on a shared server | [Hub](./docs/hub.md) |
96
93
 
97
94
  ## Commands
98
95
 
@@ -105,63 +102,44 @@ ccqa run [feature/spec...] Execute specs. Per spec, the spec.yaml `mode:
105
102
  (vitest replay) or live (Claude drives every time). One run can mix both;
106
103
  `--report` writes one unified HTML. Pass multiple targets space-separated.
107
104
  ccqa drift [feature/spec] Standalone spec ↔ codebase static audit (for PR checks)
105
+ ccqa serve Start a hub: a control-plane HTTP server that aggregates run results,
106
+ sessions, and variables (it does not execute tests)
107
+ ccqa hub push Push a finished run's report to a hub
108
+ ccqa hub session|var <cmd> Manage sessions/variables stored on a hub
108
109
  ```
109
110
 
110
- `ccqa run` flags:
111
-
112
- - `--report [dir]` — write a self-contained HTML run report (default dir: `ccqa-report/`)
113
- - `--profile <name>` — load `.ccqa/profiles/<name>.env` into the environment before resolving spec `${VAR}` references, so one spec targets dev/stg/prd without per-environment copies. See [Profiles](#profiles---profile).
114
- - `--changed` — restrict execution to specs whose `relatedPaths` intersect `git diff <base>...HEAD`. Mutually exclusive with explicit spec targets.
115
- - `--concurrency <n>` — run up to N specs in parallel **within each mode** (deterministic specs run as one phase, live specs as the next; parallelism is within a phase, not across). Default `1` (sequential, identical to before). Above 1, each spec's output is buffered and flushed as a labelled block so parallel logs stay legible. Live specs each launch their own headed Chrome, so high values spawn many browser instances.
116
- - `--base <ref>` — base ref for the git diff (default: `$GITHUB_BASE_REF`, then `origin/main`)
117
- - `--no-failure-analysis` — skip the per-failure root-cause classification (also skips the drift audit, since the audit only shows under the classification)
118
- - `--no-drift-audit` — skip the spec ↔ code drift audit while keeping the classification
119
- - `--no-evidence` — (deterministic specs only) skip step-boundary PNG capture
120
- - `--retry <n>` — (live specs only) retry each failing step up to N more times
121
- - `--format <fmt>` — `text` (default), `json` (report.json), `github` (Actions annotations)
122
- - `--out <dir>` — (live specs only, single-spec invocations) override the per-run artifact directory
123
- - `--update-agent-prompt` — (live specs only) after the run, summarise it back to Claude and rewrite `.ccqa/prompts/live.agent.md` so the next run inherits the lessons learned. `ccqa record` ships the same flag, refreshing `record.agent.md` from the trace summary.
111
+ Key `ccqa run` flags (see `ccqa run --help` for the rest):
124
112
 
125
- All Claude-driven commands accept `-m, --model <name>` (alias `sonnet` | `opus` | `haiku`, or a full model ID). The flag overrides `CCQA_MODEL`; when both are unset, the Claude Code CLI default is used. They also accept `--language <bcp47>` (e.g. `ja`, `en`) to set the language of human-readable output; the default `auto` follows the language of the spec/codebase. `--cwd <path>` works on `record` / `run` / `drift` so you can target a subpackage inside a monorepo from the repo root. Interactive commands authenticate via your local Claude Code login; commands that talk to Claude in CI (`ccqa run --report`, `ccqa drift`) additionally honor `ANTHROPIC_API_KEY`.
113
+ - `--report [dir]` write the run report (report.json + evidence PNGs) for `ccqa hub push` (default dir: `ccqa-report/`)
114
+ - `--profile <name>` — load `.ccqa/profiles/<name>.env` before resolving spec `${VAR}` references, so one spec targets dev/stg/prd. See [Profiles](#profiles---profile).
115
+ - `--changed` — restrict execution to specs whose `relatedPaths` intersect `git diff <base>...HEAD`
116
+ - `--concurrency <n>` — run up to N specs in parallel **within each mode** (deterministic phase, then live phase — parallelism is per-phase, not across phases). Default `1` (sequential, same behavior as before).
117
+ - `--no-failure-analysis` / `--no-drift-audit` — `--no-failure-analysis` skips failure classification (and its drift audit, since drift is the classification's evidence); `--no-drift-audit` keeps classification but skips just the audit.
118
+ - `--format <fmt>` — `text` (default), `json` (report.json), `github` (Actions annotations)
126
119
 
127
- `<feature/spec>` is a 2-segment alias for the on-disk path `.ccqa/features/<feature>/test-cases/<spec>/`. `ccqa run` accepts several targets space-separated (each a `<feature>/<spec>`, a bare `<feature>` for all its specs, or omitted for everything); duplicates are de-duped and `--changed` cannot be combined with explicit targets.
120
+ `<feature/spec>` is a 2-segment alias for `.ccqa/features/<feature>/test-cases/<spec>/`; `ccqa run` takes several space-separated targets (a `<feature>/<spec>`, a bare `<feature>`, or none for everything). Claude-driven commands accept `-m/--model`, `--language`, and `--cwd` (for monorepos); they use your local Claude login, and CI commands (`ccqa run --report`, `ccqa drift`) also honor `ANTHROPIC_API_KEY`.
128
121
 
129
122
  ## File structure
130
123
 
131
124
  ```
132
125
  .ccqa/
133
- perspectives.yaml # Inventory of existing coverage (machine-readable, canonical)
134
- perspectives.md # Category index, regenerated from the YAML
135
- profiles/ # `--profile <name>` env files
136
- stg.env # URLs + credential refs; commit if it uses secret-manager refs, gitignore if it holds plaintext secrets
137
- prd.env
138
- prompts/ # Run `ccqa init` to scaffold these
139
- record.user.md # Human-maintained guidance appended to `ccqa record` (trace phase)
140
- record.agent.md # Auto-updated by `ccqa record --update-agent-prompt`
141
- live.user.md # Human-maintained guidance appended to `ccqa run` (live specs)
142
- live.agent.md # Auto-updated by `ccqa run --update-agent-prompt`
126
+ perspectives.yaml # Inventory of existing coverage (canonical)
127
+ profiles/ # `--profile <name>` env files (stg.env, prd.env, ...)
128
+ prompts/ # `ccqa init` scaffolds these; *.user.md human-maintained, *.agent.md auto-updated
129
+ record.user.md record.agent.md live.user.md live.agent.md
143
130
  blocks/
144
- login/
145
- spec.yaml # Reusable block (params + steps)
131
+ login/spec.yaml # Reusable block (params + steps)
146
132
  features/
147
133
  tasks/
148
- perspectives.md # Per-category detail tables (one per case)
149
134
  test-cases/
150
135
  create-and-complete/
151
136
  spec.yaml # Test definition, with `mode: deterministic | live`
152
- actions.json # (deterministic only) Recorded actions from `ccqa record`
153
- test.spec.ts # (deterministic only) Generated vitest script
154
- runs/
155
- 2026-06-14T10-00-00-000Z/ # (live only) one `ccqa run` invocation
156
- run.json # Machine-readable summary
157
- run.md # Human-readable per-step log
158
- steps/
159
- step-01.before.png # Before-step screenshot
160
- step-01.after.png # After-step screenshot
161
- step-01.log.txt # Claude's full transcript for the step
137
+ actions.json # (deterministic) recorded actions
138
+ test.spec.ts # (deterministic) generated vitest script
139
+ runs/<timestamp>/ # (live) one `ccqa run` — run.json/run.md + steps/*.png
162
140
  ```
163
141
 
164
- Add `.ccqa/features/*/test-cases/*/runs/` to `.gitignore` — these are per-run artefacts that should not be committed. Likewise `ccqa-report*/`.
142
+ Gitignore the per-run artefacts: `.ccqa/features/*/test-cases/*/runs/` and `ccqa-report*/`.
165
143
 
166
144
  ## Profiles (`--profile`)
167
145
 
@@ -177,11 +155,10 @@ TEST_USER_PASSWORD=...
177
155
  ccqa run auth/login --profile stg # same spec, stg values
178
156
  ```
179
157
 
180
- - Name is free-form (`stg`/`prd` are conventions); a path separator / `..` / leading dot is rejected, and a missing profile exits 2. Only the name is logged, never values.
181
- - Format is a small `.env` subset (`KEY=value`, `#` comments, `export`, quotes). Profile values **override** the inherited environment.
182
- - Without `--profile`, ccqa auto-loads `<cwd>/.env` if present (like dotenv); with neither, `${VAR}` resolves against the existing `process.env` (e.g. `direnv`).
183
-
184
- **Secrets:** gitignore any profile that holds plaintext secrets. ccqa only parses `.env` files — it doesn't resolve secret-manager references — so to keep secrets off disk, drop `--profile` and run ccqa under your secret manager instead (e.g. `op run --env-file=.ccqa/profiles/stg.env -- ccqa run ...`), which injects the resolved values into `process.env` for ccqa to read.
158
+ - Format is a small `.env` subset (`KEY=value`, `#` comments, `export`, quotes); profile values **override** the inherited environment.
159
+ - Name is free-form (`stg`/`prd` by convention); path separators, `..`, and leading dots are rejected, and an unknown name exits 2. Only the name is logged, never values.
160
+ - Without `--profile`, ccqa auto-loads `<cwd>/.env` if present; with neither, `${VAR}` resolves against the existing `process.env`.
161
+ - **Secrets:** gitignore any profile holding plaintext secrets. To keep secrets off disk entirely, drop `--profile` and run ccqa under your secret manager (e.g. `op run --env-file=... -- ccqa run ...`), which injects resolved values into `process.env`.
185
162
 
186
163
  ## Live specs (`mode: live`)
187
164
 
@@ -191,27 +168,13 @@ For specs declared `mode: live` in their spec.yaml, `ccqa run` skips codegen ent
191
168
  - the codegen output for a spec is fragile (heavily timing-dependent UIs, rich-text editors, dynamic selectors)
192
169
  - you want a visual audit trail of what the page looked like at every step
193
170
 
194
- ```bash
195
- # Run a single live spec
196
- ccqa run tasks/create-and-complete
197
-
198
- # Run every spec under a feature (mixes deterministic + live as declared)
199
- ccqa run tasks
171
+ Constraints on selectors / `agent-browser` subcommands that apply during `ccqa record` (no `eval`, no `@ref`, no bare-tag positional `find`, no chained agent-browser calls) are relaxed for live specs, since there is no replay contract to honour.
200
172
 
201
- # Run every spec in the project, into a unified HTML report
202
- ccqa run --report
203
-
204
- # Retry each failing step up to 2 more times (live specs only)
205
- ccqa run --retry 2 tasks/create-and-complete
206
- ```
207
-
208
- Constraints on selectors / `agent-browser` subcommands that apply during `ccqa record` (no `eval`, no `@ref`, no bare-tag positional `find`, no chained agent-browser calls) are **relaxed** for live specs — Claude can use any subcommand and any selector style because there is no replay contract to honour.
173
+ See [Live specs](./docs/live.md) for usage examples and per-project guidance.
209
174
 
210
175
  ### Saved sessions (`session:`)
211
176
 
212
- By default each `ccqa run` of a live spec starts signed-out and logs in through its own steps. That's fine for plain form logins, but some providers gate every fresh browser with a device-trust check (an "unrecognized device" e-mail code, an MFA prompt) that a human has to clear by hand — impractical to repeat on every run, impossible in CI.
213
-
214
- For those, save the signed-in browser state once and let the spec **restore** it. ccqa does not manage authentication — `session` is purely an optional restore of cookies + localStorage. Specs that can just log in normally don't use it.
177
+ Some providers gate every fresh browser with a device-trust check (an "unrecognized device" e-mail code, an MFA prompt) that a human has to clear by hand — impractical to repeat on every run, impossible in CI. `session:` restores a saved, signed-in browser state instead.
215
178
 
216
179
  ```yaml
217
180
  title: Admin can open the settings page
@@ -221,76 +184,13 @@ steps:
221
184
  - ... # no login steps — the spec starts signed-in
222
185
  ```
223
186
 
224
- A spec can also restore several sessions at once (e.g. one provider in each), and ccqa merges them:
225
-
226
- ```yaml
227
- session:
228
- - admin # one provider, signed in as admin
229
- - admin-chat # another provider, same person
230
- ```
231
-
232
- #### Create a session — `ccqa session bootstrap`
233
-
234
- ```bash
235
- # Opens a headed browser. Log in by hand (clear any device-trust gate),
236
- # then press Enter and ccqa saves the session.
237
- ccqa session bootstrap admin --url https://app.example.com/login
238
-
239
- # List saved sessions (names + save times; no secret values shown).
240
- ccqa session ls
241
- ```
242
-
243
- Sessions are saved to `.ccqa/sessions/<profile>/<name>.json`. The `<profile>` is the same `--profile` that selects the `.ccqa/profiles/<profile>.env` file, so one flag picks both the environment and its sessions bucket; with no `--profile` the bucket is `default`. `ccqa init` drops a self-ignoring `.ccqa/sessions/.gitignore` so saved sessions stay out of git — **they contain live auth cookies and must never be committed.**
244
-
245
- When a spec names a session that hasn't been created yet, the run stops and tells you which `ccqa session bootstrap` to run, rather than starting unauthenticated.
246
-
247
- #### CI: restore the session
248
-
249
- Saved sessions live entirely inside `.ccqa/` and never touch `~/`. In CI, write each session file back to the path the run expects (read it from your secret store):
250
-
251
- ```bash
252
- # Locally, after bootstrapping, copy the file into your CI secret store:
253
- base64 -i .ccqa/sessions/default/admin.json | pbcopy # paste as CCQA_SESSION_ADMIN_B64
254
- ```
255
-
256
- ```yaml
257
- # CI step (sketch) — restore before `ccqa run`
258
- - name: Restore session
259
- env:
260
- CCQA_SESSION_ADMIN_B64: ${{ secrets.CCQA_SESSION_ADMIN_B64 }}
261
- run: |
262
- mkdir -p .ccqa/sessions/default
263
- printf '%s' "$CCQA_SESSION_ADMIN_B64" | base64 -d > .ccqa/sessions/default/admin.json
264
- ```
265
-
266
- Notes:
267
-
268
- - **Expiry.** The provider's "remember this device" window eventually lapses and the saved cookies stop working. Re-run `ccqa session bootstrap` locally and rotate the secret.
269
- - **Treat session files as credentials.** They hold live auth cookies. Keep them in a secret manager; never commit them.
270
- - **Deterministic specs ignore `session:`.** It only affects `mode: live`; vitest-replayed specs always run isolated.
271
-
272
- ### Per-project guidance (`.ccqa/prompts/live.user.md` + `live.agent.md`)
273
-
274
- ccqa's live-mode system prompt is deliberately product-agnostic. Anything specific to **your** project — staging URLs, login flow quirks, rich-editor types, common access-denied wording — belongs in two sibling files (run `ccqa init` to scaffold both):
275
-
276
- - `.ccqa/prompts/live.user.md` — human-maintained stable guidance.
277
- - `.ccqa/prompts/live.agent.md` — auto-updated by `ccqa run --update-agent-prompt` from each run's summary. You can hand-edit it, but the next `--update-agent-prompt` run may rewrite the whole file; durable rules should live in `live.user.md`.
278
-
279
- Both files (when present) are read once per invocation and appended to the system prompt under "Project-specific guidance". The `ccqa record` (trace) side has the same split: `record.user.md` + `record.agent.md`, refreshed by `ccqa record --update-agent-prompt`.
280
-
281
- Keep them short. A page or two of focused notes beats a long handbook — Claude has the spec's `expected` text to work from, these files are for the *non-obvious* product knowledge that isn't in any single spec. Examples of what's useful here:
282
-
283
- - "the rich text editor is `[contenteditable='true']` — use `fill`, not keystrokes"
284
- - "login redirects through an IDP service-selection screen; you can skip it by opening the destination URL directly"
285
- - "access-denied is signalled by a specific in-app message string — name it here so the model asserts on it"
187
+ ccqa does not manage authentication `session` is purely an optional restore of cookies + localStorage.
286
188
 
287
- Examples of what does **not** belong:
189
+ See [Saved sessions](./docs/sessions.md) for how to bootstrap a session and use it in CI.
288
190
 
289
- - per-spec details (those belong in the spec's `instruction` / `expected`)
290
- - restating the STEP_RESULT contract (already in the system prompt)
291
- - copy-pasted style guidelines from `record.user.md` (the relaxed-constraint mode doesn't need them)
191
+ ## CI result aggregation (hub)
292
192
 
293
- The combined bundle is capped at 32 KiB; anything beyond that is truncated with a warning.
193
+ `ccqa serve` starts a hub a control-plane HTTP server that aggregates CI run results, saved sessions, and variables on a shared server. It does not execute tests: a CI job (or a laptop) runs `ccqa run --report` as usual, fetching whatever sessions/variables/prompts it needs from the hub directly at run time, then `ccqa hub push` uploads the resulting report to the hub. Sessions and variables are registered on the hub ahead of time (`ccqa hub session push`, `ccqa hub var set`, or the bundled UI's Secrets tab), so a CI job needs only one secret: `CCQA_HUB_TOKEN`. One hub manages many projects — secrets are scoped per project/profile, and `--project` defaults to the current directory's name. See [docs/hub.md](./docs/hub.md) for setup and usage.
294
194
 
295
195
  ## License
296
196