@ai-dev-methodologies/rlp-desk 0.15.6 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -11,6 +11,32 @@ For pre-v0.15.4 versions, refer to `git log` and individual GitHub release notes
11
11
  - Post-v0.15.6: remove `RLP_LIFECYCLE_METRICS` flag entirely (per plan v3 ADR follow-ups).
12
12
  - Phase D.1 (handoff documents) + Phase D.2 (per-stage agent role specialization) — both deferred per `docs/plans/v0.15.4-release-runbook.md` §7.6.
13
13
 
14
+ ## [0.17.0] — 2026-06-19
15
+
16
+ **BREAKING (ADR-001): `node run.mjs run <slug> --mode agent` (the deprecated Node-leader direct-CLI alpha) now hard-errors.** Per the schedule announced in 0.16.0, the `--mode agent` entry point exits 2 with a redirect, and the Node-CLI default mode flips from `agent` to `tmux` (the canonical production leader). The `src/node/**` engine modules are retained (they back the Native Agent() path and the test suite); only the direct-CLI `--mode agent` *dispatch entry* was removed. **Migration:** replace `node run.mjs run <slug> --mode agent` with `--mode tmux`. The slash command's `--mode native` default is unaffected.
17
+
18
+ ### Changed
19
+ - `node run.mjs run <slug>` (no `--mode`) now defaults to `--mode tmux` and delegates to the zsh leader, instead of the deprecated Node leader.
20
+
21
+ ### Fixed
22
+ - Four shipped files referenced `docs/multi-mission-orchestration.md`; corrected to the real shipped path `docs/rlp-desk/multi-mission-orchestration.md` (dead link on fresh installs). Added a docs-link-resolve test.
23
+ - `uninstall` now removes the `UNLOCK.md` marker (and unlocks 0o444 files before unlink), so the `ralph-desk/` directory is fully removed.
24
+ - The A4 fallback iteration-signal write now goes through the atomic `atomic_write` helper (temp+rename) instead of a raw redirect.
25
+
26
+ ### Changed (packaging)
27
+ - The shipped `examples/calculator` scaffold moved from the legacy `.claude/ralph-desk/` path to `.rlp-desk/` (v0.13.0+ convention) and no longer ships generated runtime state.
28
+
29
+ ## [0.16.0] — 2026-06-18
30
+
31
+ Leader consolidation (ADR-001): `--mode tmux` is now the canonical production leader, self-verification works on it, and the deprecated `--mode agent` Node-CLI path is on a dated removal schedule.
32
+
33
+ ### Added
34
+ - **Self-verification now works under `--mode tmux`.** `--with-self-verification` previously required the deprecated `--mode agent` path; the report is now generated by a pure-filesystem post-pass that runs after the zsh leader exits (reading the campaign's done-claim/verdict artifacts), so the canonical production path gets SV reports without the `claude --print` no-TTY hang.
35
+
36
+ ### Deprecated
37
+ - **`node run.mjs run <slug> --mode agent` (Node-leader CLI alpha) is on a dated removal schedule** (ADR-001): 0.16.x louder banner → **0.17.0 hard-error** (and the Node-CLI default flips to `tmux`) → 0.18.0 dispatch branch removed. The `src/node/**` engine modules are retained throughout. Migrate direct-CLI wrappers to `--mode tmux` (canonical). This does NOT affect the slash command's `--mode native` default.
38
+ - **The flywheel (`--flywheel` / `--flywheel-guard`) is deprecated.** It was only ever implemented in the deprecated `--mode agent` Node path (never in the canonical zsh leader, despite a stale comment that claimed otherwise). Its only output, the advisory `next_mission_candidate` field, has no shipped runnable consumer. It will not be ported to the canonical leader; use a consumer-side wrapper for multi-mission chaining.
39
+
14
40
  ## [0.15.6] — 2026-06-18
15
41
 
16
42
  Patch: CI/test integrity, a codex command-builder security fix, and documentation reconciliation.
@@ -83,7 +83,7 @@ This creates the scaffold:
83
83
 
84
84
  ## Step 5: Customize the PRD
85
85
 
86
- Edit `.rlp-desk/plans/prd-loop-test.md` to define your user stories and acceptance criteria. See [`examples/calculator/`](../examples/calculator/.claude/ralph-desk/plans/prd-loop-test.md) for a complete example.
86
+ Edit `.rlp-desk/plans/prd-loop-test.md` to define your user stories and acceptance criteria. See [`examples/calculator/`](../examples/calculator/.rlp-desk/plans/prd-loop-test.md) for a complete example.
87
87
 
88
88
  Key sections:
89
89
  - **User Stories** with Given/When/Then acceptance criteria, Task Type, and Risk Level
@@ -649,5 +649,5 @@ an optional `next_mission_candidate` field:
649
649
 
650
650
  The leader propagates the field into `status.json`
651
651
  (`status.next_mission_candidate`). Wrappers poll either source. See
652
- `docs/multi-mission-orchestration.md` for the consumer-side polling
652
+ `docs/rlp-desk/multi-mission-orchestration.md` for the consumer-side polling
653
653
  pattern.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-dev-methodologies/rlp-desk",
3
- "version": "0.15.6",
3
+ "version": "0.17.0",
4
4
  "description": "Fresh-context iterative loops for Claude Code — autonomous task completion with independent verification",
5
5
  "scripts": {
6
6
  "postinstall": "node scripts/postinstall.js",
@@ -23,10 +23,10 @@
23
23
  "scripts/",
24
24
  "docs/rlp-desk/*.md",
25
25
  "docs/rlp-desk/blueprints/",
26
- "examples/calculator/.claude/ralph-desk/context/",
27
- "examples/calculator/.claude/ralph-desk/memos/",
28
- "examples/calculator/.claude/ralph-desk/plans/",
29
- "examples/calculator/.claude/ralph-desk/prompts/",
26
+ "examples/calculator/.rlp-desk/context/",
27
+ "examples/calculator/.rlp-desk/memos/",
28
+ "examples/calculator/.rlp-desk/plans/",
29
+ "examples/calculator/.rlp-desk/prompts/",
30
30
  "install.sh",
31
31
  "README.md",
32
32
  "CHANGELOG.md",
@@ -25,10 +25,22 @@ const files = [
25
25
  path.join(deskDir, "init_ralph_desk.zsh"),
26
26
  path.join(deskDir, "run_ralph_desk.zsh"),
27
27
  path.join(deskDir, "lib_ralph_desk.zsh"),
28
+ // PKG-6: postinstall writes the UNLOCK.md escape-hatch doc into deskDir. If we
29
+ // skip it here, the empty-dir rmdir below always sees one leftover file and the
30
+ // ralph-desk/ directory is never removed.
31
+ path.join(deskDir, "UNLOCK.md"),
28
32
  ];
29
33
 
30
34
  for (const targetPath of files) {
31
35
  try {
36
+ // Installed files are write-locked (chmod 0o444) per postinstall v5.7 §4.10.
37
+ // Restore write permission before unlink so removal is robust across
38
+ // filesystems (mirrors postinstall's unlock-before-remove).
39
+ try {
40
+ fs.chmodSync(targetPath, 0o644);
41
+ } catch (_) {
42
+ // File may be missing or already writable.
43
+ }
32
44
  fs.rmSync(targetPath, { recursive: true, force: true });
33
45
  console.log(" - " + targetPath);
34
46
  } catch (_) {
@@ -303,7 +303,7 @@ Legacy `--mode agent` typed against this slash command emits a deprecation notic
303
303
 
304
304
  #### Tmux Mode (`--mode tmux`)
305
305
 
306
- When `--mode tmux` is specified (v0.14.0+: `run.mjs` accepts the same flags as before but spawns `run_ralph_desk.zsh` as a subprocess and inherits stdio. Flywheel and self-verification flags are not honored under tmux mode they currently require the deprecated Node-leader direct-CLI path `node run.mjs --mode agent` (see "Direct Node CLI invocation" below). Native Agent() port is a post-Node-leader-retirement task):
306
+ When `--mode tmux` is specified (v0.14.0+: `run.mjs` accepts the same flags as before but spawns `run_ralph_desk.zsh` as a subprocess and inherits stdio. ARCH Wave C: `--with-self-verification` **is honored** under tmux mode via a Node post-pass that runs after the zsh leader exits (see §348). `--flywheel`/`--flywheel-guard` are deprecated (ADR-001) and remain unimplemented in the zsh leader):
307
307
 
308
308
  1. **Validate scaffold** — same as Agent() mode: check `.rlp-desk/prompts/<slug>.worker.prompt.md` etc.
309
309
  2. **Check sentinels** — same as Agent() mode.
@@ -345,7 +345,7 @@ node ~/.claude/ralph-desk/node/run.mjs run '<slug>' \
345
345
  - MUST launch with `run_in_background: true` so `/rlp-desk` returns control immediately while preserving live tmux visibility.
346
346
  - Run-in-background is used so the shell can keep the command visible and keep the pane layout stable for status checks and completion flow.
347
347
  - Do NOT kill panes after completion. Panes stay alive for inspection. User cleans up with `/rlp-desk clean <slug> --kill-session`.
348
- - v0.14.0: `--with-self-verification`, `--flywheel`, and `--flywheel-guard` are **not honored** under `--mode tmux` the zsh runner has no SV/flywheel implementation. The Node leader emits a stderr WARNING listing the dropped flags. For SV/flywheel today, use the deprecated Node-leader direct-CLI path `node run.mjs --mode agent` (see "Direct Node CLI invocation" below). The slash command's Native Agent() (`--mode native`) does not yet implement SV/flywheel — port is a post-Node-leader-retirement task.
348
+ - ARCH Wave C (ADR-001): `--with-self-verification` **is honored** under `--mode tmux`. The zsh leader cannot generate the SV report in-pane (`claude --print` hangs without a TTY hence its `$TMUX` early-return), so `run.mjs` runs the **pure-filesystem** `generateSVReport` as a **post-pass after the zsh child exits**, reading the campaign's on-disk done-claim/verdict artifacts. `--flywheel` and `--flywheel-guard` are **deprecated** (ADR-001) and remain unimplemented in the zsh leader; the Node leader emits a stderr WARNING for those two only. The slash command's Native Agent() (`--mode native`) does not yet implement SV/flywheel.
349
349
  - **For `--mode tmux` only**: the slash command invokes `node ~/.claude/ralph-desk/node/run.mjs run --mode tmux ...`. Do NOT invoke `~/.claude/ralph-desk/run_ralph_desk.zsh` directly — the Node router resolves the runner path, runs legacy detection, and surfaces actionable errors when the runner is missing. **For `--mode native`**, the slash command does NOT invoke the Node CLI — it acts as the leader itself; see Native Agent() Mode section below.
350
350
 
351
351
  **tmux UX model (5 items):**
@@ -374,7 +374,17 @@ This contract MUST be observed in every iteration of the leader loop below. Futu
374
374
 
375
375
  #### Direct Node CLI invocation (`node run.mjs run <slug> --mode agent` — deprecated alpha)
376
376
 
377
- Direct invocation of `node ~/.claude/ralph-desk/node/run.mjs run <slug> --mode agent` is **the deprecated Node-leader alpha path**. This is unrelated to the slash command's Native Agent() path above — different code, different leader, different lifecycle. The Node leader currently retains SV/flywheel implementations not yet ported to Native Agent(). The Node CLI emits a deprecation banner on this mode and is scheduled for hard-error in the next major release. For production tmux orchestration, use `--mode tmux`. For Claude Code Native Agent() campaigns, use `/rlp-desk run <slug> --mode native` from a Claude Code session.
377
+ Direct invocation of `node ~/.claude/ralph-desk/node/run.mjs run <slug> --mode agent` **hard-errors (exit 2) as of this release** (per [ADR-001](../../docs/plans/adr-001-leader-consolidation.md) §3) — it was the deprecated Node-leader alpha path, and the dated breaking change has now landed. Direct CLI invocation redirects to `--mode tmux` (production) / `--mode native` (slash), and the **Node-CLI default mode is now `tmux`**. This is unrelated to the slash command's legacy `--mode agent` native redirect — different code, different leader, different lifecycle. The `src/node/**` engine modules (which still back the Native Agent() path and the test suite, and retain SV/flywheel implementations not yet ported to Native Agent()) are **retained** only the direct-CLI `--mode agent` *entry point* hard-errors. For production tmux orchestration, use `--mode tmux` (the **canonical** leader). For Claude Code Native Agent() campaigns, use `/rlp-desk run <slug> --mode native` from a Claude Code session.
378
+
379
+ **Deprecation schedule** (per [ADR-001](../../docs/plans/adr-001-leader-consolidation.md) §3 — applies to the Node-CLI `--mode agent` entry point ONLY; the `src/node/**` engine modules are retained throughout):
380
+
381
+ | Version | Behavior of `node run.mjs run <slug> --mode agent` |
382
+ |---------|-----------------------------------------------------|
383
+ | 0.16.x | runs, with a louder deprecation banner |
384
+ | **0.17.0** | **hard-errors** (exit 2) with a redirect to `--mode tmux` / `--mode native`; the Node-CLI default also flips to `tmux` |
385
+ | 0.18.0 | the `--mode agent` dispatch branch is removed (engine modules stay) |
386
+
387
+ External wrappers calling `--mode agent` must migrate to `--mode tmux` by 0.17.0. This is a breaking CLI change for that entry point, announced in CHANGELOG at each step.
378
388
 
379
389
  ### Preparation
380
390
  1. Validate scaffold: `.rlp-desk/prompts/<slug>.worker.prompt.md` etc.
package/src/governance.md CHANGED
@@ -584,7 +584,7 @@ for iteration in 1..max_iter:
584
584
  ⑥½ Flywheel direction review (when --flywheel on-fail and consecutive_failures > 0)
585
585
  - Dispatch Flywheel agent (fresh context, --flywheel-model)
586
586
  - Read flywheel-signal.json for direction decision (hold/pivot/reduce/expand)
587
- - Optional `next_mission_candidate` field (string | null): when present, the leader propagates it to status.json so consumer wrappers can chain the next mission without code edits. See docs/multi-mission-orchestration.md.
587
+ - Optional `next_mission_candidate` field (string | null): when present, the leader propagates it to status.json so consumer wrappers can chain the next mission without code edits. See docs/rlp-desk/multi-mission-orchestration.md.
588
588
  - If --flywheel-guard on:
589
589
  - Dispatch Guard agent (fresh context, --flywheel-guard-model)
590
590
  - Read flywheel-guard-verdict.json:
package/src/node/run.mjs CHANGED
@@ -5,7 +5,7 @@ import { spawn, spawnSync } from 'node:child_process';
5
5
  import { fileURLToPath } from 'node:url';
6
6
 
7
7
  import { initCampaign } from './init/campaign-initializer.mjs';
8
- import { readStatus } from './reporting/campaign-reporting.mjs';
8
+ import { readStatus, generateSVReport } from './reporting/campaign-reporting.mjs';
9
9
  import {
10
10
  run as runCampaignMain,
11
11
  detectLegacyDeskInRunMode,
@@ -14,7 +14,11 @@ import {
14
14
  import { isClaudeEngine } from './cli/command-builder.mjs';
15
15
 
16
16
  const RUN_DEFAULTS = {
17
- mode: 'agent',
17
+ // ARCH Wave D (ADR-001 §3): the Node-CLI default mode flips from the deprecated
18
+ // 'agent' (Node-leader alpha) to 'tmux' (the canonical production leader) at the
19
+ // same step that makes --mode agent hard-error. A bare `run <slug>` now delegates
20
+ // to the zsh runner, not the deprecated Node leader.
21
+ mode: 'tmux',
18
22
  workerModel: 'haiku',
19
23
  verifierModel: 'sonnet',
20
24
  finalVerifierModel: 'opus',
@@ -49,14 +53,14 @@ function buildHelpText() {
49
53
  'Commands:',
50
54
  ' brainstorm <description> Plan before init (not implemented in the Node rewrite yet)',
51
55
  ' init <slug> [objective] Create project scaffold',
52
- ' run <slug> [options] Run loop (tmux=zsh leader [production], agent=Node leader [deprecated alpha], native=slash-only error)',
56
+ ' run <slug> [options] Run loop (tmux=zsh leader [production, default], agent=hard-errors per ADR-001, native=slash-only error)',
53
57
  ' status <slug> Show loop status',
54
58
  ' logs <slug> [N] Show iteration log (not implemented in the Node rewrite yet)',
55
59
  ' clean <slug> [--kill-session] Reset for re-run (removes sentinels + runtime/; preserves PRD/prompts/memory)',
56
60
  ' resume <slug> Resume loop (not implemented in the Node rewrite yet)',
57
61
  '',
58
62
  'Run Options:',
59
- ' --mode tmux|agent|native (CLI: tmux=production, agent=deprecated, native=errors with redirect to slash command)',
63
+ ' --mode tmux|agent|native (CLI: tmux=production [default], agent=hard-errors (ADR-001), native=errors with redirect to slash command)',
60
64
  ' --worker-model MODEL',
61
65
  ' --lock-worker-model',
62
66
  ' --verifier-model MODEL',
@@ -318,6 +322,10 @@ function buildZshEnv(slug, options, parentEnv) {
318
322
  AUTONOMOUS_MODE: options.autonomous ? '1' : '0',
319
323
  LANE_MODE: options.laneStrict ? 'strict' : 'warn',
320
324
  TEST_DENSITY_MODE: options.testDensityStrict ? 'strict' : 'warn',
325
+ // ARCH Wave C-SV: forwarded for traceability only. The zsh leader keeps its
326
+ // $TMUX early-return (no in-pane `claude --print`); the SV report itself is
327
+ // produced by the Node post-pass in runTmuxViaZsh after the zsh child exits.
328
+ WITH_SELF_VERIFICATION: options.withSelfVerification ? '1' : '0',
321
329
  };
322
330
  }
323
331
 
@@ -360,23 +368,47 @@ async function runTmuxViaZsh(slug, options, deps) {
360
368
  return 1;
361
369
  }
362
370
 
363
- // Surface flags the zsh runner cannot honor. Flywheel and self-verification
364
- // remain Node-leader features, available only in --mode agent. Warn loudly
365
- // instead of silent no-op so the operator understands the trade-off.
371
+ // Surface flags the zsh runner cannot honor. ARCH Wave C: --with-self-verification
372
+ // IS now honored in tmux mode via a post-zsh-return pass (see below) — only the
373
+ // flywheel flags remain unsupported here. Warn loudly instead of silent no-op.
366
374
  const unsupported = [];
367
375
  if (options.flywheel !== 'off') unsupported.push('--flywheel');
368
376
  if (options.flywheelGuard !== 'off') unsupported.push('--flywheel-guard');
369
- if (options.withSelfVerification) unsupported.push('--with-self-verification');
370
377
  if (unsupported.length > 0) {
371
378
  write(
372
379
  deps.stderr,
373
- `WARNING: ${unsupported.join(', ')} not honored in --mode tmux (zsh runner). Use --mode agent for those features.`,
380
+ `WARNING: ${unsupported.join(', ')} not honored in --mode tmux (zsh runner). Flywheel is deprecated (ADR-001) and unimplemented in the canonical leader.`,
374
381
  );
375
382
  }
376
383
 
377
384
  const env = buildZshEnv(slug, options, process.env);
378
385
  const spawnZsh = deps.spawnZsh ?? defaultSpawnZsh;
379
- return spawnZsh(zshPath, env, options.rootDir);
386
+ const exitCode = await spawnZsh(zshPath, env, options.rootDir);
387
+
388
+ // ARCH Wave C-SV: home self-verification onto --mode tmux. The zsh runner cannot
389
+ // produce the SV report itself (`claude --print` hangs without a TTY in a tmux
390
+ // pane — that is why lib_ralph_desk.zsh keeps its $TMUX early-return). Instead we
391
+ // run the Node PURE-FS generateSVReport as a post-pass AFTER the zsh child exits:
392
+ // real stdout, no pane, no TTY → no hang. It reads the campaign's on-disk
393
+ // iter-*-done-claim/verify-verdict artifacts the zsh leader already wrote.
394
+ if (options.withSelfVerification) {
395
+ try {
396
+ const paths = buildPaths(options.rootDir, slug);
397
+ const sv = await generateSVReport({
398
+ slug,
399
+ logsDir: paths.campaignLogDir,
400
+ prdFile: paths.prdFile,
401
+ testSpecFile: paths.testSpecFile,
402
+ analyticsFile: paths.analyticsFile,
403
+ outputDir: paths.analyticsDir,
404
+ });
405
+ write(deps.stdout, `\nSelf-verification report (tmux post-pass): ${sv.summary ?? 'generated'}`);
406
+ } catch (err) {
407
+ write(deps.stderr, `WARNING: self-verification post-pass failed: ${err.message}`);
408
+ }
409
+ }
410
+
411
+ return exitCode;
380
412
  }
381
413
 
382
414
  async function runRunCommand(args, deps) {
@@ -414,7 +446,7 @@ async function runRunCommand(args, deps) {
414
446
  );
415
447
  write(
416
448
  deps.stderr,
417
- 'If hang persists, switch to --worker-model gpt-5.5:high (codex) or --mode agent.',
449
+ 'If hang persists, switch to --worker-model gpt-5.5:high (codex).',
418
450
  );
419
451
  }
420
452
 
@@ -440,50 +472,38 @@ async function runRunCommand(args, deps) {
440
472
  );
441
473
  write(
442
474
  deps.stderr,
443
- 'or use `--mode tmux` (production) / `--mode agent` (deprecated alpha) for direct CLI invocation.',
475
+ 'or use `--mode tmux` (production) for direct CLI invocation. `--mode agent` hard-errors (ADR-001).',
444
476
  );
445
477
  return 2;
446
478
  }
447
479
 
448
- // P1.b: --mode agent (Node-leader alpha) is deprecated. The slash command's
449
- // Native Agent() path (`/rlp-desk run --mode native`) is unrelated different
450
- // code, different leader. We keep the Node-leader behavior unchanged for
451
- // backward compatibility but surface a strong deprecation banner so wrappers
452
- // can migrate before the next major release hard-errors this mode.
453
- if (
454
- options.mode === 'agent'
455
- && !process.env.RLP_DESK_QUIET_WARNINGS
456
- && process.env.NODE_ENV !== 'test'
457
- ) {
480
+ // ARCH Wave D (ADR-001 §3): --mode agent (Node-leader direct-CLI alpha) HARD-ERRORS
481
+ // as of this release. It is the dated breaking change the deprecation banner
482
+ // announced direct CLI invocation now exits 2 with a redirect to the canonical
483
+ // production leader (--mode tmux) or the slash-command Native Agent() path
484
+ // (--mode native). This is UNRELATED to the slash command's legacy `--mode agent`
485
+ // → native redirect (different code, different leader). The `src/node/**` engine
486
+ // modules (run()/runCampaign) are RETAINED — they remain the engine the Native
487
+ // Agent() path and the test suite build on; only this direct-CLI dispatch entry
488
+ // hard-errors. Mirror the --mode native slash-only exit-2 pattern above.
489
+ if (options.mode === 'agent') {
458
490
  write(
459
491
  deps.stderr,
460
- 'WARNING: --mode agent (Node-leader alpha) is deprecated.',
492
+ 'ERROR: --mode agent (Node-leader direct-CLI alpha) is no longer supported (ADR-001).',
461
493
  );
462
494
  write(
463
495
  deps.stderr,
464
- 'This is the direct Node-CLI alpha path — UNRELATED to the slash command Native Agent() path (`/rlp-desk run --mode native`).',
496
+ 'For production tmux orchestration, use `--mode tmux` (the canonical leader).',
465
497
  );
466
498
  write(
467
499
  deps.stderr,
468
- 'For production tmux orchestration, use `--mode tmux`.',
500
+ 'For Claude Code Native Agent() campaigns, use `/rlp-desk run <slug> --mode native` from a Claude Code session.',
469
501
  );
470
502
  write(
471
503
  deps.stderr,
472
- 'For Claude Code Native Agent() campaigns, use `/rlp-desk run --mode native` from a Claude Code session.',
473
- );
474
- // 2026-05-07 (v0.15.2): rlp-desk is in active stabilization. Goal: reach
475
- // omc /team/ralph/ralplan level of reliability while preserving
476
- // rlp-desk's self-driving advantages (multi-engine consensus, multi-mission
477
- // queue, BLOCK_TAGS taxonomy, structured SV reports). omc is the BENCHMARK,
478
- // not a replacement. See docs/plans/v0.15-stabilization-plan.md.
479
- write(
480
- deps.stderr,
481
- 'SCHEDULED REMOVAL: --mode agent (Node CLI alpha) will be removed in a future major release. Date TBD until stabilization milestones complete.',
482
- );
483
- write(
484
- deps.stderr,
485
- 'STABILIZATION IN PROGRESS: rlp-desk is hardening against the 10-bug regression pattern observed 2026-05-01..05-07. See docs/plans/v0.15-stabilization-plan.md.',
504
+ 'The src/node/** engine modules are retained; only the direct-CLI --mode agent entry point was removed.',
486
505
  );
506
+ return 2;
487
507
  }
488
508
 
489
509
  const result = await deps.runCampaign(slug, options);
@@ -1715,7 +1715,7 @@ async function _runCampaignBody(slug, options, paths, rootDir) {
1715
1715
  // P0-A multi-mission orchestration: optionally captured from flywheel signal.
1716
1716
  // null when the flywheel did not suggest a next mission. Consumer wrappers
1717
1717
  // poll status.next_mission_candidate to chain missions without code edits.
1718
- // See docs/multi-mission-orchestration.md.
1718
+ // See docs/rlp-desk/multi-mission-orchestration.md.
1719
1719
  state.next_mission_candidate = flywheelSignal.next_mission_candidate ?? null;
1720
1720
  // Bug #7 Fix-R cleanup: unlock before unlink so 0o444 doesn't block.
1721
1721
  await unlockSentinelFile(paths.flywheelSignalFile);
@@ -761,7 +761,7 @@ Based on your decision, update campaign memory:
761
761
  current direction. The wrapper polls this field for autonomous
762
762
  multi-mission orchestration (rlp-desk does not auto-launch missions —
763
763
  the consumer wrapper owns that policy). Field is OPTIONAL; absence is
764
- treated as null. See docs/multi-mission-orchestration.md for the
764
+ treated as null. See docs/rlp-desk/multi-mission-orchestration.md for the
765
765
  consumer-side polling pattern.
766
766
  FLYWHEEL_EOF
767
767
 
@@ -756,9 +756,18 @@ _lint_test_density() {
756
756
  us_list=$(grep -oE '^##[[:space:]]+US-[0-9]+' "$prd_file" 2>/dev/null | grep -oE 'US-[0-9]+' | sort -u)
757
757
  [[ -z "$us_list" ]] && return 0
758
758
 
759
- local audit_dir="${LOGS_DIR:-/tmp}"
760
- local audit_file="$audit_dir/test-density-audit.jsonl"
761
- [[ -d "$audit_dir" ]] || audit_file="/tmp/test-density-audit.jsonl"
759
+ # ZSH-8: prefer the campaign LOGS_DIR. When it is unavailable, avoid a fixed,
760
+ # predictable /tmp name (insecure-temp: symlink/collision risk) by creating a
761
+ # unique temp file via mktemp; fall back to a PID-scoped name only if mktemp
762
+ # is missing.
763
+ local audit_dir="${LOGS_DIR:-}"
764
+ local audit_file
765
+ if [[ -n "$audit_dir" && -d "$audit_dir" ]]; then
766
+ audit_file="$audit_dir/test-density-audit.jsonl"
767
+ else
768
+ audit_file=$(mktemp "${TMPDIR:-/tmp}/test-density-audit.XXXXXX" 2>/dev/null) \
769
+ || audit_file="${TMPDIR:-/tmp}/test-density-audit.$$.jsonl"
770
+ fi
762
771
 
763
772
  local us
764
773
  for us in ${(f)us_list}; do
@@ -67,8 +67,12 @@ SV_SKIPPED_REASON="" # set when SV is di
67
67
  # no-progress, stale-context, claude model upgrade chain, etc.), so the
68
68
  # Node leader is now reserved for `--mode agent` (LLM-driven) only.
69
69
  # `--mode tmux` invocations from src/node/run.mjs delegate here as a
70
- # subprocess via env vars. zsh continues to honor FLYWHEEL,
71
- # FLYWHEEL_GUARD, WITH_SELF_VERIFICATION.
70
+ # subprocess via env vars. ARCH Wave C / ADR-001: FLYWHEEL and FLYWHEEL_GUARD
71
+ # are NOT implemented in the zsh leader (no dispatch site) and are deprecated —
72
+ # do NOT claim otherwise. WITH_SELF_VERIFICATION is forwarded for traceability,
73
+ # but the SV report is produced by the Node post-pass in run.mjs runTmuxViaZsh
74
+ # after this script exits (this script keeps its $TMUX early-return to avoid the
75
+ # `claude --print` no-TTY hang).
72
76
  AUTONOMOUS_MODE="${AUTONOMOUS_MODE:-0}" # 1=don't stop on ambiguity, PRD is authoritative
73
77
  # P1-E Lane enforcement: WARN-only by default; --lane-strict opts into BLOCKED
74
78
  # escalation. governance §7¾. The opt-in defaults to "warn"; "strict" trips
@@ -2307,7 +2311,7 @@ poll_for_signal() {
2307
2311
  # done-claim and a fresh signal_file in that order.
2308
2312
  _kill_pane_process "$pane_id" "worker-a4"
2309
2313
  _lock_sentinel "$DONE_CLAIM_FILE"
2310
- echo '{"iteration":'"$ITERATION"',"status":"verify","us_id":"'"$dc_us_id"'","summary":"auto-generated by A4 fallback (done-claim + clean tree)","timestamp":"'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'"}' > "$signal_file"
2314
+ echo '{"iteration":'"$ITERATION"',"status":"verify","us_id":"'"$dc_us_id"'","summary":"auto-generated by A4 fallback (done-claim + clean tree)","timestamp":"'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'"}' | atomic_write "$signal_file"
2311
2315
  _emit_a4_fallback_audit "$dc_us_id" "$ITERATION" "inline_polling_a4_clean"
2312
2316
  return 0
2313
2317
  else
@@ -2881,7 +2885,13 @@ main() {
2881
2885
  log_error "Another instance is already running (PID $lock_pid). Kill $lock_pid or rm $lockfile"
2882
2886
  exit 1
2883
2887
  fi
2884
- # Stale lock — overwrite
2888
+ # Stale lock — overwrite.
2889
+ # NOTE (ZSH-4, deferred): a fully race-safe stale-lock recovery is a separate
2890
+ # distributed-lock redesign (codex review found subtle rm/create + mutex-leak
2891
+ # races in patch attempts). This finding is LOW: the outer RUNNER_LOCKDIR mkdir
2892
+ # lock (keyed on the same $ROOT) already serializes runners before this inner
2893
+ # path is reached, so the inner race is unreachable in practice. Left at the
2894
+ # tested baseline pending a dedicated redesign.
2885
2895
  log "Stale lock detected (PID ${lock_pid:-unknown} not running), recovering"
2886
2896
  echo $$ > "$lockfile"
2887
2897
  LOCKFILE_ACQUIRED=1