peaks-cli 1.3.2 → 1.3.4

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.
Files changed (115) hide show
  1. package/README.md +6 -2
  2. package/dist/src/cli/commands/core-artifact-commands.js +6 -3
  3. package/dist/src/cli/commands/gate-commands.js +28 -19
  4. package/dist/src/cli/commands/hook-handle.d.ts +17 -0
  5. package/dist/src/cli/commands/hook-handle.js +111 -0
  6. package/dist/src/cli/commands/hooks-commands.js +72 -21
  7. package/dist/src/cli/commands/progress-commands.js +9 -2
  8. package/dist/src/cli/commands/progress-start-spawn.js +30 -4
  9. package/dist/src/cli/commands/project-commands.js +8 -4
  10. package/dist/src/cli/commands/statusline-commands.js +75 -17
  11. package/dist/src/cli/commands/sub-agent-commands.d.ts +5 -0
  12. package/dist/src/cli/commands/sub-agent-commands.js +488 -0
  13. package/dist/src/cli/commands/sub-agent-dispatch-guard.d.ts +55 -0
  14. package/dist/src/cli/commands/sub-agent-dispatch-guard.js +57 -0
  15. package/dist/src/cli/commands/workflow-commands.js +2 -1
  16. package/dist/src/cli/commands/workspace-commands.js +3 -0
  17. package/dist/src/cli/program.js +9 -0
  18. package/dist/src/hooks/pre-tool-use-sub-agent.d.ts +28 -0
  19. package/dist/src/hooks/pre-tool-use-sub-agent.js +105 -0
  20. package/dist/src/services/config/config-types.d.ts +1 -1
  21. package/dist/src/services/context/artifact-meta.d.ts +72 -0
  22. package/dist/src/services/context/artifact-meta.js +105 -0
  23. package/dist/src/services/context/context-guard.d.ts +49 -0
  24. package/dist/src/services/context/context-guard.js +91 -0
  25. package/dist/src/services/context/dispatch-context-guard.d.ts +27 -0
  26. package/dist/src/services/context/dispatch-context-guard.js +192 -0
  27. package/dist/src/services/context/headroom-client.d.ts +34 -0
  28. package/dist/src/services/context/headroom-client.js +117 -0
  29. package/dist/src/services/context/shared-channel.d.ts +92 -0
  30. package/dist/src/services/context/shared-channel.js +285 -0
  31. package/dist/src/services/context/threshold.d.ts +35 -0
  32. package/dist/src/services/context/threshold.js +76 -0
  33. package/dist/src/services/dashboard/project-dashboard-service.d.ts +23 -0
  34. package/dist/src/services/dashboard/project-dashboard-service.js +21 -0
  35. package/dist/src/services/dispatch/batch-counter.d.ts +27 -0
  36. package/dist/src/services/dispatch/batch-counter.js +85 -0
  37. package/dist/src/services/dispatch/dispatch-record-writer.d.ts +93 -0
  38. package/dist/src/services/dispatch/dispatch-record-writer.js +261 -0
  39. package/dist/src/services/dispatch/heartbeat-truncator.d.ts +26 -0
  40. package/dist/src/services/dispatch/heartbeat-truncator.js +13 -0
  41. package/dist/src/services/dispatch/leak-detector.d.ts +11 -0
  42. package/dist/src/services/dispatch/leak-detector.js +72 -0
  43. package/dist/src/services/dispatch/sub-agent-dispatcher.d.ts +127 -0
  44. package/dist/src/services/dispatch/sub-agent-dispatcher.js +98 -0
  45. package/dist/src/services/ide/adapters/claude-code-adapter.d.ts +18 -0
  46. package/dist/src/services/ide/adapters/claude-code-adapter.js +80 -0
  47. package/dist/src/services/ide/adapters/trae-adapter.d.ts +42 -0
  48. package/dist/src/services/ide/adapters/trae-adapter.js +98 -0
  49. package/dist/src/services/ide/hook-protocol.d.ts +47 -0
  50. package/dist/src/services/ide/hook-protocol.js +74 -0
  51. package/dist/src/services/ide/hook-translator.d.ts +72 -0
  52. package/dist/src/services/ide/hook-translator.js +128 -0
  53. package/dist/src/services/ide/ide-detector.d.ts +10 -0
  54. package/dist/src/services/ide/ide-detector.js +19 -0
  55. package/dist/src/services/ide/ide-registry.d.ts +14 -0
  56. package/dist/src/services/ide/ide-registry.js +45 -0
  57. package/dist/src/services/ide/ide-types.d.ts +180 -0
  58. package/dist/src/services/ide/ide-types.js +2 -0
  59. package/dist/src/services/ide/resource-profile.d.ts +52 -0
  60. package/dist/src/services/ide/resource-profile.js +33 -0
  61. package/dist/src/services/ide/shared/atomic-json.d.ts +15 -0
  62. package/dist/src/services/ide/shared/atomic-json.js +58 -0
  63. package/dist/src/services/ide/shared/safe-path.d.ts +11 -0
  64. package/dist/src/services/ide/shared/safe-path.js +29 -0
  65. package/dist/src/services/memory/project-context-service.js +2 -1
  66. package/dist/src/services/memory/project-memory-service.js +4 -3
  67. package/dist/src/services/perf/perf-baseline-service.js +2 -1
  68. package/dist/src/services/progress/progress-service.d.ts +1 -1
  69. package/dist/src/services/progress/progress-service.js +18 -14
  70. package/dist/src/services/security/safe-settings-path.d.ts +12 -0
  71. package/dist/src/services/security/safe-settings-path.js +104 -0
  72. package/dist/src/services/session/getSessionDir.d.ts +1 -0
  73. package/dist/src/services/session/getSessionDir.js +27 -0
  74. package/dist/src/services/session/index.d.ts +1 -0
  75. package/dist/src/services/session/index.js +1 -0
  76. package/dist/src/services/signal/cancel-handler.d.ts +14 -0
  77. package/dist/src/services/signal/cancel-handler.js +76 -0
  78. package/dist/src/services/skill/resume-detector.d.ts +54 -0
  79. package/dist/src/services/skill/resume-detector.js +334 -0
  80. package/dist/src/services/skill/skill-scheduler.d.ts +40 -0
  81. package/dist/src/services/skill/skill-scheduler.js +53 -0
  82. package/dist/src/services/skills/hooks-settings-service.d.ts +47 -29
  83. package/dist/src/services/skills/hooks-settings-service.js +190 -144
  84. package/dist/src/services/skills/statusline-settings-service.d.ts +33 -6
  85. package/dist/src/services/skills/statusline-settings-service.js +31 -34
  86. package/dist/src/services/slice/slice-archive-service.d.ts +20 -0
  87. package/dist/src/services/slice/slice-archive-service.js +111 -0
  88. package/dist/src/services/solo/batch-heartbeat-poller.d.ts +51 -0
  89. package/dist/src/services/solo/batch-heartbeat-poller.js +88 -0
  90. package/dist/src/services/solo/status-line-renderer.d.ts +34 -0
  91. package/dist/src/services/solo/status-line-renderer.js +55 -0
  92. package/dist/src/services/standards/ide-aware-standards-service.d.ts +94 -0
  93. package/dist/src/services/standards/ide-aware-standards-service.js +89 -0
  94. package/dist/src/services/standards/project-standards-service.d.ts +1 -2
  95. package/dist/src/services/workspace/reconcile-service.d.ts +36 -0
  96. package/dist/src/services/workspace/reconcile-service.js +107 -6
  97. package/dist/src/services/workspace/reconcile-types.d.ts +12 -0
  98. package/dist/src/shared/version.d.ts +1 -1
  99. package/dist/src/shared/version.js +1 -1
  100. package/package.json +2 -1
  101. package/scripts/install-skills.mjs +112 -2
  102. package/skills/peaks-ide/SKILL.md +159 -0
  103. package/skills/peaks-ide/references/audit-log-helper.md +52 -0
  104. package/skills/peaks-qa/SKILL.md +153 -55
  105. package/skills/peaks-qa/references/qa-fanout-contract.md +150 -0
  106. package/skills/peaks-rd/SKILL.md +134 -62
  107. package/skills/peaks-solo/SKILL.md +124 -37
  108. package/skills/peaks-solo/references/browser-workflow.md +22 -20
  109. package/skills/peaks-solo/references/context-governance.md +144 -0
  110. package/skills/peaks-solo/references/headroom-integration.md +107 -0
  111. package/skills/peaks-solo/references/runbook.md +3 -3
  112. package/skills/peaks-solo/references/sub-agent-dispatch.md +261 -0
  113. package/skills/peaks-solo/references/swarm-dispatch-contract.md +3 -37
  114. package/skills/peaks-txt/SKILL.md +17 -0
  115. package/skills/peaks-ui/SKILL.md +45 -10
