session-orchestrator 5.3.0 → 5.5.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.
Files changed (260) hide show
  1. package/.agents/skills/claude-md-drift-check/SKILL.md +1 -1
  2. package/.agents/skills/test-audit/SKILL.md +21 -0
  3. package/.agents/skills/test-audit/agents/openai.yaml +5 -0
  4. package/.claude-plugin/marketplace.json +1 -1
  5. package/.claude-plugin/plugin.json +1 -1
  6. package/.codex-plugin/plugin.json +1 -1
  7. package/.codex-plugin/skills/claude-md-drift-check/SKILL.md +1 -1
  8. package/.codex-plugin/skills/test-audit/SKILL.md +21 -0
  9. package/.codex-plugin/skills/test-audit/agents/openai.yaml +5 -0
  10. package/.cursor/commands/test-audit.md +14 -0
  11. package/.cursor/rules/060-evolve.mdc +28 -13
  12. package/.cursor/skills/claude-md-drift-check/SKILL.md +1 -1
  13. package/.cursor/skills/test-audit/SKILL.md +12 -0
  14. package/.cursor-plugin/plugin.json +1 -1
  15. package/.orchestrator/policy/blocked-commands.json +1 -1
  16. package/AGENTS.md +9 -31
  17. package/CHANGELOG.md +162 -0
  18. package/README.md +14 -10
  19. package/docs/agent-authoring.md +2 -2
  20. package/docs/baseline.md +10 -1
  21. package/docs/ci-setup.md +154 -4
  22. package/docs/components.md +11 -11
  23. package/docs/events-schema.md +25 -19
  24. package/docs/install.md +14 -2
  25. package/docs/migration-v4.md +24 -17
  26. package/docs/persona-panel.md +5 -4
  27. package/docs/plugin-architecture-v3.md +1 -1
  28. package/docs/rule-authoring.md +27 -12
  29. package/docs/scope-collision-guard.md +40 -16
  30. package/docs/session-config-reference.md +61 -12
  31. package/docs/session-config-template.md +11 -2
  32. package/docs/vault-docs-architecture.md +8 -4
  33. package/hooks/_lib/hook-import-set.json +42 -29
  34. package/hooks/_lib/lock-bootstrap.mjs +118 -26
  35. package/hooks/config-protection.mjs +1 -1
  36. package/hooks/enforce-commands.mjs +28 -13
  37. package/hooks/enforce-scope.mjs +201 -23
  38. package/hooks/hooks-codex.json +1 -1
  39. package/hooks/hooks-cursor.json +5 -0
  40. package/hooks/hooks-pi.json +5 -0
  41. package/hooks/hooks.json +6 -1
  42. package/hooks/on-session-start.mjs +57 -2
  43. package/hooks/on-stop.mjs +70 -168
  44. package/hooks/post-bash-write-verify.mjs +98 -17
  45. package/hooks/post-edit-validate.mjs +15 -5
  46. package/hooks/post-tool-batch-wave-signal.mjs +32 -152
  47. package/hooks/pre-bash-memory-propose-audit.mjs +71 -10
  48. package/hooks/pre-bash-sessions-ledger-guard.mjs +28 -2
  49. package/hooks/pre-bash-staging-fence.mjs +29 -8
  50. package/hooks/pre-edit-sessions-ledger-guard.mjs +162 -0
  51. package/hooks/pre-task-scope-disjoint.mjs +1143 -279
  52. package/hooks/subagent-telemetry.mjs +96 -19
  53. package/hooks/wave-scope-commit-guard.mjs +168 -72
  54. package/package.json +2 -6
  55. package/pi/prompts/test-audit.md +12 -0
  56. package/rules/README.md +6 -1
  57. package/rules/_index.md +3 -3
  58. package/rules/always-on/bash-harness-pitfalls.md +7 -1
  59. package/rules/opt-in-domain/prompt-caching.md +5 -1
  60. package/rules/opt-in-stack/backend-data.md +9 -1
  61. package/rules/opt-in-stack/backend.md +7 -1
  62. package/rules/opt-in-stack/frontend.md +6 -1
  63. package/rules/opt-in-stack/security-web.md +7 -1
  64. package/rules/opt-in-stack/swift.md +5 -1
  65. package/scripts/apply-session-learnings.mjs +513 -0
  66. package/scripts/archive-closed-prds.mjs +40 -12
  67. package/scripts/autopilot.mjs +57 -54
  68. package/scripts/backfill-abandoned-sessions.mjs +81 -6
  69. package/scripts/backfill-learnings-from-vault.mjs +49 -22
  70. package/scripts/baseline-archetypes.mjs +1 -1
  71. package/scripts/check-package-manager.mjs +62 -5
  72. package/scripts/codex-install.mjs +3 -0
  73. package/scripts/cursor-install.mjs +47 -6
  74. package/scripts/emit-session.mjs +298 -2
  75. package/scripts/export-hw-learnings.mjs +40 -10
  76. package/scripts/fleet-checkin.mjs +170 -0
  77. package/scripts/lib/agent-frontmatter.mjs +3 -3
  78. package/scripts/lib/auto-dream.mjs +7 -6
  79. package/scripts/lib/autopilot/flags.mjs +6 -1
  80. package/scripts/lib/autopilot/loop.mjs +32 -13
  81. package/scripts/lib/autopilot/stall-sampler.mjs +13 -9
  82. package/scripts/lib/baseline-archetypes.mjs +41 -22
  83. package/scripts/lib/blocked-commands-policy.mjs +40 -0
  84. package/scripts/lib/common.mjs +41 -0
  85. package/scripts/lib/config/host-paths.mjs +79 -0
  86. package/scripts/lib/config/persona-gate-wave.mjs +3 -3
  87. package/scripts/lib/config/reaper.mjs +7 -6
  88. package/scripts/lib/config/vault-integration.mjs +151 -16
  89. package/scripts/lib/config-schema.mjs +13 -0
  90. package/scripts/lib/config.mjs +75 -10
  91. package/scripts/lib/eval/engine.mjs +13 -0
  92. package/scripts/lib/events-retention-banner.mjs +393 -0
  93. package/scripts/lib/events-rotation.mjs +21 -6
  94. package/scripts/lib/events.mjs +72 -5
  95. package/scripts/lib/fleet-protocol.mjs +288 -0
  96. package/scripts/lib/gates/gate-baseline.mjs +13 -3
  97. package/scripts/lib/gates/gate-full.mjs +7 -2
  98. package/scripts/lib/gates/gate-helpers.mjs +93 -2
  99. package/scripts/lib/gates/gate-incremental.mjs +23 -22
  100. package/scripts/lib/gates/gate-per-file.mjs +16 -7
  101. package/scripts/lib/hardening.mjs +1 -0
  102. package/scripts/lib/harness-audit/categories/category4.mjs +8 -6
  103. package/scripts/lib/instruction-budget-guard.mjs +77 -11
  104. package/scripts/lib/learnings/expiry-sweep.mjs +420 -22
  105. package/scripts/lib/learnings/io.mjs +274 -37
  106. package/scripts/lib/learnings/schema.mjs +163 -15
  107. package/scripts/lib/learnings/sizing-subject.mjs +2 -2
  108. package/scripts/lib/lock-reaper.mjs +38 -14
  109. package/scripts/lib/maintenance-due-banner.mjs +23 -8
  110. package/scripts/lib/memory-proposals/schema.mjs +11 -5
  111. package/scripts/lib/named-baseline-resolver.mjs +53 -28
  112. package/scripts/lib/named-vault-resolver.mjs +147 -5
  113. package/scripts/lib/orphan-reaper/defaults.mjs +41 -0
  114. package/scripts/lib/orphan-reaper/no-follow-append.mjs +87 -0
  115. package/scripts/lib/orphan-reaper/ps-snapshot.mjs +181 -0
  116. package/scripts/lib/orphan-reaper/reaper-audit.mjs +323 -0
  117. package/scripts/lib/orphan-reaper/reaper-decide.mjs +395 -0
  118. package/scripts/lib/orphan-reaper/scan-throttle.mjs +144 -0
  119. package/scripts/lib/orphan-reaper/scan.mjs +510 -0
  120. package/scripts/lib/orphan-reaper/trigger.mjs +173 -0
  121. package/scripts/lib/orphan-reaper.mjs +47 -1315
  122. package/scripts/lib/owner-yaml.mjs +104 -6
  123. package/scripts/lib/persona-panel/catalog-loader.mjs +1 -1
  124. package/scripts/lib/platform.mjs +206 -2
  125. package/scripts/lib/plugin-update-banner.mjs +3 -1
  126. package/scripts/lib/process-group.mjs +134 -22
  127. package/scripts/lib/project-hygiene.mjs +21 -1
  128. package/scripts/lib/quality-gate.mjs +45 -5
  129. package/scripts/lib/resource-probe.mjs +1 -1
  130. package/scripts/lib/rule-loader.mjs +100 -62
  131. package/scripts/lib/rules-sync.mjs +27 -12
  132. package/scripts/lib/scope-baseline.mjs +119 -29
  133. package/scripts/lib/scope-echo.mjs +7 -0
  134. package/scripts/lib/scope-gate.mjs +194 -27
  135. package/scripts/lib/session-close-backfill.mjs +129 -4
  136. package/scripts/lib/session-end/tail-runner.mjs +10 -5
  137. package/scripts/lib/session-lock-shape.mjs +6 -3
  138. package/scripts/lib/session-lock.mjs +320 -67
  139. package/scripts/lib/session-record-repair.mjs +183 -26
  140. package/scripts/lib/session-registry.mjs +67 -17
  141. package/scripts/lib/session-schema/constants.mjs +30 -4
  142. package/scripts/lib/session-schema/validator.mjs +28 -1
  143. package/scripts/lib/session-start-probes.mjs +242 -68
  144. package/scripts/lib/session-token-rollup.mjs +252 -54
  145. package/scripts/lib/sessions-canonical.mjs +100 -9
  146. package/scripts/lib/sessions-staleness-banner.mjs +3 -1
  147. package/scripts/lib/sh-quote.mjs +29 -0
  148. package/scripts/lib/subagents-schema.mjs +30 -3
  149. package/scripts/lib/tail-window.mjs +27 -3
  150. package/scripts/lib/telemetry/pricing.mjs +121 -71
  151. package/scripts/lib/telemetry/sync.mjs +17 -0
  152. package/scripts/lib/tests-src-ratio.mjs +215 -23
  153. package/scripts/lib/tmux-layout/layouts.mjs +1 -11
  154. package/scripts/lib/tmux-layout/telemetry-stats.mjs +12 -0
  155. package/scripts/lib/tmux-layout/tmux-shell.mjs +2 -11
  156. package/scripts/lib/ux-grill/reconcile.mjs +1 -1
  157. package/scripts/lib/validate/check-agents.mjs +1 -1
  158. package/scripts/lib/validate/check-hooks-symmetry.mjs +5 -0
  159. package/scripts/lib/validate/check-learnings-shell-writes.mjs +214 -0
  160. package/scripts/lib/validate/check-test-value-bans.mjs +388 -27
  161. package/scripts/lib/validate/check-unicode-safety.mjs +1 -0
  162. package/scripts/lib/validate/check-unwired-features.mjs +1 -1
  163. package/scripts/lib/validate/check-vcs-repo-flag.mjs +1 -1
  164. package/scripts/lib/validate-vendored-rules.mjs +206 -81
  165. package/scripts/lib/vault-mirror/auto-commit.mjs +5 -3
  166. package/scripts/lib/vault-mirror/namespace.mjs +47 -26
  167. package/scripts/lib/vault-mirror/process.mjs +350 -62
  168. package/scripts/lib/vault-mirror/pseudonym-map.mjs +14 -5
  169. package/scripts/lib/vault-mirror/render-learnings.mjs +66 -3
  170. package/scripts/lib/vault-mirror/render-sessions.mjs +28 -4
  171. package/scripts/lib/vault-mirror/telemetry.mjs +25 -11
  172. package/scripts/lib/vault-status/board-writer.mjs +53 -12
  173. package/scripts/lib/vault-status/narrative-mirror.mjs +40 -9
  174. package/scripts/lib/vcs-repo-spec.mjs +8 -0
  175. package/scripts/lib/wave-executor/dispatch-common.mjs +10 -18
  176. package/scripts/lib/wave-executor/foreign-dispatch.mjs +1 -1
  177. package/scripts/lib/wave-executor/remote-dispatch.mjs +1 -1
  178. package/scripts/lib/wave-resource-gate.mjs +34 -8
  179. package/scripts/materialize-wave-scope.mjs +7 -4
  180. package/scripts/memory-propose.mjs +18 -5
  181. package/scripts/release-session-lock.mjs +2 -1
  182. package/scripts/release.mjs +11 -3
  183. package/scripts/repair-invalid-sessions.mjs +37 -4
  184. package/scripts/run-migrate-v2-cross-repo.mjs +171 -31
  185. package/scripts/run-quality-gate.mjs +331 -307
  186. package/scripts/self-update.mjs +229 -0
  187. package/scripts/site-numbers.mjs +163 -5
  188. package/scripts/sweep-expired-learnings.mjs +603 -20
  189. package/scripts/sweep-expired-rules.mjs +2 -1
  190. package/scripts/validate-plugin.mjs +7 -0
  191. package/scripts/validate-wave-scope.mjs +21 -2
  192. package/scripts/vault-backfill.mjs +50 -37
  193. package/scripts/vault-integration-watcher.mjs +2 -1
  194. package/scripts/vault-mirror.mjs +238 -75
  195. package/scripts/wave-scope-binding.mjs +2 -1
  196. package/skills/_shared/config-reading.md +3 -3
  197. package/skills/_shared/fleet-protocol.md +134 -0
  198. package/skills/_shared/state-ownership.md +41 -12
  199. package/skills/autopilot/SKILL.md +25 -11
  200. package/skills/bootstrap/SKILL.md +6 -4
  201. package/skills/bootstrap/_shared-template.md +97 -2
  202. package/skills/bootstrap/fast-template.md +4 -1
  203. package/skills/bootstrap/private-contract.md +2 -1
  204. package/skills/bootstrap/public-fallback.md +6 -3
  205. package/skills/bootstrap/references/bootstrap-refresh-lock-flow.md +5 -3
  206. package/skills/bootstrap/references/bootstrap-retroactive-flow.md +2 -1
  207. package/skills/bootstrap/standard-template.md +2 -0
  208. package/skills/claude-md-drift-check/SKILL.md +10 -10
  209. package/skills/claude-md-drift-check/checker.mjs +26 -18
  210. package/skills/discovery/probes/ssot-code-diff.mjs +12 -6
  211. package/skills/discovery/probes/vault-narrative-staleness.mjs +6 -2
  212. package/skills/discovery/probes/vault-staleness.mjs +9 -3
  213. package/skills/docs-orchestrator/SKILL.md +12 -5
  214. package/skills/docs-orchestrator/audience-mapping.md +5 -3
  215. package/skills/evolve/SKILL.md +13 -4
  216. package/skills/evolve/references/evolve-analyze-mode.md +42 -18
  217. package/skills/memory-cleanup/SKILL.md +1 -1
  218. package/skills/persona-panel/SKILL.md +2 -2
  219. package/skills/persona-panel/persona-format.md +2 -2
  220. package/skills/persona-panel/presets/designer-lens.md +1 -1
  221. package/skills/persona-panel/presets/engineer-lens.md +1 -1
  222. package/skills/persona-panel/presets/pm-lens.md +1 -1
  223. package/skills/plan/mode-retro.md +19 -4
  224. package/skills/quality-gates/SKILL.md +6 -4
  225. package/skills/remote-offload/SKILL.md +4 -2
  226. package/skills/session-end/learning-patterns.md +23 -13
  227. package/skills/session-end/metrics-collection.md +6 -7
  228. package/skills/session-end/phase-3-2-docs-verification.md +7 -6
  229. package/skills/session-end/plan-verification.md +25 -9
  230. package/skills/session-end/references/phase-3-documentation-updates.md +13 -3
  231. package/skills/session-end/references/phase-4a-worktree-cleanup.md +2 -0
  232. package/skills/session-end/references/session-summary-template.md +1 -1
  233. package/skills/session-end/session-metrics-write.md +65 -68
  234. package/skills/session-plan/SKILL.md +0 -3
  235. package/skills/session-start/SKILL.md +8 -2
  236. package/skills/session-start/references/operations-contract.md +6 -0
  237. package/skills/session-start/references/phase-1-2-session-lock.md +32 -7
  238. package/skills/session-start/references/phase-1-7-vault-status-board.md +1 -1
  239. package/skills/session-start/references/phase-4-ssot-environment-check.md +10 -3
  240. package/skills/test-audit/SKILL.md +152 -0
  241. package/skills/test-audit/references/campaign.md +111 -0
  242. package/skills/test-audit/references/mutate.sh +50 -0
  243. package/skills/vault-mirror/SKILL.md +21 -11
  244. package/skills/wave-executor/SKILL.md +2 -2
  245. package/skills/wave-executor/circuit-breaker.md +1 -1
  246. package/skills/wave-executor/references/wave-executor-state-init.md +3 -0
  247. package/skills/wave-executor/references/wave-loop-dispatch.md +11 -1
  248. package/skills/wave-executor/references/wave-loop-review.md +4 -6
  249. package/skills/wave-executor/references/wave-loop-scope-manifest.md +13 -5
  250. package/templates/personas/README.md +5 -5
  251. package/templates/personas/accounting-compliance.v1.md +1 -1
  252. package/templates/personas/accounting-tax-advisor.v1.md +1 -1
  253. package/templates/personas/buyer-p1-cto.v1.md +1 -1
  254. package/templates/personas/buyer-p2-kanzlei.v1.md +1 -1
  255. package/templates/personas/buyer-p3-build.v1.md +1 -1
  256. package/templates/personas/buyer-p4-tech-veto.v1.md +1 -1
  257. package/templates/personas/buyer-p5-solo.v1.md +1 -1
  258. package/templates/personas/buyer-p6-ld.v1.md +1 -1
  259. package/templates/personas/klima-ai-expert.v1.md +1 -1
  260. package/templates/personas/klima-physicist.v1.md +1 -1
