peaks-cli 1.2.7 → 1.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/dist/src/cli/commands/core-artifact-commands.js +36 -1
- package/dist/src/cli/commands/perf-commands.d.ts +3 -0
- package/dist/src/cli/commands/perf-commands.js +41 -0
- package/dist/src/cli/commands/progress-close-kill.d.ts +51 -0
- package/dist/src/cli/commands/progress-close-kill.js +152 -0
- package/dist/src/cli/commands/progress-commands.d.ts +3 -0
- package/dist/src/cli/commands/progress-commands.js +348 -0
- package/dist/src/cli/commands/progress-start-spawn.d.ts +59 -0
- package/dist/src/cli/commands/progress-start-spawn.js +114 -0
- package/dist/src/cli/commands/progress-watch-render.d.ts +80 -0
- package/dist/src/cli/commands/progress-watch-render.js +308 -0
- package/dist/src/cli/commands/project-commands.js +1 -1
- package/dist/src/cli/commands/scan-commands.js +22 -0
- package/dist/src/cli/program.js +4 -0
- package/dist/src/services/config/config-types.d.ts +20 -0
- package/dist/src/services/config/config-types.js +5 -1
- package/dist/src/services/memory/project-memory-service.d.ts +1 -1
- package/dist/src/services/memory/project-memory-service.js +52 -23
- package/dist/src/services/perf/perf-baseline-service.d.ts +70 -0
- package/dist/src/services/perf/perf-baseline-service.js +213 -0
- package/dist/src/services/progress/progress-service.d.ts +179 -0
- package/dist/src/services/progress/progress-service.js +276 -0
- package/dist/src/services/scan/libraries-service.d.ts +24 -0
- package/dist/src/services/scan/libraries-service.js +419 -0
- package/dist/src/services/scan/libraries-types.d.ts +59 -0
- package/dist/src/services/scan/libraries-types.js +9 -0
- package/dist/src/services/session/index.d.ts +1 -1
- package/dist/src/services/session/index.js +1 -1
- package/dist/src/services/session/session-manager.d.ts +53 -8
- package/dist/src/services/session/session-manager.js +150 -3
- package/dist/src/services/skills/skill-presence-service.d.ts +27 -1
- package/dist/src/services/skills/skill-presence-service.js +112 -9
- package/dist/src/services/skills/skill-runbook-service.js +34 -1
- package/dist/src/services/workflow/autonomous-resume-writer.js +7 -7
- package/dist/src/shared/change-id.d.ts +30 -0
- package/dist/src/shared/change-id.js +40 -6
- package/dist/src/shared/paths.d.ts +1 -1
- package/dist/src/shared/paths.js +2 -1
- package/dist/src/shared/version.d.ts +1 -1
- package/dist/src/shared/version.js +1 -1
- package/package.json +6 -2
- package/schemas/library-breaking-changes.data.json +141 -0
- package/schemas/library-breaking-changes.meta.json +6 -0
- package/schemas/library-breaking-changes.schema.json +50 -0
- package/skills/peaks-qa/SKILL.md +25 -0
- package/skills/peaks-rd/SKILL.md +221 -2
- package/skills/peaks-solo/SKILL.md +76 -316
- package/skills/peaks-solo/references/runbook.md +166 -0
- package/skills/peaks-solo/references/workflow-gates-and-types.md +177 -0
- package/skills/peaks-solo-resume/SKILL.md +81 -0
- package/skills/peaks-solo-status/SKILL.md +120 -0
- package/skills/peaks-solo-test/SKILL.md +84 -0
- package/skills/peaks-txt/SKILL.md +8 -5
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"library": "antd",
|
|
4
|
+
"fromMajor": 4,
|
|
5
|
+
"toMajor": 5,
|
|
6
|
+
"breakingChanges": [
|
|
7
|
+
{ "api": "Drawer.width", "replacement": "Drawer.size", "since": "5.0.0" },
|
|
8
|
+
{ "api": "Modal.width (string)", "replacement": "Modal.width (number) or styles.body.width (number)", "since": "5.0.0" },
|
|
9
|
+
{ "api": "Form.create()", "replacement": "App.useForm() (under <App>)", "since": "5.0.0" },
|
|
10
|
+
{ "api": "message.useMessage()", "replacement": "App.useApp().message (under <App>)", "since": "5.0.0" },
|
|
11
|
+
{ "api": "notification.useNotification()", "replacement": "App.useApp().notification (under <App>)", "since": "5.0.0" },
|
|
12
|
+
{ "api": "import 'antd/dist/antd.css'", "replacement": "import 'antd/dist/reset.css'", "since": "5.0.0" },
|
|
13
|
+
{ "api": "<Form.Item {...layout}", "replacement": "<Form layout='vertical' | 'horizontal'> (no per-item layout prop)", "since": "5.0.0" }
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"library": "@antv/g6",
|
|
18
|
+
"fromMajor": 4,
|
|
19
|
+
"toMajor": 5,
|
|
20
|
+
"breakingChanges": [
|
|
21
|
+
{ "api": "new G6.Graph({ mode: 'default' })", "replacement": "new G6.Graph({ type: 'graph' })", "since": "5.0.0" },
|
|
22
|
+
{ "api": "graph.read(data)", "replacement": "graph.setData(data); graph.render()", "since": "5.0.0" },
|
|
23
|
+
{ "api": "graph.changeData(data)", "replacement": "graph.setData(data); graph.render()", "since": "5.0.0" },
|
|
24
|
+
{ "api": "G6.registerBehavior('drag-canvas', { getEvents() { return { ... } } })", "replacement": "G6.registerBehavior({ key: 'drag-canvas', type: 'drag-canvas', getEvents() { return { ... } } })", "since": "5.0.0" }
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"library": "@mui/material",
|
|
29
|
+
"fromMajor": 4,
|
|
30
|
+
"toMajor": 5,
|
|
31
|
+
"breakingChanges": [
|
|
32
|
+
{ "api": "import { Grid } from '@mui/material'", "replacement": "import Grid from '@mui/material/Grid2' (Grid renamed Grid2, separate import path)", "since": "5.0.0" },
|
|
33
|
+
{ "api": "createTheme({ unstable_createRheaTheme: true })", "replacement": "createTheme({ cssVariables: true })", "since": "5.0.0" },
|
|
34
|
+
{ "api": "<DialogTitle disableTypography>", "replacement": "<DialogTitle component='div'> (disableTypography removed; use component prop)", "since": "5.0.0" },
|
|
35
|
+
{ "api": "<TextField variant='standard' InputLabelProps={{ shrink: true }}>", "replacement": "<TextField variant='standard' slotProps={{ inputLabel: { shrink: true } }}>", "since": "5.0.0" }
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"library": "react-router-dom",
|
|
40
|
+
"fromMajor": 5,
|
|
41
|
+
"toMajor": 6,
|
|
42
|
+
"breakingChanges": [
|
|
43
|
+
{ "api": "<Switch>", "replacement": "<Routes>", "since": "6.0.0" },
|
|
44
|
+
{ "api": "<Redirect>", "replacement": "<Navigate>", "since": "6.0.0" },
|
|
45
|
+
{ "api": "useHistory()", "replacement": "useNavigate()", "since": "6.0.0" },
|
|
46
|
+
{ "api": "match.params", "replacement": "useParams()", "since": "6.0.0" },
|
|
47
|
+
{ "api": "withRouter(Component)", "replacement": "useNavigate() + useLocation() + useParams() hooks", "since": "6.0.0" },
|
|
48
|
+
{ "api": "<Route component={Component} />", "replacement": "<Route element={<Component />} /> (component prop renamed element)", "since": "6.0.0" },
|
|
49
|
+
{ "api": "<Route path='/:id' exact />", "replacement": "<Route path='/:id' /> (exact prop removed; paths match exactly by default)", "since": "6.0.0" }
|
|
50
|
+
]
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"library": "tailwindcss",
|
|
54
|
+
"fromMajor": 2,
|
|
55
|
+
"toMajor": 3,
|
|
56
|
+
"breakingChanges": [
|
|
57
|
+
{ "api": "tailwind.config.js (CommonJS, no 'type' in package.json)", "replacement": "tailwind.config.cjs (CommonJS) or tailwind.config.ts (ESM)", "since": "3.0.0" },
|
|
58
|
+
{ "api": "content: ['./src/**/*.{html,js}']", "replacement": "content: ['./src/**/*.{html,js,jsx,ts,tsx,vue,svelte}']", "since": "3.0.0" },
|
|
59
|
+
{ "api": "@tailwindcss/typography (default import)", "replacement": "import typography from '@tailwindcss/typography' (named default; config: { plugins: [typography] })", "since": "3.0.0" },
|
|
60
|
+
{ "api": "colors: { 'custom-blue': '#1da1f2' }", "replacement": "colors: { custom: { blue: '#1da1f2' } } (nested under named palette; tailwind.config reads as 'text-custom-blue' = 'text-custom-blue' still works but is a single nesting level removed)", "since": "3.0.0" }
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"library": "@reduxjs/toolkit",
|
|
65
|
+
"fromMajor": 1,
|
|
66
|
+
"toMajor": 2,
|
|
67
|
+
"breakingChanges": [
|
|
68
|
+
{ "api": "import { createAsyncThunk, createReducer } from '@reduxjs/toolkit' (with manual pending/fulfilled/rejected handlers)", "replacement": "import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'; createSlice auto-generates pending/fulfilled/rejected matchers", "since": "2.0.0" },
|
|
69
|
+
{ "api": "createSlice({ reducers: { ... }, extraReducers: (builder) => builder.addCase(...) })", "replacement": "createSlice({ reducers, extraReducers: (builder) => builder.addCase(...) }) — unchanged shape; check RTK 2.0 matchers for createAsyncThunk with builder.addMatcher", "since": "2.0.0" },
|
|
70
|
+
{ "api": "configureStore({ reducer, middleware: (gDM) => gDM().concat(logger) })", "replacement": "configureStore({ reducer, middleware: (gDM) => gDM({ serializableCheck: false }).concat(logger) })", "since": "2.0.0" }
|
|
71
|
+
]
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"library": "next",
|
|
75
|
+
"fromMajor": 14,
|
|
76
|
+
"toMajor": 15,
|
|
77
|
+
"breakingChanges": [
|
|
78
|
+
{ "api": "params (in pages/)", "replacement": "await params (params is now a Promise; await it before reading properties)", "since": "15.0.0" },
|
|
79
|
+
{ "api": "searchParams (in pages/)", "replacement": "await searchParams (searchParams is now a Promise)", "since": "15.0.0" },
|
|
80
|
+
{ "api": "cookies().get('name') (synchronous)", "replacement": "await cookies() (cookies() now returns a Promise; await before calling .get)", "since": "15.0.0" },
|
|
81
|
+
{ "api": "headers().get('name') (synchronous)", "replacement": "await headers() (headers() now returns a Promise)", "since": "15.0.0" },
|
|
82
|
+
{ "api": "fetch(url, { cache: 'force-cache' })", "replacement": "fetch(url, { cache: 'force-cache' }) + export const dynamic = 'force-static' OR use a Server Action", "since": "15.0.0" }
|
|
83
|
+
]
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"library": "react",
|
|
87
|
+
"fromMajor": 17,
|
|
88
|
+
"toMajor": 18,
|
|
89
|
+
"breakingChanges": [
|
|
90
|
+
{ "api": "ReactDOM.render(<App />, container)", "replacement": "createRoot(container).render(<App />)", "since": "18.0.0" },
|
|
91
|
+
{ "api": "ReactDOM.hydrate(<App />, container)", "replacement": "hydrateRoot(container, <App />)", "since": "18.0.0" },
|
|
92
|
+
{ "api": "import { render } from 'react-dom'", "replacement": "import { createRoot } from 'react-dom/client' (separate entry point)", "since": "18.0.0" },
|
|
93
|
+
{ "api": "ReactDOM.unmountComponentAtNode(container)", "replacement": "root.unmount() (returned from createRoot)", "since": "18.0.0" },
|
|
94
|
+
{ "api": "defaultProps on function components", "replacement": "default parameters (defaultProps will be removed in a future major; use destructuring defaults: function Foo({ x = 1 } = {}) {})", "since": "18.3.0" }
|
|
95
|
+
]
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"library": "typescript",
|
|
99
|
+
"fromMajor": 4,
|
|
100
|
+
"toMajor": 5,
|
|
101
|
+
"breakingChanges": [
|
|
102
|
+
{ "api": "import type { ... } from 'mod' (mixed type + value import without explicit type modifier)", "replacement": "Add `type` modifier to type-only imports explicitly (TS 5.0 enforces with verbatimModuleSyntax)", "since": "5.0.0" },
|
|
103
|
+
{ "api": "namespace X { function f(): X.Type }", "replacement": "Use `import type` or `export type` from namespaces (TS 5.0 changes how namespaces interop with modules)", "since": "5.0.0" },
|
|
104
|
+
{ "api": "experimentalDecorators metadata emit", "replacement": "Use the new TC39 stage-3 decorators; experimentalDecorators flag will be removed", "since": "5.0.0" },
|
|
105
|
+
{ "api": "enum X { A, B = A * 2 } (numeric enum with computed member before non-computed)", "replacement": "Reorder enum members: place all non-computed members before computed ones", "since": "5.0.0" }
|
|
106
|
+
]
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"library": "prisma",
|
|
110
|
+
"fromMajor": 4,
|
|
111
|
+
"toMajor": 5,
|
|
112
|
+
"breakingChanges": [
|
|
113
|
+
{ "api": "previewFeatures = ['xxx'] (in schema.prisma)", "replacement": "Move preview features to a separate block; some promoted to stable without flag", "since": "5.0.0" },
|
|
114
|
+
{ "api": "prisma.user.findMany({ include: { posts: true } }) (implicit include via relation)", "replacement": "Use `with: { posts: true }` (include renamed to with)", "since": "5.0.0" },
|
|
115
|
+
{ "api": "prisma.user.findMany({ relationJumps: { ... } })", "replacement": "Use `include` with `_count: { select: ... }` or nested select on relation fields", "since": "5.0.0" },
|
|
116
|
+
{ "api": "@prisma/client v4 ESM/CJS interop (require vs import)", "replacement": "Pure ESM in v5; use `import` syntax only; dynamic require() of generated client throws", "since": "5.0.0" }
|
|
117
|
+
]
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"library": "eslint",
|
|
121
|
+
"fromMajor": 8,
|
|
122
|
+
"toMajor": 9,
|
|
123
|
+
"breakingChanges": [
|
|
124
|
+
{ "api": ".eslintrc.json (legacy config)", "replacement": "eslint.config.js (flat config; legacy mode requires @eslint/eslintrc)", "since": "9.0.0" },
|
|
125
|
+
{ "api": "module.exports = { rules: { ... } } (CommonJS rules)", "replacement": "export default [{ rules: { ... } }] (ESM flat config; rules must be inside an array entry)", "since": "9.0.0" },
|
|
126
|
+
{ "api": "context.getSourceCode()", "replacement": "context.sourceCode (renamed; ESLint 9 deprecates getSourceCode)", "since": "9.0.0" },
|
|
127
|
+
{ "api": "rule.create({ visitor }) without meta.schema or meta.type", "replacement": "rule.create({ meta: { schema: [...], type: 'problem'|'suggestion'|'layout' }, visitor }) (ESLint 9 requires meta)", "since": "9.0.0" }
|
|
128
|
+
]
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"library": "react-hook-form",
|
|
132
|
+
"fromMajor": 6,
|
|
133
|
+
"toMajor": 7,
|
|
134
|
+
"breakingChanges": [
|
|
135
|
+
{ "api": "useForm({ defaultValues: { ... } }) (defaultValues is now required when using field arrays)", "replacement": "Always provide defaultValues; v7 removed the implicit empty default", "since": "7.0.0" },
|
|
136
|
+
{ "api": "Controller({ name, control, render: ({ field }) => ... }) (Controller is now a generic — must pass field type)", "replacement": "Controller<FieldValues, TFieldPath>({ name: 'field' as TFieldPath, ... }) (cast path to TFieldPath)", "since": "7.0.0" },
|
|
137
|
+
{ "api": "useFormContext() (no generic)", "replacement": "useFormContext<FieldValues>() (generic required for type inference)", "since": "7.0.0" },
|
|
138
|
+
{ "api": "formState.errors.foo (loose type)", "replacement": "formState.errors.foo (typed as FieldError | undefined; use ?.message for safe access)", "since": "7.0.0" }
|
|
139
|
+
]
|
|
140
|
+
}
|
|
141
|
+
]
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "Peaks Library Breaking Changes",
|
|
4
|
+
"description": "Manually-curated table of known breaking changes per (library, fromMajor, toMajor). Used by peaks-rd/qa to warn the LLM about deprecated APIs when writing code for projects on a newer major than the LLM's training data. Read by the LLM via the Read tool; the data file at library-breaking-changes.data.json holds the actual rows. Doctor validates parse-ability of this schema file.",
|
|
5
|
+
"type": "array",
|
|
6
|
+
"items": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"required": ["library", "fromMajor", "toMajor", "breakingChanges"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"library": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"minLength": 1,
|
|
13
|
+
"description": "npm package name, e.g. 'antd', '@mui/material', 'react-router-dom'."
|
|
14
|
+
},
|
|
15
|
+
"fromMajor": {
|
|
16
|
+
"type": "integer",
|
|
17
|
+
"minimum": 0,
|
|
18
|
+
"description": "The major version the breaking change applies FROM. LLM cross-references (project major === toMajor) to fire the warning."
|
|
19
|
+
},
|
|
20
|
+
"toMajor": {
|
|
21
|
+
"type": "integer",
|
|
22
|
+
"minimum": 1,
|
|
23
|
+
"description": "The major version the breaking change applies TO (i.e. the new major where the API changed)."
|
|
24
|
+
},
|
|
25
|
+
"breakingChanges": {
|
|
26
|
+
"type": "array",
|
|
27
|
+
"items": {
|
|
28
|
+
"type": "object",
|
|
29
|
+
"required": ["api", "replacement", "since"],
|
|
30
|
+
"properties": {
|
|
31
|
+
"api": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"minLength": 1,
|
|
34
|
+
"description": "The deprecated/removed API call, e.g. 'Drawer.width'. Should be a substring that the LLM can grep for in the diff's import + JSX blocks."
|
|
35
|
+
},
|
|
36
|
+
"replacement": {
|
|
37
|
+
"type": "string",
|
|
38
|
+
"description": "The v2 API to use instead, e.g. 'Drawer.size'. If empty, the API is removed entirely (no v2 equivalent)."
|
|
39
|
+
},
|
|
40
|
+
"since": {
|
|
41
|
+
"type": "string",
|
|
42
|
+
"pattern": "^[0-9]+\\.[0-9]+(\\.[0-9]+)?$",
|
|
43
|
+
"description": "The semver string where this breaking change took effect, e.g. '5.0.0'. Matches the toMajor."
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
package/skills/peaks-qa/SKILL.md
CHANGED
|
@@ -168,6 +168,17 @@ peaks openspec validate <change-id> --project <repo> --prefer-external --json
|
|
|
168
168
|
|
|
169
169
|
# 4. generate test cases — MANDATORY, write to .peaks/<session-id>/qa/test-cases/<request-id>.md
|
|
170
170
|
# categories: unit, integration, UI regression (frontend only)
|
|
171
|
+
#
|
|
172
|
+
# Optimization (slice 004): peaks-rd's parallel fan-out now includes a 4th
|
|
173
|
+
# sub-agent (`qa-test-cases-writer`) that pre-drafts this file at the
|
|
174
|
+
# end of RD implementation. If `.peaks/<sid>/qa/test-cases/<rid>.md`
|
|
175
|
+
# already exists when QA's main loop reaches this step, **QA does NOT
|
|
176
|
+
# re-draft it** — it just verifies the file is present and the
|
|
177
|
+
# per-criterion `ts` snippets are syntactically valid, then proceeds
|
|
178
|
+
# to step 5 (EXECUTE). The wall-clock win: QA's first action is
|
|
179
|
+
# "execute pre-drafted test plan" instead of "draft + execute".
|
|
180
|
+
# Fallback: if the file is missing (sub-agent failed / degraded to
|
|
181
|
+
# inline), QA drafts it inline as before.
|
|
171
182
|
|
|
172
183
|
# 5. EXECUTE tests against the actual implementation — Peaks-Cli Gate A2
|
|
173
184
|
# Run the project test command. Record output. Tests on paper are worthless.
|
|
@@ -178,6 +189,19 @@ peaks openspec validate <change-id> --project <repo> --prefer-external --json
|
|
|
178
189
|
# because code review alone does not catch: hardcoded secrets, XSS vectors,
|
|
179
190
|
# bundle size regressions, render-performance issues, or missing CSP headers.
|
|
180
191
|
# If you skip A3 or A4, Peaks-Cli Gate C will block the verdict.
|
|
192
|
+
#
|
|
193
|
+
# Before running A4, read the RD's perf-baseline at
|
|
194
|
+
# .peaks/<id>/rd/perf-baseline.md (if present) and use the
|
|
195
|
+
# captured thresholds as the comparison baseline. The QA stage
|
|
196
|
+
# is still responsible for running the actual measurement
|
|
197
|
+
# (lighthouse / k6 / autocannon / project-local bench) and
|
|
198
|
+
# for the verdict — the RD-side baseline is the *known-good
|
|
199
|
+
# reference* that lets the QA stage say "X regressed by Y%"
|
|
200
|
+
# instead of "X is bad, but I have no number for what good
|
|
201
|
+
# looks like". If the RD did not produce a perf-baseline
|
|
202
|
+
# (e.g. the slice is docs / chore / has no perf surface),
|
|
203
|
+
# surface that absence in the QA test-report under a
|
|
204
|
+
# `## Performance baseline` section.
|
|
181
205
|
|
|
182
206
|
# 6. write test-report — MANDATORY, write to .peaks/<session-id>/qa/test-reports/<request-id>.md
|
|
183
207
|
# MUST contain actual execution results (pass/fail counts, coverage %, findings).
|
|
@@ -445,6 +469,7 @@ QA cannot pass a change until the report contains evidence for every applicable
|
|
|
445
469
|
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.
|
|
446
470
|
6. **Security check** — run security review for the changed surface and dependency/config changes. Record findings, fixes, and unresolved risks.
|
|
447
471
|
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.
|
|
472
|
+
8. **Library version regressions** — when the slice's diff contains an `import` statement that matches a `breakingChanges[].api` entry in `schemas/library-breaking-changes.data.json` for the library's installed major (read from the RD-handoff's `## Library versions` section), record a `## Library version regressions` block in `qa/test-reports/<rid>.md` listing each hit. Per row: `<api>` → `<replacement>`, source `schemas/library-breaking-changes.data.json`. Treat each unreplaced hit as a **return-to-rd** reason — the LLM should fix the diff before re-handoff. (This is the QA-side counterpart of the RD `## Library version awareness` preflight; the two together form a check-and-verify pair.)
|
|
448
473
|
8. **Validation report** — write or link a report containing scope, environment, commands, sanitized browser evidence, security/performance results, pass/fail summary, residual risks, and next action.
|
|
449
474
|
9. **Acceptance coverage** — every PRD acceptance item has at least one linked QA test case (`peaks scan acceptance-coverage --rid <rid>`). **→ verified by Peaks-Cli Gate E**. This is the deterministic check that no requirement was forgotten between PRD and verdict.
|
|
450
475
|
10. **QA artifact lint** — the QA request artifact body has no unfilled placeholders (`peaks request lint <rid> --role qa`). **→ verified by Peaks-Cli Gate F**. Catches the "wrote the template, forgot to fill it" failure mode that template-style reports invite.
|
package/skills/peaks-rd/SKILL.md
CHANGED
|
@@ -88,6 +88,21 @@ On the first presence:set in a project, ensure the out-of-band status bar is ins
|
|
|
88
88
|
peaks statusline install --project <repo> # idempotent; skips if already installed
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
+
**Auto-spawn a progress watch terminal once per slice (BLOCKING on the first phase transition).** The user opens a fresh VSCode window per slice, not per Bash call. Without a separate progress terminal the user has no live signal that the sub-agent is alive — the only signal they have is the static statusline. So at the first phase transition of every slice, fire `peaks progress start` ONCE. The CLI auto-spawns a new terminal tab running `peaks progress watch` and the user can close the new tab at any time. Do NOT re-invoke on every phase change — one per slice is the contract. The LLM-side cost of this one invocation is one Bash call plus a small JSON envelope; the watch side is a 1s file poll that does not consume LLM tokens.
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# At the first phase transition of a slice (after the first
|
|
95
|
+
# peaks progress step), fire the watch:
|
|
96
|
+
peaks progress start --project <repo> --reason "rd-implementing for <rid>"
|
|
97
|
+
|
|
98
|
+
# On every subsequent phase transition, only update the
|
|
99
|
+
# progress file — the watch is already running in another tab:
|
|
100
|
+
peaks progress step --project <repo> --request-id <rid> --role rd \
|
|
101
|
+
--step "running pnpm test" --phase running
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
If `peaks progress start` is unsupported on the current platform (no terminal emulator, headless container, etc.) it returns a recoverable error envelope. Surface that in the RD handoff so the user knows the auto-spawn failed; the sub-agent can still emit `peaks progress step` writes that the user reads from the on-disk file. The auto-spawn is convenience, not a gate.
|
|
105
|
+
|
|
91
106
|
Read persistent project memory via CLI (durable, LLM-authored memories):
|
|
92
107
|
|
|
93
108
|
```bash
|
|
@@ -114,6 +129,26 @@ Use the `<request-id>` PRD assigned. RD companion artifacts (task graph, scan re
|
|
|
114
129
|
|
|
115
130
|
Concrete template and rules: `references/artifact-per-request.md`.
|
|
116
131
|
|
|
132
|
+
## Two RD artifact files — do not confuse them
|
|
133
|
+
|
|
134
|
+
RD has two distinct artifact files, and the most common regression is to write the per-slice content into the per-session file. They serve different readers and live in different places:
|
|
135
|
+
|
|
136
|
+
| File | Scope | Reader | Required content |
|
|
137
|
+
|---|---|---|---|
|
|
138
|
+
| `.peaks/<sid>/rd/tech-doc.md` | per-session — the whole RD plan for the session, all slices | Solo, future LLM, the human scrolling the session | Architecture, slice graph, mock strategy, cross-cutting decisions. **Not** the place for per-slice implementation evidence. |
|
|
139
|
+
| `.peaks/<sid>/rd/requests/<rid>.md` | per-slice — one request, one planning artifact | QA, SC, the lint gate | Red-line scope, in-scope / out-of-scope, unit-test requirements, **Implementation evidence** (file list, `pnpm test` output, git diff excerpts), MCP usage, handoff, status. **This is the file the lint gate checks for placeholders.** |
|
|
140
|
+
| `.peaks/<sid>/rd/code-review.md` | per-session — the engineering review | QA, the human reviewer | Code review findings + fixes. |
|
|
141
|
+
| `.peaks/<sid>/rd/security-review.md` | per-session — the security review | QA | Security review findings + fixes. |
|
|
142
|
+
|
|
143
|
+
**Failure mode the lint gate catches**: the LLM writes the actual implementation content into `rd/tech-doc.md` and leaves `rd/requests/<rid>.md` as the default template (with placeholder sections like "Implementation evidence: 留待 RD 实施阶段补充" and "MCP usage: N/A"). The lint gate then fails the slice with 6+ lint errors on the `<rid>.md` template even though the actual content lives in `tech-doc.md`.
|
|
144
|
+
|
|
145
|
+
**Rule**:
|
|
146
|
+
- **Per-slice content** (red-line scope, in-scope / out-of-scope, the implementation evidence list, the unit-test assertions, the handoff) → **belongs in `rd/requests/<rid>.md`**.
|
|
147
|
+
- **Per-session content** (the architecture overview, the slice roadmap, the cross-cutting concerns, the mock strategy for the whole session) → **belongs in `rd/tech-doc.md`**.
|
|
148
|
+
- When in doubt: copy the per-slice content into the `<rid>.md` artifact's "Implementation evidence" section after writing it to `tech-doc.md`. The two files can carry overlapping context; the gate only enforces that `<rid>.md` is not empty placeholders.
|
|
149
|
+
|
|
150
|
+
Concrete template and rules: `references/artifact-per-request.md`.
|
|
151
|
+
|
|
117
152
|
## Default runbook
|
|
118
153
|
|
|
119
154
|
The default sequence the RD skill should execute for a code-touching request. Skip steps that do not apply to the request type; do not skip the artifact, coverage gate, or red-line scope steps.
|
|
@@ -246,8 +281,8 @@ You cannot declare a phase complete from memory. Each gate below is a `ls` or `g
|
|
|
246
281
|
>
|
|
247
282
|
> | Type | rd:implemented requires | rd:qa-handoff also requires |
|
|
248
283
|
> |---|---|---|
|
|
249
|
-
> | feature / refactor | `rd/tech-doc.md` | `rd/code-review.md` + `rd/security-review.md` |
|
|
250
|
-
> | bugfix | `rd/bug-analysis.md` (lighter than tech-doc; root cause + fix + regression test plan) | `rd/code-review.md` + `rd/security-review.md` |
|
|
284
|
+
> | feature / refactor | `rd/tech-doc.md` | `rd/code-review.md` + `rd/security-review.md` + `rd/perf-baseline.md` (filled Results table, or `N/A — no perf surface` in Notes) + **`qa/test-cases/<rid>.md`** (added in slice 004; pre-drafted by the 4th sub-agent in the parallel fan-out) |
|
|
285
|
+
> | bugfix | `rd/bug-analysis.md` (lighter than tech-doc; root cause + fix + regression test plan) | `rd/code-review.md` + `rd/security-review.md` + **`qa/test-cases/<rid>.md`**; `rd/perf-baseline.md` only when the bug is performance-shaped (matches the L449-452 "When this applies" criteria) |
|
|
251
286
|
> | config | (none) | `rd/security-review.md` only |
|
|
252
287
|
> | docs / chore | (none) | (none) |
|
|
253
288
|
>
|
|
@@ -352,6 +387,32 @@ peaks scan diff-vs-scope --rid <rid> --project <repo> --session-id <sid> --json
|
|
|
352
387
|
# before re-running. Auto-allowed paths (test files, .peaks/, __mocks__/) never need a pattern.
|
|
353
388
|
```
|
|
354
389
|
|
|
390
|
+
**Peaks-Cli Gate B9 — RD-side perf-baseline output present (when slice has a user-perceivable perf surface):**
|
|
391
|
+
```bash
|
|
392
|
+
ls .peaks/<id>/rd/perf-baseline.md 2>&1
|
|
393
|
+
# Expected: .peaks/<id>/rd/perf-baseline.md
|
|
394
|
+
# "No such file" + slice is feature / refactor / bugfix-when-perf → BLOCKED.
|
|
395
|
+
# Run the perf-baseline sub-agent from "Parallel review fan-out" below (or
|
|
396
|
+
# `peaks perf baseline --apply` inline), then fill in the Results table
|
|
397
|
+
# with measurements (lighthouse / k6 / autocannon / project-local bench —
|
|
398
|
+
# the CLI does not run these; that is the RD's job), then re-verify.
|
|
399
|
+
# "No such file" + slice is docs / chore / pure-bugfix-no-perf → OK to proceed;
|
|
400
|
+
# this gate does not apply to those slice types.
|
|
401
|
+
# File exists but Results table is empty (only the header row, no data rows) →
|
|
402
|
+
# BLOCKED. The sub-agent scaffolds the file; the main RD loop must fill in
|
|
403
|
+
# the Path / route | Workload | Tool | Metric | Baseline | Threshold table
|
|
404
|
+
# with actual numbers before handoff.
|
|
405
|
+
# File contains the marker `N/A — no perf surface` in its Notes section →
|
|
406
|
+
# OK to proceed. This is the explicit opt-out the sub-agent writes when
|
|
407
|
+
# the slice has no user-perceivable perf surface (e.g. a feature that only
|
|
408
|
+
# adds an internal flag with no runtime cost, or a refactor that does not
|
|
409
|
+
# alter any hot path).
|
|
410
|
+
#
|
|
411
|
+
# The CLI enforcement table below the section header also gates this at the
|
|
412
|
+
# `peaks request transition rd:qa-handoff` call, so a missing or empty file
|
|
413
|
+
# is rejected by the CLI with `code: PREREQUISITES_MISSING`.
|
|
414
|
+
```
|
|
415
|
+
|
|
355
416
|
## Project standards preflight
|
|
356
417
|
|
|
357
418
|
Before RD planning or implementation work in a code repository, call the Peaks-Cli CLI:
|
|
@@ -361,6 +422,37 @@ Before RD planning or implementation work in a code repository, call the Peaks-C
|
|
|
361
422
|
|
|
362
423
|
If `CLAUDE.md` is missing, treat creation as the preferred path. If `CLAUDE.md` already exists, use `standards update` to decide whether to append a managed index block or surface review-only suggestions. Apply only when write authorization exists; otherwise keep the CLI output as a preflight next action. Do not hand-write standards file mutations inside the skill.
|
|
363
424
|
|
|
425
|
+
## Library version awareness (3rd-party breaking-change gate)
|
|
426
|
+
|
|
427
|
+
After `peaks scan libraries` lands the dependency list under `## Library versions` in `rd/project-scan.md`, RD MUST cross-check the slice's diff against `schemas/library-breaking-changes.data.json` before writing any 3rd-party API call. Concretely:
|
|
428
|
+
|
|
429
|
+
1. **Read the project's `## Library versions` section** in `.peaks/<session-id>/rd/project-scan.md`. Identify the `name` + `major` of every dependency the slice imports from.
|
|
430
|
+
2. **Open `schemas/library-breaking-changes.data.json`** (LLM reads via the `Read` tool). For each library where the installed `major` matches a `toMajor` in the table, load the corresponding `breakingChanges[]` list.
|
|
431
|
+
3. **For each `import` statement in the slice's diff** (e.g. `import { Drawer } from 'antd'`), check whether the imported symbol or its prop signature matches any `breakingChanges[].api` entry for the library's installed major.
|
|
432
|
+
4. **On a hit**:
|
|
433
|
+
- **Warn the LLM in the slice's handoff**: in `.peaks/<session-id>/rd/requests/<rid>.md` under `## Implementation evidence`, append a one-line note per hit: `- [lib-version] <library> <installed version> imports <api>; breaking-change rule says use <replacement> instead.`
|
|
434
|
+
- **Persist a `lesson` memory** at the END of `.peaks/<session-id>/rd/project-scan.md` (or the tech-doc, or the handoff — any of these is read by future RD runs):
|
|
435
|
+
```
|
|
436
|
+
<!-- peaks-memory:start -->
|
|
437
|
+
title: <library> <installed major> requires <api> → <replacement>
|
|
438
|
+
kind: lesson
|
|
439
|
+
---
|
|
440
|
+
Observed in slice <rid>: project is on <library>@<major> and the diff imported <api> which is on the breaking-changes list. Use <replacement> instead. Source: schemas/library-breaking-changes.data.json.
|
|
441
|
+
<!-- peaks-memory:end -->
|
|
442
|
+
```
|
|
443
|
+
- The next RD run will see this lesson in `peaks project memories` and skip the same drift.
|
|
444
|
+
|
|
445
|
+
**Why this exists**: the LLM's training data lags the latest major versions. The user hit `[antd: Drawer] width is deprecated. Please use size instead` in an antv6 project because the LLM wrote v5-style code. The breaking-changes table is the canonical place for "library X at major Y has these known migrations" so the LLM doesn't have to guess.
|
|
446
|
+
|
|
447
|
+
**Out of scope**: the breaking-changes table is hand-curated; auto-syncing from upstream changelogs (Context7, etc.) is a follow-up slice. Per-slice the LLM only reads the table — it does NOT maintain it.
|
|
448
|
+
|
|
449
|
+
**Data freshness check (read schemas/library-breaking-changes.meta.json first)**:
|
|
450
|
+
- Before reading `schemas/library-breaking-changes.data.json`, also read `schemas/library-breaking-changes.meta.json`.
|
|
451
|
+
- Compute `ageInDays = (today - meta.lastUpdated)`. The LLM is responsible for this date math.
|
|
452
|
+
- If `ageInDays > meta.freshnessPolicyDays` (default 180 days), surface a **freshness warning** in the handoff: `- [data-staleness] library-breaking-changes.data.json is ${ageInDays} days old (last touched ${meta.lastUpdated}); the breaking-changes below may miss library X's recent major. Re-verify against the library's official changelog before relying on these substitutions.`
|
|
453
|
+
- The warning is **informational**, not blocking. A stale table is better than no table. The LLM still applies the entries it has, just with the caveat.
|
|
454
|
+
- When a row in the table matches an `import` in the diff AND the table is fresh, proceed without the warning.
|
|
455
|
+
|
|
364
456
|
## GStack integration and code dry-runs
|
|
365
457
|
|
|
366
458
|
Use gstack as a concrete engineering workflow reference for `Think → Plan → Build → Review → Test → Ship → Reflect`:
|
|
@@ -407,6 +499,47 @@ Before every code or mock change, RD must write and then enforce a red-line scop
|
|
|
407
499
|
- Never add `tailwindcss` to a project that already uses a component library with its own CSS-in-JS solution unless the project-scan explicitly approves it
|
|
408
500
|
- If TailwindCSS is already present, use it consistently with the project's existing utility patterns; do not mix TailwindCSS utility classes with component-library `style` prop overrides on the same element
|
|
409
501
|
|
|
502
|
+
## Mandatory perf-baseline output (RD-side perf gate)
|
|
503
|
+
|
|
504
|
+
**BLOCKING — Do not hand off to QA without a perf-baseline file when the slice has a user-visible performance surface.** The QA stage's Gate A4 (performance check) needs a stable reference to diff against; without an RD-side baseline, the first time Gate A4 runs it has nothing to compare against and any regression it finds is a blind-side surprise. The user-facing pain of leaving perf to QA only has historically been a 3-cycle repair loop ("QA returns for perf", "RD ships a fix", "QA returns for perf again", "RD ships another fix", ...). The RD-side baseline closes that loop.
|
|
505
|
+
|
|
506
|
+
**When this applies:**
|
|
507
|
+
- feature / refactor slices that touch a route, hook, API, or any user-perceivable surface
|
|
508
|
+
- bugfix slices where the bug is performance-shaped (slow render, hot loop, N+1)
|
|
509
|
+
- any slice where the PRD mentions a number (LCP / FCP / TBT / p95 / rps / etc.)
|
|
510
|
+
|
|
511
|
+
**When this does NOT apply:**
|
|
512
|
+
- docs / chore slices
|
|
513
|
+
- pure bugfixes whose fix is "remove the bug" (no perf surface)
|
|
514
|
+
- any slice where the slice is documentation-only or otherwise has no perf surface — in that case write `N/A — no perf surface` in the file's "Notes" section and surface that fact in the RD handoff
|
|
515
|
+
|
|
516
|
+
**How to produce the file:**
|
|
517
|
+
|
|
518
|
+
```bash
|
|
519
|
+
# 1. dry-run preview (default)
|
|
520
|
+
peaks perf baseline --project <repo>
|
|
521
|
+
# → ok: true, data.plannedWrites shows the file path, no files written
|
|
522
|
+
|
|
523
|
+
# 2. apply — scaffolds the file at .peaks/<sid>/rd/perf-baseline.md
|
|
524
|
+
peaks perf baseline --project <repo> --apply --reason "capturing baseline for Gate A4 diff"
|
|
525
|
+
# → ok: true, data.writtenFiles includes the path
|
|
526
|
+
|
|
527
|
+
# 3. fill in the file's Results table
|
|
528
|
+
# (lighthouse / k6 / autocannon / project-local bench — the
|
|
529
|
+
# CLI does not call any of these; that is the RD's job)
|
|
530
|
+
# open .peaks/<sid>/rd/perf-baseline.md and complete the
|
|
531
|
+
# "Path / route | Workload | Tool | Metric | Baseline | Threshold"
|
|
532
|
+
# table
|
|
533
|
+
|
|
534
|
+
# 4. hand off to QA. The QA stage reads the file's Results
|
|
535
|
+
# table as the input to Gate A4 — see peaks-qa SKILL.md
|
|
536
|
+
# Gate A4.
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
**Idempotency:** re-running `peaks perf baseline --apply` on a session where the file already exists is a no-op (the CLI does not overwrite hand-edited content). This is the normal RD retry pattern (re-measurement, threshold adjustment, etc.). If the RD really does want to overwrite, delete the file first and re-run.
|
|
540
|
+
|
|
541
|
+
**The role of the CLI vs. the actual measurement:** the CLI is the *scaffolding*. It writes the file, exposes the path, and keeps the file's structure stable so QA can rely on it. The CLI does NOT call lighthouse / k6 / autocannon — those are project-shape dependent and the right tool is a project-local concern, not a peaks-cli concern. The CLI is justified (4-grounds check): it gates the QA-side decision on a stable artefact, it requires --apply for a destructive write, and it is invokable from a hook on session init. It is *not* a machine-enforced gate that prose cannot enforce — the measurement is the RD's responsibility.
|
|
542
|
+
|
|
410
543
|
## Implementation completion gates
|
|
411
544
|
|
|
412
545
|
RD cannot mark a development slice complete until all of these are true. Each gate below maps to a hard verification gate in the Transition Verification Gates section — run the corresponding command, see the output.
|
|
@@ -420,6 +553,7 @@ RD cannot mark a development slice complete until all of these are true. Each ga
|
|
|
420
553
|
4. for frontend or UI-affecting slices, RD self-test has launched the app and used Playwright MCP for real browser end-to-end validation with visible-browser confirmation (install via `peaks mcp plan/apply --capability playwright-mcp.browser-validation --yes` if not yet present; navigate with `mcp__playwright__browser_navigate`, capture with `browser_snapshot` / `browser_take_screenshot` / `browser_console_messages` / `browser_network_requests`, sanitize route/actions and observations before retention, record acceptance result, close with `browser_close`); if login, CAPTCHA, SSO, or MFA appears, the headed browser is already visible — wait for the user to complete login and explicitly confirm completion before continuing;
|
|
421
554
|
5. code review has been performed with findings recorded and CRITICAL/HIGH issues fixed before progression; unresolved CRITICAL/HIGH findings only allow a blocked handoff; **→ verified by Peaks-Cli Gate B3** — evidence file must exist at `.peaks/<id>/rd/code-review.md`
|
|
422
555
|
6. security review has been performed for the changed surface, with CRITICAL/HIGH issues fixed before progression and particular attention to user input, file system access, external calls, auth, secrets, and dependency changes; **→ verified by Peaks-Cli Gate B4** — evidence file must exist at `.peaks/<id>/rd/security-review.md`
|
|
556
|
+
6.5. perf-baseline output is in place for any slice with a user-perceivable performance surface — `peaks perf baseline --apply` has been run and `.peaks/<session-id>/rd/perf-baseline.md` exists with the Results table filled in with measurements (or `N/A — no perf surface` in Notes for slices without a perf surface). For docs / chore / pure-bugfix-no-perf, the file is not required. Run the fan-out from "Parallel review fan-out" below; **→ verified by Peaks-Cli Gate B9** — evidence file must exist at `.peaks/<id>/rd/perf-baseline.md` and contain a non-empty Results table or the N/A marker.
|
|
423
557
|
7. the post-check dry-run has passed and is linked in the handoff;
|
|
424
558
|
8. the tech-doc artifact (`.peaks/<session-id>/rd/tech-doc.md`) is written and linked from the request artifact. **→ verified by Peaks-Cli Gate B**
|
|
425
559
|
9. the RD request artifact body has no unfilled placeholders, TBD markers, or bare-bullet stubs (`peaks request lint <rid> --role rd`). **→ verified by Peaks-Cli Gate B5**
|
|
@@ -429,6 +563,89 @@ RD cannot mark a development slice complete until all of these are true. Each ga
|
|
|
429
563
|
|
|
430
564
|
If any gate fails, return to development for fixes or hand off as blocked. Do not describe the work as done, shippable, or ready for QA.
|
|
431
565
|
|
|
566
|
+
## Parallel review fan-out (code-review + security-review + perf-baseline + qa-test-cases)
|
|
567
|
+
|
|
568
|
+
**When RD reaches the end of implementation, the four review activities (code review, security review, perf baseline, AND QA test-cases draft) run in parallel via Task() sub-agents, not sequentially.** This is the same fan-out pattern peaks-solo uses for the post-PRD swarm (see `peaks-solo/SKILL.md` "Peaks-Cli Swarm parallel phase" L659-764). RD itself, when it is the main loop, behaves as a sub-agent orchestrator: it issues 4 Task() calls in a single message and waits for all to return before aggregating findings and transitioning to `qa-handoff`.
|
|
569
|
+
|
|
570
|
+
**Why 4 sub-agents (added in slice 004):** the original 3-way fan-out (code-review + security-review + perf-baseline) cut the RD→QA wall-clock by running 3 LLM writes in parallel, but `qa/test-cases/<rid>.md` was still written sequentially by QA's main loop AFTER the RD handoff landed. Drafting QA test-cases in the same fan-out means the QA main loop's first action is "execute the pre-drafted test plan + write test-report" instead of "draft a test plan from scratch + execute + write report". Wall-clock drop: ~30-40% on the RD→QA-verdict segment for `feature` / `refactor` / `bugfix` slices.
|
|
571
|
+
|
|
572
|
+
**When to fan out:**
|
|
573
|
+
- Feature / refactor slices: all four sub-agents always run.
|
|
574
|
+
- Bugfix slices: code-review + security-review + qa-test-cases always run; perf-baseline runs only when the bug is performance-shaped (matches the "When this applies" criteria in the perf-baseline section above).
|
|
575
|
+
- Config / docs / chore slices: no fan-out (no review surface). Document N/A in the request artifact. (qa-test-cases also skipped — config / docs / chore have no acceptance surface to validate.)
|
|
576
|
+
|
|
577
|
+
**The Task() template (mirror of peaks-solo L705-717):**
|
|
578
|
+
|
|
579
|
+
```
|
|
580
|
+
Task(
|
|
581
|
+
subagent_type="general-purpose",
|
|
582
|
+
description="<role> review for rid=<rid>",
|
|
583
|
+
prompt="<role contract below>, plus runtime args: project=<repo>, session-id=<sid>, request-id=<rid>. Write your evidence file at .peaks/<sid>/<evidence-path> and return ONLY the path. Do not call Skill(...). Do not set presence. Do not prompt the user. Do not commit, push, install hooks, or mutate settings.json. Do not edit any source file — review only."
|
|
584
|
+
)
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
Note: sub-agents 1-3 write to `rd/<evidence-path>`, sub-agent 4 writes to `qa/test-cases/<rid>.md` (QA's dir). The role name in the description differentiates them.
|
|
588
|
+
|
|
589
|
+
**Sub-agent 1 — code-reviewer (always runs for feature / refactor / bugfix):**
|
|
590
|
+
- Read the git diff for this slice (`git diff main...HEAD` or equivalent).
|
|
591
|
+
- Read `.peaks/<sid>/rd/tech-doc.md` for slice intent.
|
|
592
|
+
- Inspect for: correctness, type safety, error handling, mutation patterns, file-size, naming, dead code, regressions, contract drift.
|
|
593
|
+
- Output: `.peaks/<sid>/rd/code-review.md` with sections: Summary, Findings (CRITICAL/HIGH/MEDIUM/LOW with file:line), Required Fixes (CRITICAL+HIGH only), Recommended (MEDIUM+LOW), Verdict (pass | return-to-rd | blocked).
|
|
594
|
+
- Required for Gate B3.
|
|
595
|
+
|
|
596
|
+
**Sub-agent 2 — security-reviewer (always runs for feature / refactor / bugfix):**
|
|
597
|
+
- Read the git diff and the file list.
|
|
598
|
+
- Read `.peaks/<sid>/rd/tech-doc.md` for the slice's threat model.
|
|
599
|
+
- Inspect for: hardcoded secrets, unsanitized input, path traversal, SQL injection, XSS, missing auth, dependency changes, external API surface, command injection via Bash guards.
|
|
600
|
+
- Output: `.peaks/<sid>/rd/security-review.md` with the same shape (Summary, Findings, Required Fixes, Recommended, Verdict).
|
|
601
|
+
- Required for Gate B4.
|
|
602
|
+
|
|
603
|
+
**Sub-agent 3 — perf-baseline-reviewer (feature / refactor / bugfix-when-perf only):**
|
|
604
|
+
- Read the git diff and the slice's PRD/tech-doc for any mentioned numbers (LCP / FCP / TBT / p95 / rps).
|
|
605
|
+
- Run `peaks perf baseline --project <repo> --apply --reason "parallel fan-out for rid=<rid>"` to scaffold `.peaks/<sid>/rd/perf-baseline.md` (idempotent: re-run is a no-op per `src/services/perf/perf-baseline-service.ts:188-201`).
|
|
606
|
+
- Inspect the slice for a user-perceivable performance surface (route, hook, API, render, hot loop, N+1).
|
|
607
|
+
- Decide: perf surface exists → leave the scaffold in place for the main RD loop to fill in the Results table with actual measurements (lighthouse / k6 / autocannon / project-local bench — the CLI does NOT run these). No perf surface → write `N/A — no perf surface` in the file's Notes section and return.
|
|
608
|
+
- Output: `.peaks/<sid>/rd/perf-baseline.md` (scaffolded, or N/A stub), plus a one-line return string: `perf-baseline: scaffolded — main loop must fill Results table` OR `perf-baseline: N/A — no perf surface`.
|
|
609
|
+
- Required for Gate B9. The Results-table-filling happens in the main RD loop AFTER the fan-out returns and BEFORE `rd:qa-handoff` transition.
|
|
610
|
+
|
|
611
|
+
**Sub-agent 4 — qa-test-cases-writer (always runs for feature / refactor / bugfix; added in slice 004):**
|
|
612
|
+
- Read the git diff for this slice.
|
|
613
|
+
- Read `.peaks/<sid>/rd/tech-doc.md` (or `bug-analysis.md` for bugfix) for the slice's acceptance criteria.
|
|
614
|
+
- Read `.peaks/<sid>/prd/requests/<rid>.md` for the user's "Acceptance criteria" section.
|
|
615
|
+
- Draft the test plan: enumerate every acceptance criterion from the PRD as a separate test case; for each, write a `ts` test snippet (using vitest, jest, or the project's test framework per the existing test files), assert the expected outcome, and link the test to the PRD criterion by ID or section reference.
|
|
616
|
+
- Include the standard test plan sections: ## Test cases (with `ts` code blocks), ## Test case summary (table), ## Mandatory validation gates (units / API / browser / security / performance), ## Regression matrix, ## Verdict.
|
|
617
|
+
- The test cases do NOT need to be executed by this sub-agent — execution is the QA main loop's job, AFTER the RD handoff lands. The sub-agent's contract is: "produce a runnable, exhaustive, type-correct test plan that QA can execute verbatim."
|
|
618
|
+
- Output: `.peaks/<sid>/qa/test-cases/<rid>.md`.
|
|
619
|
+
- Required for Gate C (RD-side qa-handoff transition, added in slice 004). When this file is present at RD's qa-handoff transition, QA's main loop can skip its own "draft test plan" step and proceed directly to "execute pre-drafted test plan + write test-report + security-findings + performance-findings + verdict".
|
|
620
|
+
- Failure mode: if the PRD is missing or the acceptance criteria are too vague to enumerate, this sub-agent returns `blocked` with a `blockedReason` like `prd-missing` or `acceptance-criteria-vague`; the main RD loop then escalates via AskUserQuestion before falling back to inline QA test-case drafting.
|
|
621
|
+
|
|
622
|
+
**Hard prohibitions on all 4 sub-agents (mirror of peaks-solo L729-734):**
|
|
623
|
+
- Do NOT call `Skill(skill="...")` — would re-enter RD or another skill and break the fan-out.
|
|
624
|
+
- Do NOT call `peaks skill presence:set` — only the main RD loop owns presence.
|
|
625
|
+
- Do NOT open interactive user prompts. If something is unclear, return `blocked` and let the main loop handle the user.
|
|
626
|
+
- Do NOT commit, push, install hooks, or mutate `~/.claude/settings.json` or `.claude/settings.json`. Only the main RD loop holds those permissions.
|
|
627
|
+
- Do NOT edit any source file under `src/`, `tests/`, `skills/`, `bin/`, `scripts/`, `docs/`, `schemas/`. Review only. (Sub-agent 4, qa-test-cases-writer, may write test code in the test plan body, but does NOT write to `tests/` files on disk — that is the QA main loop's job, after the verdict is issued.)
|
|
628
|
+
|
|
629
|
+
**Aggregation (after all 4 sub-agents return):**
|
|
630
|
+
|
|
631
|
+
1. Restore presence: `peaks skill presence:set peaks-rd --project <repo> --gate review-fan-out-converged`
|
|
632
|
+
2. Run the 4 `ls` checks (Gate B3 code-review, Gate B4 security-review, Gate B9 perf-baseline, Gate C2 qa-test-cases — the last one is a new check added in slice 004).
|
|
633
|
+
3. Read each evidence file. Aggregate CRITICAL/HIGH across code-review + security-review.
|
|
634
|
+
4. If any CRITICAL or HIGH finding exists in code-review.md or security-review.md: fix in the main RD loop, then re-launch ONLY the affected sub-agent(s) to verify the fix. Loop until clean, or mark as blocked if the issue cannot be resolved.
|
|
635
|
+
5. For perf-baseline: if scaffolded, run the project's perf measurement tool, fill in the Results table (Path / route | Workload | Tool | Metric | Baseline | Threshold), and `git diff` the file to confirm the table has data (not just the header row). If N/A, no measurement needed.
|
|
636
|
+
6. For qa-test-cases: the file is now pre-drafted by sub-agent 4. The main RD loop does NOT re-draft it; it only verifies (a) the file exists, (b) every PRD acceptance criterion is enumerated, (c) every `ts` test snippet is syntactically valid (the sub-agent's contract guarantees the last two; the main loop's job is just the `ls` check). If the sub-agent's draft is incomplete, fix it inline in the main RD loop (small edits only) OR re-launch the sub-agent (large re-drafts).
|
|
637
|
+
7. Re-run all 4 `ls` checks to confirm the evidence files are present and not empty.
|
|
638
|
+
8. Only then transition `peaks request transition <rid> --role rd --state qa-handoff --project <repo> --json`.
|
|
639
|
+
|
|
640
|
+
**Degradation when a sub-agent fails or returns blocked:**
|
|
641
|
+
- code-review sub-agent fails: fall back to inline RD code review (the L486-506 Gate B3 is still required; only the fan-out is degraded). TXT handoff note: `code-review-subagent-degraded-to-inline`.
|
|
642
|
+
- security-review sub-agent fails: same fallback. TXT note: `security-review-subagent-degraded-to-inline`.
|
|
643
|
+
- perf-baseline sub-agent fails: same fallback. TXT note: `perf-baseline-subagent-degraded-to-inline`.
|
|
644
|
+
- qa-test-cases sub-agent fails: fall back to inline QA test-case drafting at the start of QA's main loop (i.e. QA drafts the test cases itself, instead of receiving the pre-drafted file). TXT note: `qa-test-cases-subagent-degraded-to-inline-qa-draft`. The wall-clock win is reduced but not eliminated — QA's drafting is still faster than writing from scratch because the test plan can be drafted from the PRD + tech-doc directly.
|
|
645
|
+
- 2 or more fail: do not hand off as clean; transition to `qa-handoff` with `--allow-incomplete --reason "<degradation>"` OR block.
|
|
646
|
+
|
|
647
|
+
**Why this works (3-loop repair closure):** the original 3-loop repair pain (`qa return for perf → rd fix → qa return for perf again → ...`) was caused by perf being QA-only. This fan-out moves perf measurement to the RD side AND runs it in parallel with the other reviews, so the RD handoff is complete on the first attempt instead of after several cycles. **Slice 004 extends the same pattern to QA test-cases** so the QA→verdict loop is also faster on the first attempt.
|
|
648
|
+
|
|
432
649
|
## Refactor hard gates
|
|
433
650
|
|
|
434
651
|
If a request is refactor, cleanup, architecture adjustment, module split, or technical debt work:
|
|
@@ -570,4 +787,6 @@ Do not run upstream installer flows, mutate agent settings, or commit `.codegrap
|
|
|
570
787
|
|
|
571
788
|
Do not bypass PRD/QA artifacts. Do not install hooks, agents, MCP, or settings. Ask the Peaks-Cli CLI to handle runtime side effects.
|
|
572
789
|
|
|
790
|
+
Do not bypass the parallel review fan-out when the slice has a code-review / security-review / perf-baseline surface — see `## Parallel review fan-out` above for the contract. The three review activities are fan-out, not sequential; sequential re-implementation of the same logic by the main RD loop defeats the wall-clock benefit and is treated as a red-line violation.
|
|
791
|
+
|
|
573
792
|
Reference: `references/refactor-workflow.md`.
|