session-orchestrator 5.2.0 → 5.4.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 (427) hide show
  1. package/.agents/skills/architecture/SKILL.md +3 -1
  2. package/.agents/skills/autopilot/SKILL.md +5 -1
  3. package/.agents/skills/autopilot/agents/openai.yaml +5 -0
  4. package/.agents/skills/bootstrap/SKILL.md +5 -1
  5. package/.agents/skills/bootstrap/agents/openai.yaml +5 -0
  6. package/.agents/skills/brainstorm/SKILL.md +5 -1
  7. package/.agents/skills/brainstorm/agents/openai.yaml +5 -0
  8. package/.agents/skills/claude-md-drift-check/SKILL.md +4 -2
  9. package/.agents/skills/close/SKILL.md +5 -1
  10. package/.agents/skills/close/agents/openai.yaml +5 -0
  11. package/.agents/skills/convergence-monitoring/SKILL.md +4 -2
  12. package/.agents/skills/debug/SKILL.md +5 -1
  13. package/.agents/skills/debug/agents/openai.yaml +5 -0
  14. package/.agents/skills/discovery/SKILL.md +5 -1
  15. package/.agents/skills/discovery/agents/openai.yaml +5 -0
  16. package/.agents/skills/dispatcher/SKILL.md +5 -1
  17. package/.agents/skills/dispatcher/agents/openai.yaml +5 -0
  18. package/.agents/skills/docs-orchestrator/SKILL.md +3 -1
  19. package/.agents/skills/ecosystem-health/SKILL.md +3 -1
  20. package/.agents/skills/eli5/SKILL.md +5 -1
  21. package/.agents/skills/eli5/agents/openai.yaml +5 -0
  22. package/.agents/skills/eval/SKILL.md +6 -2
  23. package/.agents/skills/eval/agents/openai.yaml +5 -0
  24. package/.agents/skills/evolve/SKILL.md +6 -2
  25. package/.agents/skills/evolve/agents/openai.yaml +5 -0
  26. package/.agents/skills/frontmatter-guard/SKILL.md +3 -1
  27. package/.agents/skills/gitlab-ops/SKILL.md +3 -1
  28. package/.agents/skills/gitlab-portfolio/SKILL.md +3 -1
  29. package/.agents/skills/go/SKILL.md +5 -1
  30. package/.agents/skills/go/agents/openai.yaml +5 -0
  31. package/.agents/skills/grill/SKILL.md +5 -1
  32. package/.agents/skills/grill/agents/openai.yaml +5 -0
  33. package/.agents/skills/harness-audit/SKILL.md +5 -1
  34. package/.agents/skills/harness-audit/agents/openai.yaml +5 -0
  35. package/.agents/skills/hook-development/SKILL.md +3 -1
  36. package/.agents/skills/mcp-builder/SKILL.md +3 -1
  37. package/.agents/skills/memory-cleanup/SKILL.md +5 -1
  38. package/.agents/skills/memory-cleanup/agents/openai.yaml +5 -0
  39. package/.agents/skills/mode-selector/SKILL.md +3 -1
  40. package/.agents/skills/navigator/SKILL.md +22 -0
  41. package/.agents/skills/navigator/agents/openai.yaml +5 -0
  42. package/.agents/skills/npm-publish/SKILL.md +4 -2
  43. package/.agents/skills/peekaboo-driver/SKILL.md +3 -1
  44. package/.agents/skills/persona-panel/SKILL.md +5 -1
  45. package/.agents/skills/persona-panel/agents/openai.yaml +5 -0
  46. package/.agents/skills/plan/SKILL.md +5 -1
  47. package/.agents/skills/plan/agents/openai.yaml +5 -0
  48. package/.agents/skills/playwright-driver/SKILL.md +3 -1
  49. package/.agents/skills/portfolio/SKILL.md +5 -1
  50. package/.agents/skills/portfolio/agents/openai.yaml +5 -0
  51. package/.agents/skills/quality-gates/SKILL.md +3 -1
  52. package/.agents/skills/reconcile/SKILL.md +5 -1
  53. package/.agents/skills/reconcile/agents/openai.yaml +5 -0
  54. package/.agents/skills/release/SKILL.md +5 -1
  55. package/.agents/skills/release/agents/openai.yaml +5 -0
  56. package/.agents/skills/remote-offload/SKILL.md +3 -1
  57. package/.agents/skills/repo-audit/SKILL.md +5 -1
  58. package/.agents/skills/repo-audit/agents/openai.yaml +5 -0
  59. package/.agents/skills/session/SKILL.md +21 -0
  60. package/.agents/skills/session/agents/openai.yaml +5 -0
  61. package/.agents/skills/session-end/SKILL.md +3 -1
  62. package/.agents/skills/session-plan/SKILL.md +3 -1
  63. package/.agents/skills/session-start/SKILL.md +3 -1
  64. package/.agents/skills/spinout/SKILL.md +5 -1
  65. package/.agents/skills/spinout/agents/openai.yaml +5 -0
  66. package/.agents/skills/sunset-review/SKILL.md +5 -1
  67. package/.agents/skills/sunset-review/agents/openai.yaml +5 -0
  68. package/.agents/skills/templates-ack/SKILL.md +21 -0
  69. package/.agents/skills/templates-ack/agents/openai.yaml +5 -0
  70. package/.agents/skills/test/SKILL.md +5 -1
  71. package/.agents/skills/test/agents/openai.yaml +5 -0
  72. package/.agents/skills/test-audit/SKILL.md +21 -0
  73. package/.agents/skills/test-audit/agents/openai.yaml +5 -0
  74. package/.agents/skills/test-runner/SKILL.md +3 -1
  75. package/.agents/skills/tmux-layout/SKILL.md +3 -1
  76. package/.agents/skills/using-orchestrator/SKILL.md +3 -1
  77. package/.agents/skills/ux-grill/SKILL.md +5 -1
  78. package/.agents/skills/ux-grill/agents/openai.yaml +5 -0
  79. package/.agents/skills/vault-mirror/SKILL.md +3 -1
  80. package/.agents/skills/vault-sync/SKILL.md +3 -1
  81. package/.agents/skills/wave-executor/SKILL.md +3 -1
  82. package/.agents/skills/write-executable-plan/SKILL.md +3 -1
  83. package/.claude-plugin/marketplace.json +1 -1
  84. package/.claude-plugin/plugin.json +1 -1
  85. package/.codex-plugin/plugin.json +4 -4
  86. package/.codex-plugin/skills/claude-md-drift-check/SKILL.md +1 -1
  87. package/.codex-plugin/skills/convergence-monitoring/SKILL.md +1 -3
  88. package/.codex-plugin/skills/eval/SKILL.md +1 -1
  89. package/.codex-plugin/skills/evolve/SKILL.md +1 -1
  90. package/.codex-plugin/skills/navigator/SKILL.md +22 -0
  91. package/.codex-plugin/skills/{convergence-monitoring → navigator}/agents/openai.yaml +2 -2
  92. package/.codex-plugin/skills/npm-publish/SKILL.md +1 -3
  93. package/.codex-plugin/skills/session/SKILL.md +1 -1
  94. package/.codex-plugin/skills/test-audit/SKILL.md +21 -0
  95. package/.codex-plugin/skills/{npm-publish → test-audit}/agents/openai.yaml +1 -1
  96. package/.cursor/commands/eval.md +1 -1
  97. package/.cursor/commands/navigator.md +15 -0
  98. package/.cursor/commands/session.md +1 -1
  99. package/.cursor/commands/test-audit.md +14 -0
  100. package/.cursor/rules/000-session-orchestrator.mdc +0 -2
  101. package/.cursor/rules/050-plan.mdc +1 -1
  102. package/.cursor/rules/060-evolve.mdc +27 -12
  103. package/.cursor/skills/claude-md-drift-check/SKILL.md +1 -1
  104. package/.cursor/skills/convergence-monitoring/SKILL.md +1 -0
  105. package/.cursor/skills/eval/SKILL.md +1 -1
  106. package/.cursor/skills/navigator/SKILL.md +13 -0
  107. package/.cursor/skills/npm-publish/SKILL.md +1 -0
  108. package/.cursor/skills/test-audit/SKILL.md +12 -0
  109. package/.cursor-plugin/plugin.json +1 -1
  110. package/.orchestrator/policy/blocked-commands.json +12 -3
  111. package/AGENTS.md +9 -30
  112. package/CHANGELOG.md +206 -0
  113. package/README.md +13 -9
  114. package/SECURITY.md +12 -0
  115. package/agents/dialectic-deriver.md +13 -10
  116. package/agents/eval-judge.md +67 -45
  117. package/agents/skill-applied-judge.md +34 -19
  118. package/commands/session.md +7 -3
  119. package/docs/agent-authoring.md +2 -2
  120. package/docs/baseline.md +22 -7
  121. package/docs/ci-setup.md +57 -4
  122. package/docs/codex-setup.md +14 -2
  123. package/docs/components.md +12 -10
  124. package/docs/events-schema.md +65 -15
  125. package/docs/persona-panel.md +5 -4
  126. package/docs/rule-authoring.md +84 -17
  127. package/docs/scope-collision-guard.md +26 -4
  128. package/docs/session-config-reference.md +154 -12
  129. package/docs/session-config-template.md +41 -3
  130. package/docs/telemetry.md +2 -0
  131. package/hooks/_lib/hook-import-set.json +87 -6
  132. package/hooks/_lib/subagent-transcript.mjs +582 -31
  133. package/hooks/config-protection.mjs +11 -3
  134. package/hooks/cwd-change-restore.mjs +11 -3
  135. package/hooks/enforce-commands.mjs +70 -23
  136. package/hooks/enforce-scope.mjs +143 -33
  137. package/hooks/hooks-codex.json +1 -1
  138. package/hooks/hooks-cursor.json +5 -0
  139. package/hooks/hooks-pi.json +5 -0
  140. package/hooks/hooks.json +6 -1
  141. package/hooks/loop-guard.mjs +11 -3
  142. package/hooks/on-session-end.mjs +58 -23
  143. package/hooks/on-session-start.mjs +101 -11
  144. package/hooks/on-stop.mjs +170 -22
  145. package/hooks/operator-steer.mjs +11 -3
  146. package/hooks/post-bash-issue-budget-refund.mjs +18 -8
  147. package/hooks/post-bash-write-verify.mjs +3 -2
  148. package/hooks/post-edit-import-probe.mjs +17 -9
  149. package/hooks/post-edit-validate.mjs +13 -5
  150. package/hooks/post-subagent-discovery-validator.mjs +98 -13
  151. package/hooks/post-tool-batch-wave-signal.mjs +202 -38
  152. package/hooks/post-tool-failure-corrective-context.mjs +11 -5
  153. package/hooks/post-tooluse-frontend-slop.mjs +10 -4
  154. package/hooks/pre-auq-clarity.mjs +15 -2
  155. package/hooks/pre-bash-destructive-guard.mjs +80 -9
  156. package/hooks/pre-bash-issue-budget.mjs +16 -11
  157. package/hooks/pre-bash-memory-propose-audit.mjs +137 -56
  158. package/hooks/pre-bash-sessions-ledger-guard.mjs +419 -22
  159. package/hooks/pre-bash-staging-fence.mjs +335 -31
  160. package/hooks/pre-bash-templates-first.mjs +19 -14
  161. package/hooks/pre-edit-sessions-ledger-guard.mjs +162 -0
  162. package/hooks/pre-task-scope-disjoint.mjs +792 -74
  163. package/hooks/subagent-telemetry.mjs +111 -38
  164. package/hooks/wave-scope-commit-guard.mjs +197 -100
  165. package/monitors/monitors.json +1 -1
  166. package/output-styles/wave-summary.md +1 -1
  167. package/package.json +3 -3
  168. package/pi/prompts/eval.md +1 -1
  169. package/pi/prompts/navigator.md +12 -0
  170. package/pi/prompts/session.md +1 -1
  171. package/pi/prompts/test-audit.md +12 -0
  172. package/rules/README.md +7 -2
  173. package/rules/_index.md +3 -3
  174. package/rules/always-on/bash-harness-pitfalls.md +7 -1
  175. package/rules/opt-in-domain/prompt-caching.md +6 -2
  176. package/rules/opt-in-stack/backend-data.md +10 -2
  177. package/rules/opt-in-stack/backend.md +10 -4
  178. package/rules/opt-in-stack/frontend.md +7 -2
  179. package/rules/opt-in-stack/security-web.md +10 -4
  180. package/rules/opt-in-stack/swift.md +6 -2
  181. package/scripts/apply-session-learnings.mjs +492 -0
  182. package/scripts/archive-closed-prds.mjs +2 -1
  183. package/scripts/autopilot.mjs +70 -53
  184. package/scripts/backfill-abandoned-sessions.mjs +118 -16
  185. package/scripts/baseline-archetypes.mjs +1 -1
  186. package/scripts/check-package-manager.mjs +62 -5
  187. package/scripts/check-sessions-integrity.mjs +300 -0
  188. package/scripts/cursor-install.mjs +1 -4
  189. package/scripts/dialectic-deriver.mjs +50 -13
  190. package/scripts/emit-session.mjs +371 -31
  191. package/scripts/eval-session.mjs +65 -3
  192. package/scripts/export-hw-learnings.mjs +22 -3
  193. package/scripts/fleet-checkin.mjs +147 -0
  194. package/scripts/generate-agents-skills.mjs +102 -29
  195. package/scripts/generate-cursor-adapter.mjs +61 -16
  196. package/scripts/lib/agent-frontmatter.mjs +3 -3
  197. package/scripts/lib/agent-status.mjs +2 -31
  198. package/scripts/lib/auq/clarity.mjs +10 -2
  199. package/scripts/lib/auq/parse.mjs +12 -31
  200. package/scripts/lib/auq/schema.mjs +56 -41
  201. package/scripts/lib/auto-dialectic.mjs +304 -15
  202. package/scripts/lib/auto-dream.mjs +7 -6
  203. package/scripts/lib/autopilot/flags.mjs +18 -2
  204. package/scripts/lib/autopilot/kill-switches.mjs +6 -3
  205. package/scripts/lib/autopilot/loop.mjs +19 -2
  206. package/scripts/lib/autopilot/stall-sampler.mjs +80 -23
  207. package/scripts/lib/baseline-archetypes.mjs +41 -22
  208. package/scripts/lib/ci-status-banner.mjs +376 -16
  209. package/scripts/lib/command-blocker.mjs +275 -28
  210. package/scripts/lib/config/dialectic.mjs +12 -3
  211. package/scripts/lib/config/gate.mjs +74 -0
  212. package/scripts/lib/config/host-paths.mjs +79 -0
  213. package/scripts/lib/config/persona-gate-wave.mjs +3 -3
  214. package/scripts/lib/config/reaper.mjs +163 -0
  215. package/scripts/lib/config-schema.mjs +13 -0
  216. package/scripts/lib/config.mjs +85 -10
  217. package/scripts/lib/convergence-monitor.mjs +74 -11
  218. package/scripts/lib/ecosystem-health.mjs +11 -0
  219. package/scripts/lib/eval/engine.mjs +421 -53
  220. package/scripts/lib/eval/judge.mjs +463 -40
  221. package/scripts/lib/eval/schema.mjs +10 -1
  222. package/scripts/lib/events-rotation.mjs +221 -25
  223. package/scripts/lib/events-schema.mjs +114 -0
  224. package/scripts/lib/events.mjs +545 -7
  225. package/scripts/lib/fleet-protocol.mjs +270 -0
  226. package/scripts/lib/frontmatter-guard.mjs +21 -10
  227. package/scripts/lib/gates/gate-baseline.mjs +40 -5
  228. package/scripts/lib/gates/gate-full.mjs +35 -5
  229. package/scripts/lib/gates/gate-helpers.mjs +336 -23
  230. package/scripts/lib/gates/gate-incremental.mjs +49 -23
  231. package/scripts/lib/gates/gate-per-file.mjs +42 -8
  232. package/scripts/lib/gitlab-portfolio/markdown-writer.mjs +6 -1
  233. package/scripts/lib/instruction-budget-guard.mjs +208 -8
  234. package/scripts/lib/io.mjs +42 -8
  235. package/scripts/lib/issue-close-strip-labels.mjs +207 -49
  236. package/scripts/lib/js-mask.mjs +197 -0
  237. package/scripts/lib/learnings/evolve-telemetry.mjs +11 -7
  238. package/scripts/lib/learnings/expiry-sweep.mjs +34 -3
  239. package/scripts/lib/learnings/io.mjs +154 -26
  240. package/scripts/lib/learnings/schema.mjs +163 -15
  241. package/scripts/lib/learnings/sizing-subject.mjs +2 -2
  242. package/scripts/lib/maintenance-due-banner.mjs +53 -88
  243. package/scripts/lib/memory-proposals/schema.mjs +11 -5
  244. package/scripts/lib/named-baseline-resolver.mjs +53 -28
  245. package/scripts/lib/named-vault-resolver.mjs +104 -5
  246. package/scripts/lib/orphan-reaper/defaults.mjs +41 -0
  247. package/scripts/lib/orphan-reaper/ps-snapshot.mjs +181 -0
  248. package/scripts/lib/orphan-reaper/reaper-audit.mjs +291 -0
  249. package/scripts/lib/orphan-reaper/reaper-decide.mjs +395 -0
  250. package/scripts/lib/orphan-reaper/scan-throttle.mjs +92 -0
  251. package/scripts/lib/orphan-reaper/scan.mjs +506 -0
  252. package/scripts/lib/orphan-reaper.mjs +316 -0
  253. package/scripts/lib/owner-yaml.mjs +104 -6
  254. package/scripts/lib/peer-cards/merger.mjs +48 -10
  255. package/scripts/lib/peer-cards/reader.mjs +78 -2
  256. package/scripts/lib/persona-panel/catalog-loader.mjs +1 -1
  257. package/scripts/lib/process-group.mjs +950 -0
  258. package/scripts/lib/project-hygiene.mjs +21 -1
  259. package/scripts/lib/quality-gate.mjs +152 -33
  260. package/scripts/lib/reconcile/backlog.mjs +368 -0
  261. package/scripts/lib/reconcile/engine.mjs +55 -188
  262. package/scripts/lib/reconcile/rule-expiry-sweep.mjs +302 -60
  263. package/scripts/lib/reconcile/sanitize.mjs +69 -3
  264. package/scripts/lib/reconcile-nudge-banner.mjs +138 -45
  265. package/scripts/lib/resource-probe/parsers.mjs +31 -0
  266. package/scripts/lib/resource-probe.mjs +1 -1
  267. package/scripts/lib/rule-loader.mjs +141 -74
  268. package/scripts/lib/rules-sync.mjs +27 -12
  269. package/scripts/lib/scope-baseline.mjs +3 -4
  270. package/scripts/lib/scope-echo.mjs +39 -2
  271. package/scripts/lib/scope-gate.mjs +605 -1
  272. package/scripts/lib/session-close-backfill.mjs +33 -6
  273. package/scripts/lib/session-id.mjs +9 -20
  274. package/scripts/lib/session-invocation.mjs +20 -0
  275. package/scripts/lib/session-record-repair.mjs +183 -26
  276. package/scripts/lib/session-registry.mjs +27 -2
  277. package/scripts/lib/session-schema/constants.mjs +56 -2
  278. package/scripts/lib/session-schema/normalizer.mjs +56 -4
  279. package/scripts/lib/session-schema/validator.mjs +28 -1
  280. package/scripts/lib/session-schema.mjs +8 -3
  281. package/scripts/lib/session-start-probes.mjs +95 -10
  282. package/scripts/lib/session-token-rollup.mjs +245 -52
  283. package/scripts/lib/sessions-canonical.mjs +118 -4
  284. package/scripts/lib/sessions-integrity-banner.mjs +7 -1
  285. package/scripts/lib/sessions-staleness-banner.mjs +193 -51
  286. package/scripts/lib/sh-quote.mjs +29 -0
  287. package/scripts/lib/skill-evidence-window.mjs +891 -0
  288. package/scripts/lib/skill-evolution/candidate-intake.mjs +133 -12
  289. package/scripts/lib/skill-evolution/engine.mjs +18 -9
  290. package/scripts/lib/skill-judge.mjs +45 -3
  291. package/scripts/lib/subagents-schema.mjs +30 -3
  292. package/scripts/lib/tail-window.mjs +56 -0
  293. package/scripts/lib/telemetry/pricing.mjs +118 -71
  294. package/scripts/lib/telemetry/schema.mjs +30 -0
  295. package/scripts/lib/telemetry/sync.mjs +61 -6
  296. package/scripts/lib/telemetry-flush-health-banner.mjs +4 -22
  297. package/scripts/lib/test-runner/issue-reconcile.mjs +48 -16
  298. package/scripts/lib/tests-src-ratio.mjs +140 -23
  299. package/scripts/lib/tmux-layout/layouts.mjs +1 -11
  300. package/scripts/lib/tmux-layout/telemetry-stats.mjs +72 -13
  301. package/scripts/lib/tmux-layout/tmux-shell.mjs +2 -11
  302. package/scripts/lib/user-invocable-skills.mjs +23 -3
  303. package/scripts/lib/ux-grill/reconcile.mjs +48 -22
  304. package/scripts/lib/validate/check-agents-skills.mjs +26 -15
  305. package/scripts/lib/validate/check-agents.mjs +1 -1
  306. package/scripts/lib/validate/check-cursor-adapter.mjs +1 -0
  307. package/scripts/lib/validate/check-entry-guard.mjs +13 -50
  308. package/scripts/lib/validate/check-hook-entry-guards.mjs +636 -0
  309. package/scripts/lib/validate/check-hooks-symmetry.mjs +5 -0
  310. package/scripts/lib/validate/check-learnings-shell-writes.mjs +214 -0
  311. package/scripts/lib/validate/check-pi-prompts.mjs +1 -0
  312. package/scripts/lib/validate/check-rules.mjs +7 -5
  313. package/scripts/lib/validate/check-skill-links.mjs +9 -1
  314. package/scripts/lib/validate/check-skill-script-paths.mjs +239 -27
  315. package/scripts/lib/validate/check-test-git-config-target.mjs +24 -34
  316. package/scripts/lib/validate/check-test-value-bans.mjs +87 -14
  317. package/scripts/lib/validate/check-unicode-safety.mjs +1 -0
  318. package/scripts/lib/validate/check-untracked-test-deps.mjs +7 -102
  319. package/scripts/lib/validate/check-unwired-features.mjs +130 -27
  320. package/scripts/lib/validate/check-validator-registration.mjs +34 -10
  321. package/scripts/lib/validate/confidential-names.mjs +10 -0
  322. package/scripts/lib/validate-vendored-rules.mjs +210 -84
  323. package/scripts/lib/vault-mirror/namespace.mjs +46 -8
  324. package/scripts/lib/vault-mirror/process.mjs +10 -3
  325. package/scripts/lib/vault-mirror/render-sessions.mjs +12 -2
  326. package/scripts/lib/vault-mirror/telemetry.mjs +8 -1
  327. package/scripts/lib/vault-status/board-writer.mjs +48 -11
  328. package/scripts/lib/vault-status/narrative-mirror.mjs +71 -16
  329. package/scripts/lib/vault-yaml.mjs +118 -0
  330. package/scripts/lib/wave-executor/dispatch-common.mjs +10 -18
  331. package/scripts/lib/wave-executor/foreign-dispatch.mjs +1 -1
  332. package/scripts/lib/wave-executor/remote-dispatch.mjs +1 -1
  333. package/scripts/lib/wave-resource-gate.mjs +34 -8
  334. package/scripts/lib/worktree/lifecycle.mjs +153 -1
  335. package/scripts/memory-propose.mjs +18 -5
  336. package/scripts/release-session-lock.mjs +306 -0
  337. package/scripts/release.mjs +40 -8
  338. package/scripts/repair-invalid-sessions.mjs +37 -4
  339. package/scripts/resolve-session-invocation.mjs +59 -0
  340. package/scripts/run-migrate-v2-cross-repo.mjs +158 -30
  341. package/scripts/run-quality-gate.mjs +357 -197
  342. package/scripts/site-numbers.mjs +163 -5
  343. package/scripts/sweep-expired-learnings.mjs +56 -5
  344. package/scripts/sweep-expired-rules.mjs +16 -4
  345. package/scripts/validate-plugin.mjs +19 -0
  346. package/scripts/validate-wave-scope.mjs +32 -105
  347. package/scripts/vault-integration-watcher.mjs +2 -1
  348. package/scripts/vault-mirror.mjs +81 -47
  349. package/scripts/wave-scope-binding.mjs +2 -1
  350. package/skills/_shared/config-reading.md +3 -3
  351. package/skills/_shared/fleet-protocol.md +131 -0
  352. package/skills/_shared/platform-tools.md +23 -11
  353. package/skills/_shared/state-ownership.md +5 -0
  354. package/skills/autopilot/SKILL.md +47 -18
  355. package/skills/bootstrap/SKILL.md +1 -1
  356. package/skills/bootstrap/_shared-template.md +1 -1
  357. package/skills/bootstrap/fast-template.md +1 -1
  358. package/skills/bootstrap/private-contract.md +2 -1
  359. package/skills/bootstrap/public-fallback.md +6 -3
  360. package/skills/bootstrap/references/bootstrap-retroactive-flow.md +2 -1
  361. package/skills/claude-md-drift-check/SKILL.md +10 -10
  362. package/skills/claude-md-drift-check/checker.mjs +26 -18
  363. package/skills/convergence-monitoring/README.md +8 -1
  364. package/skills/convergence-monitoring/SIGNALS.md +50 -6
  365. package/skills/convergence-monitoring/SKILL.md +15 -6
  366. package/skills/eval/SKILL.md +39 -24
  367. package/skills/eval/rubric-v1.md +1 -0
  368. package/skills/eval/rubric-v2.md +457 -0
  369. package/skills/evolve/SKILL.md +3 -3
  370. package/skills/evolve/references/evolve-analyze-mode.md +10 -6
  371. package/skills/evolve/references/evolve-dialectic-mode.md +42 -25
  372. package/skills/gitlab-ops/SKILL.md +3 -2
  373. package/skills/memory-cleanup/SKILL.md +1 -1
  374. package/skills/navigator/SKILL.md +193 -0
  375. package/skills/navigator/references/account-check.sh +87 -0
  376. package/skills/navigator/references/fleet-decisions.mjs +231 -0
  377. package/skills/navigator/references/slot-check.sh +114 -0
  378. package/skills/npm-publish/SKILL.md +1 -1
  379. package/skills/persona-panel/SKILL.md +2 -2
  380. package/skills/persona-panel/persona-format.md +2 -2
  381. package/skills/persona-panel/presets/designer-lens.md +1 -1
  382. package/skills/persona-panel/presets/engineer-lens.md +1 -1
  383. package/skills/persona-panel/presets/pm-lens.md +1 -1
  384. package/skills/plan/mode-retro.md +19 -4
  385. package/skills/quality-gates/SKILL.md +6 -4
  386. package/skills/reconcile/SKILL.md +11 -0
  387. package/skills/remote-offload/SKILL.md +4 -2
  388. package/skills/session-end/SKILL.md +13 -16
  389. package/skills/session-end/discovery-scan.md +1 -1
  390. package/skills/session-end/learning-patterns.md +22 -12
  391. package/skills/session-end/metrics-collection.md +5 -6
  392. package/skills/session-end/phase-3-6-tail.md +55 -9
  393. package/skills/session-end/references/phase-3-documentation-updates.md +2 -2
  394. package/skills/session-end/references/phase-4a-worktree-cleanup.md +2 -0
  395. package/skills/session-end/references/phase-5-issue-cleanup.md +9 -14
  396. package/skills/session-end/references/session-summary-template.md +1 -1
  397. package/skills/session-end/session-metrics-write.md +32 -60
  398. package/skills/session-plan/SKILL.md +17 -8
  399. package/skills/session-plan/references/session-plan-task-classification.md +2 -2
  400. package/skills/session-start/SKILL.md +6 -0
  401. package/skills/session-start/references/operations-contract.md +4 -0
  402. package/skills/session-start/references/phase-1-7-vault-status-board.md +1 -1
  403. package/skills/session-start/references/phase-4-ssot-environment-check.md +4 -3
  404. package/skills/test-audit/SKILL.md +152 -0
  405. package/skills/test-audit/references/campaign.md +111 -0
  406. package/skills/test-audit/references/mutate.sh +50 -0
  407. package/skills/ux-grill/SKILL.md +1 -1
  408. package/skills/wave-executor/SKILL.md +9 -5
  409. package/skills/wave-executor/circuit-breaker.md +2 -0
  410. package/skills/wave-executor/references/wave-executor-state-init.md +8 -3
  411. package/skills/wave-executor/references/wave-loop-dispatch.md +5 -2
  412. package/skills/wave-executor/references/wave-loop-review.md +3 -5
  413. package/templates/personas/README.md +5 -5
  414. package/templates/personas/accounting-compliance.v1.md +1 -1
  415. package/templates/personas/accounting-tax-advisor.v1.md +1 -1
  416. package/templates/personas/buyer-p1-cto.v1.md +1 -1
  417. package/templates/personas/buyer-p2-kanzlei.v1.md +1 -1
  418. package/templates/personas/buyer-p3-build.v1.md +1 -1
  419. package/templates/personas/buyer-p4-tech-veto.v1.md +1 -1
  420. package/templates/personas/buyer-p5-solo.v1.md +1 -1
  421. package/templates/personas/buyer-p6-ld.v1.md +1 -1
  422. package/templates/personas/klima-ai-expert.v1.md +1 -1
  423. package/templates/personas/klima-physicist.v1.md +1 -1
  424. package/.cursor/commands/convergence-monitoring.md +0 -13
  425. package/.cursor/commands/npm-publish.md +0 -13
  426. package/pi/prompts/convergence-monitoring.md +0 -11
  427. package/pi/prompts/npm-publish.md +0 -11