@@ -356,6 +356,11 @@ slopcheck:
356
356
  | `max-turns` | integer or string | `auto` | Maximum agent turns before PARTIAL. Auto expands PER SESSION TYPE inside the resolved shape (`scripts/lib/session-shape.mjs` `MAX_TURNS_DEFAULT`, § Session Shapes above): housekeeping=8, feature=15, deep=25 (`maxTurnsDefault` in the shape JSON, applied to every wave). The `ultradeep` profile does **not** use one flat number — it sets `max-turns` PER WAVE: 40 for the Research+Code-Discovery wave, 25 for Impl-Core/Impl-Polish/Quality, 15 for Release/Finalization (the Synthesis-Gate wave is coordinator-direct and carries no `max-turns` at all). |
357
357
  | `auto-commit-per-wave` | boolean | `false` | Automatically commit each wave's work after the Quality-Lite gate passes. Checkpoint commits per wave reduce the risk of data loss from `git stash` collisions in parallel sessions (V3.3 RESCUE incident — see GitLab #214). When `false`, all work is committed at session-end via `/close`. Requires `persistence: true`; the flag is silently ignored when `persistence: false`. Trade-off: each wave produces an additional commit; git log shows N+1 commits instead of 1. Use `/simplify` or `git rebase -i --autosquash` before final close to squash if a clean history is desired. **Implementation note:** the procedural commit sequence (`scripts/lib/auto-commit.mjs`) is deferred to V3.6. Until then, setting this flag to `true` triggers a session-start warning that auto-commits are not yet active — the flag is a no-op but is validated so projects can opt in early. <!-- path-check: historical --> |