@@ -3,6 +3,36 @@ name: peaks-qa
3
3
  description: QA and verification skill for Peaks. Use when a workflow needs unit-test coverage evidence, regression matrices, baseline reports, validation reports, acceptance checks, or refactor verification gates.
4
4
  ---
5
5
 
6
+ ## Two-axis naming convention
7
+
8
+ > **Read once at the top of this file; the rest of the skill is written against it.**
9
+
10
+ The `.peaks/` workspace is partitioned by **two orthogonal axes**. Every path in this SKILL.md uses one of them; mixing them is the original `.peaks/<sid>/` / `.peaks/_runtime/<sid>/` bug class this slice corrects.
11
+
12
+ | Axis | Path root | Holds | When to use |
13
+ |---|---|---|---|
14
+ | **change-id axis** (reviewable artifacts) | `.peaks/<changeId>/...` | PRD, RD plan, code-review, security-review, test-cases, handoff capsules, gate targets | The artifact should be reviewable on its own and survives across sessions for the same change. Change-id is the unit of work. |
15
+ | **session-id axis** (ephemeral state) | `.peaks/_runtime/<sessionId>/...` | Session bindings (`.peaks/_runtime/session.json`), live in-flight state, the per-session project-scan and tech-doc scaffold while the session is open | The artifact is session-scoped and only meaningful while the parent session is live. |
16
+ | **sub-agent axis** | `.peaks/_sub_agents/<sessionId>/...` | Sub-agent dispatch records, sub-agent heartbeats, per-sub-agent shared channel entries, sub-agent artifact outputs | A sub-agent ran in a parent session. The axis nests under the parent session-id; sub-agent outputs are flushed into the change-id root on commit. |
17
+
18
+ **Which CLI commands operate on which axis:**
19
+
20
+ - **change-id axis** (reviewable artifacts): `peaks request init`, `peaks request transition`, `peaks request show`, `peaks request lint`, `peaks request repair-status`, `peaks scan diff-vs-scope`, `peaks scan acceptance-coverage`. Inputs reference `.peaks/<changeId>/...`.
21
+ - **session-id axis** (ephemeral state): `peaks session info`, `peaks session start`, `peaks session finish`, `peaks session list`. Reads/writes `.peaks/_runtime/<sessionId>/session.json`.
22
+ - **sub-agent axis** (under parent session-id): `peaks sub-agent dispatch`, `peaks sub-agent heartbeat`, `peaks sub-agent share`, `peaks sub-agent shared-read`. All output paths are under `.peaks/_sub_agents/<sessionId>/...`.
23
+
24
+ **Placeholder convention used in this file:**
25
+
26
+ - `<changeId>` / `<change-id>` — the change-id axis. Use when describing a path that lives at `.peaks/<changeId>/...` (root-level, NOT inside `_runtime/`).
27
+ - `<sessionId>` / `<session-id>` — the session-id axis. Use when describing a path that lives at `.peaks/_runtime/<sessionId>/...` or `.peaks/_sub_agents/<sessionId>/...`. The long form `<session-id>` is used inside bash / shell examples where `<sessionId>` would break parsing.
28
+ - The bare `<sid>` placeholder is **forbidden** in new content — it is ambiguous between the two axes. Legacy occurrences are replaced by this convention; new content must use the right axis label.
29
+
30
+ **Cross-references:**
31
+
32
+ - Slice `2026-06-05-change-id-as-unit-of-work` (commits `48958fc` + `928eb53`) — established the change-id axis as the canonical root for reviewable artifacts (`src/shared/change-id.ts:131,335`, `src/services/scan/acceptance-coverage-service.ts:155`).
33
+ - Slice `005-session-runtime-dir-regression` (commit `178a47e`) — added the `getSessionDir()` resolver at `src/services/session/getSessionDir.ts` and routed 4 stragglers that were constructing `.peaks/${sessionId}` (no `_runtime/`) through the canonical resolver. Defense-in-depth scan: `tests/unit/services/session/session-dir-canonical.test.ts`.
34
+ - Slice `006-5th-writer-changeid-path` (this slice) — disambiguates the SKILL.md placeholders and adds the regression test `tests/unit/skills/skills-skill-md-naming.test.ts` that mechanically enforces (a) zero bare `<sid>`, (b) every `.peaks/<X>/` reference has an axis label, (c) the "Two-axis naming convention" callout is present in `peaks-solo`, `peaks-rd`, `peaks-qa`.
35
+
6
36
  # Peaks-Cli QA
7
37
 
8
38
  Peaks-Cli QA proves that planned changes are protected and accepted.
@@ -11,29 +41,31 @@ Peaks-Cli QA proves that planned changes are protected and accepted.
11
41
 
12
42
  These two contracts are non-negotiable. The previous prose-only phrasing let the LLM skip the browser gate entirely when an auth wall appeared, and let screenshots land in the project root because the LLM forgot to pass `filename`. Both fail modes are blocking violations; the rules below are what a reviewer should hold the skill to.
13
43
 
14
- ### Contract 1 — Screenshot path is mandatory and must land under .peaks/<sid>/qa/screenshots/
44
+ ### Contract 1 — Screenshot path is mandatory and must land under .peaks/_runtime/<sessionId>/qa/screenshots/
15
45
 
