peaks-cli 1.3.6 → 1.3.8

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 (33) hide show
  1. package/dist/src/cli/commands/core-artifact-commands.js +119 -14
  2. package/dist/src/cli/commands/request-commands.js +31 -1
  3. package/dist/src/cli/commands/slice-commands.js +9 -5
  4. package/dist/src/cli/commands/workspace-commands.js +46 -2
  5. package/dist/src/services/artifacts/request-artifact-service.d.ts +16 -0
  6. package/dist/src/services/artifacts/request-artifact-service.js +18 -2
  7. package/dist/src/services/session/caller-binding-service.d.ts +70 -0
  8. package/dist/src/services/session/caller-binding-service.js +148 -0
  9. package/dist/src/services/session/caller-id-types.d.ts +77 -0
  10. package/dist/src/services/session/caller-id-types.js +46 -0
  11. package/dist/src/services/session/index.d.ts +4 -0
  12. package/dist/src/services/session/index.js +5 -0
  13. package/dist/src/services/session/platform-fallbacks.d.ts +31 -0
  14. package/dist/src/services/session/platform-fallbacks.js +35 -0
  15. package/dist/src/services/session/resolve-caller-id.d.ts +57 -0
  16. package/dist/src/services/session/resolve-caller-id.js +88 -0
  17. package/dist/src/services/session/session-manager.d.ts +55 -0
  18. package/dist/src/services/session/session-manager.js +68 -0
  19. package/dist/src/services/skills/skill-presence-service.d.ts +21 -4
  20. package/dist/src/services/skills/skill-presence-service.js +75 -11
  21. package/dist/src/services/slice/slice-check-service.js +36 -18
  22. package/dist/src/services/slice/slice-check-types.d.ts +40 -6
  23. package/dist/src/services/slice/slice-check-types.js +11 -1
  24. package/dist/src/shared/version.d.ts +1 -1
  25. package/dist/src/shared/version.js +1 -1
  26. package/package.json +1 -1
  27. package/skills/peaks-qa/SKILL.md +5 -2
  28. package/skills/peaks-rd/SKILL.md +18 -133
  29. package/skills/peaks-rd/references/rd-transition-gates.md +148 -0
  30. package/skills/peaks-solo/SKILL.md +18 -209
  31. package/skills/peaks-solo/references/frontend-only-mode.md +73 -0
  32. package/skills/peaks-solo/references/micro-cycle.md +4 -2
  33. package/skills/peaks-solo/references/project-scan-checklist.md +136 -0
@@ -69,16 +69,27 @@ function parseVitestSummary(stdout, fallbackDuration) {
69
69
  durationMs: durationMatch ? Math.round(parseFloat(durationMatch[1]) * 1000) : fallbackDuration
70
70
  };
71
71
  }