358
358
 
359
+ **Guard coverage (moved from CLAUDE.md Critical Gotchas, 2026-09-25).** **Destructive-Command Guard is active in main + subagent waves on harnesses with a compatible command hook.** On Claude Code, and through the supported Cursor and Pi bridges, `hooks/pre-bash-destructive-guard.mjs` applies `.orchestrator/policy/blocked-commands.json`:
360
+ **12 of its 16 rules are `severity: block`, the other 4 only warn** (measured 2026-09-19: `jq '[.rules[].severity]|group_by(.)|map({(.[0]):length})|add' .orchestrator/policy/blocked-commands.json`).
361
+ The 16th is `ledger-delete-protected` (#1401): `rm`/`mv`/`unlink` on `.orchestrator/metrics/**` — added after a wave agent deleted a rotated 53.896-line ledger archive that no rule covered, because `rm` existed only as the pattern `rm -rf` and the redirect denylist's `*.jsonl` did not match `events.jsonl.1`.
362
+ On Codex, the destructive-command rules are instructions only because no compatible `PreToolUse` command handler is wired. Rule source of truth: [`.claude/rules/parallel-sessions.md`](../.claude/rules/parallel-sessions.md) (PSA-003). Per-session bypass via Session Config: `allow-destructive-ops: true` (intentional maintenance only).
363
+
359
364
  ### enforcement-gates: the five gate keys (#800/#915)
360
365
 
361
366
  `enforcement-gates` is surfaced to the hook layer as `gates` inside the wave's
@@ -775,7 +780,25 @@ vault-integration:
775
780
  vault-name: # optional (#660) — per-project vault namespace override
776
781
  ```
777
782
 
778
- > **Host-local override (#653; extended #819).** `vault-dir` resolves host-locally with precedence: env-var (`SO_VAULT_DIR`) > `owner.yaml` `paths.vault-dir` > the committed default. `plan-baseline-path` resolves with an extra per-context tier in between: `SO_BASELINE_PATH` env > `owner.yaml` `baselines:` directory-prefix match against cwd > `owner.yaml` `paths.baseline-path` (legacy scalar) > the committed default. This keeps maintainer-specific absolute paths out of version control. Resolvers: `scripts/lib/config/host-paths.mjs` (both keys) and `scripts/lib/named-baseline-resolver.mjs` (the `baselines:` match tier).
783
+ > **Host-local override (#653; extended #819, agents/vault#319, #1448).** `vault-dir` resolves host-locally with precedence: env-var (`SO_VAULT_DIR`) > `owner.yaml` `vault-dirs:` directory-prefix match against cwd > `owner.yaml` `paths.vault-dir` > the committed default. `plan-baseline-path` resolves the same way: `SO_BASELINE_PATH` env > `owner.yaml` `baselines:` directory-prefix match against cwd > `owner.yaml` `paths.baseline-path` (legacy scalar) > the committed default. The match tier exists because one host-wide `paths.vault-dir` otherwise redirects EVERY repo on the host into one vault, including a repo whose own vault lives elsewhere on that host. First match wins, so list the more specific prefix first:
784
+ >
785
+ > ```yaml
786
+ > # ~/.config/session-orchestrator/owner.yaml
787
+ > paths:
788
+ > vault-dir: ~/Projects/work/vault # host-wide default
789
+ > vault-dirs:
790
+ > - path: ~/Projects/private-world/vault # used for any cwd under the prefix
791
+ > match: { path-prefix: ~/Projects/private-world/ }
792
+ > ```
793
+ >
794
+ > A leading `~` is expanded to the home directory: `path-prefix` when matching, and the `path` / `paths.vault-dir` value the two owner.yaml tiers return (`match`, `owner`). The `env` and `committed` tiers pass through unexpanded; `scripts/vault-mirror.mjs` expands its `--vault-dir` at entry, so a `~/…` from any tier reaches the vault rather than `<cwd>/~/…`.
795
+ >
796
+ > The parsed config reports which tier won as `vault-integration.vault-dir-source` (`env`, `match`, `owner`, `committed`). This keeps maintainer-specific absolute paths out of version control. Resolvers: `scripts/lib/config.mjs` (`resolveVaultDir`, exported; `scripts/vault-backfill.mjs` resolves its stub root through it, #1094), `scripts/lib/config/host-paths.mjs` (`resolveHostPath`, used for `plan-baseline-path`) and `scripts/lib/named-baseline-resolver.mjs` (the `baselines:` / `vault-dirs:` match tier).
797
+ >
798
+ > **Fake-repoRoot trap (moved from CLAUDE.md Critical Gotchas, 2026-09-25).** A throwaway invocation of a vault writer (`mirrorNarrative()`, `vault-mirror.mjs`, the board writer) with a synthetic `repoRoot` does **not** land in a sandbox — the fake repo path only fakes the SOURCE, never the DESTINATION. A reviewer in this repo walked into exactly that.
799
+ > Export `SO_VAULT_DIR=<tmpdir>` before ANY manual invocation of vault-writing code. <!-- consistency:exempt:runtime-only -->
800
+ >
801
+ > **Host-local switch (#1448).** A host can switch the integration off or soften it without touching the committed file, e.g. a host with no vault clone, where `vault-mirror.mjs` would otherwise exit 2 (`missing-vault-dir`) and a `strict` repo would block `/close`. Precedence: env `SO_VAULT_INTEGRATION=off|warn|strict` > `owner.yaml` `vault-integration: { enabled: false }` or `vault-integration: { mode: off|warn|strict }` > the committed block. The host may only LOWER the committed level (`strict` → `warn` → `off`); `enabled: true` or a stronger mode is ignored, so a host can never mirror a repo that did not opt in. An invalid `owner.yaml` `vault-integration:` section is dropped on its own (the rest of `owner.yaml` stays in force). When the host lowered the level, `vault-integration.host-override` names the tier (`env:SO_VAULT_INTEGRATION` or `owner.yaml`), otherwise it is `null`; session-end then prints `vault-mirror: bewusst aus auf diesem Host (<tier>)` instead of failing.
779
802
 
780
803
  > **`SO_CONFIG_HOME` — the host-private config directory itself.** A sibling override, one layer below `owner.yaml`'s own contents rather than a key inside it: `scripts/lib/config/private-config-dir.mjs` (`resolvePrivateConfigDir()`) is THE resolver (#1223) for the directory holding `owner.yaml`, `host-private.json`, and the host-alias ledger (`SO_HOST_ALIASES_FILE`) — `scripts/lib/host-identity.mjs`'s `_privateDir()` delegates to it — with precedence env-var (`SO_CONFIG_HOME`, names the private dir ITSELF) > `XDG_CONFIG_HOME` (names its PARENT) > the homedir default `~/.config/session-orchestrator`. Both env vars are read with `.trim() || fallback`, not a bare `||` (`.claude/rules/development.md` § Error Handling env-var-fallback-whitespace trap).
781
804
 
@@ -784,10 +807,10 @@ vault-integration:
784
807
  | Field | Type | Default | Description |
785
808
  |-------|------|---------|-------------|
786
809
  | `vault-integration.enabled` | boolean | `false` | If true, session-end and evolve skills invoke `vault-mirror.mjs` to sync learnings and sessions into the vault. When false (or missing), mirroring is skipped silently. |
787
- | `vault-integration.vault-dir` | string or null | `null` | Absolute path to the vault repository. Falls back to `$VAULT_DIR` env variable if not set. Required when `enabled` is true. |
810
+ | `vault-integration.vault-dir` | string or null | `null` | Absolute path to the vault repository. Host-local tiers override it (see the note above). If it is still empty after them, only the bash snippet in session-end and evolve falls back to the `$VAULT_DIR` env variable. Required when `enabled` is true. |
788
811
  | `vault-integration.mode` | string | `warn` | Mirror error handling. `strict` blocks session close if the mirror exits non-zero. `warn` reports errors but does not block. `off` bypasses mirror invocation entirely (useful when transitioning). |
789
812
  | `vault-integration.vault-name` | string or null | `null` | Optional override for the per-project vault namespace segment (#660). When set (or via CLI `--vault-name`), vault writes go to `40-learnings/<vault-name>/` and `50-sessions/<vault-name>/`, sanitised to a kebab slug. When null/absent, the namespace is derived from the git origin via `deriveRepo()`. Owner-privacy leaks (personal home path / private slug / personal name) are redacted to `redacted-repo`. NOT a filesystem path → NOT host-path-resolved. **Coverage gap:** portfolio board rows are NOT yet namespace-aware — the override only reaches `40-learnings/`, `50-sessions/`, and the per-repo narrative mirror (`narrative-mirror.mjs`, #832 item 2); tracked separately in #832. Resolver: `scripts/lib/vault-mirror/namespace.mjs` (`resolveRepoNamespace`). |
790
- | `vault-integration.gitlab-groups` | string[] or null | `null` | List of GitLab group paths to scan for repos missing `.vault.yaml`. Consumed by `scripts/vault-backfill.mjs` (via `readVaultIntegrationConfig()`) and the `/plan retro` vault-backfill sub-mode (`skills/plan/mode-retro.md` Phase 1.6 Step 1). When null/unset, the backfill CLI exits with a "no groups configured" notice. |
813
+ | `vault-integration.gitlab-groups` | string[] or null | `null` | List of GitLab group paths to scan for repos missing `.vault.yaml`. Parsed by `_parseVaultIntegration` (`scripts/lib/config/vault-integration.mjs`) and consumed by `scripts/vault-backfill.mjs`. Accepts a comma string, `[a, b]`, or a YAML block list; in the inline-object form more than one group needs `[a, b]`; an empty list is `null`. YAML semantics: `null`, `~` and an empty value mean unset (as a list element too, where they are dropped), and each element loses one pair of matching quotes — `["a"]` is the group `a`, and only a quoted `"null"` element is a group named `null`. Also consumed by the `/plan retro` vault-backfill sub-mode (`skills/plan/mode-retro.md` Phase 1.6 Step 1). When null/unset and neither `--groups` nor `--yes` is passed, the backfill CLI exits 1 with `no GitLab groups specified — pass --groups <CSV> or set vault-integration.gitlab-groups in CLAUDE.md`. |
791
814
 
792
815
  ### Environment override: `VAULT_MIRROR_CANONICAL_SUFFIX`
793
816
 
@@ -843,7 +866,7 @@ Opt-out configuration for the agent-writable memory tool. During a wave, an agen
843
866
 
844
867
  This is a Hermes-style memory-write API **without** Hermes' overwrites-manual-edits critique: the operator confirmation is mandatory and there is no silent overwrite path. Three safety layers keep the surface conservative:
845
868
 
846
- 1. **Quota per wave** — `quota-per-wave` (default `5`) caps how many proposals any single agent may queue within one wave. Excess proposals exit `1` and the call-site logs the rejection.
869
+ 1. **Quota per wave** — `quota-per-wave` (default `5`) caps how many proposals ONE WAVE may queue, all of its agents together — not each agent: the store counts a wave's records by `wave_id` only (`scripts/lib/memory-proposals/store.mjs`). In a wave of N agents the 6th proposal of the wave exits `1` regardless of which agent sends it, so one agent that proposes five times uses up the quota for every sibling. Excess proposals exit `1` and the call-site logs the rejection.
847
870
  2. **Confidence floor** — `confidence-floor` (default `0.5`) rejects low-confidence proposals before they reach the operator (exit `2`). Tuned so a learning is only proposed when the agent is at least 50% sure of the insight.
848
871
  3. **AUQ confirm-or-discard** — the session-end phase never auto-persists. Every proposal is `AskUserQuestion`-gated; the operator can accept, reject, or edit before commit.
849
872
 
@@ -853,14 +876,14 @@ All fields live under the top-level `memory` object in your Session Config host
853
876
  memory:
854
877
  proposals:
855
878
  enabled: true # default true; opt-out master toggle for the memory.propose feature
856
- quota-per-wave: 5 # max proposals an agent may queue per wave (exit 1 on overflow)
879
+ quota-per-wave: 5 # max proposals per wave, all agents together (exit 1 on overflow)
857
880
  confidence-floor: 0.5 # proposals below this confidence are rejected (exit 2)
858
881
  ```
859
882
 
860
883
  | Field | Type | Default | Description |
861
884
  |-------|------|---------|-------------|
862
885
  | `memory.proposals.enabled` | boolean | `true` | Master toggle for the entire memory-proposals feature. When `false`, the `memory.propose` CLI exits `3` (rejected-wrong-context) for every call and session-end Phase 3.6.3 is skipped. When `true`, agents may queue proposals during waves and the coordinator surfaces them at session-end. PRD F2.1 / issue #501. |
863
- | `memory.proposals.quota-per-wave` | integer | `5` | Maximum number of proposals one wave-executor agent can queue per wave. The 6th proposal from the same agent in the same wave exits `1` (quota-exceeded). Bounds: integer ≥ 0. Set to `0` to disable proposals from agents without disabling the feature entirely (operator can still propose). |
886
+ | `memory.proposals.quota-per-wave` | integer | `5` | Maximum number of proposals a wave can queue, counted across ALL of its agents (the store counts records by `wave_id` only). The 6th proposal of a wave exits `1` (quota-exceeded) whichever agent sends it — in a wave of N agents, the first five proposals of the wave win. Bounds: integer ≥ 0. Set to `0` to disable proposals from agents without disabling the feature entirely (operator can still propose). |
864
887
  | `memory.proposals.confidence-floor` | float | `0.5` | Minimum confidence (0.0..1.0) required for a proposal to be queued. Proposals with `--confidence < confidence-floor` exit `2` (rejected-low-confidence) before reaching the operator. Bounds: `0.0 ≤ value ≤ 1.0`. Set to `0.0` to accept any confidence (operator filters at AUQ time). |
865
888
 
866
889
  ### Agent CLI invocation
@@ -900,7 +923,7 @@ A successful dry-run exits `0` with stdout status `dry-run-ok` (see updated exit
900
923
  |-----------|-----------------|---------|--------------|
901
924
  | `0` | `queued` | Queued | Proposal accepted into the per-wave staging directory; awaits operator confirmation at session-end Phase 3.6.3. |
902
925
  | `0` | `dry-run-ok` | Validated, not written | `--dry-run` was passed and the proposal (argv + schema) validated successfully. No write to `proposals.jsonl` occurs; the wrong-context gates are bypassed under this flag (#741.3). |
903
- | `1` | `quota-exceeded` | Rejected — quota exceeded | This agent has already queued `quota-per-wave` proposals in this wave. Subsequent calls from the same agent fail until the next wave. Not applicable under `--dry-run` (gate bypassed). |
926
+ | `1` | `quota-exceeded` | Rejected — quota exceeded | This wave has already queued `quota-per-wave` proposals, from any of its agents. Every further call in this wave fails, whichever agent makes it, until the next wave. Not applicable under `--dry-run` (gate bypassed). |
904
927
  | `2` | `rejected-low-confidence` | Rejected — low confidence | `--confidence` argument is below `confidence-floor`. Tighten the insight or raise the confidence (operator can still tune the floor). |
905
928
  | `3` | `rejected-wrong-context` | Rejected — wrong context | Feature disabled (`enabled: false`), STATE.md not active, or `SO_WAVE_AGENT != "1"` (call originated outside a wave-executor agent context). Not applicable under `--dry-run` (gate bypassed). |
906
929
  | `4` | `error` | Arg error | Missing or malformed flag — invalid `--type`, empty `--subject`, non-numeric `--confidence`. The CLI prints a one-line usage message on stderr. |
@@ -1350,7 +1373,7 @@ remote-hosts:
1350
1373
 
1351
1374
  **Two enums, never conflated.** `roles-allowed` holds `agent-mapping` roles (`test`, `ui`, `perf`) — NOT wave roles (`Impl-Core`, `Quality`, …). The wave→role translation is `OFFLOADABLE_WAVE_ROLES` in `scripts/lib/wave-resource-gate.mjs`; a wave role absent from that map is local-only by default.
1352
1375
 
1353
- **Placement contract.** The gate applies its offload arm only after the HR-004 heavy-repo cap, and only when the resource verdict was `reduce` or `coordinator-direct`. It does NOT probe the network: the coordinator supplies a readiness witness (`remoteReady: { m5: true }`, or an async `probeFn`). With no witness, no host counts as ready and the decision stays local — the gate fails toward local, never toward an unverified host. A role in `NEVER_FOREIGN_ROLES` (`scripts/lib/wave-executor/dispatch-common.mjs`) is never offloaded regardless.
1376
+ **Placement contract.** The gate applies its offload arm only after the HR-004 heavy-repo cap, and only when the resource verdict was `reduce` or `coordinator-direct` — or, with `offload-first: true`, on `proceed` as well (see § `offload-first` below). It does NOT probe the network: the coordinator supplies a readiness witness (`remoteReady: { m5: true }`, or an async `probeFn`). With no witness, no host counts as ready and the decision stays local — the gate fails toward local, never toward an unverified host. A role in `NEVER_FOREIGN_ROLES` (`scripts/lib/wave-executor/dispatch-common.mjs`) is never offloaded regardless.
1354
1377
 
1355
1378
  **agent-mapping interaction.** A declared alias is what an `agent-mapping` value of the form `<role>: ssh:<alias>` validates against; naming an undeclared host throws at parse time, naming the `ssh` channel with no target throws as for any other channel.
1356
1379
 
@@ -1358,6 +1381,32 @@ Read by: `scripts/lib/config/remote-hosts.mjs` (parser), `scripts/lib/config.mjs
1358
1381
 
1359
1382
  See `skills/remote-offload/SKILL.md` for the wave-executor-side decision rule, the three offload channels, and how a declared alias here is what an `agent-mapping` `ssh:<alias>` value validates against.
1360
1383
 
1384
+ ### `offload-first` (#1465)
1385
+
1386
+ Opt-in switch that makes placement the FIRST choice for an offloadable wave role, not only the answer to local pressure. Scalar key, so a trailing `# comment` on its line is fine (the block-header gotcha above does not apply).
1387
+
1388
+ ```yaml
1389
+ offload-first: false # true = offloadable roles go to a witnessed-ready remote host even on `proceed`
1390
+ ```
1391
+
1392
+ | Field | Type | Default | Description |
1393
+ |-------|------|---------|-------------|
1394
+ | `offload-first` | boolean | `false` | When `true`, the gate's offload arm fires on a `proceed` verdict too, not only on `reduce` / `coordinator-direct`. `false` (or absent) changes nothing. |
1395
+
1396
+ **Behaviour with `offload-first: true`.**
1397
+
1398
+ - Only roles in `OFFLOADABLE_WAVE_ROLES` (`scripts/lib/wave-resource-gate.mjs`) move: wave roles `quality` / `test` → `test`, `ui` → `ui`, `perf` → `perf`. The table is NOT extended by this switch — build, lint and audit work is covered by the Quality wave's `test` role. `impl-core`, `security-review`, `migration`, `release`, `secrets`, `incident` and `refactor-crosscut` never leave the local host.
1399
+ - The target is the FIRST declared `remote-hosts` entry whose `roles-allowed` carries the mapped role AND that is witnessed ready (`remoteReady: { m5: true }` or an async `probeFn`). The gate still never probes the network itself, so the witness is mandatory for the switch to have any effect: without one, nothing offloads even with the switch on.
1400
+ - The HR-004 heavy-repo cap still binds the offloaded agent count.
1401
+ - No ready host for the role → the verdict is unchanged (`proceed`, or the `reduce`/`coordinator-direct` the resource rules computed) and `reasons` carries `offload-first: no ready host for '<role>' — staying local`.
1402
+ - Switch on but no `remote-hosts` declared → the verdict is unchanged and `reasons` carries `offload-first: true but no remote-hosts declared — staying local`. `validateSessionConfig()` (`scripts/lib/config-schema.mjs`) additionally emits a warn-level cross-field finding `offload-first-cross-field` for that combination; it never flips `ok`.
1403
+ - `resource-awareness: false` remains a FULL opt-out (no probe, no HR-004 cap, no placement), as documented in § Environment Awareness — the switch does not change that.
1404
+ - On the `probe failed (ignored)` path placement DOES apply when the switch is on, because placement needs no measurement; the `probe failed (ignored)` reason is kept.
1405
+
1406
+ **Committed-only.** There is no host-local precedence (env > `owner.yaml` > committed) for this key: the existing `resolveDispatcherAutonomy` resolver is enum-specific and `owner.yaml` freezes its allowed sections, so reusing it would need a schema change for a need nobody has raised yet (BV-001) — the value in the committed Session Config is the value that applies.
1407
+
1408
+ Read by: `scripts/lib/config.mjs` (parser), `scripts/lib/config-schema.mjs` (cross-field warning), `scripts/lib/wave-resource-gate.mjs` (placement).
1409
+
1361
1410
  ## Evolve Extra Sources (#638)
1362
1411
 
1363
1412
  Opt-in EXTRA learning sources for `/evolve`. A domain measurement (e.g. an eval-learn regression harness) runs OUT-OF-BAND and writes a sidecar JSON of regression flags; `/evolve` then READS each declared sidecar and emits a `domain-regression` learning candidate per flag that has persisted across ≥2 consecutive sessions. This is a strict **read-only consumption contract**: `/evolve` never runs the domain measurement — it only consumes the sidecar output. Absent/empty ⇒ `[]` ⇒ no extra sources are read; existing `/evolve` runs are unaffected.
@@ -1572,12 +1621,12 @@ reaper:
1572
1621
  | `reaper.mode` | `report` \| `kill` | `report` | `report` runs the scan in dry-run (decide + audit, no signal); `kill` arms the signal path (PRD Stufe 2, after calibration). An unrecognised value falls back to `report` — never to `kill`. |
1573
1622
  | `reaper.min-age-seconds` | integer (≥ 0) | `300` | DevWatchdog's hard limit for `tsgo`; the 2026-09-20 orphans were 7–17 min old, well above it. Self-healing clamp: a value below `min-scan-interval-seconds` is widened to it, because a process younger than one scan period can be born and reaped between two scans. |
1574
1623
  | `reaper.min-scan-interval-seconds` | integer (≥ 1) | `30` | DevWatchdog's normal scan cadence. The throttle that keeps a `PostToolBatch` storm from taxing every tool call. |
1575
- | `reaper.kill-grace-ms` | integer (≥ 0) | `10000` | `DEFAULT_KILL_GRACE_MS` from `dispatch-common.mjs:61` — repo convention, not newly invented. SIGTERM → grace → SIGKILL. |
1624
+ | `reaper.kill-grace-ms` | integer (≥ 0) | `10000` | `DEFAULT_KILL_GRACE_MS` from `process-group.mjs:52` — repo convention, not newly invented. SIGTERM → grace → SIGKILL. |
1576
1625
  | `reaper.verify-wait-ms` | integer (≥ 0) | `500` | Wait before reading the effect back. Without it the 2026-09-20 check falsely reported "still alive" measuring immediately after `kill -9` (PRD B6: a sent signal proves nothing). |
1577
1626
  | `reaper.max-hook-latency-ms` | integer (≥ 1) | `50` | Ceiling the TRIGGER may delay a hook by — the config read, the marker `stat` and the detached spawn, measured with `performance.now()` in `maybeTriggerOrphanScan()`. Overrunning it writes ONE stderr WARN line and nothing else: no event (a `PostToolBatch`-class hook emitting per fire is the always-on signal HR-101 calls a broken instrument) and no abort (the child is already detached by then). The scan itself is not covered — that is the point of spawning detached. |
1578
1627
  | `reaper.false-alarm-window` | integer (≥ 1) | `50` | Rolling window of audit decisions the HR-101 10 % false-alarm rate is judged over — a window in DECISIONS, not calendar time, so the rate has a population on quiet hosts too. Reaches the scan as `--false-alarm-window` on the detached child's argv and becomes `runOrphanScan`'s `falseAlarmWindow`; the CLI refuses `0`, which `falseAlarmRate()` would read as “every firing ever recorded” rather than as a window. |
1579
1628
 
1580
- **Used by:** `hooks/post-tool-batch-wave-signal.mjs`, `hooks/on-stop.mjs` (both via `maybeTriggerOrphanScan()`), `scripts/lib/orphan-reaper.mjs`, `scripts/lib/config/reaper.mjs` (`_parseReaper`). PRD `docs/prd/2026-09-20-prozessgruppen-kill-und-waisen-waechter.md`, Epic #1425, issue #1432.
1629
+ **Used by:** `hooks/post-tool-batch-wave-signal.mjs`, `hooks/on-stop.mjs` (both via `maybeTriggerOrphanScan()` from `scripts/lib/orphan-reaper/trigger.mjs`), `scripts/lib/orphan-reaper.mjs`, `scripts/lib/config/reaper.mjs` (`_parseReaper`). PRD `docs/prd/2026-09-20-prozessgruppen-kill-und-waisen-waechter.md`, Epic #1425, issue #1432.
1581
1630
 
1582
1631
  ## Gate Timeout — Path B (#1425 A3)
1583
1632
 
@@ -1834,7 +1883,7 @@ persona-gate-wave:
1834
1883
  after: quality # quality | impl-polish — wave name after which to fire
1835
1884
  threshold: "all" # "M-of-N" | "all" | "N-of-N" — passed to parseThreshold
1836
1885
  personas: [] # list of persona names from .claude/personas/; empty = all catalog
1837
- dispatch-model: claude-opus-4-7 # alias or full model ID — default 'claude-opus-4-7'
1886
+ dispatch-model: opus # alias or full model ID — default 'opus'
1838
1887
  mode: off # off | warn | strict
1839
1888
  ```
1840
1889
 
@@ -1844,7 +1893,7 @@ persona-gate-wave:
1844
1893
  | `persona-gate-wave.after` | string (`quality` \| `impl-polish`) | `quality` | The wave role after which the hook fires. The hook runs once per session, immediately after the named wave's STATE.md update. |
1845
1894
  | `persona-gate-wave.threshold` | string | `"all"` | Voting threshold passed to `parseThreshold()` from `scripts/lib/persona-panel/threshold.mjs`. Accepts `"all"`, `"any"`, or `"M-of-N"` where `1 ≤ M ≤ N ≤ 20`. Example: `"6-of-6"` requires every persona to vote PASS; `"4-of-6"` allows two dissenters. |
1846
1895
  | `persona-gate-wave.personas` | string[] | `[]` | Roster of persona names to dispatch. Each entry must match `^[a-z0-9-]{1,64}$` and refer to a persona file under `.claude/personas/<name>.md`. When the list is empty (default), every persona in the catalog is dispatched. |
1847
- | `persona-gate-wave.dispatch-model` | string | `claude-opus-4-7` | Model used for each persona agent dispatch. Accepts the same shape as agent frontmatter `model:` — one of `inherit` \| `sonnet` \| `opus` \| `haiku`, or a full model ID like `claude-opus-4-7`. |
1896
+ | `persona-gate-wave.dispatch-model` | string | `opus` | Model used for each persona agent dispatch. Accepts the same shape as agent frontmatter `model:` — one of `inherit` \| `sonnet` \| `opus` \| `haiku` \| `fable`, or a full model ID like `claude-opus-5-5`. Default is the alias `opus`, which tracks the current Opus; pin a full ID only for a named reproducibility need. |
1848
1897
  | `persona-gate-wave.mode` | string (`off` \| `warn` \| `strict`) | `off` | Behaviour on consolidator result. `off` skips dispatch entirely even when `enabled: true` (silent no-op). `warn` consolidates and logs findings under a `Persona-gate:` bullet in the wave progress update without blocking. `strict` consolidates and on any non-PROCEED verdict prompts the operator via `AskUserQuestion` to proceed-as-is, revise remaining waves, or abort. |
1849
1898
 
1850
1899
  **Validation:**
@@ -410,6 +410,14 @@ The gate never probes the network. Without a readiness witness no host counts as
410
410
 
411
411
  Read by: `scripts/lib/config/remote-hosts.mjs`, `scripts/lib/wave-resource-gate.mjs`.
412
412
 
413
+ `offload-first` (#1465) makes placement the first choice instead of the answer to pressure: with `true`, an offloadable role (`test` / `ui` / `perf`) goes to the first witnessed-ready declared host even when the gate verdict is `proceed`. It needs both a `remote-hosts` entry and a readiness witness to act; without them the wave stays local and the gate names the reason.
414
+
415
+ ```yaml
416
+ offload-first: false # true = offloadable roles go to a witnessed-ready remote host even on `proceed`
417
+ ```
418
+
419
+ Read by: `scripts/lib/config.mjs`, `scripts/lib/config-schema.mjs`, `scripts/lib/wave-resource-gate.mjs`.
420
+
413
421
  ## Evolve Extra Sources (#638)
414
422
 
415
423
  Opt-in EXTRA learning sources for `/evolve`. A `domain-regression` measurement (e.g. an eval-learn harness) runs OUT-OF-BAND and writes a sidecar JSON; `/evolve` then READS each declared sidecar and emits a `domain-regression` learning candidate per persistent regression flag. `/evolve` NEVER runs the measurement itself — this is a strict read-only consumption contract. Absent/empty ⇒ `[]` ⇒ no extra sources are read.
@@ -856,7 +864,7 @@ persona-gate-wave:
856
864
  after: quality # quality | impl-polish
857
865
  threshold: all # all | any | <m>-of-<n>
858
866
  personas: [] # persona slugs the panel dispatches
859
- dispatch-model: claude-opus-4-7
867
+ dispatch-model: opus # alias or full model ID — default 'opus'
860
868
  mode: off # off | warn | strict — enabled: true with mode: off never fires
861
869
 
862
870
  # Agentic test orchestrator (/test) — run profiles and artifact retention
@@ -886,6 +894,7 @@ remote-hosts:
886
894
  roles-allowed: [test, ui, perf] # subset of test|ui|perf (default: all three)
887
895
  repo-path: ~/Projects/Alice # optional SAFE path (default: null)
888
896
  claude-path: ~/.local/bin/claude # optional SAFE path (default: null)
897
+ offload-first: false # #1465: true = offloadable roles go to a witnessed-ready remote host even on `proceed`
889
898
 
890
899
  # Evolve extra-sources — opt-in EXTRA /evolve learning sources (#638)
891
900
  evolve:
@@ -1015,7 +1024,7 @@ reaper:
1015
1024
  mode: report # report (decide + audit only) | kill (send signals — PRD Stufe 2)
1016
1025
  min-age-seconds: 300 # DevWatchdog's hard limit for tsgo; the 2026-09-20 orphans were 7–17 min old
1017
1026
  min-scan-interval-seconds: 30 # throttle; keeps a PostToolBatch storm from taxing every tool call
1018
- kill-grace-ms: 10000 # DEFAULT_KILL_GRACE_MS from dispatch-common.mjs:61 — repo convention
1027
+ kill-grace-ms: 10000 # DEFAULT_KILL_GRACE_MS from process-group.mjs:52 — repo convention
1019
1028
  verify-wait-ms: 500 # wait before reading the effect back (a sent signal proves nothing)
1020
1029
  max-hook-latency-ms: 50 # ceiling a scan may delay a hook by
1021
1030
  false-alarm-window: 50 # rolling window of audit decisions the HR-101 10 % rate is judged over
@@ -169,10 +169,14 @@ entirely. Source: `docs/session-config-reference.md` § Docs Orchestrator.
169
169
  The `docs-writer` agent operates under a **hallucination ban**: every
170
170
  substantive paragraph must trace to one of the canonical four sources, or
171
171
  carry an inline `<!-- REVIEW: source needed -->` marker. The four sources are
172
- defined once and reused everywhere:
173
-
174
- 1. **diff** — `git diff $SESSION_START_REF..HEAD`
175
- 2. **git-log** — `git log $SESSION_START_REF..HEAD --format="%H %s%n%b"`
172
+ defined once — in `skills/docs-orchestrator/SKILL.md` — and reused everywhere.
173
+ Diffs take `"$SESSION_RANGE"`, ONE complete range (the pinned SHA's
174
+ `<sha>..HEAD`, else the resolved `<base>...HEAD` from the accessor in
175
+ `skills/session-end/plan-verification.md`); only the log keeps the two-dot
176
+ `$SESSION_START_REF..HEAD`. An empty range or ref is a skip, never "no changes":
177
+
178
+ 1. **diff** — `git diff "$SESSION_RANGE"`
179
+ 2. **git-log** — `git log "$SESSION_START_REF..HEAD" --format="%H %s%n%b"`
176
180
  3. **session-memory** — `~/.claude/projects/<project>/memory/session-*.md` and
177
181
  `.orchestrator/` outputs
178
182
  4. **affected-files** — files in the wave-scope `allowedPaths` block
@@ -1,6 +1,6 @@
1
1
  {
2
- "generated_at": "2026-09-22T06:04:50.134Z",
3
- "head": "132e3ae1b222cc3a5e52e2a1e67e9688832f2c20",
2
+ "generated_at": "2026-10-03T07:30:53.188Z",
3
+ "head": "0cfbaa2c4fad16d825b94b8000ca8aea3dc9af68",
4
4
  "entries": [
5
5
  {
6
6
  "file": "hooks/_lib/atomic-json.mjs",
@@ -61,6 +61,7 @@
61
61
  "pre-bash-sessions-ledger-guard.mjs",
62
62
  "pre-bash-staging-fence.mjs",
63
63
  "pre-bash-templates-first.mjs",
64
+ "pre-edit-sessions-ledger-guard.mjs",
64
65
  "pre-task-scope-disjoint.mjs",
65
66
  "skill-invocation-telemetry.mjs",
66
67
  "subagent-telemetry.mjs"
@@ -239,6 +240,12 @@
239
240
  "pre-bash-templates-first.mjs"
240
241
  ]
241
242
  },
243
+ {
244
+ "file": "hooks/pre-edit-sessions-ledger-guard.mjs",
245
+ "reachable_from": [
246
+ "pre-edit-sessions-ledger-guard.mjs"
247
+ ]
248
+ },
242
249
  {
243
250
  "file": "hooks/pre-task-scope-disjoint.mjs",
244
251
  "reachable_from": [
@@ -301,6 +308,7 @@
301
308
  {
302
309
  "file": "scripts/lib/command-blocker.mjs",
303
310
  "reachable_from": [
311
+ "on-stop.mjs",
304
312
  "post-bash-issue-budget-refund.mjs",
305
313
  "post-bash-write-verify.mjs",
306
314
  "post-edit-validate.mjs",
@@ -308,7 +316,8 @@
308
316
  "pre-bash-issue-budget.mjs",
309
317
  "pre-bash-memory-propose-audit.mjs",
310
318
  "pre-bash-staging-fence.mjs",
311
- "pre-bash-templates-first.mjs"
319
+ "pre-bash-templates-first.mjs",
320
+ "pre-task-scope-disjoint.mjs"
312
321
  ]
313
322
  },
314
323
  {
@@ -320,7 +329,6 @@
320
329
  "post-bash-issue-budget-refund.mjs",
321
330
  "post-edit-validate.mjs",
322
331
  "post-subagent-discovery-validator.mjs",
323
- "post-tool-batch-wave-signal.mjs",
324
332
  "pre-bash-issue-budget.mjs",
325
333
  "pre-bash-templates-first.mjs"
326
334
  ]
@@ -835,8 +843,7 @@
835
843
  "file": "scripts/lib/env-check.mjs",
836
844
  "reachable_from": [
837
845
  "post-bash-write-verify.mjs",
838
- "post-edit-validate.mjs",
839
- "pre-bash-memory-propose-audit.mjs"
846
+ "post-edit-validate.mjs"
840
847
  ]
841
848
  },
842
849
  {
@@ -947,6 +954,12 @@
947
954
  "skill-invocation-telemetry.mjs"
948
955
  ]
949
956
  },
957
+ {
958
+ "file": "scripts/lib/fleet-protocol.mjs",
959
+ "reachable_from": [
960
+ "on-session-start.mjs"
961
+ ]
962
+ },
950
963
  {
951
964
  "file": "scripts/lib/frontend-detect/detect.mjs",
952
965
  "reachable_from": [
@@ -963,8 +976,7 @@
963
976
  "file": "scripts/lib/hardening.mjs",
964
977
  "reachable_from": [
965
978
  "post-bash-write-verify.mjs",
966
- "post-edit-validate.mjs",
967
- "pre-bash-memory-propose-audit.mjs"
979
+ "post-edit-validate.mjs"
968
980
  ]
969
981
  },
970
982
  {
@@ -1016,6 +1028,7 @@
1016
1028
  "pre-bash-sessions-ledger-guard.mjs",
1017
1029
  "pre-bash-staging-fence.mjs",
1018
1030
  "pre-bash-templates-first.mjs",
1031
+ "pre-edit-sessions-ledger-guard.mjs",
1019
1032
  "pre-task-scope-disjoint.mjs",
1020
1033
  "skill-invocation-telemetry.mjs"
1021
1034
  ]
@@ -1045,6 +1058,7 @@
1045
1058
  "pre-bash-sessions-ledger-guard.mjs",
1046
1059
  "pre-bash-staging-fence.mjs",
1047
1060
  "pre-bash-templates-first.mjs",
1061
+ "pre-edit-sessions-ledger-guard.mjs",
1048
1062
  "pre-task-scope-disjoint.mjs",
1049
1063
  "skill-invocation-telemetry.mjs",
1050
1064
  "subagent-telemetry.mjs"
@@ -1145,7 +1159,21 @@
1145
1159
  ]
1146
1160
  },
1147
1161
  {
1148
- "file": "scripts/lib/orphan-reaper.mjs",
1162
+ "file": "scripts/lib/orphan-reaper/defaults.mjs",
1163
+ "reachable_from": [
1164
+ "on-stop.mjs",
1165
+ "post-tool-batch-wave-signal.mjs"
1166
+ ]
1167
+ },
1168
+ {
1169
+ "file": "scripts/lib/orphan-reaper/scan-throttle.mjs",
1170
+ "reachable_from": [
1171
+ "on-stop.mjs",
1172
+ "post-tool-batch-wave-signal.mjs"
1173
+ ]
1174
+ },
1175
+ {
1176
+ "file": "scripts/lib/orphan-reaper/trigger.mjs",
1149
1177
  "reachable_from": [
1150
1178
  "on-stop.mjs",
1151
1179
  "post-tool-batch-wave-signal.mjs"
@@ -1242,13 +1270,6 @@
1242
1270
  "on-session-start.mjs"
1243
1271
  ]
1244
1272
  },
1245
- {
1246
- "file": "scripts/lib/process-group.mjs",
1247
- "reachable_from": [
1248
- "on-stop.mjs",
1249
- "post-tool-batch-wave-signal.mjs"
1250
- ]
1251
- },
1252
1273
  {
1253
1274
  "file": "scripts/lib/resource-probe.mjs",
1254
1275
  "reachable_from": [
@@ -1264,9 +1285,7 @@
1264
1285
  {
1265
1286
  "file": "scripts/lib/resource-probe/parsers.mjs",
1266
1287
  "reachable_from": [
1267
- "on-session-start.mjs",
1268
- "on-stop.mjs",
1269
- "post-tool-batch-wave-signal.mjs"
1288
+ "on-session-start.mjs"
1270
1289
  ]
1271
1290
  },
1272
1291
  {
@@ -1284,10 +1303,12 @@
1284
1303
  {
1285
1304
  "file": "scripts/lib/scope-gate.mjs",
1286
1305
  "reachable_from": [
1306
+ "on-stop.mjs",
1287
1307
  "post-bash-write-verify.mjs",
1288
1308
  "post-edit-validate.mjs",
1289
1309
  "post-tool-batch-wave-signal.mjs",
1290
- "pre-bash-memory-propose-audit.mjs"
1310
+ "pre-bash-memory-propose-audit.mjs",
1311
+ "pre-task-scope-disjoint.mjs"
1291
1312
  ]
1292
1313
  },
1293
1314
  {
@@ -1387,8 +1408,7 @@
1387
1408
  "reachable_from": [
1388
1409
  "on-session-end.mjs",
1389
1410
  "on-session-start.mjs",
1390
- "on-stop.mjs",
1391
- "post-tool-batch-wave-signal.mjs"
1411
+ "on-stop.mjs"
1392
1412
  ]
1393
1413
  },
1394
1414
  {
@@ -1643,13 +1663,6 @@
1643
1663
  "pre-bash-staging-fence.mjs"
1644
1664
  ]
1645
1665
  },
1646
- {
1647
- "file": "scripts/lib/wave-executor/dispatch-common.mjs",
1648
- "reachable_from": [
1649
- "on-stop.mjs",
1650
- "post-tool-batch-wave-signal.mjs"
1651
- ]
1652
- },
1653
1666
  {
1654
1667
  "file": "scripts/lib/wave-sizing.mjs",
1655
1668
  "reachable_from": [