16
- Every `mcp__playwright__browser_take_screenshot` call **MUST** pass `filename` whose absolute path is **inside** `.peaks/<session-id>/qa/screenshots/`. Concrete form:
46
+ Every Playwright screenshot tool call (via `peaks mcp call --capability playwright-mcp.browser-validation --tool browser_take_screenshot --args-json '<args>' --json`) **MUST** pass `filename` (in the args object) whose absolute path is **inside** `.peaks/_runtime/<sessionId>/qa/screenshots/`. Concrete form:
17
47
 
18
48
  ```bash
19
- mcp__playwright__browser_take_screenshot \
20
- filename=".peaks/<sid>/qa/screenshots/<state-or-step>.png" \
21
- fullPage=true
49
+ peaks mcp call \
50
+ --capability playwright-mcp.browser-validation \
51
+ --tool browser_take_screenshot \
52
+ --args-json '{"filename":".peaks/_runtime/<session-id>/qa/screenshots/<state-or-step>.png","fullPage":true}' \
53
+ --json
22
54
  ```
23
55
 
24
- The default behaviour of Playwright MCP when `filename` is omitted or points outside that directory is to write a screenshot to the current working directory, which leaves `.png` files scattered at the project root. **This is a workflow violation.** If a screenshot does land outside `.peaks/<sid>/qa/screenshots/` for any reason (e.g. an upstream tool wrote there), QA MUST move it into that directory before declaring the test report complete; do not commit project-root `.png` files. Sanitise before retention: no login URLs, cookies, headers, tokens, storage state, browser traces, or screenshots/logs containing PII or SSO/MFA material.
56
+ The default behaviour of Playwright MCP when `filename` is omitted or points outside that directory is to write a screenshot to the current working directory, which leaves `.png` files scattered at the project root. **This is a workflow violation.** If a screenshot does land outside `.peaks/_runtime/<session-id>/qa/screenshots/` for any reason (e.g. an upstream tool wrote there), QA MUST move it into that directory before declaring the test report complete; do not commit project-root `.png` files. Sanitise before retention: no login URLs, cookies, headers, tokens, storage state, browser traces, or screenshots/logs containing PII or SSO/MFA material.
25
57
 
26
58
  This rule is enforced by a Peaks-Cli preflight check inside this skill:
27
59
 
28
60
  ```bash
29
61
  # After every browser_take_screenshot batch and before declaring the test report complete:
30
- ls .peaks/<sid>/qa/screenshots/*.png 2>&1
62
+ ls .peaks/_runtime/<session-id>/qa/screenshots/*.png 2>&1
31
63
  # Expected: at least one .png file under the screenshots directory.
32
64
  # "No such file" → BLOCKED. Either the screenshot was never taken, or
33
65
  # it landed in the project root (move it before continuing).
34
66
  find . -maxdepth 1 -name '*.png' 2>&1
35
67
  # Expected: empty. Any .png at the project root is a leak — move it
36
- # to .peaks/<sid>/qa/screenshots/ before completing this skill.
68
+ # to .peaks/_runtime/<session-id>/qa/screenshots/ before completing this skill.
37
69
  ```
38
70
 
39
71
  ### Contract 2 — Login / CAPTCHA / SSO / MFA wall is a hard block, not a skip
@@ -60,10 +92,40 @@ This is the hard-block replacement for the previous "wait for the user" prose. W
60
92
 
61
93
  ## Sub-agent dispatch (when launched by peaks-solo swarm)
62
94
 
63
- When this skill is launched as a sub-agent via `Task(subagent_type="general-purpose", ...)` from `peaks-solo`, the following sections of THIS skill are **suspended** for the sub-agent run:
95
+ When this skill is launched as a sub-agent via `peaks sub-agent dispatch <role>` (then the LLM executes the returned toolCall) from `peaks-solo`, the following sections of THIS skill are **suspended** for the sub-agent run:
96
+
97
+ ## QA fan-out (业务 + 性能 + 安全 并发, 业务可再分)
98
+
99
+ When peaks-qa is the **main loop** (i.e. it is the active skill and is about to run its own sub-agent dispatch, rather than being a sub-agent itself), it fans out the 3 QA review activities concurrently using the same `peaks sub-agent dispatch` primitive:
100
+
101
+ ```
102
+ peaks sub-agent dispatch qa-business \
103
+ --prompt "<qa-business contract, plus runtime args project=<repo>, session-id=<session-id>, request-id=<rid>>" \
104
+ --request-id <rid> --session-id <session-id> --project <repo> --json
105
+
106
+ peaks sub-agent dispatch qa-perf \
107
+ --prompt "<qa-perf contract, plus runtime args>" \
108
+ --request-id <rid> --session-id <session-id> --project <repo> --json
109
+
110
+ peaks sub-agent dispatch qa-security \
111
+ --prompt "<qa-security contract, plus runtime args>" \
112
+ --request-id <rid> --session-id <session-id> --project <repo> --json
113
+ ```
114
+
115
+ All three are issued in a single message; the LLM fires all 3 returned toolCalls in parallel; the IDE runs them concurrently; peaks-qa then collects the three envelopes and merges their outputs into:
116
+
117
+ - `.peaks/_runtime/<sessionId>/qa/test-reports/<rid>.md` (business findings)
118
+ - `.peaks/_runtime/<sessionId>/qa/performance-findings.md` (perf findings)
119
+ - `.peaks/_runtime/<sessionId>/qa/security-findings.md` (security findings)
120
+
121
+ ## 业务测试细分 (optional)
122
+
123
+ If the PRD or project warrants it, subdivide `qa-business` further into roles like `qa-business-api` / `qa-business-frontend` / `qa-business-regression`; each gets its own `peaks sub-agent dispatch` call. Names are convention not contract — the dispatcher accepts any non-empty string. **Subdivision must stay ≤ 2 levels deep** (RL-4): `qa-business-api` is fine, `qa-business-api-user` is not. Two levels of depth is the empirical sweet spot — past that, the reducer cannot audit the boundaries between sub-agents, and prompts start overlapping.
124
+
125
+ For the full contract (heartbeat instructions for each sub-agent, batch-id discipline, 30s cadence, 100-truncation, 5min stale) see `skills/peaks-qa/references/qa-fanout-contract.md` and `skills/peaks-solo/references/sub-agent-dispatch.md` §G6.
64
126
 
65
127
  - **Session id** — use the parent's sid (read `.peaks/_runtime/session.json` or pass `--session-id <parent-sid>` to any session-creating CLI). Do NOT spawn your own session. The new `peaks session info --active` reads the canonical binding for you.
66
- - **Skill presence (MANDATORY first action)** — do NOT call `peaks skill presence:set peaks-qa`. The sub-agent must not overwrite `.peaks/.active-skill.json`; the main Solo loop owns that file. If you need to mark your own state, write a marker file at `.peaks/<session-id>/system/sub-agent-qa.json` and only that.
128
+ - **Skill presence (MANDATORY first action)** — do NOT call `peaks skill presence:set peaks-qa`. The sub-agent must not overwrite `.peaks/.active-skill.json`; the main Solo loop owns that file. If you need to mark your own state, write a marker file at `.peaks/_runtime/<sessionId>/system/sub-agent-qa.json` and only that.
67
129
  - **Workspace initialization** — Solo has already run `peaks workspace init` before fan-out. Do not re-run it.
68
130
  - **Mode selection** — Solo has already chosen the mode.