@@ -0,0 +1,231 @@
1
+ /**
2
+ * skills/navigator/references/fleet-decisions.mjs
3
+ *
4
+ * Pure decision functions for the navigator's headless fleet: whether a new
5
+ * headless run may start on this host (slot gate), whether a target repo is
6
+ * already occupied by another session (busy gate), and which account the host
7
+ * should run on (account watch).
8
+ *
9
+ * Measurement lives elsewhere — `slot-check.sh` and `account-check.sh` in this
10
+ * directory collect the raw numbers and pipe them in here. This module reads
11
+ * no environment variables, no files and no clock except the `now` argument,
12
+ * so every rule below is testable with plain values.
13
+ *
14
+ * Shared principle: a value that could not be measured is never read as
15
+ * "free". Every gate fails closed on missing, NaN or non-number input; only
16
+ * an explicit `override: true` (an owner decision) bypasses a gate.
17
+ *
18
+ * Slot gate thresholds (free memory % from the OS pressure verdict):
19
+ * free >= 50 → cap 4
20
+ * free >= 35 → cap 3
21
+ * otherwise → cap 0
22
+ * load1 > 40 → cap 0 regardless of memory
23
+ * allowed = runs < cap
24
+ *
25
+ * Busy gate: busy when any Codex rollout for the repo is younger than 30 min
26
+ * or any `session.lock` is younger than 6 h (counts measured by the caller).
27
+ *
28
+ * Account watch: usable = 5-hour and 7-day usage both below 97 %. Among usable
29
+ * rows the earliest 7-day reset within 3 days wins (tie-break lower 7-day
30
+ * usage); if none is that near, the lowest 7-day usage wins. The active row is
31
+ * kept when its reset lies within 1800 s of the target's, either side (same
32
+ * reset, no flapping). A reset date in the past is stale data and the row is
33
+ * skipped. Rows are identified by `slot` only — the alias never reaches the
34
+ * output (SEC-008).
35
+ *
36
+ * CLI: `node fleet-decisions.mjs slot|busy|account` reads one JSON document
37
+ * from stdin and prints the decision as one JSON line.
38
+ * exit 0 — allowed / not busy / stay or switch
39
+ * exit 1 — refused / busy / no usable account
40
+ * exit 2 — unparseable input or unknown subcommand
41
+ */
42
+
43
+ import { readFileSync } from 'node:fs';
44
+ import { fileURLToPath } from 'node:url';
45
+
46
+ // ---------------------------------------------------------------------------
47
+ // Constants
48
+ // ---------------------------------------------------------------------------
49
+
50
+ const FREE_PCT_CAP4 = 50;
51
+ const FREE_PCT_CAP3 = 35;
52
+ const LOAD1_MAX = 40;
53
+ const USAGE_LIMIT_PCT = 97;
54
+ const NEAR_RESET_MS = 3 * 24 * 60 * 60 * 1000;
55
+ const RESET_TIE_MS = 1800 * 1000;
56
+
57
+ /** @param {unknown} v @returns {v is number} */
58
+ function isNum(v) {
59
+ return typeof v === 'number' && Number.isFinite(v);
60
+ }
61
+
62
+ // ---------------------------------------------------------------------------
63
+ // Slot gate
64
+ // ---------------------------------------------------------------------------
65
+
66
+ /**
67
+ * Decide whether one more headless run may start on this host.
68
+ *
69
+ * @param {{ freePct?: unknown, load1?: unknown, runs?: unknown, override?: unknown }} input
70
+ * @returns {{ allowed: boolean, cap: number, reason: string }}
71
+ */
72
+ export function slotDecision({ freePct, load1, runs, override } = {}) {
73
+ const memOk = isNum(freePct);
74
+ const loadOk = isNum(load1);
75
+ let cap = 0;
76
+ if (memOk && loadOk) {
77
+ if (freePct >= FREE_PCT_CAP4) cap = 4;
78
+ else if (freePct >= FREE_PCT_CAP3) cap = 3;
79
+ if (load1 > LOAD1_MAX) cap = 0;
80
+ }
81
+ if (override === true) return { allowed: true, cap, reason: 'override' };
82
+
83
+ const ctx = `(free ${memOk ? `${freePct}%` : '?'}, load1 ${loadOk ? load1 : '?'})`;
84
+ if (!memOk) return { allowed: false, cap: 0, reason: `no slot: free memory not measurable ${ctx}` };
85
+ if (!loadOk) return { allowed: false, cap: 0, reason: `no slot: load1 not measurable ${ctx}` };
86
+ if (!isNum(runs) || !Number.isInteger(runs) || runs < 0) {
87
+ return { allowed: false, cap, reason: `no slot: run count not measurable ${ctx}` };
88
+ }
89
+ const allowed = runs < cap;
90
+ return { allowed, cap, reason: `${allowed ? 'slot free' : 'no slot'}: ${runs} runs, cap ${cap} ${ctx}` };
91
+ }
92
+
93
+ // ---------------------------------------------------------------------------
94
+ // Busy gate
95
+ // ---------------------------------------------------------------------------
96
+
97
+ /**
98
+ * Decide whether a repo is occupied by another session.
99
+ *
100
+ * @param {{ codexRolloutsFresh?: unknown, lockFresh?: unknown, override?: unknown }} input
101
+ * @returns {{ busy: boolean, reason: string }}
102
+ */
103
+ export function busyDecision({ codexRolloutsFresh, lockFresh, override } = {}) {
104
+ if (override === true) return { busy: false, reason: 'override' };
105
+ const valid = (v) => isNum(v) && v >= 0;
106
+ if (!valid(codexRolloutsFresh) || !valid(lockFresh)) {
107
+ return { busy: true, reason: 'busy: occupancy not measurable (codex rollouts or session.lock count missing)' };
108
+ }
109
+ const counts = `${codexRolloutsFresh} codex rollouts (30 min), ${lockFresh} session.lock (6 h)`;
110
+ if (codexRolloutsFresh > 0 || lockFresh > 0) return { busy: true, reason: `busy: ${counts}` };
111
+ return { busy: false, reason: `free: ${counts}` };
112
+ }
113
+
114
+ // ---------------------------------------------------------------------------
115
+ // Account watch
116
+ // ---------------------------------------------------------------------------
117
+
118
+ /**
119
+ * Reduce one raw account row to the fields the decision needs, or null when it
120
+ * is not measurable. Copies nothing else — in particular not the alias. Never
121
+ * throws: a hostile row (throwing getter, proxy) counts as not measurable.
122
+ *
123
+ * @param {unknown} r
124
+ * @param {number} nowMs
125
+ * @returns {{ id: string|number, active: boolean, p7: number, p5: number, resetMs: number } | null}
126
+ */
127
+ function parseAccountRow(r, nowMs) {
128
+ try {
129
+ if (!r || typeof r !== 'object') return null;
130
+ const { slot, active, p7, p5, resetAt } = /** @type {Record<string, unknown>} */ (r);
131
+ const slotOk = (typeof slot === 'string' && slot !== '') || isNum(slot);
132
+ const resetMs = typeof resetAt === 'string' ? Date.parse(resetAt) : NaN;
133
+ if (!slotOk || !isNum(p7) || !isNum(p5) || !Number.isFinite(resetMs) || resetMs < nowMs) return null;
134
+ return { id: /** @type {string|number} */ (slot), active: active === true, p7, p5, resetMs };
135
+ } catch {
136
+ return null;
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Pick the account the host should run on. Never throws; malformed rows
142
+ * (non-string/non-number slot, missing usage, unparseable or past reset) are
143
+ * skipped and counted in the reason. The output carries the slot only, never
144
+ * the alias (SEC-008).
145
+ *
146
+ * @param {Array<{ slot: unknown, alias?: string, active: boolean, p7: number|null, p5: number|null, resetAt: string|null }>} rows
147
+ * @param {Date|number} now
148
+ * @returns {{ action: 'stay'|'switch'|'none', target: string|number|null, reason: string }}
149
+ */
150
+ export function chooseAccount(rows, now) {
151
+ const nowMs = now instanceof Date ? now.getTime() : Number(now);
152
+ if (!Number.isFinite(nowMs)) return { action: 'none', target: null, reason: 'no decision: now is not a valid time' };
153
+ const list = Array.isArray(rows) ? rows : [];
154
+
155
+ let skipped = 0;
156
+ const parsed = [];
157
+ for (const r of list) {
158
+ const row = parseAccountRow(r, nowMs);
159
+ if (row === null) skipped += 1;
160
+ else parsed.push(row);
161
+ }
162
+ const skipNote = skipped > 0 ? `; ${skipped} row(s) skipped without data` : '';
163
+
164
+ const usable = parsed.filter((r) => r.p5 < USAGE_LIMIT_PCT && r.p7 < USAGE_LIMIT_PCT);
165
+ const active = parsed.find((r) => r.active === true) ?? null;
166
+ const activeUsable = active !== null && usable.includes(active);
167
+
168
+ if (usable.length === 0) {
169
+ return { action: 'none', target: null, reason: `no usable account (all >= ${USAGE_LIMIT_PCT}% or without data)${skipNote}` };
170
+ }
171
+
172
+ const near = usable.filter((r) => r.resetMs - nowMs <= NEAR_RESET_MS);
173
+ let target;
174
+ if (near.length > 0) {
175
+ target = near.reduce((a, b) => (b.resetMs < a.resetMs || (b.resetMs === a.resetMs && b.p7 < a.p7) ? b : a));
176
+ } else {
177
+ target = usable.reduce((a, b) => (b.p7 < a.p7 ? b : a));
178
+ }
179
+
180
+ if (activeUsable && active !== target && Math.abs(active.resetMs - target.resetMs) <= RESET_TIE_MS) {
181
+ target = active;
182
+ }
183
+
184
+ const desc = (r) => `${r.id} (7d ${r.p7}%, reset in ${((r.resetMs - nowMs) / 86400000).toFixed(1)} d)`;
185
+ if (active === target) return { action: 'stay', target: target.id, reason: `stay on ${desc(target)}${skipNote}` };
186
+ return {
187
+ action: 'switch',
188
+ target: target.id,
189
+ reason: `switch ${active ? active.id : '-'} -> ${desc(target)}${skipNote}`,
190
+ };
191
+ }
192
+
193
+ // ---------------------------------------------------------------------------
194
+ // CLI
195
+ // ---------------------------------------------------------------------------
196
+
197
+ function runCli(argv) {
198
+ const mode = argv[2];
199
+ if (mode !== 'slot' && mode !== 'busy' && mode !== 'account') {
200
+ process.stderr.write('usage: node fleet-decisions.mjs slot|busy|account < input.json\n');
201
+ return 2;
202
+ }
203
+ let input;
204
+ try {
205
+ input = JSON.parse(readFileSync(0, 'utf8'));
206
+ } catch {
207
+ process.stderr.write('fleet-decisions: stdin is not valid JSON\n');
208
+ return 2;
209
+ }
210
+ if (mode === 'slot' || mode === 'busy') {
211
+ if (!input || typeof input !== 'object' || Array.isArray(input)) {
212
+ process.stderr.write(`fleet-decisions: ${mode} expects one JSON object\n`);
213
+ return 2;
214
+ }
215
+ const d = mode === 'slot' ? slotDecision(input) : busyDecision(input);
216
+ process.stdout.write(`${JSON.stringify(d)}\n`);
217
+ return mode === 'slot' ? (d.allowed ? 0 : 1) : d.busy ? 1 : 0;
218
+ }
219
+ const rows = Array.isArray(input) ? input : input && Array.isArray(input.accounts) ? input.accounts : null;
220
+ if (!rows) {
221
+ process.stderr.write('fleet-decisions: account expects a JSON array or {"accounts": [...]}\n');
222
+ return 2;
223
+ }
224
+ const d = chooseAccount(rows, Date.now());
225
+ process.stdout.write(`${JSON.stringify(d)}\n`);
226
+ return d.action === 'none' ? 1 : 0;
227
+ }
228
+
229
+ if (process.argv[1] === fileURLToPath(import.meta.url)) {
230
+ process.exitCode = runCli(process.argv);
231
+ }
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env bash
2
+ # slot-check.sh — measure the slot gate and the busy gate for one repo, decide via fleet-decisions.mjs.
3
+ #
4
+ # Usage: slot-check.sh <repo-path>
5
+ #
6
+ # Measures only; every rule lives in fleet-decisions.mjs next to this file.
7
+ # slot gate: free memory % (memory_pressure), 1-min load (vm.loadavg, integer),
8
+ # running headless runs (`timeout -k 60 <n>[smhd] claude -p` + `... codex exec`);
9
+ # anchored on the timeout wrapper because one Codex run spawns three processes matching `codex exec`
10
+ # busy gate: Codex rollouts for <repo-path> younger than 30 min, <repo-path>/.orchestrator/session.lock
11
+ # younger than 6 h
12
+ # A value that cannot be measured is passed as null; the decision module fails closed on it.
13
+ #
14
+ # Env:
15
+ # NAVIGATOR_CODEX_HOME Codex home directory (default: $HOME/.codex; empty/whitespace = unset)
16
+ # FLEET_SLOT_OVERRIDE=1 owner override for the slot gate
17
+ # FLEET_BUSY_OVERRIDE=1 owner override for the busy gate
18
+ #
19
+ # Exit: 0 both gates pass, 1 at least one gate refuses, 2 usage error.
20
+ set -u
21
+
22
+ if [ "$#" -ne 1 ] || [ -z "$1" ]; then
23
+ echo "usage: slot-check.sh <repo-path>" >&2
24
+ exit 2
25
+ fi
26
+ repo=${1%/}
27
+ here=$(cd "$(dirname "$0")" && pwd)
28
+ decide="$here/fleet-decisions.mjs"
29
+
30
+ # Trim leading/trailing whitespace; a whitespace-only value counts as unset.
31
+ trim() {
32
+ local v=$1
33
+ v=${v#"${v%%[![:space:]]*}"}
34
+ v=${v%"${v##*[![:space:]]}"}
35
+ printf '%s' "$v"
36
+ }
37
+ codex_home=$(trim "${NAVIGATOR_CODEX_HOME:-}")
38
+ [ -n "$codex_home" ] || codex_home=$HOME/.codex
39
+
40
+ # Rollouts record the cwd as the session saw it; match both the logical and the physical path.
41
+ repo_abs=$(cd "$repo" 2>/dev/null && pwd)
42
+ repo_phys=$(cd "$repo" 2>/dev/null && pwd -P)
43
+
44
+ # Print the argument if it is a non-negative integer, else the JSON literal null.
45
+ num_or_null() {
46
+ case "$1" in
47
+ ''|*[!0-9]*) printf 'null' ;;
48
+ *) printf '%s' "$1" ;;
49
+ esac
50
+ }
51
+
52
+ # --- slot gate measurements ---------------------------------------------------
53
+ free_pct=$(memory_pressure 2>/dev/null | awk '/free percentage/{gsub("%","",$NF); print $NF}')
54
+ load1=$(sysctl -n vm.loadavg 2>/dev/null | awk '{print int($2)}')
55
+ # Count pgrep matches: rc 0 → count, rc 1 → 0 (no match), rc >= 2 → empty (not measurable).
56
+ count_runs() {
57
+ local out rc
58
+ out=$(pgrep -f "$1")
59
+ rc=$?
60
+ case "$rc" in
61
+ 0) printf '%s' "$out" | grep -c . ;;
62
+ 1) printf '0' ;;
63
+ *) printf '' ;;
64
+ esac
65
+ }
66
+ runs=''
67
+ if command -v pgrep >/dev/null 2>&1; then
68
+ claude_runs=$(count_runs '^timeout -k 60 [0-9]+[smhd]? claude -p')
69
+ codex_runs=$(count_runs '^timeout -k 60 [0-9]+[smhd]? codex exec')
70
+ if [ -n "$claude_runs" ] && [ -n "$codex_runs" ]; then
71
+ runs=$((claude_runs + codex_runs))
72
+ fi
73
+ fi
74
+
75
+ # --- busy gate measurements ---------------------------------------------------
76
+ # Only the first line of each rollout is matched, as a fixed string; file content is never evaluated.
77
+ if [ -z "$repo_abs" ] || [ -z "$repo_phys" ]; then
78
+ # Repo path not resolvable: both busy counts are unknown, the decision fails closed.
79
+ codex_fresh=''
80
+ lock_fresh=''
81
+ else
82
+ codex_fresh=0
83
+ if [ -d "$codex_home/sessions" ]; then
84
+ codex_fresh=$(find "$codex_home/sessions" -name 'rollout-*.jsonl' -mmin -30 2>/dev/null |
85
+ while IFS= read -r f; do
86
+ head -1 "$f" 2>/dev/null |
87
+ grep -qF -e "\"cwd\":\"$repo_abs\"" -e "\"cwd\":\"$repo_phys\"" && echo x
88
+ done | wc -l | tr -d ' ')
89
+ fi
90
+ lock_fresh=$(find "$repo_abs/.orchestrator" -maxdepth 1 -name session.lock -mmin -360 2>/dev/null | wc -l | tr -d ' ')
91
+ fi
92
+
93
+ slot_override=false
94
+ [ "${FLEET_SLOT_OVERRIDE:-0}" = 1 ] && slot_override=true
95
+ busy_override=false
96
+ [ "${FLEET_BUSY_OVERRIDE:-0}" = 1 ] && busy_override=true
97
+
98
+ slot_json=$(printf '{"freePct":%s,"load1":%s,"runs":%s,"override":%s}' \
99
+ "$(num_or_null "$free_pct")" "$(num_or_null "$load1")" "$(num_or_null "$runs")" "$slot_override")
100
+ busy_json=$(printf '{"codexRolloutsFresh":%s,"lockFresh":%s,"override":%s}' \
101
+ "$(num_or_null "$codex_fresh")" "$(num_or_null "$lock_fresh")" "$busy_override")
102
+
103
+ slot_out=$(printf '%s' "$slot_json" | node "$decide" slot)
104
+ slot_rc=$?
105
+ busy_out=$(printf '%s' "$busy_json" | node "$decide" busy)
106
+ busy_rc=$?
107
+
108
+ echo "slot: $slot_out"
109
+ echo "busy: $busy_out"
110
+
111
+ if [ "$slot_rc" -ne 0 ] || [ "$busy_rc" -ne 0 ]; then
112
+ exit 1
113
+ fi
114
+ exit 0
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: npm-publish
3
- user-invocable: true
3
+ user-invocable: false
4
4
  model: sonnet