72
- async function runUnitTests(projectRoot) {
72
+ async function runUnitTests(projectRoot, runTests) {
73
73
  const start = Date.now();
74
- const result = runCommand('npx', ['vitest', 'run', '--reporter=default', '--coverage=false'], projectRoot, 600_000);
74
+ // Default: changed-only suite (`vitest run --changed`) runs only tests
75
+ // related to git-changed files. Cost drops from 30s+ to ~1-3s in steady
76
+ // state. Opt-in to the full suite via `runTests: true` (CLI flag
77
+ // `--run-tests`). See `references/runbook.md` for the rationale and
78
+ // `tests/unit/slice-check-service.test.ts` for the regression net.
79
+ const args = runTests
80
+ ? ['vitest', 'run', '--reporter=default', '--coverage=false']
81
+ : ['vitest', 'run', '--changed', '--reporter=default', '--coverage=false'];
82
+ const description = runTests
83
+ ? 'npx vitest run (full test suite, coverage off)'
84
+ : 'npx vitest run --changed (tests for git-changed files only, coverage off)';
85
+ const result = runCommand('npx', args, projectRoot, 600_000);
75
86
  const summary = parseVitestSummary(result.stdout, result.durationMs);
76
87
  // Vitest doesn't always print the per-bucket counts cleanly; infer "passed"
77
88
  // as total - failed - skipped when failed/skipped buckets are present.
78
89
  const passed = Math.max(summary.tests - summary.failed - summary.skipped, 0);
79
90
  return {
80
91
  name: 'unit-tests',
81
- description: 'npx vitest run (full test suite, coverage off)',
92
+ description,
82
93
  status: result.status,
83
94
  durationMs: result.durationMs,
84
95
  detail: result.status === 'pass'
@@ -89,6 +100,7 @@ async function runUnitTests(projectRoot) {
89
100
  passed,
90
101
  failed: summary.failed,
91
102
  skipped: summary.skipped,
103
+ mode: runTests ? 'full' : 'changed',
92
104
  exitCode: result.exitCode
93
105
  }
94
106
  };
@@ -206,40 +218,45 @@ export async function sliceCheck(options) {
206
218
  }
207
219
  const totalStart = Date.now();
208
220
  const stages = [];
221
+ let unitTestsRunMode = 'skipped';
209
222
  // Stage 1: typecheck
210
223
  stages.push(await runTypecheck(options.projectRoot));
211
- // Stage 2: full vitest
212
- if (!options.skipTests) {
213
- const unitTests = await runUnitTests(options.projectRoot);
214
- // Opt-in override: if --allow-pre-existing-failures is set AND the
224
+ // Stage 2: unit-tests — by default changed-only suite, opt-in to full
225
+ if (options.skipTests) {
226
+ stages.push({
227
+ name: 'unit-tests',
228
+ description: 'npx vitest run (skipped per --skip-tests)',
229
+ status: 'skipped',
230
+ durationMs: 0,
231
+ detail: 'Skipped: --skip-tests was set. Use the peaks-solo-test skill to run the full suite manually.'
232
+ });
233
+ unitTestsRunMode = 'skipped';
234
+ }
235
+ else {
236
+ const unitTests = await runUnitTests(options.projectRoot, options.runTests === true);
215
237
  // unit-test stage failed, downgrade `failed` to `skipped` with a
216
238
  // reason that names the failure count and points to the long-term
217
- // fix. Does NOT affect the other 3 stages.
239
+ // fix. Does NOT affect the other 3 stages. Only meaningful when
240
+ // the stage actually runs (skipped-tests bypass short-circuits
241
+ // above).
218
242
  if (options.allowPreExistingFailures === true &&
219
243
  unitTests.status === 'fail') {
220
244
  const failureCount = unitTests.data?.failed ?? 0;
221
245
  stages.push({
222
246
  name: 'unit-tests',
223
- description: 'npx vitest run (overridden via --allow-pre-existing-failures)',
247
+ description: `npx vitest run ${options.runTests === true ? '' : '--changed '} (overridden via --allow-pre-existing-failures)`.trim(),
224
248
  status: 'skipped',
225
249
  durationMs: unitTests.durationMs,
226
250
  detail: `pre-existing failures: ${failureCount} failing test(s) under coverage.exclude or unrelated to this slice; user opted in via --allow-pre-existing-failures. For the long-term fix, mark these tests .skip or move to coverage.exclude (see dogfood-2-f1-f4.md F17c).`,
227
251
  data: { ...(unitTests.data ?? {}), overriddenFrom: 'fail', failureCount }
228
252
  });
253
+ unitTestsRunMode = 'overridden';
229
254
  }
230
255
  else {
231
256
  stages.push(unitTests);
257
+ unitTestsRunMode = options.runTests === true ? 'full' : 'changed';
232
258
  }
233
259
  }
234
- else {
235
- stages.push({
236
- name: 'unit-tests',
237
- description: 'npx vitest run (skipped per --skip-tests)',
238
- status: 'skipped',
239
- durationMs: 0,
240
- detail: 'Skipped: --skip-tests was set.'
241
- });
242
- }
243
260
  // Stage 3: 3-way review fanout check
244
261
  stages.push(await runReviewFanout(options.projectRoot, rid, options.refreshFanout));
245
262
  // Stage 4: gate verify-pipeline
@@ -260,6 +277,7 @@ export async function sliceCheck(options) {
260
277
  projectRoot: options.projectRoot,
261
278
  rid,
262
279
  stages,
280
+ unitTestsRunMode,
263
281
  boundaryReady,
264
282
  totalDurationMs: Date.now() - totalStart,
265
283
  nextActions
@@ -7,13 +7,23 @@
7
7
  * off to peaks-qa:
8
8
  *
9
9
  * 1. typecheck (`npx tsc --noEmit`)
10
- * 2. unit tests (`npx vitest run`)
10
+ * 2. unit tests by default the **changed-only** suite
11
+ * (`npx vitest run --changed`). Pass `--run-tests` to opt in to the
12
+ * full suite (`npx vitest run`); pass `--skip-tests` to skip
13
+ * entirely (e.g. docs-only or config-only slices).
11
14
  * 3. 3-way review fan-out (code-review + security-review + perf-baseline)
12
15
  * 4. gate machinery (`peaks workflow verify-pipeline --rid <rid>`)
13
16
  *
14
17
  * The micro-cycle itself (per-bug TDD) runs OUTSIDE slice check — only
15
18
  * single-test runs (`vitest -t "<name>"`) are allowed in micro-cycles.
16
19
  * This command is for the BOUNDARY, not the inner loop.
20
+ *
21
+ * The unit-test stage emits a `unitTestsRunMode` field on the result
22
+ * envelope so downstream tooling and the QA test-report can record
23
+ * which mode actually ran: `"changed"` (default), `"full"` (with
24
+ * `--run-tests`), `"skipped"` (with `--skip-tests`), or `"overridden"`
25
+ * (with `--allow-pre-existing-failures` when the run failed and the
26
+ * stage was downgraded to `skipped` with a reason).
17
27
  */
18
28
  export type SliceCheckStageStatus = 'pass' | 'fail' | 'skipped';
19
29
  export type SliceCheckStage = {
@@ -36,6 +46,15 @@ export type SliceCheckResult = {
36
46
  rid: string | null;
37
47
  /** All stages in execution order. */
38
48
  stages: SliceCheckStage[];
49
+ /**
50
+ * Which unit-test mode actually ran. One of:
51
+ * - `"changed"` — default: `npx vitest run --changed` (tests for git-changed files only)
52
+ * - `"full"` — opt-in via `--run-tests`: `npx vitest run` (full suite)
53
+ * - `"skipped"` — opt-in via `--skip-tests` (stage not executed)
54
+ * - `"overridden"` — full mode + `--allow-pre-existing-failures` and the run failed;
55
+ * stage downgraded to `skipped` with the pre-existing-failure reason
56
+ */
57
+ unitTestsRunMode: 'changed' | 'full' | 'skipped' | 'overridden';
39
58
  /** True iff every stage passed (or was skipped) and the boundary is OK to hand off. */
40
59
  boundaryReady: boolean;
41
60
  /** Total wall-clock duration in ms. */
@@ -54,17 +73,32 @@ export type SliceCheckOptions = {
54
73
  */
55
74
  refreshFanout: boolean;
56
75
  /**
57
- * When true, skip the unit-test stage. Useful when a slice has no unit
58
- * tests (e.g. a docs-only or config-only slice).
76
+ * When true, run the **full** `npx vitest run` suite at the boundary.
77
+ * When false (the default), run the **changed-only** suite
78
+ * (`npx vitest run --changed`) which only exercises tests related to
79
+ * git-changed files. The changed-only mode is the new default as of
80
+ * run 017 — full suite costs 30s+ on this repo; the changed-only
81
+ * mode costs ~1-3s in steady state and is what catches the
82
+ * regressions that actually matter. The service treats `undefined`
83
+ * the same as `false`.
84
+ */
85
+ runTests?: boolean;
86
+ /**
87
+ * When true, skip the unit-test stage entirely. Useful when a slice
88
+ * has no test surface (e.g. a docs-only or config-only slice), or
89
+ * when the user wants a "typecheck + review + gate" boundary check
90
+ * without any test execution.
59
91
  */
60
92
  skipTests: boolean;
61
93
  /**
62
94
  * When true, an `unit-tests` stage that fails is reported as `skipped`
63
95
  * (with a `reason` naming the pre-existing failure count) instead of
64
96
  * `failed`. Used to opt in to bypassing the 28 pre-existing Windows
65
- * test failures documented in dogfood-2-f1-f4.md F17. Does NOT affect
66
- * the other 3 stages (typecheck / review-fanout / gate-verify-pipeline).
67
- * Default: false. The service treats `undefined` the same as `false`.
97
+ * test failures documented in dogfood-2-f1-f4.md F17. Only meaningful
98
+ * when the unit-test stage actually runs (i.e. not when `skipTests`
99
+ * is true). Does NOT affect the other 3 stages (typecheck /
100
+ * review-fanout / gate-verify-pipeline). Default: false. The service
101
+ * treats `undefined` the same as `false`.
68
102
  */
69
103
  allowPreExistingFailures?: boolean;
70
104
  };
@@ -7,12 +7,22 @@
7
7
  * off to peaks-qa:
8
8
  *
9
9
  * 1. typecheck (`npx tsc --noEmit`)
10
- * 2. unit tests (`npx vitest run`)
10
+ * 2. unit tests by default the **changed-only** suite
11
+ * (`npx vitest run --changed`). Pass `--run-tests` to opt in to the
12
+ * full suite (`npx vitest run`); pass `--skip-tests` to skip
13
+ * entirely (e.g. docs-only or config-only slices).
11
14
  * 3. 3-way review fan-out (code-review + security-review + perf-baseline)
12
15
  * 4. gate machinery (`peaks workflow verify-pipeline --rid <rid>`)
13
16
  *
14
17
  * The micro-cycle itself (per-bug TDD) runs OUTSIDE slice check — only
15
18
  * single-test runs (`vitest -t "<name>"`) are allowed in micro-cycles.
16
19
  * This command is for the BOUNDARY, not the inner loop.
20
+ *
21
+ * The unit-test stage emits a `unitTestsRunMode` field on the result
22
+ * envelope so downstream tooling and the QA test-report can record
23
+ * which mode actually ran: `"changed"` (default), `"full"` (with
24
+ * `--run-tests`), `"skipped"` (with `--skip-tests`), or `"overridden"`
25
+ * (with `--allow-pre-existing-failures` when the run failed and the
26
+ * stage was downgraded to `skipped` with a reason).
17
27
  */
18
28
  export {};
@@ -1 +1 @@
1
- export declare const CLI_VERSION = "1.3.6";
1
+ export declare const CLI_VERSION = "1.3.8";
@@ -1 +1 @@
1
- export const CLI_VERSION = "1.3.6";
1
+ export const CLI_VERSION = "1.3.8";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "peaks-cli",
3
- "version": "1.3.6",
3
+ "version": "1.3.8",
4
4
  "description": "Cross-AI-IDE workflow-gating CLI + skill family (Claude Code shipped, Trae in progress; Codex / Cursor / Qoder / Tongyi Lingma on the roadmap).",
5
5
  "author": "SquabbyZ",
6
6
  "license": "MIT",
@@ -356,7 +356,10 @@ ls .peaks/<changeId>/qa/test-cases/<rid>.md
356
356
  ```bash
357
357
  # Run the project's test command. Do NOT skip this. Writing test cases is not enough.
358
358
  # Example (adapt to project):
359
- npx vitest run --reporter=verbose 2>&1 | tail -30
359
+ # QA validation defaults to the CHANGED-ONLY suite (matches `peaks slice check` default as of run 017).
360
+ # Use the full suite only when the slice is structurally significant or when the user explicitly asks
361
+ # for it (e.g. via /peaks-solo-test or `peaks slice check --run-tests`).
362
+ npx vitest run --changed --reporter=verbose 2>&1 | tail -30
360
363
  # Expected: exit code 0, actual test output with pass/fail counts
361
364
  # "0 tests executed" or "no test files found" → BLOCKED. Tests were written but not run.
362
365
  # Record the raw test output and link it in the test report.
@@ -504,7 +507,7 @@ QA must generate test cases, not merely inspect existing ones. Every QA invocati
504
507
 
505
508
  **Acceptance linkage (MANDATORY)** — every test case MUST have an `**Acceptance:**` field that references one or more acceptance items from the PRD by their position-based IDs (A1 = first bullet, A2 = second, …). The `peaks scan acceptance-coverage --rid <rid> --project <repo>` command parses both the PRD and this file, builds the coverage map, and fails the QA `verdict-issued` gate if any acceptance item has zero linked test cases. Test cases that genuinely have no acceptance owner (e.g. defense-in-depth regressions) should still include `- **Acceptance:** —` and explain in the **Evidence** field; the coverage report flags these as `unlinkedTestCases` for review without auto-blocking.
506
509
 
507
- **Test-case execution**: Run the project's test command and record results against each generated test case. If the project uses Jest, run `npx jest --coverage` and link the coverage report. If the project uses Vitest, run `npx vitest run --coverage`. Record the coverage percentage for changed files in the test report.
510
+ **Test-case execution**: Run the project's test command and record results against each generated test case. If the project uses Jest, run `npx jest --coverage` and link the coverage report. If the project uses Vitest, run `npx vitest run --changed --coverage` by default (matches the new `peaks slice check` default as of run 017); use the full suite `npx vitest run --coverage` only when the slice warrants a deeper regression check, or when invoked via /peaks-solo-test or `peaks slice check --run-tests`. Record the coverage percentage for changed files in the test report.
508
511
 
509
512
  ## Mandatory test-report output
510
513
 
@@ -266,7 +266,7 @@ peaks codegraph affected --project <repo> <changed-files...> --json
266
266
  # Without project rules, security review and code review triggers won't fire.
267
267
 
268
268
  # 7. AFTER implementation, BEFORE QA handoff — RUN THESE GATES:
269
- # Peaks-Cli Gate B2: unit tests exist and pass → npx vitest run (or project equivalent)
269
+ # Peaks-Cli Gate B2: unit tests exist and pass for the changed surface → npx vitest run --changed (or project equivalent; the changed-only mode is the peaks slice check default as of run 017; use --run-tests for the full suite, or invoke /peaks-solo-test to run the full suite standalone)
270
270
  # Peaks-Cli Gate B3: code review evidence → .peaks/<changeId>/rd/code-review.md
271
271
  # Peaks-Cli Gate B4: security review evidence → .peaks/<changeId>/rd/security-review.md
272
272
  # Peaks-Cli Gate B5 (NEW): RD artifact body has no unfilled placeholders.
@@ -295,141 +295,26 @@ For refactor work, the coverage ≥ 95% gate in `Refactor hard gates` still appl
295
295
 
296
296
  You cannot declare a phase complete from memory. Each gate below is a `ls` or `grep` command you **MUST run** and whose output you **MUST see** before proceeding. If any file shows "No such file" or any command returns empty, the phase is incomplete.
297
297
 
298
- > **CLI enforcement (NEW)**: the gates below are now ALSO enforced by `peaks request transition`. The CLI checks the same files before allowing the transition and fails with `code: PREREQUISITES_MISSING` if any are absent. The exact required files depend on the request type chosen at `peaks request init --type <feature|bugfix|refactor|docs|config|chore>` (default `feature`):
299
- >
300
- > | Type | rd:implemented requires | rd:qa-handoff also requires |
301
- > |---|---|---|
302
- > | 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) |
303
- > | 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) |
304
- > | config | (none) | `rd/security-review.md` only |
305
- > | docs / chore | (none) | (none) |
306
- >
307
- > The escape hatch `--allow-incomplete --reason "<text>"` still exists for one-off exceptions; the bypass is recorded in the artifact transition note.
308
-
309
- **Peaks-Cli Gate A — After project-scan read (before any implementation):**
310
- ```bash
311
- ls .peaks/<changeId>/rd/project-scan.md
312
- # Expected output: .peaks/<changeId>/rd/project-scan.md
313
- # "No such file" → STOP, create the project-scan first. Do not write code.
314
- ```
315
-
316
- **Peaks-Cli Gate A2 — Before tech-doc write: project structure verified (PATH CORRECTNESS — CRITICAL):**
317
- ```bash
318
- # Verify EVERY file path and directory in the tech-doc exists in the actual project.
319
- # Do not assume paths. Do not guess directory structures. Open the files and verify.
320
- # Example verification (adapt paths to the actual tech-doc):
321
- ls <every-single-directory-path-in-tech-doc> 2>&1 | grep -c "No such file"
322
- # Expected: 0 (zero "No such file" errors)
323
- # Any "No such file" → WRONG PATH. Fix the tech-doc BEFORE writing another word.
324
- # This gate exists because a tech-doc with wrong paths wastes QA time,
325
- # breaks the implementation, and forces the user to correct the engineer.
326
- ```
327
-
328
- **Peaks-Cli Gate A3 — Before implementation: project standards files exist (CLAUDE.md + .claude/rules/):**
329
- ```bash
330
- ls CLAUDE.md .claude/rules/common/coding-style.md .claude/rules/common/code-review.md .claude/rules/common/security.md 2>&1 | grep -c "No such file"
331
- # Expected: 0 (all four files exist)
332
- # Any missing → BLOCKED. Run `peaks standards init --project .` to generate them FIRST.
333
- # Do not write a single line of implementation code without standards files in place.
334
- # Without CLAUDE.md and .claude/rules/, code review and security review triggers won't fire.
335
- ```
336
-
337
- **Peaks-Cli Gate B — Before QA handoff:**
338
- ```bash
339
- ls .peaks/<changeId>/rd/requests/<rid>.md \
340
- .peaks/<changeId>/rd/tech-doc.md
341
- # Both must exist. Missing either → BLOCKED, do not hand off to QA
342
- ```
343
-
344
- **Peaks-Cli Gate B2 — Before QA handoff: unit tests exist and pass:**
345
- ```bash
346
- # Run the project's test command against changed files. Record the output.
347
- # Example (adapt to project test runner):
348
- npx vitest run --reporter=verbose 2>&1 | tail -20
349
- # Expected: exit code 0, all tests passing, coverage for new/changed code recorded
350
- # Any failing test or zero tests for new code → BLOCKED. Write tests, then re-run.
351
- ```
352
-
353
- **Peaks-Cli Gate B3 — Before QA handoff: code review evidence exists:**
354
- ```bash
355
- ls .peaks/<changeId>/rd/code-review.md 2>&1
356
- # Expected: .peaks/<changeId>/rd/code-review.md
357
- # "No such file" → BLOCKED. Run code review (use code-reviewer agent or equivalent),
358
- # record findings, fix CRITICAL/HIGH issues, then re-check.
359
- ```
360
-
361
- **Peaks-Cli Gate B4 — Before QA handoff: security review evidence exists:**
362
- ```bash
363
- ls .peaks/<changeId>/rd/security-review.md 2>&1
364
- # Expected: .peaks/<changeId>/rd/security-review.md
365
- # "No such file" → BLOCKED. Run security review (use security-reviewer agent or equivalent),
366
- # fix CRITICAL/HIGH issues, record findings, then re-check.
367
- ```
298
+ The full per-gate contract — including the CLI enforcement table (per `--type` required files), the `ls` / `grep` shell snippets for Gate A, A2, A3, B, B2, B3, B4, B5, B6, B7, B8, B9, and the expected outcomes lives in [`references/rd-transition-gates.md`](references/rd-transition-gates.md). Read that file before declaring a phase complete. The summary below is the index; the reference file is the contract.
368
299
 
369
- **Peaks-Cli Gate B5 RD artifact body has no unfilled placeholders:**
370
- ```bash
371
- peaks request lint <rid> --role rd --project <repo> --session-id <session-id> --json
372
- # Expected: ok=true. exit 0.
373
- # ok=false → BLOCKED. The lint output lists every <placeholder>, "- ..." stub,
374
- # and TBD/TODO marker with line numbers. Fill them in before attempting handoff.
375
- ```
300
+ > **CLI enforcement**: the gates below are ALSO enforced by `peaks request transition`. The CLI checks the same files before allowing the transition and fails with `code: PREREQUISITES_MISSING` if any are absent. Per-type required files: see the table at the top of `references/rd-transition-gates.md`. The escape hatch `--allow-incomplete --reason "<text>"` still exists for one-off exceptions.
376
301
 
377
- **Peaks-Cli Gate B6 Declared --type matches the actual diff:**
378
- ```bash
379
- peaks scan request-type-sanity --project <repo> --type <type> --json
380
- # Expected: consistent=true. exit 0.
381
- # consistent=false → BLOCKED. Either the implementation scope-creeped beyond what
382
- # the declared type covers, or the type was mis-classified at PRD time. Re-classify
383
- # (`peaks request init` with the corrected --type) or trim the scope.
384
- ```
302
+ **Index of gates** (full contract in `references/rd-transition-gates.md`):
385
303
 
386
- **Peaks-Cli Gate B7 Repair cycle cap (only relevant during RD↔QA repair loop):**
387
- ```bash
388
- peaks request repair-status <rid> --project <repo> --session-id <session-id> --json
389
- # Expected: atCap=false. exit 0.
390
- # atCap=true BLOCKED. Three repair cycles already attempted; emit a blocked TXT
391
- # handoff via Solo rather than entering a fourth cycle.
392
- ```
393
-
394
- **Peaks-Cli Gate B8 Diff stays inside the declared red-line scope:**
395
- ```bash
396
- peaks scan diff-vs-scope --rid <rid> --project <repo> --session-id <session-id> --json
397
- # Expected: ok=true. exit 0.
398
- # violations[] non-empty BLOCKED. A changed file matches an explicit out-of-scope
399
- # pattern. Revert it, or only with PRD approvalexpand the RD red-line scope.
400
- # unclassified[] non-empty → BLOCKED. A changed file does not match any declared
401
- # in-scope pattern. Either add it to the in-scope list (intentional widening, requires
402
- # PRD approval) or revert the change.
403
- # patternsDeclared=false → BLOCKED. The RD artifact's `## Red-line scope` section has
404
- # no concrete path or glob patterns. Fill it in with paths like `src/services/login/**`
405
- # before re-running. Auto-allowed paths (test files, .peaks/, __mocks__/) never need a pattern.
406
- ```
407
-
408
- **Peaks-Cli Gate B9 — RD-side perf-baseline output present (when slice has a user-perceivable perf surface):**
409
- ```bash
410
- ls .peaks/<changeId>/rd/perf-baseline.md 2>&1
411
- # Expected: .peaks/<changeId>/rd/perf-baseline.md
412
- # "No such file" + slice is feature / refactor / bugfix-when-perf → BLOCKED.
413
- # Run the perf-baseline sub-agent from "Parallel review fan-out" below (or
414
- # `peaks perf baseline --apply` inline), then fill in the Results table
415
- # with measurements (lighthouse / k6 / autocannon / project-local bench —
416
- # the CLI does not run these; that is the RD's job), then re-verify.
417
- # "No such file" + slice is docs / chore / pure-bugfix-no-perf → OK to proceed;
418
- # this gate does not apply to those slice types.
419
- # File exists but Results table is empty (only the header row, no data rows) →
420
- # BLOCKED. The sub-agent scaffolds the file; the main RD loop must fill in
421
- # the Path / route | Workload | Tool | Metric | Baseline | Threshold table
422
- # with actual numbers before handoff.
423
- # File contains the marker `N/A — no perf surface` in its Notes section →
424
- # OK to proceed. This is the explicit opt-out the sub-agent writes when
425
- # the slice has no user-perceivable perf surface (e.g. a feature that only
426
- # adds an internal flag with no runtime cost, or a refactor that does not
427
- # alter any hot path).
428
- #
429
- # The CLI enforcement table below the section header also gates this at the
430
- # `peaks request transition rd:qa-handoff` call, so a missing or empty file
431
- # is rejected by the CLI with `code: PREREQUISITES_MISSING`.
432
- ```
304
+ | Gate | When | File / command | Why |
305
+ |---|---|---|---|
306
+ | A | After project-scan read, before any implementation | `ls .peaks/<changeId>/rd/project-scan.md` | Confirms the project-scan exists before code edits |
307
+ | A2 | Before tech-doc write | `ls <every-path-in-tech-doc> \| grep -c "No such file"` | Catches wrong paths in the tech-doc |
308
+ | A3 | Before implementation | `ls CLAUDE.md .claude/rules/...` | Confirms project standards exist |
309
+ | B | Before QA handoff | `ls rd/requests/<rid>.md rd/tech-doc.md` | Both files must exist |
310
+ | B2 | Before QA handoff | `npx vitest run --changed` | Unit tests pass on the changed surface |
311
+ | B3 | Before QA handoff | `ls rd/code-review.md` | Code review evidence exists |
312
+ | B4 | Before QA handoff | `ls rd/security-review.md` | Security review evidence exists |
313
+ | B5 | Before QA handoff | `peaks request lint` | RD artifact has no unfilled placeholders |
314
+ | B6 | Before QA handoff | `peaks scan request-type-sanity` | Declared `--type` matches the diff |
315
+ | B7 | Before QA handoff (repair only) | `peaks request repair-status` | Cycle count under the 3-cycle cap |
316
+ | B8 | Before QA handoff | `peaks scan diff-vs-scope` | Diff stays in red-line scope |
317
+ | B9 | Before QA handoff (perf surface) | `ls rd/perf-baseline.md` | Perf baseline filled (or `N/A no perf surface`) |
433
318
 
434
319
  ## Project standards preflight
435
320
 
@@ -0,0 +1,148 @@
1
+ # Peaks-Cli RD transition verification gates
2
+
3
+ > Extracted from `skills/peaks-rd/SKILL.md` on 2026-06-09 (slice 019 — slim skill files to references) to keep SKILL.md under the 800-line cap from `common/coding-style.md`. The content below is the verbatim "Transition verification gates" section that was previously inline; nothing was paraphrased, just relocated.
4
+
5
+ ## Transition verification gates (MANDATORY — run the command, see the output)
6
+
7
+ You cannot declare a phase complete from memory. Each gate below is a `ls` or `grep` command you **MUST run** and whose output you **MUST see** before proceeding. If any file shows "No such file" or any command returns empty, the phase is incomplete.
8
+
9
+ > **CLI enforcement (NEW)**: the gates below are now ALSO enforced by `peaks request transition`. The CLI checks the same files before allowing the transition and fails with `code: PREREQUISITES_MISSING` if any are absent. The exact required files depend on the request type chosen at `peaks request init --type <feature|bugfix|refactor|docs|config|chore>` (default `feature`):
10
+ >
11
+ > | Type | rd:implemented requires | rd:qa-handoff also requires |
12
+ > |---|---|---|
13
+ > | 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) |
14
+ > | 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) |
15
+ > | config | (none) | `rd/security-review.md` only |
16
+ > | docs / chore | (none) | (none) |
17
+ >
18
+ > The escape hatch `--allow-incomplete --reason "<text>"` still exists for one-off exceptions; the bypass is recorded in the artifact transition note.
19
+
20
+ **Peaks-Cli Gate A — After project-scan read (before any implementation):**
21
+ ```bash
22
+ ls .peaks/<changeId>/rd/project-scan.md
23
+ # Expected output: .peaks/<changeId>/rd/project-scan.md
24
+ # "No such file" → STOP, create the project-scan first. Do not write code.
25
+ ```
26
+
27
+ **Peaks-Cli Gate A2 — Before tech-doc write: project structure verified (PATH CORRECTNESS — CRITICAL):**
28
+ ```bash
29
+ # Verify EVERY file path and directory in the tech-doc exists in the actual project.
30
+ # Do not assume paths. Do not guess directory structures. Open the files and verify.
31
+ # Example verification (adapt paths to the actual tech-doc):
32
+ ls <every-single-directory-path-in-tech-doc> 2>&1 | grep -c "No such file"
33
+ # Expected: 0 (zero "No such file" errors)
34
+ # Any "No such file" → WRONG PATH. Fix the tech-doc BEFORE writing another word.
35
+ # This gate exists because a tech-doc with wrong paths wastes QA time,
36
+ # breaks the implementation, and forces the user to correct the engineer.
37
+ ```
38
+
39
+ **Peaks-Cli Gate A3 — Before implementation: project standards files exist (CLAUDE.md + .claude/rules/):**
40
+ ```bash
41
+ ls CLAUDE.md .claude/rules/common/coding-style.md .claude/rules/common/code-review.md .claude/rules/common/security.md 2>&1 | grep -c "No such file"
42
+ # Expected: 0 (all four files exist)
43
+ # Any missing → BLOCKED. Run `peaks standards init --project .` to generate them FIRST.
44
+ # Do not write a single line of implementation code without standards files in place.
45
+ # Without CLAUDE.md and .claude/rules/, code review and security review triggers won't fire.
46
+ ```
47
+
48
+ **Peaks-Cli Gate B — Before QA handoff:**
49
+ ```bash
50
+ ls .peaks/<changeId>/rd/requests/<rid>.md \
51
+ .peaks/<changeId>/rd/tech-doc.md
52
+ # Both must exist. Missing either → BLOCKED, do not hand off to QA
53
+ ```
54
+
55
+ **Peaks-Cli Gate B2 — Before QA handoff: unit tests exist and pass for the changed surface:**
56
+ ```bash
57
+ # Run the project's test command against changed files. Record the output.
58
+ # Example (adapt to project test runner):
59
+ npx vitest run --changed --reporter=verbose 2>&1 | tail -20
60
+ # Expected: exit code 0, all changed-surface tests passing, coverage for new/changed code recorded
61
+ # Any failing test or zero tests for new code → BLOCKED. Write tests, then re-run.
62
+ #
63
+ # To run the FULL suite (slower; not the default for `peaks slice check`),
64
+ # drop `--changed` or use `npx vitest run --reporter=verbose`. The peaks-solo-test
65
+ # skill is the user-facing wrapper for the full suite; the slice check's
66
+ # `--run-tests` flag is the CLI opt-in.
67
+ ```
68
+
69
+ **Peaks-Cli Gate B3 — Before QA handoff: code review evidence exists:**
70
+ ```bash
71
+ ls .peaks/<changeId>/rd/code-review.md 2>&1
72
+ # Expected: .peaks/<changeId>/rd/code-review.md
73
+ # "No such file" → BLOCKED. Run code review (use code-reviewer agent or equivalent),
74
+ # record findings, fix CRITICAL/HIGH issues, then re-check.
75
+ ```
76
+
77
+ **Peaks-Cli Gate B4 — Before QA handoff: security review evidence exists:**
78
+ ```bash
79
+ ls .peaks/<changeId>/rd/security-review.md 2>&1
80
+ # Expected: .peaks/<changeId>/rd/security-review.md
81
+ # "No such file" → BLOCKED. Run security review (use security-reviewer agent or equivalent),
82
+ # fix CRITICAL/HIGH issues, record findings, then re-check.
83
+ ```
84
+
85
+ **Peaks-Cli Gate B5 — RD artifact body has no unfilled placeholders:**
86
+ ```bash
87
+ peaks request lint <rid> --role rd --project <repo> --session-id <session-id> --json
88
+ # Expected: ok=true. exit 0.
89
+ # ok=false → BLOCKED. The lint output lists every <placeholder>, "- ..." stub,
90
+ # and TBD/TODO marker with line numbers. Fill them in before attempting handoff.
91
+ ```
92
+
93
+ **Peaks-Cli Gate B6 — Declared --type matches the actual diff:**
94
+ ```bash
95
+ peaks scan request-type-sanity --project <repo> --type <type> --json
96
+ # Expected: consistent=true. exit 0.
97
+ # consistent=false → BLOCKED. Either the implementation scope-creeped beyond what
98
+ # the declared type covers, or the type was mis-classified at PRD time. Re-classify
99
+ # (`peaks request init` with the corrected --type) or trim the scope.
100
+ ```
101
+
102
+ **Peaks-Cli Gate B7 — Repair cycle cap (only relevant during RD↔QA repair loop):**
103
+ ```bash
104
+ peaks request repair-status <rid> --project <repo> --session-id <session-id> --json
105
+ # Expected: atCap=false. exit 0.
106
+ # atCap=true → BLOCKED. Three repair cycles already attempted; emit a blocked TXT
107
+ # handoff via Solo rather than entering a fourth cycle.
108
+ ```
109
+
110
+ **Peaks-Cli Gate B8 — Diff stays inside the declared red-line scope:**
111
+ ```bash
112
+ peaks scan diff-vs-scope --rid <rid> --project <repo> --session-id <session-id> --json
113
+ # Expected: ok=true. exit 0.
114
+ # violations[] non-empty → BLOCKED. A changed file matches an explicit out-of-scope
115
+ # pattern. Revert it, or — only with PRD approval — expand the RD red-line scope.
116
+ # unclassified[] non-empty → BLOCKED. A changed file does not match any declared
117
+ # in-scope pattern. Either add it to the in-scope list (intentional widening, requires
118
+ # PRD approval) or revert the change.
119
+ # patternsDeclared=false → BLOCKED. The RD artifact's `## Red-line scope` section has
120
+ # no concrete path or glob patterns. Fill it in with paths like `src/services/login/**`
121
+ # before re-running. Auto-allowed paths (test files, .peaks/, __mocks__/) never need a pattern.
122
+ ```
123
+
124
+ **Peaks-Cli Gate B9 — RD-side perf-baseline output present (when slice has a user-perceivable perf surface):**
125
+ ```bash
126
+ ls .peaks/<changeId>/rd/perf-baseline.md 2>&1
127
+ # Expected: .peaks/<changeId>/rd/perf-baseline.md
128
+ # "No such file" + slice is feature / refactor / bugfix-when-perf → BLOCKED.
129
+ # Run the perf-baseline sub-agent from "Parallel review fan-out" below (or
130
+ # `peaks perf baseline --apply` inline), then fill in the Results table
131
+ # with measurements (lighthouse / k6 / autocannon / project-local bench —
132
+ # the CLI does not run these; that is the RD's job), then re-verify.
133
+ # "No such file" + slice is docs / chore / pure-bugfix-no-perf → OK to proceed;
134
+ # this gate does not apply to those slice types.
135
+ # File exists but Results table is empty (only the header row, no data rows) →
136
+ # BLOCKED. The sub-agent scaffolds the file; the main RD loop must fill in
137
+ # the Path / route | Workload | Tool | Metric | Baseline | Threshold table
138
+ # with actual numbers before handoff.
139
+ # File contains the marker `N/A — no perf surface` in its Notes section →
140
+ # OK to proceed. This is the explicit opt-out the sub-agent writes when
141
+ # the slice has no user-perceivable perf surface (e.g. a feature that only
142
+ # adds an internal flag with no runtime cost, or a refactor that does not
143
+ # alter any hot path).
144
+ #
145
+ # The CLI enforcement table below the section header also gates this at the
146
+ # `peaks request transition rd:qa-handoff` call, so a missing or empty file
147
+ # is rejected by the CLI with `code: PREREQUISITES_MISSING`.
148
+ ```