69
131
  - **Statusline install** — already done by Solo at session startup.
@@ -73,7 +135,7 @@ What the sub-agent **MUST** still do:
73
135
  0. **Do NOT call `peaks request init`** — Solo has already initialised the request artefact slot in the main loop before fan-out. The sub-agent reads it via `peaks request show <rid> --role qa --project <repo> --json` if it needs to.
74
136
  2. `peaks request show <rid> --role prd --project <repo> --json` (and `--role rd`, `--role ui` if UI is in the swarm plan).
75
137
  3. Standards preflight (dry-run only).
76
- 4. Write `.peaks/<session-id>/qa/test-cases/<rid>.md` with test cases that link to PRD acceptance items.
138
+ 4. Write `.peaks/_runtime/<sessionId>/qa/test-cases/<rid>.md` with test cases that link to PRD acceptance items.
77
139
  5. Return only a compact JSON envelope:
78
140
 
79
141
  ```json
@@ -81,7 +143,7 @@ What the sub-agent **MUST** still do:
81
143
  "role": "qa-test-cases",
82
144
  "rid": "<rid>",
83
145
  "status": "ok" | "blocked" | "skipped",
84
- "artefacts": [".peaks/<sid>/qa/test-cases/<rid>.md"],
146
+ "artefacts": [".peaks/_runtime/<sessionId>/qa/test-cases/<rid>.md"],
85
147
  "warnings": [],
86
148
  "blockedReason": null
87
149
  }
@@ -137,9 +199,9 @@ Every QA invocation — feature, bug, refactor, clarification — must write **t
137
199
 
138
200
  | # | File | Path | Reader | Content |
139
201
  |---|------|------|--------|---------|
140
- | 1 | Test cases | `.peaks/<session-id>/qa/test-cases/<request-id>.md` | RD (before impl), QA | Generated test scenarios with status |
141
- | 2 | Test report | `.peaks/<session-id>/qa/test-reports/<request-id>.md` | QA, SC, Solo | Summary, coverage%, security, perf, risks |
142
- | 3 | Request artifact | `.peaks/<session-id>/qa/requests/<request-id>.md` | Solo, RD↔QA loop | Verdict, boundary check, links to #1 and #2 |
202
+ | 1 | Test cases | `.peaks/_runtime/<sessionId>/qa/test-cases/<request-id>.md` | RD (before impl), QA | Generated test scenarios with status |
203
+ | 2 | Test report | `.peaks/_runtime/<sessionId>/qa/test-reports/<request-id>.md` | QA, SC, Solo | Summary, coverage%, security, perf, risks |
204
+ | 3 | Request artifact | `.peaks/_runtime/<sessionId>/qa/requests/<request-id>.md` | Solo, RD↔QA loop | Verdict, boundary check, links to #1 and #2 |
143
205
 
144
206
  Concrete template and rules: `references/artifact-per-request.md`.
145
207
 
@@ -167,12 +229,12 @@ peaks codegraph affected --project <repo> <changed-files...> --json # regressi
167
229
  peaks openspec validate <change-id> --project <repo> --json
168
230
  peaks openspec validate <change-id> --project <repo> --prefer-external --json # optional
169
231
 
170
- # 4. generate test cases — MANDATORY, write to .peaks/<session-id>/qa/test-cases/<request-id>.md
232
+ # 4. generate test cases — MANDATORY, write to .peaks/_runtime/<sessionId>/qa/test-cases/<request-id>.md
171
233
  # categories: unit, integration, UI regression (frontend only)
172
234
  #
173
235
  # Optimization (slice 004): peaks-rd's parallel fan-out now includes a 4th
174
236
  # sub-agent (`qa-test-cases-writer`) that pre-drafts this file at the
175
- # end of RD implementation. If `.peaks/<sid>/qa/test-cases/<rid>.md`
237
+ # end of RD implementation. If `.peaks/_runtime/<sessionId>/qa/test-cases/<rid>.md`
176
238
  # already exists when QA's main loop reaches this step, **QA does NOT
177
239
  # re-draft it** — it just verifies the file is present and the
178
240
  # per-criterion `ts` snippets are syntactically valid, then proceeds
@@ -183,8 +245,8 @@ peaks openspec validate <change-id> --project <repo> --prefer-external --json
183
245
 
184
246
  # 5. EXECUTE tests against the actual implementation — Peaks-Cli Gate A2
185
247
  # Run the project test command. Record output. Tests on paper are worthless.
186
- # Peaks-Cli Gate A3: Run security review → .peaks/<id>/qa/security-findings.md
187
- # Peaks-Cli Gate A4: Run performance check → .peaks/<id>/qa/performance-findings.md
248
+ # Peaks-Cli Gate A3: Run security review → .peaks/<changeId>/qa/security-findings.md
249
+ # Peaks-Cli Gate A4: Run performance check → .peaks/<changeId>/qa/performance-findings.md
188
250
  # CRITICAL: Peaks-Cli Gate A3 and Peaks-Cli Gate A4 are NON-NEGOTIABLE. You MUST run actual security
189
251
  # and performance checks — not just write a checklist item. These gates exist
190
252
  # because code review alone does not catch: hardcoded secrets, XSS vectors,
@@ -192,7 +254,7 @@ peaks openspec validate <change-id> --project <repo> --prefer-external --json
192
254
  # If you skip A3 or A4, Peaks-Cli Gate C will block the verdict.
193
255
  #
194
256
  # Before running A4, read the RD's perf-baseline at
195
- # .peaks/<id>/rd/perf-baseline.md (if present) and use the
257
+ # .peaks/<changeId>/rd/perf-baseline.md (if present) and use the
196
258
  # captured thresholds as the comparison baseline. The QA stage
197
259
  # is still responsible for running the actual measurement
198
260
  # (lighthouse / k6 / autocannon / project-local bench) and
@@ -204,7 +266,7 @@ peaks openspec validate <change-id> --project <repo> --prefer-external --json
204
266
  # surface that absence in the QA test-report under a
205
267
  # `## Performance baseline` section.
206
268
 
207
- # 6. write test-report — MANDATORY, write to .peaks/<session-id>/qa/test-reports/<request-id>.md
269
+ # 6. write test-report — MANDATORY, write to .peaks/_runtime/<sessionId>/qa/test-reports/<request-id>.md
208
270
  # MUST contain actual execution results (pass/fail counts, coverage %, findings).
209
271
  # A template with placeholder text does not pass Peaks-Cli Gate B.
210
272
 
@@ -227,19 +289,23 @@ peaks mcp apply --capability playwright-mcp.browser-validation --yes --json
227
289
  # and does NOT satisfy Peaks-Cli Gate D. Treating prod build as a fallback is a workflow violation.
228
290
  # 4. After browser validation completes, KILL the dev server. Do not leave it running.
229
291
  # Playwright MCP MUST simulate real user operations — not just take static screenshots.