5
5
  description: Use when publishing this package to npm — a version release (npm publish), verifying the registry/pi.dev listing, or diagnosing npm auth failures (E403 2FA/token errors). Token-based flow via NPM_TOKEN in .env.local with a temp userconfig, the leakage gate before every publish, post-publish verification and marker/badge upkeep. Trigger on "publish to npm", "npm release", "E403 publish error".
6
6
  ---
@@ -184,8 +184,8 @@ Dispatch one Agent per persona from the active catalog set.
184
184
 
185
185
  **Model selection per persona:**
186
186
  - If `persona.model` is a full Claude model ID (`MODEL_ID_RE`): use it as-is.
187
- - If `persona.model` is `opus` or unset AND `persona.tier == 'domain-expert'`: override to
188
- `claude-opus-4-7` (empirically validated — Opus finds real problems Sonnet misses; see vault
187
+ - If `persona.model` is `opus` or unset AND `persona.tier == 'domain-expert'`: use the alias
188
+ `opus`, which tracks the current Opus — pin a full ID only for a named reproducibility need (empirically validated — Opus finds real problems Sonnet misses; see vault
189
189
  learning `[[persona-opus-finds-real-failing-cibadge]]`).
190
190
  - Otherwise: use the persona's declared model alias.
191
191
 
@@ -28,7 +28,7 @@ name: ai-expert
28
28
  schema_version: 1
29
29
  version: "2"
30
30
  role: "AI/ML domain expert — evaluates technical accuracy and implementation quality"
31
- model: claude-opus-4-7
31
+ model: opus
32
32
  tier: domain-expert
33
33
  output_contract:
34
34
  type: object
@@ -59,7 +59,7 @@ evaluation_criteria:
59
59
  | `schema_version` | integer | Must be `1`. |
60
60
  | `version` | string | Non-empty string. Persona content version. Increment on any output-affecting change. Used in sidecar + trend-tracking (#459). |
61
61
  | `role` | string | Identity statement. Injected verbatim as prompt opener. Keep under 200 chars. |
62
- | `model` | string | Full model ID (`MODEL_ID_RE`) or alias (`inherit|sonnet|opus|haiku`). Validated at load time. Recommend `claude-opus-4-7` for `domain-expert` and `compliance` tiers (Opus finds real issues Sonnet misses — vault learning `[[persona-opus-finds-real-failing-cibadge]]`). |
62
+ | `model` | string | Full model ID (`MODEL_ID_RE`) or alias (`inherit|sonnet|opus|haiku`). Validated at load time. Recommend the Opus tier via alias `opus` for `domain-expert` and `compliance` tiers (Opus finds real issues Sonnet misses — vault learning `[[persona-opus-finds-real-failing-cibadge]]`); the alias tracks the current Opus; pin a full model ID only for a named reproducibility need, and name the reason. |
63
63
  | `output_contract` | object | Inline JSON Schema Draft 2020-12. `$ref/$defs/allOf/anyOf` FORBIDDEN (H3). Must require `verdict` + `rationale`. AJV compile wrapped in 2s AbortSignal timeout. |
64
64
  | `evaluation_criteria` | array | Non-empty. Each string max 512 chars. Injected wrapped in `<persona-criteria>` delimiters (M1). Write as statements, not questions. |
65
65
  | `tier` | enum | `domain-expert` \| `buyer-persona` \| `auditor` \| `compliance` \| `reviewer` \| `custom`. Affects model selection (Phase 3). |
@@ -3,7 +3,7 @@ name: designer-lens
3
3
  schema_version: 1
4
4
  version: "1"
5
5
  role: "Designer lens — evaluates interaction flow, cognitive load, consistency, and accessibility"
6
- model: claude-opus-4-7
6
+ model: opus
7
7
  tier: domain-expert
8
8
  evaluation_criteria:
9
9
  - "The interaction flow is legible on first encounter — a new user can predict what happens next without hidden state."
@@ -3,7 +3,7 @@ name: engineer-lens
3
3
  schema_version: 1
4
4
  version: "1"
5
5
  role: "Engineer lens — evaluates feasibility, complexity, failure modes, and long-term maintainability"
6
- model: claude-opus-4-7
6
+ model: opus
7
7
  tier: domain-expert
8
8
  evaluation_criteria:
9
9
  - "Failure modes are enumerated — what breaks under load, bad input, or partial failure, and how the system responds."
@@ -3,7 +3,7 @@ name: pm-lens
3
3
  schema_version: 1
4
4
  version: "1"
5
5
  role: "Product Manager lens — evaluates user value, outcome-metric clarity, and scope discipline"
6
- model: claude-opus-4-7
6
+ model: opus
7
7
  tier: domain-expert
8
8
  evaluation_criteria:
9
9
  - "The change is tied to a specific, named user or business problem — not a solution in search of one."
@@ -236,10 +236,11 @@ If issues were created and a 5+-action Epic wrapper was used (see `SKILL.md` §
236
236
 
237
237
  ### 3.3 Update Learnings
238
238
 
239
- Append new patterns to `.orchestrator/metrics/learnings.jsonl`. Use the same JSONL schema as session-end writes (see session-end/SKILL.md for canonical field reference):
239
+ Collect new patterns as learning objects in the same strict schema session-end uses (canonical field reference: `skills/session-end/learning-patterns.md` § 3.5a):
240
240
 
241
241
  ```json
242
242
  {
243
+ "schema_version": 1,
243
244
  "id": "<uuid-v4>",
244
245
  "type": "fragile-file|effective-sizing|recurring-issue|scope-guidance|deviation-pattern",
245
246
  "subject": "<what the learning is about>",
@@ -247,11 +248,25 @@ Append new patterns to `.orchestrator/metrics/learnings.jsonl`. Use the same JSO
247
248
  "evidence": "<supporting data>",
248
249
  "confidence": 0.5,
249
250
  "source_session": "retro-YYYY-MM-DD",
250
- "created_at": "<ISO 8601>",
251
- "expires_at": "<ISO 8601 + learning-expiry-days (default: 30)>"
251
+ "scope": "local",
252
+ "host_class": null,
253
+ "anonymized": false,
254
+ "file_paths": ["<repo-relative path(s) this learning applies to>"],
255
+ "created_at": "<ISO 8601>"
252
256
  }
253
257
  ```
254
258
 
259
+ `scope` MUST be `local|private|public` — a file path goes in `file_paths`, never in `scope` (GH#69). `schema_version` is the integer `1`. Omit `expires_at`: the CLI derives it per `type` via `deriveExpiresAt()`.
260
+
261
+ Write them **only** through `scripts/apply-session-learnings.mjs` (#1446) — never by hand, never with a shell redirect. Put `{"confidence_updates": [...], "new_learnings": [...]}` in a sidecar under `.orchestrator/tmp/` via the Write tool, preview, then apply. `--decay-rate 0` keeps a retro from applying the per-session passive decay a second time:
262
+
263
+ ```bash
264
+ node scripts/apply-session-learnings.mjs --input .orchestrator/tmp/retro-learnings.json --decay-rate 0 --json
265
+ node scripts/apply-session-learnings.mjs --input .orchestrator/tmp/retro-learnings.json --decay-rate 0 --apply --json
266
+ ```
267
+
268
+ Exit `1` means a record failed validation (the message names its id) and nothing was written.
269
+
255
270
  Typical retro learning types:
256
271
  - `fragile-file` — hotspots correlating with failures or carryover
257
272
  - `effective-sizing` — wave/agent configs producing best completion rates
@@ -259,7 +274,7 @@ Typical retro learning types:
259
274
  - `scope-guidance` — session scope calibration insights
260
275
  - `deviation-pattern` — systematic plan deviations indicating planning gaps
261
276
 
262
- Before writing, check existing entries for matching `type` + `subject`. Confirm (+0.15 confidence, cap 1.0) or contradict (-0.2). New learnings start at 0.5.
277
+ Before writing, check existing entries for matching `type` + `subject`. A match is not a new learning: list its `id` in `confidence_updates` with `"operation": "confirm"` (+0.15, cap 1.0) or `"contradict"` (-0.2) — the CLI applies both. New learnings start at 0.5.
263
278
 
264
279
  ### 3.4 Optional Baseline Update
265
280
 
@@ -71,9 +71,11 @@ as the session baseline for later comparison.
71
71
 
72
72
  **Script output schema (Baseline):**
73
73
  ```json
74
- {"variant": "baseline", "typecheck": {"status": "pass|fail|skip", "output": "string"}, "test": {"status": "pass|fail|skip", "output": "string"}}
74
+ {"variant": "baseline", "typecheck": {"status": "pass|fail|skip"}, "test": {"status": "pass|fail|skip"}, "typecheck_output": "string", "test_output": "string"}
75
75
  ```
76
76
 
77
+ In every variant, each command object that was actually spawned also carries its per-command kill ladder: `timed_out` (boolean), `kill_signals` (string[]) and `survivors` (pid[]). A skipped or stubbed command has none of the three keys (absent, never `false`/`[]`). `scripts/run-quality-gate.mjs` joins them into `orchestrator.quality_gate.{passed,failed}` (#1457). A run whose joined `timed_out` is `true` is recorded as `.failed` in every variant, although Baseline, Incremental and Per-File still exit 0 (#1459, decided 2026-10-01).
78
+
77
79
  ## Variant 2: Incremental
78
80
 
79
81
  **Used by:** wave-executor (after implementation waves)
@@ -91,8 +93,8 @@ Metrics output (for consuming skills to capture):
91
93
  {
92
94
  "variant": "incremental",
93
95
  "duration_seconds": null,
94
- "typecheck": "pass|fail|skip",
95
- "test": "pass|fail|skip",
96
+ "typecheck": {"status": "pass|fail|skip"},
97
+ "test": {"status": "pass|fail|skip"},
96
98
  "errors": []
97
99
  }
98
100
  ```
@@ -182,7 +184,7 @@ node "${CLAUDE_PLUGIN_ROOT:-${CODEX_PLUGIN_ROOT:-$PLUGIN_ROOT}}/scripts/run-qual
182
184
  node "${CLAUDE_PLUGIN_ROOT:-${CODEX_PLUGIN_ROOT:-$PLUGIN_ROOT}}/scripts/run-quality-gate.mjs" --variant per-file --config "$CONFIG" --files specific-file.ts
183
185
  ```
184
186
 
185
- The script handles graceful degradation (missing tools → skip), structured JSON output matching the schemas above, and proper exit codes (0=pass, 1=error, 2=gate-failed).
187
+ The script handles graceful degradation (missing tools → skip), structured JSON output matching the schemas above, and proper exit codes (0=pass, 1=error, 2=gate-failed). Only Full Gate exits 2: the three reporting variants exit 0 after a failing or killed check, so their verdict is in the JSON envelope (a kill also turns the event into `.failed`; a plain failing check does not).
186
188
 
187
189
  ## Baseline Cache (#258)
188
190
 
@@ -394,6 +394,17 @@ consolidation survives the next `/reconcile`:
394
394
  regenerates that learning as a standalone file on the next run.
395
395
  - **A merged file's `expires-at` is the EARLIEST of its parts**, never the
396
396
  latest: it must not outlive its shortest-lived content.
397
+ - **An EXPIRED file no longer dedupes** (#1387): the provenance reader skips it
398
+ whole, so its learnings become re-proposable — fail-open on an unparseable
399
+ date. Two known limits, measured 2026-09-18: this is the on-disk half only
400
+ (79 of this repo's 92 provenance keys are ALSO sidecar-terminal, so just 13
401
+ return), and a file the sweep cannot split or cannot read
402
+ (`no-1to1-mapping`, `no-provenance-block`, `unreadable`, and since GH#70
403
+ `no-counter-sentence` — the fail-closed branch that touches such a file not
404
+ at all, deletion included; none in the live tree today, `skipped: []` over 7
405
+ files) that expires legitimately
406
+ re-proposes on every run with no mechanical exit. Detail:
407
+ `docs/rule-authoring.md` § Consolidated rules.
397
408
  - **A dropped learning must be STAMPED before deletion, or it regenerates.**
398
409
  `rm .claude/rules/<slug>.md` alone leaves `isProcessed()` false and no
399
410
  on-disk marker, so the engine re-proposes it. Stamp it terminal first with
@@ -28,12 +28,14 @@ Exit codes (`offload --help`, measured 2026-09-02): `0` ok · `1` usage/config
28
28
 
29
29
  ## 1. Decision rule — offload vs reduce
30
30
 
31
- The gate decides, not the coordinator. `applyOffloadDecision()` in `scripts/lib/wave-resource-gate.mjs` only fires when the resource verdict is already `reduce` or `coordinator-direct`, and only AFTER the HR-004 heavy-repo cap — a capped wave that offloads still respects the cap. It never probes the network; the coordinator supplies a readiness WITNESS:
31
+ The gate decides, not the coordinator. `applyOffloadDecision()` in `scripts/lib/wave-resource-gate.mjs` fires when the resource verdict is `reduce` or `coordinator-direct` (and, with `offload-first: true`, on `proceed` as well — see below), and only AFTER the HR-004 heavy-repo cap — a capped wave that offloads still respects the cap. It never probes the network; the coordinator supplies a readiness WITNESS:
32
32
 
33
33
  - `opts.remoteReady` — `{ [alias]: boolean }`, built from the SessionStart banner line `Offload <alias>: ready=yes …`, or
34
34
  - `opts.probeFn` — an async `(alias) => boolean` fallback, consulted only for aliases `remoteReady` doesn't answer for (backed by `remoteDoctor()`, i.e. `offload doctor -H <alias> --brief` parsed by `parseDoctorLine()`).
35
35
 
36
- With neither supplied, no host counts as ready and the wave 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`: `impl-core`, `security-review`, `migration`, `release`, `secrets`) is never offloaded regardless of readiness.
36
+ With neither supplied, no host counts as ready and the wave 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`: `impl-core`, `security-review`, `migration`, `release`, `secrets`, `incident`, `refactor-crosscut`) is never offloaded regardless of readiness.
37
+
38
+ With `offload-first: true` in Session Config (#1465, default `false`) the placement arm also fires on `proceed`, so an offloadable role goes to a witnessed-ready host without waiting for local pressure. The witness stays mandatory — without `remoteReady`/`probeFn` nothing moves — and a wave that stays local carries a named reason (`offload-first: no ready host for '<role>' — staying local`, or `… no remote-hosts declared — staying local`).
37
39
 
38
40
  ## 2. What is declared where
39
41
 
@@ -151,23 +151,20 @@ discipline as `createSpiralCarryoverIssue`).
151
151
 
152
152
  > Gate: Only run if `persistence` is `true` in Session Config. Skip silently otherwise.
153
153
 
154
- After STATE.md is finalized with `status: completed` (Phase 3.4) and Recommendations are written (Phase 3.7a), release the distributed session-lock so the next session can acquire it cleanly:
154
+ After STATE.md is finalized with `status: completed` (Phase 3.4) and Recommendations are written (Phase 3.7a), release the distributed session-lock with ONE verifying command:
155
155
 
156
- ```javascript
157
- import { release } from 'scripts/lib/session-lock.mjs';
158
- // sessionId is the physical raw value established by session-start Phase 1.2
159
- // and stored in .orchestrator/session.lock `session_id`. It is not STATE.md
160
- // `session:` or `semantic_session_id`, both of which are attribution labels.
161
- const rawSessionId = sessionId;
162
- const result = release({ sessionId: rawSessionId, repoRoot: process.cwd() });
163
- // result.ok is always true unless a filesystem error occurred.
164
- // result.deleted === true → lock file removed successfully.
165
- // result.deleted === false → lock was absent or had a different raw session_id.
156
+ ```bash
157
+ node scripts/release-session-lock.mjs --session-id "<raw session_id>" --json
166
158
  ```
167
159
 
168
- If `result.deleted === false`, log `info: session-lock not released — already absent or raw session_id mismatch` and continue. An active lock whose raw id differs is ambiguous: do **not** retry release with an equal `semantic_session_id`, STATE.md `session`, or owner proof. Leave that live lock for its TTL/Reaper lifecycle.
160
+ `--session-id` is the PHYSICAL raw value established by session-start Phase 1.2 and stored in `.orchestrator/session.lock` `session_id` — never STATE.md `session:` and never `semantic_session_id`, both of which are attribution labels.
161
+
162
+ The command releases the lock only when that raw id owns it, emits the terminal `orchestrator.session.lock.released` breadcrumb, and then RE-READS the lock path: **exit 0 means the lock is provably gone.** It replaces the hand-executed `release()` this phase used to prescribe, which deleted the lock silently — the SessionEnd hook then found `status: 'absent'` and emitted nothing either, so a lock lifecycle ended with no terminal event at all (#1395: 5 `lock.acquired` against 0 `lock.released` in this repo). `outcome: "absent"` is a normal exit-0 result (idempotent re-run; nothing was released, so no event is written).
163
+
164
+ A non-zero exit is a WARN, never a blocker — log `⚠ session-lock: <outcome>` and continue; the TTL provides automatic expiry for the next session:
169
165
 
170
- If `result.ok === false` (rare filesystem error), log `⚠ session-lock: release failed — <result.reason>` and continue. Do NOT block the close for a lock-release failure — the TTL provides automatic expiry for the next session.
166
+ - **exit 1** — the lock is owned by a different raw session id, so nothing was touched. That is ambiguous by design: do **not** retry with an equal `semantic_session_id`, STATE.md `session`, or owner proof. Leave that live lock for its TTL/Reaper lifecycle.
167
+ - **exit 2** — system error (unreadable/corrupt lock, owner-proof mismatch, the lock still present after release, or the breadcrumb could not be written).
171
168
 
172
169
  The lock is released here — AFTER all STATE.md writes are complete and BEFORE the commit is staged in Phase 4.1. This ordering ensures a clean handover when the current raw owner releases it: the lock file is absent from the working tree when the commit is assembled, so it is not accidentally staged.
173
170
 
@@ -260,7 +257,7 @@ swallow it with `|| true`.
260
257
 
261
258
  ## Phase 5: Issue Cleanup
262
259
 
263
- > Always runs. Closes resolved issues (stripping `status:*` labels first via `stripStatusLabels`, #308), updates partially-done issues, and in Step 3 FILES the Phase 1.65 gate's carry-list — the deferred `createSpiralCarryoverIssue` call for SPIRAL/FAILED items and the `markOpenQuestionAnsweredOnDisk` write live here, not in Phase 1.65 (atomicity). Step 3b folds non-exempt over-cap creations into one `[Backlog-Sammel]` collector under the `issue-budget` cap; discovery findings from Phase 1.5 are filed at the end. Full procedure: [`references/phase-5-issue-cleanup.md`](references/phase-5-issue-cleanup.md).
260
+ > Always runs. Closes resolved issues via the single `node "$PLUGIN_ROOT/scripts/lib/issue-close-strip-labels.mjs" --close [--vcs gitlab|github] [-R <spec>] <id>...` CLI call (strips `status:*` labels, closes, then re-reads each id; a `closed: false` in its per-id JSON output is a finding, not done — #308), updates partially-done issues, and in Step 3 FILES the Phase 1.65 gate's carry-list — the deferred `createSpiralCarryoverIssue` call for SPIRAL/FAILED items and the `markOpenQuestionAnsweredOnDisk` write live here, not in Phase 1.65 (atomicity). Step 3b folds non-exempt over-cap creations into one `[Backlog-Sammel]` collector under the `issue-budget` cap; discovery findings from Phase 1.5 are filed at the end. Full procedure: [`references/phase-5-issue-cleanup.md`](references/phase-5-issue-cleanup.md).
264
261
 
265
262
  ## Phase 6: Final Report
266
263
 
@@ -280,7 +277,7 @@ Present to the user the **Session Summary**: Completed / Carried Over / Dropped
280
277
  | `references/phase-3-documentation-updates.md` | Phase 3 full procedural body — final heartbeat (#590-3), 3.0 Defensive Cleanup, 3.1 SSOT files, 3.2/3.2a docs + handover, 3.3 rules freshness, 3.4/3.4a STATE.md write + snapshot cleanup, 3.45 Telemetry Flush, 3.5/3.5a/3.6.x memory + learnings + tail dispatcher, 3.7/3.7a/3.7b/3.7c/3.7d metrics, recommendations, durable commit, vault board, session-eval |
281
278
  | `phase-3-2-docs-verification.md` | Phase 3.2 full procedural body — docs-tasks load, SESSION_START_REF, per-task loop, mode-gated report, Documentation Coverage block |
282
279
  | `learning-patterns.md` | Phases 3.5a + 3.6 extraction heuristics, confidence updates, passive decay, and JSONL write procedure |
283
- | `phase-3-6-tail.md` | Phase 3.6.x tail — detail procedures for the tail phases: 3.6.3 Memory-Proposals Collection (`collectProposals` + AUQ multiSelect + `promoteAndClear`, composing `writeApproved` + `clearProposalsJsonl` behind a mechanical write-before-clear guard, #828), **3.6.4 Expired-Learnings Sweep — MECHANICAL since 2026-09-09**: after `planTailPhases()`, call `runTailPhases({ repoRoot, plan })` from `scripts/lib/session-end/tail-runner.mjs` (delegating to `runExpiredSweep`) and report `result['3.6.4']` (`ran`, `scanned`, `archived`); the event `orchestrator.learnings.sweep_applied` is the proof it ran (Epic #723 B4), **3.6.5 Auto-Dream — RETIRED** and **3.6.7 Auto-Dialectic — RETIRED** (both replaced by the session-start `maintenance-due` probe, `checkMaintenanceDue` in `scripts/lib/maintenance-due-banner.mjs`; headings kept as two-line stubs because other docs cite them), 3.6.6 Skill-Applied Judge (#645 L3 — `runSkillJudge`, coordinator-writes), 3.6.8 Reconciliation Rule Proposals (#696 FA3 — `runReconcile` + AUQ + `writeApprovedRules`). Loaded on demand by the SKILL.md skip-plan dispatcher (#724) — only phases with `run: true` in the `planTailPhases()` plan execute |
280
+ | `phase-3-6-tail.md` | Phase 3.6.x tail — detail procedures for the tail phases: 3.6.3 Memory-Proposals Collection (`collectProposals` + AUQ multiSelect + `promoteAndClear`, composing `writeApproved` + `clearProposalsJsonl` behind a mechanical write-before-clear guard, #828), **3.6.4 Expired-Learnings Sweep — MECHANICAL since 2026-09-09**: after `planTailPhases()`, call `runTailPhases({ repoRoot, plan })` from `scripts/lib/session-end/tail-runner.mjs` (delegating to `runExpiredSweep`) and report `result['3.6.4']` (`ran`, `scanned`, `archived`); the event `orchestrator.learnings.sweep_applied` is the proof it ran (Epic #723 B4), **3.6.5 Auto-Dream — RETIRED** and **3.6.7 Auto-Dialectic — RETIRED** (both replaced by the session-start `maintenance-due` probe, `checkMaintenanceDue` in `scripts/lib/maintenance-due-banner.mjs`; headings kept as two-line stubs because other docs cite them), 3.6.6 Skill-Applied Judge (#645 L3 — two calls, not one: `buildSkillEvidence` from `scripts/lib/skill-evidence-window.mjs` renders this session's transcript into the evidence window, then `runSkillJudge` judges it and the coordinator writes each judgment via `appendSkillJudgment`; on empty evidence text `runSkillJudge` returns `status: 'no-evidence'` and does NOT dispatch, #1399 — the exact call shape is in the sub-file, do not reconstruct it here), 3.6.8 Reconciliation Rule Proposals (#696 FA3 — `runReconcile` + AUQ + `writeApprovedRules`). Loaded on demand by the SKILL.md skip-plan dispatcher (#724) — only phases with `run: true` in the `planTailPhases()` plan execute |
284
281
  | `scripts/lib/session-end/phase-skip.mjs` | Phase 3.6.x tail skip-plan aggregator (#724) — `planTailPhases({repoRoot, config, sessionId, platform})` → `{plan, skippedReport}`; side-effect-free (reconcile/sweep via dry-run — no writes), never-throws (per-phase probe error fail-opens to `run: true`). Since 2026-09-09 it plans FOUR phases, not six: the 3.6.5 (auto-dream) and 3.6.7 (auto-dialectic) deciders were removed with those phases' retirement. Its APPLY half for 3.6.4 is `scripts/lib/session-end/tail-runner.mjs` (`runTailPhases`, `runExpiredSweep`) — the planner fails OPEN, the runner fails CLOSED |
285
282
  | `references/phase-3-documentation-updates.md` § 3.45 | Telemetry Flush (advisory, #844; MECHANICAL since #1138 — `hooks/on-session-end.mjs` calls `flush()` itself at the end of every teardown and emits an `orchestrator.telemetry.flush` breadcrumb, so this phase is the DESCRIPTION and the fallback, never the trigger; a coordinator that skips it changes nothing) — `flush()` from `scripts/lib/telemetry/sync.mjs` drains the host-local send-queue fire-and-forget; no config key (send-gate is `resolveConsent()` inside the module, fail-closed); skip when `persistence: false`; never-throw + ~3s-bounded, offline → bounded oldest-dropped queue, optional `Telemetry: sent/queued/gated` close-summary line, NEVER an error banner; runs late in the close after Phase 3.7 |
286
283
  | `session-metrics-write.md` | Phase 3.7 JSONL append, vault-mirror invocation, durable narrative mirror (`mirrorNarrative`, #675), and behavior matrix |
@@ -292,7 +289,7 @@ Present to the user the **Session Summary**: Completed / Carried Over / Dropped
292
289
  | (inline) Phase 4 | Commit & Push — stage individually (PSA-004), commit, push to origin, then the `github-mirror-push` block (4 states: not-a-repo / no `github` remote / pushed / push failed) |
293
290
  | `references/phase-4a-worktree-cleanup.md` | Phase 4a full procedural body — auto-promoted-worktree detection (`detectAutoPromotedWorktree`, marker-keyed since #1069), clean-check, clean auto-remove path, dirty 3-option AUQ (`Behalten`/`Löschen`/`Manuell`), PSA-003 + #490 ordering rationale |
294
291
  | `references/phase-4b-worktree-orphan-sweep.md` | Phase 4b full procedural body — `checkWorktreeOrphans()` read-only proposal set, the coordinator-rendered AUQ, opt-in `worktree-orphans.enabled` gate |
295
- | `references/phase-5-issue-cleanup.md` | Phase 5 full procedural body — close resolved issues (`stripStatusLabels`, #308), Step 3 filing of the Phase 1.65 carry-list incl. the deferred `createSpiralCarryoverIssue` and `markOpenQuestionAnsweredOnDisk`, Step 3b `[Backlog-Sammel]` overflow, discovery-issue creation |
292
+ | `references/phase-5-issue-cleanup.md` | Phase 5 full procedural body — close resolved issues via `node "$PLUGIN_ROOT/scripts/lib/issue-close-strip-labels.mjs" --close` (strip `status:*` → close → re-read; `closed: false` is a finding, not done, #308), Step 3 filing of the Phase 1.65 carry-list incl. the deferred `createSpiralCarryoverIssue` and `markOpenQuestionAnsweredOnDisk`, Step 3b `[Backlog-Sammel]` overflow, discovery-issue creation |
296
293
  | `references/phase-5-issue-cleanup.md` § Step 3b.2 (issue-budget reconcile) | Phase 5 issue-budget cross-check — `reconcileIssueBudget({ repoRoot, record, sessionId, rawSessionId, config })` from `scripts/lib/issue-budget-reconcile.mjs` runs on the in-memory session record BEFORE it is appended to `sessions.jsonl`, `emitIssueBudgetReconciled` records `orchestrator.issue_budget.reconciled`, and `formatIssueBudgetReconcileWarn(result)` prints the verdict (`match` / `no-ledger` / `escaped` / `stale-record`) in the Final Report. Ordered AFTER the overflow drain (which resets `overflow[]`) and BEFORE `reapStaleBudgetFiles` (which must not remove the file being read) |
297
294
  | `references/session-summary-template.md` | Phase 6 Final Report — the full Session Summary template (Completed / Carried Over / Dropped at Handover Gate / New Issues / Unresolved Review Findings / Metrics incl. Docs Health + Custom Phases / Next Session Recommendations) plus the Test-delta and Documentation-Coverage anchors |
298
295
 
@@ -27,7 +27,7 @@ Agent({
27
27
  run_in_background: false
28
28
  })
29
29
  ```
30
- On Codex CLI / Cursor IDE: execute probes sequentially within the current context (no Agent dispatch).
30
+ Use the native delegation tools actually exposed by the current runtime, following [Platform Tool Adaptation](../_shared/platform-tools.md). If the runtime exposes no suitable delegation tool, execute the probes sequentially within the current context.
31
31
  - Collect verified findings from the discovery output
32
32
  - Parse the discovery output for the **findings** array and **stats** object (see Parsing callout below)
33
33
  - Store the stats object for Phase 1.7 metrics collection (`discovery_stats` field)