@cloverleaf/reference-impl 0.12.0 → 0.13.1

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.
@@ -1,9 +1,24 @@
1
1
  ---
2
2
  name: cloverleaf-ui-review
3
- description: Run the UI Reviewer agent on a task in the `ui-review` state (full pipeline only). Computes diff-affected routes via CLI; if empty, skips axe and advances ui-review qa. Otherwise dispatches a subagent with Playwright + axe-core scoped to those routes. Usage — /cloverleaf-ui-review <TASK-ID>.
3
+ description: Run the UI Reviewer council member on a task's feature branch as a standalone one-off. Computes diff-affected routes via CLI; if empty, skips axe and emits a trivial pass. Otherwise dispatches a subagent with Playwright + axe-core scoped to those routes, capturing per-engine visual baselines. Emit-only — it writes a feedback envelope + reports the verdict (and surfaces baselines_pending) for the delivery council or a human to apply. It does NOT advance the task FSM. Usage — /cloverleaf-ui-review <TASK-ID>.
4
4
  ---
5
5
 
6
- # Cloverleaf — ui-review
6
+ # Cloverleaf — ui-review (emit-only council member)
7
+
8
+ The delivery states `ui-review`/`qa` no longer exist — the `@cloverleaf/standard` task FSM collapsed the delivery
9
+ gates into a single `council` phase (Council Slice 4). The UI Reviewer is now a **council member** that the runner
10
+ (`/cloverleaf-run`) dispatches and aggregates alongside the other members. A single member cannot drive the
11
+ multi-member council forward (that would bypass the others' gating), so this standalone skill is **emit-only**: it
12
+ computes the affected routes, dispatches the UI reviewer prompt (capturing per-engine visual baselines), emits the
13
+ feedback envelope, and reports the verdict. **It does not advance the FSM** — the council or a human applies the
14
+ aggregated verdict via `apply-council-verdict`.
15
+
16
+ **Baselines still gate at the council.** The per-engine (cross-browser) baseline capture and the `baselines_pending`
17
+ sidecar mechanism survive unchanged: when the UI reviewer captures new or resized baselines it sets
18
+ `baselines_pending=true` via `write-ui-review-state`. The old `ui-review → qa` hold moved to the **council pass**:
19
+ the runner holds a council `pass` at `baselines_pending` until `/cloverleaf-approve-baselines <TASK-ID>` clears it and
20
+ re-runs the council. This standalone skill just **surfaces** `baselines_pending` in its report; it does not advance
21
+ the FSM.
7
22
 
8
23
  ## Steps
9
24
 
@@ -27,7 +42,7 @@ description: Run the UI Reviewer agent on a task in the `ui-review` state (full
27
42
  ```
28
43
  cloverleaf-cli load-task <repo_root> <TASK-ID>
29
44
  ```
30
- Verify `status === "ui-review"`. If not, report and stop.
45
+ Light guard only: confirm the task exists and is not terminal (`merged`/`rejected`/`escalated`). Do NOT hard-require any particular state — this skill reviews the branch, not a specific FSM state. If the task is terminal, report and stop.
31
46
 
32
47
  3. Confirm feature branch exists: `git rev-parse --verify cloverleaf/<TASK-ID>`. If missing, report and stop.
33
48
 
@@ -42,14 +57,13 @@ description: Run the UI Reviewer agent on a task in the `ui-review` state (full
42
57
  AFFECTED=$(cloverleaf-cli affected-routes <repo_root> <TASK-ID>)
43
58
  ```
44
59
 
45
- 6. **Empty-set early-exit.** If `AFFECTED` is `[]`, skip the subagent entirely:
60
+ 6. **Empty-set early-exit.** If `AFFECTED` is `[]`, skip the subagent entirely — there are no renderable routes to check, so the UI member's verdict is a trivial `pass`. Do NOT advance the FSM:
46
61
  ```bash
47
- cloverleaf-cli advance-status <repo_root> <TASK-ID> qa agent '' full_pipeline
48
62
  cd <repo_root>
49
63
  git add .cloverleaf/
50
- git commit -m "cloverleaf: <TASK-ID> ui-review skipped (no renderable routes) → qa"
64
+ git diff --cached --quiet || git commit -m "cloverleaf: <TASK-ID> ui-review skipped (no renderable routes)"
51
65
  ```
52
- Report: "✓ UI Review skipped (no renderable routes affected). State qa. Next: `/cloverleaf-qa <TASK-ID>`."
66
+ Report: "✓ UI Reviewer verdict: **pass** (skipped no renderable routes affected). This is one council member's verdict — the delivery council (`/cloverleaf-run <TASK-ID>`) or a human applies the aggregated verdict; this skill does not advance the FSM."
53
67
  Stop here.
54
68
 
55
69
  7. Allocate a free preview port:
@@ -62,21 +76,30 @@ description: Run the UI Reviewer agent on a task in the `ui-review` state (full
62
76
  git diff main..cloverleaf/<TASK-ID>
63
77
  ```
64
78
 
65
- 9. **Browser cache env var.** Before the Task-tool dispatch, ensure `PLAYWRIGHT_BROWSERS_PATH=~/.cache/ms-playwright` is exported so the subagent inherits it. This keeps Playwright from re-downloading ~300 MB of browser binaries inside the worktree.
79
+ 9. **Browser cache env var.** Before the Task-tool dispatch, export the Playwright cache location so the subagent inherits it. This keeps Playwright from re-downloading ~300 MB of browser binaries inside the worktree.
80
+
81
+ ```bash
82
+ export PLAYWRIGHT_BROWSERS_PATH="${PLAYWRIGHT_BROWSERS_PATH:-$HOME/.cache/ms-playwright}"
83
+ ```
84
+
85
+ Defer to a value the operator already set — `README.md` documents `PLAYWRIGHT_BROWSERS_PATH` as a supported override for a non-default cache directory, and hard-coding `~/.cache/ms-playwright` here would silently discard it. `ui-reviewer.md` runs the same expression itself, so this step is an optimisation, not a precondition the member depends on.
66
86
 
67
87
  10. Dispatch the UI Reviewer subagent via the Task tool:
68
88
  - `subagent_type`: `general-purpose`
69
89
  - `model`: `sonnet`
70
90
  - Prompt: contents of `$(cloverleaf-cli plugin-root)/prompts/ui-reviewer.md` with substitutions:
71
91
  - `{{task}}`, `{{diff}}`, `{{branch}}`, `{{base_branch}}`, `{{repo_root}}`, `{{preview_port}}`
92
+ - `{{taskId}}` → the TASK-ID from step 1 (**required** — the prompt roots its run artifacts and the `state.json` sidecar at `{{repo_root}}/.cloverleaf/runs/{{taskId}}/ui-review/`. Left unsubstituted, the sidecar lands under a literal `{{taskId}}` directory, step 12's `read-ui-review-state` finds nothing, `baselines_pending` reads `false`, and the human baseline-approval gate silently passes with unapproved baselines)
72
93
  - `{{affected_routes}}` → the value of `$AFFECTED` (verbatim — may be `"all"`, a JSON array, or `[]` but step 6 handled `[]` already)
73
94
  - `{{ui_review_config}}` → JSON-stringified result of `cloverleaf-cli ui-review-config <repo_root>` (used by the subagent to scope viewport sizes, thresholds, and axe rule overrides)
74
95
 
96
+ Substitute **every** `{{…}}` token above before dispatch: `ui-reviewer.md` declares exactly these nine, and none may reach the subagent literal.
97
+
75
98
  **Dispatch conventions:** invoke the Task tool in foreground mode (its default — do NOT pass `run_in_background: true`). The Task tool returns the subagent's final message as a string in the result. Do NOT use Bash `sleep` to poll an output file — the harness blocks foreground `sleep`, and background dispatch is unnecessary here because the foreground Task tool already blocks until the subagent finishes.
76
99
 
77
100
  11. Parse the subagent's response. Expect `{"verdict": "pass"|"bounce"|"escalate", "summary": "...", "findings": [...]}`.
78
101
 
79
- 12. **Read the baseline-approval sidecar** (after the subagent completes, regardless of verdict):
102
+ 12. **Read the baseline-approval sidecar** (after the subagent completes, regardless of verdict — the per-engine baseline capture + `baselines_pending` mechanism survives the collapse):
80
103
  ```bash
81
104
  UI_STATE=$(cloverleaf-cli read-ui-review-state <repo_root> <TASK-ID>)
82
105
  BASELINES_PENDING=$(echo "$UI_STATE" | node -e "process.stdout.write(JSON.parse(require('fs').readFileSync('/dev/stdin','utf-8')).baselines_pending ? 'true' : 'false')")
@@ -86,49 +109,50 @@ description: Run the UI Reviewer agent on a task in the `ui-review` state (full
86
109
  BASELINES_PENDING=$(cloverleaf-cli read-ui-review-state <repo_root> <TASK-ID> | node -e "const s=require('fs').readFileSync('/dev/stdin','utf-8'); process.stdout.write(JSON.parse(s).baselines_pending?'true':'false')")
87
110
  ```
88
111
 
89
- 13. Branch on verdict:
112
+ 13. **Emit the verdict + envelope (no FSM advance).**
90
113
 
91
- **Pass:**
114
+ Persist artifacts + the feedback envelope, then report the verdict and surface `baselines_pending`. **Never call `advance-status`** — the council/human applies the aggregated verdict.
92
115
 
93
- Check `BASELINES_PENDING`:
116
+ **Pass:**
117
+ 1. Commit artifacts: `git add .cloverleaf/ && (git diff --cached --quiet || git commit -m "cloverleaf: <TASK-ID> ui-review verdict (emit-only)")`.
118
+ 2. Report, branching on `BASELINES_PENDING`:
94
119
 
95
- - If `BASELINES_PENDING` is `true`:
96
- - Do NOT advance to `qa`.
97
- - Commit artifacts: `git add .cloverleaf/ && git commit -m "cloverleaf: <TASK-ID> ui-review passed (baselines pending approval)"`.
98
- - Report:
99
- > "✓ UI Review passed (no a11y errors), but **baselines_pending** is true: one or more new or resized visual baselines were captured and require human approval before advancing to qa.
100
- > Run `/cloverleaf-approve-baselines <TASK-ID>` to review the new baseline images and approve them, which will clear the flag and advance the task to qa."
101
- - Stop here (task remains in `ui-review` status).
120
+ - If `BASELINES_PENDING` is `true`:
121
+ > "✓ UI Reviewer verdict: **pass** (no a11y errors), but **baselines_pending** is true: one or more new or resized visual baselines were captured and require human approval.
122
+ > This is one council member's verdict the delivery council (`/cloverleaf-run <TASK-ID>`) or a human applies the aggregated verdict; this skill does not advance the FSM. The runner holds a council **pass** at `baselines_pending`: inspect the new baseline images, then run `/cloverleaf-approve-baselines <TASK-ID>` (which clears the flag) so the re-run's council pass applies."
102
123
 
103
- - If `BASELINES_PENDING` is `false` (or state.json is absent):
104
- ```
105
- cloverleaf-cli advance-status <repo_root> <TASK-ID> qa agent '' full_pipeline
106
- ```
107
- Commit: `git add .cloverleaf/ && git commit -m "cloverleaf: <TASK-ID> ui-review passed → qa"`.
108
- Report: "✓ UI Review passed. State → qa. Next: `/cloverleaf-qa <TASK-ID>`."
124
+ - If `BASELINES_PENDING` is `false` (or state.json is absent):
125
+ > "✓ UI Reviewer verdict: **pass** (no a11y errors, no baselines pending). This is one council member's verdict — the delivery council (`/cloverleaf-run <TASK-ID>`) or a human applies the aggregated verdict (`apply-council-verdict`); this skill does not advance the FSM."
109
126
 
110
127
  **Bounce:**
111
128
  1. Write feedback: `echo '<envelope-json>' > /tmp/cloverleaf-fb-u.json`
112
129
  2. `cloverleaf-cli write-feedback <repo_root> <TASK-ID> /tmp/cloverleaf-fb-u.json --prefix=u`
113
- 3. Commit the persisted feedback file (was missing pre-v0.4.1 — bug #3):
130
+ 3. Commit the persisted feedback file:
114
131
  ```bash
115
132
  cd <repo_root>
116
133
  git add .cloverleaf/feedback/
117
134
  git commit -m "cloverleaf: <TASK-ID> ui-review feedback"
118
135
  ```
119
- 4. `cloverleaf-cli advance-status <repo_root> <TASK-ID> implementing agent '' full_pipeline`
120
- 5. Commit: `git add .cloverleaf/ && git commit -m "cloverleaf: <TASK-ID> ui-review bounced → implementing"`.
121
- 6. Report: "✗ UI Review bounced. Findings: <summary by severity>. State → implementing. Next: `/cloverleaf-implement <TASK-ID>`."
136
+ 4. Report: "✗ UI Reviewer verdict: **bounce**. Findings: <summary by severity>. Feedback emitted to `.cloverleaf/feedback/<TASK-ID>-u<N>.json`. The delivery council or a human applies the verdict (a council bounce loops the task back to `implementing`); this skill does not advance the FSM."
122
137
 
123
138
  **Escalate:**
124
- 1. `cloverleaf-cli advance-status <repo_root> <TASK-ID> escalated agent`
125
- 2. Commit: `git add .cloverleaf/ && git commit -m "cloverleaf: <TASK-ID> ui-review escalated"`.
126
- 3. Report: "✗ UI Review escalated (infrastructure issue). Review and retry manually."
139
+ 1. Write feedback: `echo '<envelope-json>' > /tmp/cloverleaf-fb-u.json`
140
+ 2. `cloverleaf-cli write-feedback <repo_root> <TASK-ID> /tmp/cloverleaf-fb-u.json --prefix=u`
141
+ 3. Commit the persisted feedback file:
142
+ ```bash
143
+ cd <repo_root>
144
+ git add .cloverleaf/feedback/
145
+ git commit -m "cloverleaf: <TASK-ID> ui-review feedback"
146
+ ```
147
+ 4. Report: "✗ UI Reviewer verdict: **escalate** (infrastructure issue). Feedback emitted to `.cloverleaf/feedback/<TASK-ID>-u<N>.json`. The council or a human applies the verdict (a council escalate → `escalated`); this skill does not advance the FSM. Review and retry manually."
127
148
 
128
149
  ## Rules
129
150
 
130
151
  - Never push.
131
152
  - Do not modify source code — UI Reviewer is read-only.
132
- - Always teardown preview server + worktree on error.
133
- - Empty-set early-exit (step 6) skips the browser entirely no Playwright invocation, no worktree.
134
- - On illegal state transition, report and stop without partial commits.
153
+ - **The subagent owns preview-server and worktree teardown** (`ui-reviewer.md` step 13) — including on error. It holds the only handles: `$SERVER_PID` from the backgrounded dev server and `$WT` from `git worktree add`. Neither variable exists in your shell; you never created either resource.
154
+ - Your own cleanup is bounded to what you can reach from the repo root: `git -C <repo_root> worktree prune` clears any worktree registration the subagent left behind.
155
+ - **Never kill by command-line pattern.** `pkill -f "astro dev"` — or `pkill -f "port=$PREVIEW_PORT"` — also matches the command line of the shell running it, so the shell kills itself: exit 144, and every command after it in the same compound statement silently never runs. Cleanup that looked issued never ran.
156
+ - If `$PREVIEW_PORT` is still listening after the subagent returns, report the port rather than killing blind.
157
+ - Empty-set early-exit (step 6) skips the browser entirely — no Playwright invocation, no worktree — and emits a trivial `pass`.
158
+ - Emit-only: never call `advance-status`. This is one council member's verdict; the council/human applies it.