230
- # The minimum interaction sequence for every frontend page/flow:
231
- # mcp__playwright__browser_navigate → URL (after allow-list), launches headed browser
232
- # mcp__playwright__browser_snapshot → accessibility tree per regression seed
233
- # mcp__playwright__browser_click → click buttons, tabs, links, modals
234
- # mcp__playwright__browser_type → type into form fields, search inputs
235
- # mcp__playwright__browser_select_option → select dropdown values
236
- # mcp__playwright__browser_fill_form → fill complete forms as a user would
237
- # mcp__playwright__browser_take_screenshot → capture each state AFTER interaction
238
- # mcp__playwright__browser_console_messages + browser_network_requests error feedback loop
239
- # mcp__playwright__browser_wait_for → wait for async data to render
240
- # mcp__playwright__browser_close → end the session cleanly
292
+ # The minimum interaction sequence for every frontend page/flow uses the peaks mcp
293
+ # plan/apply/call pattern (skill body NEVER bakes in the bare MCP tool prefix;
294
+ # the prefix is owned by the LLM runtime). The four steps:
295
+ # 1. Detect install: peaks mcp list --json | grep playwright
296
+ # 2. Plan: peaks mcp plan --capability playwright-mcp.browser-validation --json
297
+ # (read envCheck.missing; if non-empty, refuse to apply and ask the user to set the env vars)
298
+ # 3. Apply: peaks mcp apply --capability playwright-mcp.browser-validation --yes --json
299
+ # 4. Call tools: peaks mcp call --capability playwright-mcp.browser-validation \
300
+ # --tool <toolName> --args-json '<argsObject>' --json
301
+ # Tool names (resolved by the LLM from the registered server, NOT hardcoded here):
302
+ # browser_navigate / browser_snapshot / browser_click / browser_type /
303
+ # browser_select_option / browser_fill_form / browser_take_screenshot /
304
+ # browser_console_messages / browser_network_requests / browser_wait_for / browser_close.
241
305
  # Static screenshots without user-interaction simulation do NOT pass this gate.
242
306
  # Block QA pass if Playwright MCP is unavailable.
307
+ # For sub-agents dispatched via `peaks sub-agent dispatch` (where the LLM cannot
308
+ # directly call MCP tools via the bare prefix), use `peaks mcp call` for every MCP operation.
243
309
  #
244
310
  # CLEANUP: After browser validation completes (all screenshots saved, console/network
245
311
  # evidence captured), QA MUST kill every process it started during verification.
@@ -284,8 +350,8 @@ You cannot declare a phase complete from memory. Each gate below is a `ls` or `g
284
350
 
285
351
  **Peaks-Cli Gate A — After test-case generation:**
286
352
  ```bash
287
- ls .peaks/<id>/qa/test-cases/<rid>.md
288
- # Expected output: .peaks/<id>/qa/test-cases/<rid>.md
353
+ ls .peaks/<changeId>/qa/test-cases/<rid>.md
354
+ # Expected output: .peaks/<changeId>/qa/test-cases/<rid>.md
289
355
  # "No such file" → STOP, generate test cases first. Do not proceed to validation.
290
356
  ```
291
357
 
@@ -302,8 +368,8 @@ npx vitest run --reporter=verbose 2>&1 | tail -30
302
368
  **Peaks-Cli Gate A3 — Security test executed (NOT just a checklist item):**
303
369
  ```bash
304
370
  # Run security review against the changed surface. Record findings.
305
- ls .peaks/<id>/qa/security-findings.md 2>&1
306
- # Expected: .peaks/<id>/qa/security-findings.md
371
+ ls .peaks/<changeId>/qa/security-findings.md 2>&1
372
+ # Expected: .peaks/<changeId>/qa/security-findings.md
307
373
  # "No such file" → BLOCKED. Run security review against changed files,
308
374
  # record every finding with severity, then re-check.
309
375
  ```
@@ -311,30 +377,30 @@ ls .peaks/<id>/qa/security-findings.md 2>&1
311
377
  **Peaks-Cli Gate A4 — Performance test executed:**
312
378
  ```bash
313
379
  # Run available performance check against the changed surface. Record findings.
314
- ls .peaks/<id>/qa/performance-findings.md 2>&1
315
- # Expected: .peaks/<id>/qa/performance-findings.md
380
+ ls .peaks/<changeId>/qa/performance-findings.md 2>&1
381
+ # Expected: .peaks/<changeId>/qa/performance-findings.md
316
382
  # "No such file" → BLOCKED. Run performance check (build-size, Lighthouse,
317
383
  # bundle analysis, or project equivalent), record baseline vs. after, then re-check.
318
384
  ```
319
385
 
320
386
  **Peaks-Cli Gate B — After test-report write (MUST contain execution results, not just planned cases):**
321
387
  ```bash
322
- ls .peaks/<id>/qa/test-reports/<rid>.md
323
- # Expected output: .peaks/<id>/qa/test-reports/<rid>.md
388
+ ls .peaks/<changeId>/qa/test-reports/<rid>.md
389
+ # Expected output: .peaks/<changeId>/qa/test-reports/<rid>.md
324
390
  # "No such file" → STOP, write the test report first. Do not issue a verdict.
325
391
  # Additionally verify the report is not a placeholder:
326
- grep -c "pass\|fail\|blocked" .peaks/<id>/qa/test-reports/<rid>.md
392
+ grep -c "pass\|fail\|blocked" .peaks/<changeId>/qa/test-reports/<rid>.md
327
393
  # Expected: non-zero count (report contains actual pass/fail/blocked results)
328
394
  # Zero → the report is empty/template-only. Tests were not executed.
329
395
  ```
330
396
 
331
397
  **Peaks-Cli Gate C — Before issuing verdict:**
332
398
  ```bash
333
- ls .peaks/<id>/qa/test-cases/<rid>.md \
334
- .peaks/<id>/qa/test-reports/<rid>.md \
335
- .peaks/<id>/qa/security-findings.md \
336
- .peaks/<id>/qa/performance-findings.md \
337
- .peaks/<id>/qa/requests/<rid>.md
399
+ ls .peaks/<changeId>/qa/test-cases/<rid>.md \
400
+ .peaks/<changeId>/qa/test-reports/<rid>.md \
401
+ .peaks/<changeId>/qa/security-findings.md \
402
+ .peaks/<changeId>/qa/performance-findings.md \
403
+ .peaks/<changeId>/qa/requests/<rid>.md
338
404
  # All five must exist. Missing any → QA incomplete, verdict blocked.
339
405
  # NOTE: security-findings.md and performance-findings.md are NOT optional.
340
406
  # If you can't run a full security scan, run at minimum: grep for secrets,
@@ -345,7 +411,7 @@ ls .peaks/<id>/qa/test-cases/<rid>.md \
345
411
 
346
412
  **Peaks-Cli Gate E — Acceptance coverage (every PRD acceptance item has a linked test case):**
347
413
  ```bash
348
- peaks scan acceptance-coverage --rid <rid> --project <repo> --session-id <sid> --json
414
+ peaks scan acceptance-coverage --rid <rid> --project <repo> --session-id <session-id> --json
349
415
  # Expected: ok=true. exit 0.
350
416
  # uncovered[] non-empty → BLOCKED. List of acceptance items without test cases is in the output.
351
417
  # Add `- **Acceptance:** A<N>` lines to the matching test cases in qa/test-cases/<rid>.md, then re-run.
@@ -357,7 +423,7 @@ peaks scan acceptance-coverage --rid <rid> --project <repo> --session-id <sid> -
357
423
 
358
424
  **Peaks-Cli Gate F — QA artifact body has no unfilled placeholders:**
359
425
  ```bash
