@cloverleaf/reference-impl 0.11.1 → 0.13.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/.claude-plugin/plugin.json +1 -1
- package/README.md +101 -37
- package/VERSION +1 -1
- package/config/council.json +10 -2
- package/dist/cli.mjs +27 -8
- package/dist/council.mjs +327 -45
- package/dist/events.mjs +3 -8
- package/dist/ids.mjs +7 -0
- package/dist/qa-rules.mjs +19 -3
- package/dist/task.mjs +6 -25
- package/dist/work-item.mjs +2 -3
- package/lib/cli.ts +28 -8
- package/lib/council-config.ts +1 -0
- package/lib/council-result.ts +4 -3
- package/lib/council.ts +399 -47
- package/lib/events.ts +4 -8
- package/lib/ids.ts +7 -0
- package/lib/qa-rules.ts +24 -3
- package/lib/task.ts +7 -33
- package/lib/work-item.ts +2 -4
- package/package.json +5 -3
- package/prompts/documenter.md +1 -1
- package/prompts/implementer.md +8 -2
- package/prompts/qa.md +6 -9
- package/prompts/reviewer.md +4 -2
- package/prompts/ui-reviewer.md +83 -11
- package/skills/cloverleaf-approve-baselines/SKILL.md +18 -26
- package/skills/cloverleaf-discover/SKILL.md +7 -1
- package/skills/cloverleaf-document/SKILL.md +5 -6
- package/skills/cloverleaf-implement/SKILL.md +24 -30
- package/skills/cloverleaf-merge/SKILL.md +14 -23
- package/skills/cloverleaf-new-task/SKILL.md +23 -4
- package/skills/cloverleaf-qa/SKILL.md +25 -24
- package/skills/cloverleaf-review/SKILL.md +24 -18
- package/skills/cloverleaf-run/SKILL.md +53 -103
- package/skills/cloverleaf-run-plan/SKILL.md +19 -26
- package/skills/cloverleaf-security-review/SKILL.md +22 -17
- package/skills/cloverleaf-ui-review/SKILL.md +59 -35
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: cloverleaf-run
|
|
3
|
-
description: End-to-end orchestrator.
|
|
3
|
+
description: End-to-end orchestrator. Drives every task through one universal delivery council — implement → documenting → council → final-gate/implementing/escalated. The lane is a risk_class profile selector (delivery-fast / delivery-full); security, UI, and QA are council members. Usage — /cloverleaf-run <TASK-ID>.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Cloverleaf — run (orchestrator)
|
|
@@ -11,128 +11,71 @@ description: End-to-end orchestrator. Reads task.risk_class to dispatch fast lan
|
|
|
11
11
|
|
|
12
12
|
Do NOT `git checkout main` from a walker worktree — main is held by the primary repo. To compare against main, use `git diff main..HEAD` or `git show main:<path>`. Sub-skills run from the worktree's current branch and stay on it; the walker (in the primary repo) does the final merge to main itself after all tasks reach final-gate.
|
|
13
13
|
|
|
14
|
-
##
|
|
14
|
+
## Bounce budget
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
MAX_REVIEWER_BOUNCES = 3
|
|
18
|
-
MAX_UI_REVIEWER_BOUNCES = 3
|
|
19
|
-
MAX_QA_BOUNCES = 3
|
|
20
|
-
MAX_SECURITY_BOUNCES = 3
|
|
21
|
-
```
|
|
16
|
+
The delivery council owns the loop. `council_bounces` (max 3) counts council bounces back to the Implementer; `plan_review_bounces` (max 3) counts decisive plan-review bounces. On either cap, escalate (section 6). Security, UI, and QA are **council members**, not separate gates — there is no per-agent counter.
|
|
22
17
|
|
|
23
18
|
These counters live in-session (not persisted). Rerunning `/cloverleaf-run` resets.
|
|
24
19
|
|
|
25
|
-
## Security gate (both lanes)
|
|
26
|
-
|
|
27
|
-
Run this immediately after the task reaches `automated-gates` (Reviewer passed) and BEFORE the lane's next move (fast lane: merge; full pipeline: detect-ui-paths). Initialize `security_bounces = 0` at orchestrator start (alongside the other bounce counters).
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
cloverleaf-cli classify-security <repo_root> <TASK-ID> --branch cloverleaf/<TASK-ID>
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Parse the JSON. If `classify-security` exits non-zero or emits unparseable output, do NOT silently skip security review (fail-open is unsafe for a security gate). Warn to the user and treat the task as `effective: "high"` — i.e. proceed into security-review anyway (fail toward more scrutiny). If `/cloverleaf-security-review` then cannot run either (e.g. branch/tooling broken), surface the failure and stop rather than merging unreviewed.
|
|
34
|
-
|
|
35
|
-
If `effective == "low"` → skip the gate, proceed with the lane.
|
|
36
|
-
|
|
37
|
-
If `effective == "high"`:
|
|
38
|
-
- If `declared == "low"` (under-classification: `diff_detected` true), you may proactively run `classify-security` to confirm, but the writeback to `security_class: "high"` is now mechanical — the CLI handles it automatically when `advance-status` moves the task to `security-review`. No manual scripting of the writeback is required.
|
|
39
|
-
- `cloverleaf-cli advance-status <repo_root> <TASK-ID> security-review agent`; commit.
|
|
40
|
-
- Inline `/cloverleaf-security-review <TASK-ID>` steps. Reload the task:
|
|
41
|
-
- `status == "automated-gates"` → security review passed; proceed with the lane.
|
|
42
|
-
- `status == "implementing"` → bounced. `security_bounces += 1`. If `security_bounces >= MAX_SECURITY_BOUNCES`, escalate (section 6). Else re-enter the implement→review loop (fast lane section 4 / full pipeline section 5.1), which re-runs the security gate on its next pass.
|
|
43
|
-
- `status == "escalated"` → the security reviewer found a blocker; stop and surface to the user (a human must review `.cloverleaf/feedback/`). This is the security reviewer's own escalation, distinct from a bounce-budget exhaustion.
|
|
44
|
-
|
|
45
|
-
### Refusal and recover
|
|
46
|
-
|
|
47
|
-
In v0.8.1, `advance-status` from `automated-gates` to any post-gate state (`ui-review`, `qa`, `merged`) may exit with **exit code 2** when the task is high-security and has no pass verdict recorded (`security_review_verdict` is absent or not `"pass"`). This is a **security-gate refusal** — the CLI is enforcing that high-security tasks must pass security review before proceeding.
|
|
48
|
-
|
|
49
|
-
Recovery sequence:
|
|
50
|
-
1. Advance the task to `security-review` first: `cloverleaf-cli advance-status <repo_root> <TASK-ID> security-review agent`; commit.
|
|
51
|
-
2. Run `/cloverleaf-security-review <TASK-ID>` to execute the security review.
|
|
52
|
-
3. Retry the original `advance-status` call. If the review passed, the CLI will now allow the transition.
|
|
53
|
-
|
|
54
20
|
## Steps
|
|
55
21
|
|
|
56
|
-
1. Capture TASK-ID.
|
|
57
|
-
|
|
58
|
-
2. Load task: `cloverleaf-cli load-task <repo_root> <TASK-ID>`. Verify `status === "pending"`. If not, report and stop.
|
|
22
|
+
1. Capture TASK-ID. Initialize `council_bounces = 0`, `plan_review_bounces = 0`.
|
|
59
23
|
|
|
60
|
-
|
|
61
|
-
- `task.risk_class === "low"` → section 4 (Fast Lane)
|
|
62
|
-
- `task.risk_class === "high"` → section 5 (Full Pipeline)
|
|
24
|
+
2. Load task: `cloverleaf-cli load-task <repo_root> <TASK-ID>`. Verify `status === "pending"`. If not, report and stop. **Preflight:** `load-task` does not schema-validate. Before dispatching any agent, confirm the task document is schema-valid: `context.rfc` is present, and `risk_class` / `security_class` are `low` or `high`. An invalid task otherwise clears every precondition and fails at its first real transition — after the Implementer has already produced a branch and commits.
|
|
63
25
|
|
|
64
|
-
|
|
26
|
+
If any `advance-status` later fails with `orphan event written to … but task save failed`, the event file it names records a transition that did not happen: delete that file before retrying, or the retry will number the next event around it.
|
|
65
27
|
|
|
66
|
-
|
|
28
|
+
3. **Tactical plan (+ optional decisive plan-review).**
|
|
29
|
+
a. `cloverleaf-cli council-plan <repo_root> <TASK-ID> task.plan_review`. **A decisive `task.plan_review` is not currently wired — do not bind one.** `/cloverleaf-implement <TASK-ID>` always completes both advances (`pending → tactical-plan → implementing`) in a single dispatch and stops at `implementing`; there is no point at which a plan-review verdict can be applied. If a consumer's `.cloverleaf/config/council.json` bound `plan.mode === "decisive"` for this gate anyway, §3b's `cloverleaf-cli apply-council-verdict <repo_root> <TASK-ID> task.plan_review '<verdict>'` would fail — it requires the task to still be at `tactical-plan`, and by the time `/cloverleaf-implement` returns it is already at `implementing`. The shipped default binds no profile to `task.plan_review` (`plan.profile` is always `null` here), so this limitation does not affect the packaged pipeline; it is tracked as a follow-up, not built in this fix. Otherwise (no decisive plan-review bound — the shipped default) simply inline `/cloverleaf-implement <TASK-ID>`, which walks `pending → tactical-plan → implementing` and stops at `implementing`.
|
|
30
|
+
b. **Reserved — not reachable today.** Applying a decisive `task.plan_review` verdict requires the task to still be at `tactical-plan`, and 3a never leaves it there under the current `/cloverleaf-implement`, so skip 3b unconditionally and continue to 3c. The bullets below record the intended reload logic for when a real stop-at-`tactical-plan` mode exists:
|
|
31
|
+
- `implementing` (pass) → continue to 3c.
|
|
32
|
+
- `pending` (bounce) → `plan_review_bounces += 1`; if `>= 3` escalate (section 6); else return to 3a.
|
|
33
|
+
- `escalated` → stop and surface.
|
|
34
|
+
c. Finish the Implementer (task at `implementing`), then reach `documenting` for **every** `risk_class`:
|
|
35
|
+
- `risk_class: "high"` → run `/cloverleaf-document <TASK-ID>` (the Documenter adds doc commits and advances `implementing → documenting`).
|
|
36
|
+
- `risk_class: "low"` (no docs) → the **runner** advances the state itself: `cloverleaf-cli advance-status <repo_root> <TASK-ID> documenting agent`, then commit (`git add .cloverleaf/ && (git diff --cached --quiet || git commit -m "cloverleaf: <TASK-ID> → documenting")`).
|
|
67
37
|
|
|
68
|
-
|
|
38
|
+
Either way the task reaches `documenting` before §4a advances `documenting → council`.
|
|
69
39
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
d. If `status === "implementing"`: Reviewer bounced. `reviewer_bounces += 1`. If `reviewer_bounces >= MAX_REVIEWER_BOUNCES`, escalate (section 6). Else continue loop.
|
|
75
|
-
e. Else: unexpected state. Report and stop.
|
|
40
|
+
4. **Delivery council.**
|
|
41
|
+
a. Enter the phase: `cloverleaf-cli advance-status <repo_root> <TASK-ID> council agent`. Commit. (Council entry classifies security — a sensitive diff upgrades `security_class` to `high` so the blocking security member runs.)
|
|
42
|
+
b. `cloverleaf-cli council-plan <repo_root> <TASK-ID> task.review`. The plan always carries a profile: the shipped default binds `task.review` to `delivery-fast` (`risk_class: low`) / `delivery-full` (`risk_class: high`); a consumer `.cloverleaf/config/council.json` overrides.
|
|
43
|
+
c. Run the council members (section 7.2), reach the verdict (7.3 chair / 7.4 deterministic), and — **before** applying it — run the **baselines-hold check (section 4.1)**. Then, once cleared, `cloverleaf-cli apply-council-verdict <repo_root> <TASK-ID> task.review '<verdict>'`. Commit the remainder: `git add .cloverleaf/ && (git diff --cached --quiet || git commit -m "cloverleaf: <TASK-ID> council review (<verdict>)")`.
|
|
76
44
|
|
|
77
|
-
|
|
45
|
+
### 4.1 Baselines hold (before applying a council pass)
|
|
78
46
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
Initialize `reviewer_bounces = 0`, `ui_reviewer_bounces = 0`, `qa_bounces = 0`, `security_bounces = 0`.
|
|
82
|
-
|
|
83
|
-
5.1. **Implementer → Documenter → Reviewer loop:**
|
|
84
|
-
|
|
85
|
-
Loop:
|
|
86
|
-
a. Inline `/cloverleaf-implement <TASK-ID>` steps.
|
|
87
|
-
b. Inline `/cloverleaf-document <TASK-ID>` steps.
|
|
88
|
-
c. Inline `/cloverleaf-review <TASK-ID>` steps.
|
|
89
|
-
d. Reload task. If `status === "automated-gates"`: pass! Exit this loop.
|
|
90
|
-
e. If `status === "implementing"`: Reviewer bounced. `reviewer_bounces += 1`. If `reviewer_bounces >= MAX_REVIEWER_BOUNCES`, escalate. Else continue loop.
|
|
91
|
-
f. Else: unexpected. Report and stop.
|
|
92
|
-
|
|
93
|
-
**Security gate.** Run the **Security gate (both lanes)** (above) now, before UI-path detection. Then continue to 5.2.
|
|
94
|
-
|
|
95
|
-
5.2. **UI-path detection and conditional UI Review:**
|
|
47
|
+
The collapse removed the old `ui-review → qa` hold that `baselines_pending` guarded; the hold moves to **council pass**. After the members run (the `ui` member captures baselines and, on new/resized baselines, sets `baselines_pending=true` via `write-ui-review-state` — that mechanism is unchanged), and **before** applying a council `pass` that would advance `council → final-gate`, read the ui-review state:
|
|
96
48
|
|
|
97
49
|
```bash
|
|
98
|
-
cloverleaf-cli
|
|
50
|
+
cloverleaf-cli read-ui-review-state <repo_root> <TASK-ID>
|
|
99
51
|
```
|
|
100
52
|
|
|
101
|
-
If
|
|
102
|
-
|
|
103
|
-
- UI-review loop:
|
|
104
|
-
a. Inline `/cloverleaf-ui-review <TASK-ID>` steps.
|
|
105
|
-
b. Reload task. If `status === "qa"`: pass! Exit UI-review loop.
|
|
106
|
-
c. If `status === "implementing"`: UI Reviewer bounced. `ui_reviewer_bounces += 1`. If `>= MAX_UI_REVIEWER_BOUNCES`, escalate. Else return to section 5.1 (Implementer re-runs, which then re-documents, re-reviews).
|
|
107
|
-
d. Else: unexpected. Report and stop.
|
|
108
|
-
|
|
109
|
-
If output is `false`: skip UI review. Advance: `cloverleaf-cli advance-status <repo_root> <TASK-ID> qa agent --path=full_pipeline`. Commit.
|
|
110
|
-
|
|
111
|
-
5.3. **QA loop:**
|
|
53
|
+
- If the council verdict is `pass` **and** `baselines_pending` is `true`: do **NOT** apply the verdict. Surface to the human: "⏸ `<TASK-ID>` — new visual baselines need approval. Inspect the captured baseline images, then run `/cloverleaf-approve-baselines <TASK-ID>` (which clears `baselines_pending`) and re-run `/cloverleaf-run <TASK-ID>` — the `ui` member now passes and the council pass applies." Stop here (leave the task at `council`); the re-run re-dispatches the council with `baselines_pending=false`.
|
|
54
|
+
- Otherwise (`baselines_pending` is `false`, or the verdict is `bounce` / `escalate`): proceed to apply the verdict (step 4c). This is a runner **convention** — no FSM change, exactly as the old `ui-review → qa` hold was a convention. `/cloverleaf-approve-baselines` and the `write-baseline` guard are unchanged.
|
|
112
55
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
d. Else: unexpected. Report and stop.
|
|
118
|
-
|
|
119
|
-
5.4. **Final merge:** Inline `/cloverleaf-merge <TASK-ID>` steps (branches to full-pipeline gate per state).
|
|
56
|
+
5. **Branch on the task's new status** (reload with `load-task`):
|
|
57
|
+
- `final-gate` (pass) → run the advisory `final_gate` council (section 7.6) if bound, then inline `/cloverleaf-merge <TASK-ID>`.
|
|
58
|
+
- `implementing` (bounce) → `council_bounces += 1`. If `>= 3`, escalate (section 6). Else return to 3c (re-implement; the batched council feedback is in `.cloverleaf/feedback/`).
|
|
59
|
+
- `escalated` → stop and surface (`.cloverleaf/feedback/` + `.cloverleaf/runs/<TASK-ID>/council/task.review.json`).
|
|
120
60
|
|
|
121
61
|
### 6. Escalation
|
|
122
62
|
|
|
123
63
|
- `cloverleaf-cli advance-status <repo_root> <TASK-ID> escalated agent`
|
|
124
64
|
- Commit: `git add .cloverleaf/ && git commit -m "cloverleaf: <TASK-ID> escalated (bounce budget exhausted)"`.
|
|
125
|
-
- Report: "✗ Escalated `<TASK-ID>`. Review `.cloverleaf/feedback/` and either refine the task or take over manually. Counters:
|
|
65
|
+
- Report: "✗ Escalated `<TASK-ID>`. Review `.cloverleaf/feedback/` and either refine the task or take over manually. Counters: council_bounces=<N>, plan_review_bounces=<N>."
|
|
126
66
|
|
|
127
|
-
|
|
67
|
+
## 7. Delivery council mechanics
|
|
128
68
|
|
|
129
|
-
|
|
69
|
+
The council member-dispatch, verdict, and apply steps referenced by steps 3b / 4c / 5.
|
|
130
70
|
|
|
131
|
-
7.
|
|
71
|
+
7.2 **Run the council members (verdict-only).** Re-run `cloverleaf-cli council-plan <repo_root> <TASK-ID> task.review` to get `plan.rounds`, `plan.aggregation`, `plan.on_round_bounce`, and (for a chair profile) `plan.chair`. For each round **in order**: dispatch **all active members in the round concurrently** — issue their Task-tool calls **in a single message** so the harness runs them in parallel — and capture each member's `{verdict, summary, findings}` envelope. Do **not** advance state (the task stays at `council` until you apply the verdict at step 4c). Rounds still run in sequence; only members *within* a round are concurrent. (Built-in members resolve to the shipped `reviewer`/`security-reviewer`/`ui-reviewer`/`qa` prompts by their `promptPath`; a custom role resolves to `.cloverleaf/prompts/<file>.md`.)
|
|
132
72
|
|
|
133
|
-
|
|
73
|
+
**Dispatch conventions:** invoke the Task tool in foreground (default — never `run_in_background`); do not poll with foreground `sleep`. Substitute the five base tokens, plus every entry in that member's `substitutions` map from the plan:
|
|
74
|
+
- `{{task}}`, `{{branch}}` (`cloverleaf/<TASK-ID>`), `{{base_branch}}` (`main`), `{{repo_root}}`, `{{diff}}` (`git diff main..cloverleaf/<TASK-ID> -- ':(exclude).cloverleaf/'`) — the five base tokens, always present.
|
|
75
|
+
- `{{<key>}}` for every key in `substitutions`: `council-plan` resolves each member's extra tokens beyond the five base ones (e.g. `test_rules` for `reviewer`, `qa_rules` for `qa`, `affected_routes` / `ui_review_config` / `taskId` for `ui`; `security`'s map is empty — its prompt needs no extra tokens).
|
|
76
|
+
- **`{{preview_port}}` — the one exception.** `ui-reviewer.md` declares it, but it is deliberately NOT in the plan's `substitutions`: planning must stay side-effect free and cannot allocate a port without one. When dispatching the `ui` member, the runner must allocate a free port itself and substitute `{{preview_port}}` before dispatch — the same way the standalone `cloverleaf-ui-review` skill does: `PREVIEW_PORT=$(node -e "const net=require('net');const s=net.createServer();s.listen(0,()=>{console.log(s.address().port);s.close()})")`.
|
|
134
77
|
|
|
135
|
-
|
|
78
|
+
Never dispatch a member with an unresolved `{{…}}` token. The three bullets above are the complete set of substitution sources: the five base tokens, every key in that member's `substitutions`, and — for `ui` only — `{{preview_port}}`. Apply all three, then scan the filled prompt text; if any `{{…}}` remains, stop and report rather than letting the member improvise. (Nothing should: `tests/council.test.ts` pins every built-in prompt's declared tokens against exactly those three sources, so a leftover means the prompt and `MEMBER_TOKENS` have drifted.)
|
|
136
79
|
|
|
137
80
|
Persist each member's envelope: `echo '<envelope>' > /tmp/clv-council-<member>.json && cloverleaf-cli write-feedback <repo_root> <TASK-ID> /tmp/clv-council-<member>.json --prefix=<prefix>`, where `<prefix>` is `r`/`s`/`u`/`q` for the built-ins and the **member id** for a custom role. Collect a members array `[{ "member": "<id>", "verdict": "<pass|bounce|escalate>", "blocking": <plan member blocking>, "weight": <plan member weight> }]`.
|
|
138
81
|
|
|
@@ -145,17 +88,24 @@ Initialize `council_bounces = 0`.
|
|
|
145
88
|
- Otherwise (a blocking member bounced; no member escalated) **dispatch the chair.** Build enriched inputs `[{ "member", "verdict", "blocking", "weight", "envelope": <the member's /tmp/clv-council-<member>.json object> }]`; run `context=$(cloverleaf-cli chair-context '<enriched-inputs-json>')`. Dispatch the chair prompt at `plan.chair.promptPath` as a **read-only** foreground subagent, substituting `{{task}}`, `{{repo_root}}`, and `{{member_verdicts}}` = `$context`; capture its `{verdict, rationale, forward}` output. Then run `cloverleaf-cli chair-verdict '<chair-raw-json>' '<members-json>'` and capture the council verdict JSON.
|
|
146
89
|
- **Else (deterministic):** map `plan.aggregation` to the CLI rule (a string passes through; `{ "quorum": k }` → `quorum:k`) and run `cloverleaf-cli aggregate-verdicts '<members-json>' <rule>`; capture the council verdict JSON.
|
|
147
90
|
|
|
148
|
-
7.4 **Apply.**
|
|
149
|
-
|
|
150
|
-
7.5 **Branch on the task's new status (reload with `load-task`):**
|
|
151
|
-
- `automated-gates` (fast lane pass) or `final-gate` (full pipeline pass) → proceed to the merge: inline `/cloverleaf-merge <TASK-ID>`.
|
|
152
|
-
- `implementing` (bounce) → `council_bounces += 1`. If `council_bounces >= 3`, escalate (section 6). Else return to 7.1.
|
|
153
|
-
- `escalated` → stop and surface to the user (review `.cloverleaf/feedback/` and `.cloverleaf/runs/<TASK-ID>/council/task.review.json`).
|
|
91
|
+
7.4 **Apply.** After the baselines-hold check (section 4.1) clears, run `cloverleaf-cli apply-council-verdict <repo_root> <TASK-ID> task.review '<council-verdict-json>'`. The FSM walk may self-commit some transitions (e.g. `security_class → high`, the rework verdict-reset), so the wrap-up commit can find nothing staged — that is expected. Commit the remainder: `git add .cloverleaf/ && (git diff --cached --quiet || git commit -m "cloverleaf: <TASK-ID> council review (<verdict>)")`. The verdict drives the FSM: `pass` → `council → final-gate`; `bounce` → `council → implementing`; `escalate` → `council → escalated` (branch per step 5).
|
|
154
92
|
|
|
155
93
|
On a chair **bounce**, the result artifact's `forward` array names the members whose feedback the Implementer should prioritize; the chair `rationale` frames them. The council result artifact at `.cloverleaf/runs/<TASK-ID>/council/task.review.json` records per-member verdicts, the aggregate (or chair) verdict, `forward` (for a chair bounce), and the security basis (incl. an omitted or out-voted `security` member). On any member-dispatch failure or unparseable envelope, stop and report — never treat a failed member as a pass.
|
|
156
94
|
|
|
95
|
+
### 7.6 Advisory `final_gate` council (opt-in)
|
|
96
|
+
|
|
97
|
+
`final-gate` is the human merge pause. Before inlining `/cloverleaf-merge <TASK-ID>` at the final gate (step 5), check for an advisory council:
|
|
98
|
+
|
|
99
|
+
1. `cloverleaf-cli council-plan <repo_root> <TASK-ID> task.final_gate`.
|
|
100
|
+
2. If `plan.source !== "consumer"` or `plan.profile === null`, skip — proceed to the plain human merge (today's behavior).
|
|
101
|
+
3. Otherwise dispatch `plan.rounds` per §7.2 (parallel within a round), reviewing `{{diff}}` = `git diff main..cloverleaf/<TASK-ID> -- ':(exclude).cloverleaf/'`, and reach a verdict per §7.3 (chair) or §7.4-style `aggregate-verdicts` (deterministic). Then `cloverleaf-cli apply-council-verdict <repo_root> <TASK-ID> task.final_gate '<council-verdict-json>'`. This **posts** the advisory result to `.cloverleaf/runs/<TASK-ID>/council/task.final_gate.json` + a feedback envelope and **drives no transition** (the task stays at `final-gate`). Commit: `git add .cloverleaf/ && (git diff --cached --quiet || git commit -m "cloverleaf: <TASK-ID> advisory final_gate council (<verdict>)")`.
|
|
102
|
+
4. Surface the council verdict + rationale to the human at the merge confirmation. The human still drives `/cloverleaf-merge` (merge) or reject; the advisory council never merges.
|
|
103
|
+
|
|
104
|
+
`task.plan_review` (decisive, at `tactical-plan`) is **not currently wired** (see §3a/§3b); `task.final_gate` is advisory-only and post-only.
|
|
105
|
+
|
|
157
106
|
## Rules
|
|
158
107
|
|
|
159
|
-
-
|
|
160
|
-
- On any sub-skill error or escalation, orchestrator stops with clear message.
|
|
108
|
+
- The delivery council owns the bounce loop: `council_bounces` (max 3) and `plan_review_bounces` (max 3). There is no per-agent counter — security, UI, and QA are members.
|
|
109
|
+
- On any sub-skill error or escalation, the orchestrator stops with a clear message.
|
|
161
110
|
- Human merge gate is NOT skipped; confirmation is still required at merge time.
|
|
111
|
+
- The baselines-hold is a convention: a council `pass` is held at `baselines_pending` until `/cloverleaf-approve-baselines <TASK-ID>` clears it and the council is re-run.
|
|
@@ -162,7 +162,7 @@ description: Autonomous DAG walker for Cloverleaf Plans. Given a PLAN-ID in stat
|
|
|
162
162
|
|
|
163
163
|
- **`tool_decision_required`** → let the walker policy decide (auto-approve per rules, defer to user for anything not covered).
|
|
164
164
|
|
|
165
|
-
- **`turn_completed [DONE]`** → the session has finished its current turn with a `[DONE]` terminal token. If the on-disk task status is `final-gate
|
|
165
|
+
- **`turn_completed [DONE]`** → the session has finished its current turn with a `[DONE]` terminal token. If the on-disk task status is `final-gate`, push onto the final-gate queue. Otherwise continue monitoring.
|
|
166
166
|
|
|
167
167
|
- **`turn_completed [NEEDS-INPUT]`** → the session is paused waiting for a user reply. Surface the assistant's last message to the driver and send the user's response via `mcp__claw-drive__send_turn`.
|
|
168
168
|
|
|
@@ -179,7 +179,7 @@ description: Autonomous DAG walker for Cloverleaf Plans. Given a PLAN-ID in stat
|
|
|
179
179
|
```
|
|
180
180
|
This covers transient API errors (e.g. HTTP 503, `API Error: 503`) and the `temporarily unavailable` service message without requiring a Session A nudge from the human.
|
|
181
181
|
|
|
182
|
-
e. **Drain the final-gate queue serially and merge on main.** Session B does NOT invoke `/cloverleaf-merge` — it stops at
|
|
182
|
+
e. **Drain the final-gate queue serially and merge on main.** Session B does NOT invoke `/cloverleaf-merge` — it stops at final-gate and reports. The walker performs the merge on main in the primary repo. For each queued task:
|
|
183
183
|
|
|
184
184
|
**Scope check (BEFORE the y/N prompt).** Run `cloverleaf-cli check-scope` and capture its output and exit code:
|
|
185
185
|
|
|
@@ -204,10 +204,10 @@ description: Autonomous DAG walker for Cloverleaf Plans. Given a PLAN-ID in stat
|
|
|
204
204
|
|
|
205
205
|
1. Print a full summary to the driver:
|
|
206
206
|
```
|
|
207
|
-
⏵ <TASK-ID> ready to merge
|
|
207
|
+
⏵ <TASK-ID> ready to merge
|
|
208
208
|
Reviewer: <summary>
|
|
209
209
|
UI Reviewer: <summary or "skipped">
|
|
210
|
-
QA: <summary or "
|
|
210
|
+
QA: <summary or "skipped">
|
|
211
211
|
Session <session_id>, worktree <worktree_path>
|
|
212
212
|
|
|
213
213
|
Confirm merge? (y/N, or ask a question)
|
|
@@ -224,7 +224,7 @@ description: Autonomous DAG walker for Cloverleaf Plans. Given a PLAN-ID in stat
|
|
|
224
224
|
echo "$CHANGED_FILES" | xargs grep -l -E '^(<{7}|={7}|>{7})' 2>/dev/null
|
|
225
225
|
# Do NOT proceed; mark task escalated and surface to user
|
|
226
226
|
else
|
|
227
|
-
git -C <repo_root> merge --no-ff cloverleaf/<TASK-ID> -m "cloverleaf: <TASK-ID> merged
|
|
227
|
+
git -C <repo_root> merge --no-ff cloverleaf/<TASK-ID> -m "cloverleaf: <TASK-ID> merged"
|
|
228
228
|
fi
|
|
229
229
|
```
|
|
230
230
|
|
|
@@ -232,12 +232,8 @@ description: Autonomous DAG walker for Cloverleaf Plans. Given a PLAN-ID in stat
|
|
|
232
232
|
|
|
233
233
|
After a **successful** `git merge --no-ff`, advance state and commit:
|
|
234
234
|
```bash
|
|
235
|
-
# Fast lane:
|
|
236
|
-
cloverleaf-cli emit-gate-decision <repo_root> <TASK-ID> human_merge approve human
|
|
237
|
-
cloverleaf-cli advance-status <repo_root> <TASK-ID> merged human human_merge fast_lane
|
|
238
|
-
# Full pipeline (task is already at final-gate):
|
|
239
235
|
cloverleaf-cli emit-gate-decision <repo_root> <TASK-ID> final_approval_gate approve human
|
|
240
|
-
cloverleaf-cli advance-status <repo_root> <TASK-ID> merged human final_approval_gate
|
|
236
|
+
cloverleaf-cli advance-status <repo_root> <TASK-ID> merged human final_approval_gate
|
|
241
237
|
```
|
|
242
238
|
```bash
|
|
243
239
|
git -C <repo_root> add .cloverleaf/ && git -C <repo_root> commit -m "cloverleaf: <TASK-ID> merged"
|
|
@@ -350,32 +346,29 @@ stay on the worktree's current branch (`cloverleaf/<TASK-ID>`).
|
|
|
350
346
|
|
|
351
347
|
Plan: invoke `/cloverleaf-run <TASK-ID>`.
|
|
352
348
|
|
|
353
|
-
**DO NOT invoke `/cloverleaf-merge`**.
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
real `git merge --no-ff` itself after human approval — the worktree's main
|
|
358
|
-
branch can't be checked out concurrently, which is why the walker owns the
|
|
359
|
-
merge. If `/cloverleaf-run` would normally invoke `/cloverleaf-merge`
|
|
360
|
-
internally (fast-lane orchestrator), interrupt before that step and exit.
|
|
361
|
-
|
|
362
|
-
All four v0.5.2+v0.5.3+v0.5.4+v0.5.5 dogfood fixes are in place:
|
|
363
|
-
- /cloverleaf-merge actor: human final_approval_gate full_pipeline.
|
|
349
|
+
**DO NOT invoke `/cloverleaf-merge`**. Delivery lands the task at `final-gate`; do NOT invoke `/cloverleaf-merge`; report status + summaries at that point and exit cleanly. The walker runs in the primary repo on `main` and performs the real `git merge --no-ff` itself after human approval — the worktree's main branch can't be checked out concurrently, which is why the walker owns the merge.
|
|
350
|
+
|
|
351
|
+
All v0.5.2+v0.5.3+v0.5.4+v0.5.5 dogfood fixes are in place:
|
|
352
|
+
- /cloverleaf-merge actor: human final_approval_gate.
|
|
364
353
|
- cloverleaf-cli prep-worktree is idempotent.
|
|
365
354
|
- Documenter runs `git status --porcelain` and stages every modified doc.
|
|
366
355
|
- cloverleaf-ui-review uses /cloverleaf-approve-baselines (fully-qualified).
|
|
367
356
|
|
|
368
|
-
Expected: zero interventions until you reach
|
|
369
|
-
then exit.
|
|
357
|
+
Expected: zero interventions until you reach final-gate, then exit.
|
|
370
358
|
|
|
371
359
|
Do not push. Do not publish. Report merge + state commit SHAs on completion.
|
|
372
360
|
```
|
|
373
361
|
|
|
374
362
|
## Walker policy
|
|
375
363
|
|
|
376
|
-
The walker spawns each Session B with a conservative
|
|
364
|
+
The walker spawns each Session B with a conservative policy resolving every tool call to one of four outcomes:
|
|
365
|
+
|
|
366
|
+
- **auto-approve** — Read/Glob/Grep, git reads (including `git -C <path> …`), `npm`/`npx`, `node <script>`, `cloverleaf-cli` anywhere in a compound script, and the usual `set -e` / `cd` / `export` / `source` prefixes.
|
|
367
|
+
- **auto-defer** — pauses for a human: `sudo`/`su`, and anything that runs code the command regex cannot inspect (`node -e`/`-p`, `python -c`, `perl -e`, `sh -c`, `eval`), plus `chmod -R 777`, `chown -R`, `truncate`, `systemctl stop`.
|
|
368
|
+
- **auto-reject** — recursive `rm`, `git push`, `git reset --hard`, `npm publish`, `curl … | bash`, disk-destructive ops (`dd if=`, `mkfs`, `shred`, `fdisk`), writes to real block devices, and writes to claw-drive's own policy file or `.claw-drive/` runtime state.
|
|
369
|
+
- **escalate** — everything else goes to the walker for human-in-the-loop handling.
|
|
377
370
|
|
|
378
|
-
The concrete policy
|
|
371
|
+
The concrete policy is `.cloverleaf/claw-drive-policy.json` in this repo — a starting template, not a guarantee; tune it for your own project. It tracks claw-drive's shipped starter with a few deliberate divergences, each recorded in the file's own `_comment`. After editing it, run `node .cloverleaf/policy-check.mjs`, which asserts the decision for every command in `.cloverleaf/policy-probes.tsv` and exits non-zero on a regression.
|
|
379
372
|
|
|
380
373
|
## Rules
|
|
381
374
|
|
|
@@ -395,4 +388,4 @@ The concrete policy JSON is the same one used during the CLV-16..CLV-20 dogfood
|
|
|
395
388
|
|
|
396
389
|
**RFC-direct task participation in RFC auto-advance.** Tasks with no `parent` field but with `context.rfc` set (created via `/cloverleaf-new-task --rfc=<RFC-ID>`) are *first-class* participants in the `can_auto_advance_rfc` check. They block the advance when in-flight; they count toward delivery when merged. See `cloverleaf-cli rfc-tasks <repo_root> <RFC-ID>` for the categorized view this dispatch reads from, or `reference-impl/README.md` § "Plans vs RFC-direct tasks" for the user-facing pattern docs.
|
|
397
390
|
|
|
398
|
-
**Security-review escalations.** When a task's effective `security_class` is high, `/cloverleaf-run` routes it through `security-review`
|
|
391
|
+
**Security-review escalations.** When a task's effective `security_class` is high, `/cloverleaf-run` routes it through `security-review` as a council member. A `blocker` finding (e.g. a leaked credential) advances the task to `escalated`, which surfaces through the walker's existing escalation path — expect and surface these like any other escalation; do not auto-retry a security blocker.
|
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: cloverleaf-security-review
|
|
3
|
-
description: Run the Security Reviewer
|
|
3
|
+
description: Run the Security Reviewer council member on a task's feature branch as a standalone one-off. Hybrid two-pass (deterministic secret scan + LLM vulnerability judgment). Emit-only — it records the `security_review_verdict`, writes a feedback envelope, and reports the verdict (pass/bounce/escalate) for the delivery council or a human to apply. It does NOT advance the task FSM. Usage — /cloverleaf-security-review <TASK-ID>.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Cloverleaf — security review
|
|
6
|
+
# Cloverleaf — security review (emit-only council member)
|
|
7
|
+
|
|
8
|
+
The delivery states `security-review`/`automated-gates` no longer exist — the `@cloverleaf/standard` task FSM
|
|
9
|
+
collapsed them into a single `council` phase (Council Slice 4). The Security Reviewer is now a **council member**
|
|
10
|
+
that the runner (`/cloverleaf-run`) dispatches; its blocking verdict gates the aggregated council result. A single
|
|
11
|
+
member cannot drive the multi-member council to merge, so this standalone skill is **emit-only**: it runs the two
|
|
12
|
+
passes against the task's branch, records the `security_review_verdict`, emits the feedback envelope, and reports
|
|
13
|
+
the verdict. **It does not advance the FSM** — the council or a human applies the aggregated verdict via
|
|
14
|
+
`apply-council-verdict` (which is what advances `council → final-gate`/`implementing`/`escalated` and records the
|
|
15
|
+
authoritative security backstop for high-security tasks).
|
|
7
16
|
|
|
8
17
|
## Steps
|
|
9
18
|
|
|
@@ -14,7 +23,7 @@ description: Run the Security Reviewer agent on a task in the `security-review`
|
|
|
14
23
|
|
|
15
24
|
1. Capture the TASK-ID argument.
|
|
16
25
|
|
|
17
|
-
2. Load the task: `cloverleaf-cli load-task <repo_root> <TASK-ID>`.
|
|
26
|
+
2. Load the task: `cloverleaf-cli load-task <repo_root> <TASK-ID>`. 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 the current status and stop.
|
|
18
27
|
|
|
19
28
|
3. Confirm the branch `cloverleaf/<TASK-ID>` exists: `git rev-parse --verify cloverleaf/<TASK-ID>`. If missing, report the discrepancy and stop. Compute the diff for the subagent (do NOT check out): `git diff main..cloverleaf/<TASK-ID>`.
|
|
20
29
|
|
|
@@ -38,43 +47,39 @@ description: Run the Security Reviewer agent on a task in the `security-review`
|
|
|
38
47
|
- else any `error` or `warning` → `verdict: "bounce"`
|
|
39
48
|
- else (only `info`, or none) → `verdict: "pass"`
|
|
40
49
|
|
|
41
|
-
7. **
|
|
50
|
+
7. **Emit the verdict + envelope (no FSM advance).**
|
|
51
|
+
|
|
52
|
+
Record the member's `security_review_verdict` on the task (a live field the council's `council → final-gate` backstop reads for high-security tasks), then emit the merged feedback envelope. **Never call `advance-status`** — the council/human applies the aggregated verdict.
|
|
42
53
|
|
|
43
54
|
**Pass:**
|
|
44
55
|
```bash
|
|
45
56
|
cloverleaf-cli set-task-field <repo_root> <TASK-ID> security_review_verdict pass
|
|
46
57
|
git -C <repo_root> add .cloverleaf/ && git -C <repo_root> commit -m "cloverleaf: <TASK-ID> security_review_verdict → pass"
|
|
47
|
-
cloverleaf-cli advance-status <repo_root> <TASK-ID> automated-gates agent
|
|
48
|
-
git -C <repo_root> add .cloverleaf/ && git -C <repo_root> commit -m "cloverleaf: <TASK-ID> security review passed → automated-gates"
|
|
49
58
|
```
|
|
50
|
-
Report: "✓ Security
|
|
59
|
+
Report: "✓ Security Reviewer verdict: **pass**. Recorded `security_review_verdict=pass`. 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."
|
|
51
60
|
|
|
52
61
|
**Bounce:**
|
|
53
62
|
```bash
|
|
54
63
|
echo '<merged-envelope-json>' > /tmp/cloverleaf-fb-s.json
|
|
55
|
-
cloverleaf-cli write-feedback <repo_root> <TASK-ID> /tmp/cloverleaf-fb-s.json
|
|
64
|
+
cloverleaf-cli write-feedback <repo_root> <TASK-ID> /tmp/cloverleaf-fb-s.json --prefix=s
|
|
56
65
|
git -C <repo_root> add .cloverleaf/feedback/ && git -C <repo_root> commit -m "cloverleaf: <TASK-ID> security review feedback"
|
|
57
66
|
cloverleaf-cli set-task-field <repo_root> <TASK-ID> security_review_verdict bounce
|
|
58
67
|
git -C <repo_root> add .cloverleaf/ && git -C <repo_root> commit -m "cloverleaf: <TASK-ID> security_review_verdict → bounce"
|
|
59
|
-
cloverleaf-cli advance-status <repo_root> <TASK-ID> implementing agent
|
|
60
|
-
git -C <repo_root> add .cloverleaf/ && git -C <repo_root> commit -m "cloverleaf: <TASK-ID> security review bounced → implementing"
|
|
61
68
|
```
|
|
62
|
-
Report: "✗ Security
|
|
69
|
+
Report: "✗ Security Reviewer verdict: **bounce**. Findings: <summarize by severity>. Feedback emitted to `.cloverleaf/feedback/<TASK-ID>-s<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."
|
|
63
70
|
|
|
64
71
|
**Escalate (blocker found):**
|
|
65
72
|
```bash
|
|
66
73
|
echo '<merged-envelope-json>' > /tmp/cloverleaf-fb-s.json
|
|
67
|
-
cloverleaf-cli write-feedback <repo_root> <TASK-ID> /tmp/cloverleaf-fb-s.json
|
|
74
|
+
cloverleaf-cli write-feedback <repo_root> <TASK-ID> /tmp/cloverleaf-fb-s.json --prefix=s
|
|
68
75
|
git -C <repo_root> add .cloverleaf/feedback/ && git -C <repo_root> commit -m "cloverleaf: <TASK-ID> security review feedback"
|
|
69
76
|
cloverleaf-cli set-task-field <repo_root> <TASK-ID> security_review_verdict escalate
|
|
70
77
|
git -C <repo_root> add .cloverleaf/ && git -C <repo_root> commit -m "cloverleaf: <TASK-ID> security_review_verdict → escalate"
|
|
71
|
-
cloverleaf-cli advance-status <repo_root> <TASK-ID> escalated agent
|
|
72
|
-
git -C <repo_root> add .cloverleaf/ && git -C <repo_root> commit -m "cloverleaf: <TASK-ID> security review escalated (blocker finding)"
|
|
73
78
|
```
|
|
74
|
-
Report: "⚠ Security
|
|
79
|
+
Report: "⚠ Security Reviewer verdict: **escalate** — a BLOCKER was found. Recorded `security_review_verdict=escalate` and emitted feedback to `.cloverleaf/feedback/<TASK-ID>-s<N>.json`. A human MUST review `.cloverleaf/feedback/` before this can proceed. The council or a human applies the verdict (a council escalate is un-lowerable → `escalated`); this skill does not advance the FSM."
|
|
75
80
|
|
|
76
81
|
## Rules
|
|
77
82
|
|
|
78
83
|
- Never push. Read-only on source — the security reviewer does not modify code.
|
|
79
|
-
- A `blocker` (e.g. a leaked credential) ALWAYS
|
|
80
|
-
-
|
|
84
|
+
- A `blocker` (e.g. a leaked credential) ALWAYS yields an `escalate` verdict; never let a bounce loop silently "fix" it. The council/human enforces the terminal escalation.
|
|
85
|
+
- Emit-only: never call `advance-status`. This is one council member's verdict; the council/human applies it.
|
|
@@ -1,9 +1,24 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: cloverleaf-ui-review
|
|
3
|
-
description: Run the UI Reviewer
|
|
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
|
-
|
|
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)
|
|
64
|
+
git diff --cached --quiet || git commit -m "cloverleaf: <TASK-ID> ui-review skipped (no renderable routes)"
|
|
51
65
|
```
|
|
52
|
-
Report: "✓ UI
|
|
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,
|
|
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.
|
|
112
|
+
13. **Emit the verdict + envelope (no FSM advance).**
|
|
90
113
|
|
|
91
|
-
**
|
|
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
|
-
|
|
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
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
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.
|
|
125
|
-
2.
|
|
126
|
-
3.
|
|
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
|
-
-
|
|
133
|
-
-
|
|
134
|
-
-
|
|
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.
|