360
- peaks request lint <rid> --role qa --project <repo> --session-id <sid> --json
426
+ peaks request lint <rid> --role qa --project <repo> --session-id <session-id> --json
361
427
  # Expected: ok=true. exit 0.
362
428
  # ok=false → BLOCKED. Lint output lists every <placeholder>, "- ..." stub, and TBD marker.
363
429
  # Fill them in before issuing the verdict.
@@ -367,7 +433,7 @@ peaks request lint <rid> --role qa --project <repo> --session-id <sid> --json
367
433
  ```bash
368
434
  # Verify browser screenshots exist. Screenshots are the only acceptable evidence
369
435
  # that Playwright MCP actually launched and interacted with the running app.
370
- ls .peaks/<id>/qa/screenshots/*.png 2>&1
436
+ ls .peaks/<changeId>/qa/screenshots/*.png 2>&1
371
437
  # Expected: one or more .png files
372
438
  # "No such file" → BLOCKED. Playwright MCP was not used or screenshots not saved.
373
439
  # Screenshots, logs, manual steps, or other tools must NOT substitute for this gate.
@@ -379,7 +445,7 @@ ls .peaks/<id>/qa/screenshots/*.png 2>&1
379
445
  ```
380
446
  ```bash
381
447
  # Verify console and network checks were actually performed
382
- grep -c "browser_console_messages\|browser_network_requests" .peaks/<id>/qa/test-reports/<rid>.md
448
+ grep -c "browser_console_messages\|browser_network_requests" .peaks/<changeId>/qa/test-reports/<rid>.md
383
449
  # Expected: non-zero count (means console/network were checked)
384
450
  # Zero → BLOCKED. Browser error feedback loop was not executed.
385
451
  ```
@@ -417,7 +483,7 @@ Before QA passes or returns work to RD, it must independently recheck the implem
417
483
 
418
484
  ## Mandatory test-case generation
419
485
 
420
- QA must generate test cases, not merely inspect existing ones. Every QA invocation that validates code changes must produce a test-case artifact at `.peaks/<session-id>/qa/test-cases/<request-id>.md`.
486
+ QA must generate test cases, not merely inspect existing ones. Every QA invocation that validates code changes must produce a test-case artifact at `.peaks/_runtime/<sessionId>/qa/test-cases/<request-id>.md`.
421
487
 
422
488
  **Minimum test-case categories:**
423
489
 
@@ -445,7 +511,7 @@ QA must generate test cases, not merely inspect existing ones. Every QA invocati
445
511
 
446
512
  ## Mandatory test-report output
447
513
 
448
- Every QA invocation must produce a test-report artifact at `.peaks/<session-id>/qa/test-reports/<request-id>.md`. This is separate from both the test-case file and the request artifact — do not merge.
514
+ Every QA invocation must produce a test-report artifact at `.peaks/_runtime/<sessionId>/qa/test-reports/<request-id>.md`. This is separate from both the test-case file and the request artifact — do not merge.
449
515
 
450
516
  **Minimum test-report sections:**
451
517
 
@@ -466,7 +532,13 @@ QA cannot pass a change until the report contains evidence for every applicable
466
532
  1. **Test-report** — enforced by Peaks-Cli Gate B.
467
533
  2. **Unit tests** — run the project test command or a focused test command that covers new/changed code. For legacy projects below the target coverage, require coverage for the new or changed code rather than failing on pre-existing uncovered code.
468
534
  3. **API validation** — when the change touches API contracts, data loading, request handling, auth, or integrations, exercise the relevant API path and record request/response evidence or a justified local substitute.
469
- 4. **Frontend browser validation** — when the repository has a frontend or the change affects UI, launch the app and use Playwright MCP for real browser end-to-end validation. This means **simulating real user operations**: clicking buttons, filling forms, selecting dropdowns, navigating between pages, waiting for async data to render, and verifying each resulting state. Static screenshots without interaction are insufficient. Confirm Playwright MCP is installed via `peaks mcp list --json`; install through `peaks mcp plan/apply --capability playwright-mcp.browser-validation --yes` if missing. Use `mcp__playwright__browser_navigate` (launches headed browser), `mcp__playwright__browser_click` (simulate clicks on tabs/buttons/links), `mcp__playwright__browser_type` (type into inputs), `mcp__playwright__browser_select_option` (select dropdowns), `mcp__playwright__browser_fill_form` (fill complete forms), `mcp__playwright__browser_wait_for` (wait for async rendering), and `mcp__playwright__browser_take_screenshot` (capture state after each interaction). If login, CAPTCHA, SSO, or MFA appears, the visible browser is already open; wait for the user to complete login and explicitly confirm completion before continuing. Capture sanitized interaction sequences, sanitized screenshots per state, sanitized console (`browser_console_messages`) and network (`browser_network_requests`) failures. Close with `mcp__playwright__browser_close` when done. (Chrome DevTools MCP is an optional secondary surface for CDP inspection of an already-running Chrome on `:9222`; it does NOT launch a browser and cannot simulate user interaction.)
535
+ 4. **Frontend browser validation** — when the repository has a frontend or the change affects UI, launch the app and use Playwright MCP for real browser end-to-end validation. This means **simulating real user operations**: clicking buttons, filling forms, selecting dropdowns, navigating between pages, waiting for async data to render, and verifying each resulting state. Static screenshots without interaction are insufficient. Confirm Playwright MCP is installed via `peaks mcp list --json`; install through `peaks mcp plan/apply --capability playwright-mcp.browser-validation --yes` if missing. Route every browser interaction through the canonical `peaks mcp call` envelope:
536
+
537
+ ```
538
+ peaks mcp call --capability playwright-mcp.browser-validation --tool <toolName> --args-json '<argsObject>' --json
539
+ ```
540
+
541
+ The Playwright tool names that drive validation are: `browser_navigate` (launches headed browser), `browser_click` (simulate clicks on tabs/buttons/links), `browser_type` (type into inputs), `browser_select_option` (select dropdowns), `browser_fill_form` (fill complete forms), `browser_wait_for` (wait for async rendering), `browser_take_screenshot` (capture state after each interaction), `browser_close` (close the browser when done), `browser_console_messages` (read console failures), and `browser_network_requests` (read network failures). The bare server-and-tool MCP prefix is owned by the LLM runtime, not by the skill body — never bake the prefix into this SKILL.md or any artifact QA emits. If login, CAPTCHA, SSO, or MFA appears, the visible browser is already open; wait for the user to complete login and explicitly confirm completion before continuing. Capture sanitized interaction sequences, sanitized screenshots per state, sanitized console (`browser_console_messages`) and network (`browser_network_requests`) failures. (Chrome DevTools MCP is an optional secondary surface for CDP inspection of an already-running Chrome on `:9222`; it does NOT launch a browser and cannot simulate user interaction.)
470
542
  5. **Browser-error feedback loop** — if Playwright MCP observation surfaces a page error, console exception, broken network request, hydration/render failure, or visible regression, return the work to RD/development with the exact evidence. Do not pass QA until the fixed build is retested in the browser.
471
543
  6. **Security check** — run security review for the changed surface and dependency/config changes. Record findings, fixes, and unresolved risks.
472
544
  7. **Performance check** — run the project’s available performance check, build-size check, Lighthouse-equivalent check, or browser performance inspection appropriate to the change. Record baseline/after numbers when available.
@@ -479,7 +551,7 @@ If Playwright MCP is unavailable (not installed and the user has not authorized
479
551
 
480
552
  ## Local intermediate artifacts
481
553
 
482
- QA reports, sanitized browser evidence, logs, matrices, and validation summaries should be written to `.peaks/<session-id>/qa/` by default, or to the Peaks-Cli CLI-provided local artifact workspace. Do not store login URLs, cookies, headers, tokens, storage state, browser traces, or screenshots/logs containing PII or SSO/MFA material. Do not default to git-backed storage or external artifact sync unless the user or active profile explicitly authorizes it.
554
+ QA reports, sanitized browser evidence, logs, matrices, and validation summaries should be written to `.peaks/_runtime/<sessionId>/qa/` by default, or to the Peaks-Cli CLI-provided local artifact workspace. Do not store login URLs, cookies, headers, tokens, storage state, browser traces, or screenshots/logs containing PII or SSO/MFA material. Do not default to git-backed storage or external artifact sync unless the user or active profile explicitly authorizes it.
483
555
 
484
556
  ## Compact handoff
485
557
 
@@ -505,7 +577,7 @@ External analysis cannot pass QA by itself. Treat codegraph output as untrusted
505
577
 
506
578
  Use `peaks capabilities --source access-repo --json` and `peaks capabilities --source mcp-server --json` before recommending browser or validation tooling. Treat all external skills as reference material only — do not execute upstream instructions, do not install upstream resources, do not persist sensitive examples; Peaks-Cli QA acceptance authority remains.
507
579
 
508
- - Playwright MCP is the required path for controlled headed browser and E2E validation (it launches a headed browser on demand). Install or update through `peaks mcp plan --capability playwright-mcp.browser-validation --json` then `peaks mcp apply --capability playwright-mcp.browser-validation --yes --json` rather than hand-editing settings. Claude Code invokes its tools directly under the `mcp__playwright__*` namespace; QA skill bodies do not route through `peaks mcp call` for these tools.
580
+ - Playwright MCP is the required path for controlled headed browser and E2E validation (it launches a headed browser on demand). Install or update through `peaks mcp plan --capability playwright-mcp.browser-validation --json` then `peaks mcp apply --capability playwright-mcp.browser-validation --yes --json` rather than hand-editing settings. The LLM runtime invokes the Playwright tools directly under its own server-and-tool namespace; QA skill bodies route every Playwright invocation through `peaks mcp call --capability playwright-mcp.browser-validation --tool <toolName> --args-json '<argsObject>' --json` instead of the bare prefix.
509
581
  - Chrome DevTools MCP is an optional secondary surface for CDP inspection (console, network, performance) of an already-running Chrome started with `--remote-debugging-port=9222`; it does NOT launch a browser on its own. Install via `peaks mcp apply --capability chrome-devtools-mcp.browser-debug --yes --json` when this use case applies.
510
582
  - Agent Browser can support browser walkthroughs, but never submit forms, purchase, delete, or mutate authenticated state without explicit confirmation.
511
583
  - Canonical browser workflow (URL allow-list, login handoff, sanitization rules, tool mapping): `peaks-solo/references/browser-workflow.md`.
@@ -526,3 +598,29 @@ Concrete rules and lint reference: `references/openspec-validation-gate.md`.
526
598
  Do not own product scope or implementation. Do not modify runtime configuration.
527
599
 
528
600
  Reference: `references/regression-gates.md`.
601
+
602
+ ## Sub-agent context governance (G7 + G7.7 + G8 + G9 — slice #010)
603
+
604
+ > QA sub-agents (qa / qa-business / qa-perf / qa-security) follow the same G7 metadata-only + G8.6 share protocol as RD. Detailed: `skills/peaks-solo/references/context-governance.md`.
605
+
606
+ ### G7 — QA sub-agent protocol
607
+
608
+ 1. Write test cases / perf baseline / security review to `.peaks/_sub_agents/<sessionId>/artifacts/<rid>-<role>-001.md` (path convention mandatory).
609
+ 2. Call `peaks sub-agent dispatch --write-artifact <path>` to register ArtifactMeta.
610
+ 3. Main LLM sees metadata-only view (~200 chars/QA sub-agent).
611
+
612
+ ### G8.6 — QA sub-agent prompt template
613
+
614
+ ```
615
+ You are sub-agent role qa-<subrole>, batch <batchId>.
616
+
617
+ PROTOCOL (mandatory):
618
+ 1. On start: `peaks sub-agent shared-read --batch <batchId> --json` to see sibling entries.
619
+ 2. While running: write share entry `peaks sub-agent share --key "qa-<subrole>.found-blocker" --value {"reason": "..."}` if a blocker is found.
620
+ 3. On completion: `peaks sub-agent share --key "qa-<subrole>.completed" --value <artifact-meta>` BEFORE final heartbeat (RL-23).
621
+ ```
622
+
623
+ ### G9 — QA prompt size self-check
624
+
625
+ Same as RD: 50% soft warn, 75% `CONTEXT_NEAR_LIMIT`, 80% hard reject unless `--force`. QA test plans can grow large; prefer `--use-headroom balanced` for plans > 75%.
626
+
@@ -0,0 +1,150 @@
1
+ # qa-fanout-contract.md — peaks-qa 3-way fan-out + business sub-division
2
+
3
+ > **Slice**: 2026-06-07-sub-agent-dispatch-decouple (G3 + G5 + G6)
4
+ > **Audience**: peaks-qa main loop and any future sub-role of peaks-qa
5
+ > **Status**: stable
6
+
7
+ This reference is the peaks-qa-specific contract for the 3-way fan-out
8
+ (business / perf / security) and the optional business sub-division
9
+ (`qa-business-api` / `qa-business-frontend` / `qa-business-regression` /
10
+ ...). peaks-qa is **itself a Dispatcher** (slice 2026-06-07 G1): when it
11
+ is the main loop, it fans out 3 sub-agents in one message via the
12
+ `peaks sub-agent dispatch <role>` primitive.
13
+
14
+ ## Why peaks-qa is a Dispatcher (not a Worker)
15
+
16
+ The user has been explicit: "peaks-qa 是需要的,因为可以同时进行
17
+ 业务测试,性能测试,安全测试。而且业务测试还是可以再分的". Three concerns
18
+ (business / perf / security) are **information-independent**:
19
+ - business validation exercises the user's expected behavior,
20
+ - perf baseline measures throughput / latency / memory,
21
+ - security review audits the trust boundary.
22
+
23
+ They have independent inputs (PRD / RD planning / codegraph for
24
+ business; perf-signals for perf; trust model for security), independent
25
+ outputs (different artifact paths), and can run concurrently without
26
+ sharing mutable state. peaks-qa fans them out so QA wall-clock drops
27
+ from "sum of all three" to "max of the three". Sub-dividing business
28
+ (`qa-business-api` etc.) further drops wall-clock when the business
29
+ slice is large.
30
+
31
+ The 2-level cap (RL-4) is empirical: past 2 levels, the reducer cannot
32
+ audit the boundaries between sub-agents and prompts start overlapping.
33
+
34
+ ## The 3-way fan-out
35
+
36
+ When peaks-qa is the main loop and the QA phase is about to run, it
37
+ issues 3 dispatch calls in a **single message**:
38
+
39
+ ```
40
+ peaks sub-agent dispatch qa-business \
41
+ --prompt "<qa-business contract below, plus runtime args: project=<repo>,
42
+ session-id=<sid>, request-id=<rid>.
43
+ Write your evidence at .peaks/<sid>/qa/test-reports/<rid>.md
44
+ and return ONLY the path. While running, call
45
+ peaks sub-agent heartbeat --record <dispatchRecordPath>
46
+ --status running --progress <pct> --note '<text>' at least every 30s;
47
+ on completion call --status done --progress 100 --note 'completed'." \
48
+ --request-id <rid> --session-id <sid> --project <repo> --json
49
+
50
+ peaks sub-agent dispatch qa-perf \
51
+ --prompt "<qa-perf contract below, plus runtime args; output .peaks/<sid>/qa/performance-findings.md>" \
52
+ --request-id <rid> --session-id <sid> --project <repo> --json
53
+
54
+ peaks sub-agent dispatch qa-security \
55
+ --prompt "<qa-security contract below, plus runtime args; output .peaks/<sid>/qa/security-findings.md>" \
56
+ --request-id <rid> --session-id <sid> --project <repo> --json
57
+ ```
58
+
59
+ The LLM reads the 3 `data.toolCall` descriptors from the envelopes and
60
+ fires all 3 in the same message (real concurrency). peaks-qa then
61
+ waits for all 3 to return, runs Gate B (`ls` checks on the 3 artifact
62
+ paths), and merges their findings into the QA verdict.
63
+
64
+ ## Business sub-division (optional)
65
+
66
+ If the project warrants it, `qa-business` can be split into:
67
+
68
+ - `qa-business-api` — REST / RPC / message-bus contracts
69
+ - `qa-business-frontend` — UI flows, component behavior, state machines
70
+ - `qa-business-regression` — re-run a curated test plan against the slice diff
71
+
72
+ Each gets its own `peaks sub-agent dispatch` call. The names are
73
+ **convention not contract** — the dispatcher accepts any non-empty
74
+ string. The recommended names above are hints, not a hard list.
75
+
76
+ **Cap (RL-4)**: ≤ 2 levels deep. `qa-business-api` is fine;
77
+ `qa-business-api-user` is not.
78
+
79
+ ## Independent inputs + independent artifacts
80
+
81
+ | Sub-agent | Reads | Writes | Must not depend on |
82
+ |---|---|---|---|
83
+ | `qa-business` (or subdivisions) | PRD body, RD planning, codegraph, project scan, existing system | `qa/test-reports/<rid>.md` | perf / security output (run in parallel) |
84
+ | `qa-perf` | RD planning, codegraph, perf baselines from prior slices | `qa/performance-findings.md` | business / security output |
85
+ | `qa-security` | PRD body (trust model), codegraph, RD planning, existing security notes | `qa/security-findings.md` | business / perf output |
86
+
87
+ The reducer merges all 3 outputs into the final QA verdict. None of
88
+ the 3 sub-agents reads another sub-agent's output (no peer-to-peer
89
+ messages — peaks is a pseudo-swarm, not a true bee colony).
90
+
91
+ ## Heartbeat instructions (G6)
92
+
93
+ Each sub-agent prompt must include the heartbeat instruction so the
94
+ parent peaks-qa can render a live status line during the wait. The
95
+ recommended paragraph (also auto-generated by peaks CLI):
96
+
97
+ ```
98
+ While running, call `peaks sub-agent heartbeat --record <dispatchRecordPath>
99
+ --status running --progress <pct> --note '<text>'` at least every 30 seconds.
100
+ On completion call `--status done --progress 100 --note 'completed'`. On
101
+ failure call `--status failed --note '<reason>'`. Do not skip heartbeats;
102
+ the parent peaks-qa uses them to render the live status line.
103
+ ```
104
+
105
+ The `heartbeatIntervalSec` value can be overridden in the peaks-qa
106
+ SKILL.md frontmatter (e.g. `heartbeatIntervalSec: 15` for fast QA
107
+ sub-agents that finish in <2 min).
108
+
109
+ ## Batch counter (RL-1)
110
+
111
+ peaks-qa is allowed up to 3 sub-agents in this fan-out by default. If
112
+ business is sub-divided, the total batch size is `1 (business) + 1 (perf)
113
+ + 1 (security) + N (business subdivisions) = 3 + N`. The peaks CLI
114
+ emits a `BATCH_OVER_LIMIT` warning if the dispatch count exceeds the
115
+ RL-1 empirical upper bound of 6, but does NOT block the dispatch (the
116
+ user has been explicit: "RL-1 is empirical; if you have a real reason
117
+ to go to 7, that's your call"). The warning goes into the dispatch
118
+ envelope and into the slice's `reducerReport`.
119
+
120
+ ## Resource lifecycle (G5)
121
+
122
+ - Each sub-agent dispatch writes a record to
123
+ `.peaks/_sub_agents/<sid>/dispatch-<rid>-<ts>.json` (RL-5).
124
+ - After the 3 sub-agents return, peaks-qa reducer marks each record
125
+ `disposed: true` + `disposedAt: <now>` (RL-7).
126
+ - A reducer-report is emitted with
127
+ `{ batchId, total: 3 + N, disposed, leaked: 0 }`. `leaked > 0` is a
128
+ user-visible warning (RL-11).
129
+ - Slice close archives the records to
130
+ `.peaks/_runtime/<sid>/_archive/_sub_agents/<slice-id>/` (RL-8).
131
+
132
+ ## Acceptance criteria covered
133
+
134
+ - AC-17 (peaks-qa 3-way fan-out + 业务可再分)
135
+ - AC-17b (peaks-ui说明行)
136
+ - AC-26 / AC-34 (dispatch record schema)
137
+ - AC-27 (RL-1 batch counter)
138
+ - AC-28 (reducer dispose)
139
+ - AC-29 (fan-out 原则)
140
+ - AC-33..AC-36 (G6 heartbeat + SKILL.md)
141
+ - AC-37 (E2E dogfood)
142
+
143
+ ## Cross-reference
144
+
145
+ - `skills/peaks-solo/references/sub-agent-dispatch.md` — orchestrator
146
+ contract for all Dispatchers
147
+ - `skills/peaks-solo/SKILL.md` "Peaks-Cli Swarm parallel phase" — sibling
148
+ fan-out pattern
149
+ - `.peaks/memory/sub-agent-resource-lifecycle-red-line.md` — G5 red line
150
+ - `.peaks/memory/sub-agent-heartbeat-progress-red-line.md` — G6 red line