session-orchestrator 5.12.0 → 5.13.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 (385) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +4 -1
  3. package/.codex-plugin/agents/explorer.toml +1 -1
  4. package/.codex-plugin/agents/session-reviewer.toml +2 -2
  5. package/.codex-plugin/agents/wave-worker.toml +1 -1
  6. package/.codex-plugin/plugin.json +1 -1
  7. package/.cursor-plugin/plugin.json +1 -1
  8. package/.orchestrator/policy/blocked-commands.json +8 -0
  9. package/.orchestrator/policy/public-export.json +30 -0
  10. package/CHANGELOG.md +162 -4
  11. package/README.md +126 -127
  12. package/agents/analyst.md +7 -2
  13. package/agents/architect-reviewer.md +7 -2
  14. package/agents/code-implementer.md +4 -2
  15. package/agents/db-specialist.md +9 -2
  16. package/agents/dialectic-deriver.md +9 -3
  17. package/agents/docs-writer.md +7 -2
  18. package/agents/eval-judge.md +7 -1
  19. package/agents/qa-strategist.md +7 -2
  20. package/agents/security-reviewer.md +9 -2
  21. package/agents/session-reviewer.md +18 -2
  22. package/agents/skill-applied-judge.md +7 -1
  23. package/agents/test-writer.md +9 -2
  24. package/agents/ui-developer.md +9 -2
  25. package/agents/ux-evaluator.md +6 -1
  26. package/commands/session.md +1 -1
  27. package/commands/templates-ack.md +89 -18
  28. package/docs/agent-authoring.md +30 -11
  29. package/docs/ci-setup.md +38 -2
  30. package/docs/codex-setup.md +33 -9
  31. package/docs/components.md +13 -2
  32. package/docs/cursor-setup.md +3 -3
  33. package/docs/events-schema.md +5 -4
  34. package/docs/evidence-candidates.md +63 -0
  35. package/docs/fleet-checkin-audit.md +7 -4
  36. package/docs/github-mirror-protection.md +150 -3
  37. package/docs/install.md +90 -17
  38. package/docs/instruction-delivery.md +1 -1
  39. package/docs/migration-v4.md +2 -2
  40. package/docs/mods.md +118 -0
  41. package/docs/owner-config-schema.md +1 -0
  42. package/docs/plugin-architecture-v3.md +1 -1
  43. package/docs/pm-skills-marketplace.md +4 -3
  44. package/docs/rule-authoring.md +24 -13
  45. package/docs/scope-collision-guard.md +2 -1
  46. package/docs/session-config-reference.md +49 -15
  47. package/docs/session-config-template.md +30 -22
  48. package/docs/sessions-ledger-repair.md +137 -0
  49. package/docs/vault-docs-architecture.md +1 -1
  50. package/hooks/_lib/hook-import-set.json +406 -73
  51. package/hooks/_lib/hook-root.mjs +301 -0
  52. package/hooks/_lib/lock-bootstrap.mjs +434 -4
  53. package/hooks/_lib/orchestrator-ignore.mjs +3 -0
  54. package/hooks/_lib/subagent-transcript.mjs +2 -2
  55. package/hooks/_lib/vcs-create-matcher.mjs +13 -17
  56. package/hooks/cwd-change-restore.mjs +5 -1
  57. package/hooks/enforce-commands.mjs +4 -3
  58. package/hooks/enforce-scope.mjs +11 -1
  59. package/hooks/hooks-codex.json +48 -2
  60. package/hooks/hooks.json +31 -31
  61. package/hooks/on-session-end.mjs +38 -15
  62. package/hooks/on-session-start.mjs +139 -49
  63. package/hooks/on-stop.mjs +11 -6
  64. package/hooks/post-bash-issue-budget-refund.mjs +6 -1
  65. package/hooks/post-bash-write-verify.mjs +8 -4
  66. package/hooks/post-edit-validate.mjs +45 -52
  67. package/hooks/post-subagent-discovery-validator.mjs +2 -2
  68. package/hooks/post-tool-batch-wave-signal.mjs +8 -4
  69. package/hooks/post-tool-failure-corrective-context.mjs +5 -1
  70. package/hooks/pre-bash-destructive-guard.mjs +220 -8
  71. package/hooks/pre-bash-issue-budget.mjs +6 -1
  72. package/hooks/pre-bash-sessions-ledger-guard.mjs +691 -123
  73. package/hooks/pre-bash-staging-fence.mjs +258 -14
  74. package/hooks/pre-bash-templates-first.mjs +28 -27
  75. package/hooks/run-node.sh +1 -1
  76. package/hooks/skill-invocation-telemetry.mjs +15 -8
  77. package/hooks/subagent-telemetry.mjs +77 -14
  78. package/hooks/wave-scope-commit-guard.mjs +143 -14
  79. package/mods/so-hud/.claude-plugin/plugin.json +11 -0
  80. package/mods/so-hud/README.md +57 -0
  81. package/mods/so-hud/hooks/beacon-io.mjs +101 -0
  82. package/mods/so-hud/hooks/heredoc-scan.ts +394 -0
  83. package/mods/so-hud/hooks/hooks.json +1 -0
  84. package/mods/so-hud/hooks/logic.ts +182 -0
  85. package/mods/so-hud/hooks/register.tsx +670 -0
  86. package/mods/so-hud/hooks/rules.ts +2998 -0
  87. package/mods/so-hud/tsconfig.json +8 -0
  88. package/mods/so-hud/types/index.d.ts +36 -0
  89. package/package.json +4 -2
  90. package/rules/_index.md +1 -1
  91. package/rules/always-on/ask-via-tool.md +1 -1
  92. package/rules/always-on/loop-and-monitor.md +17 -194
  93. package/rules/always-on/parallel-sessions.md +3 -1
  94. package/rules/opt-in-stack/backend-data.md +1 -1
  95. package/rules/opt-in-stack/backend.md +1 -1
  96. package/rules/opt-in-stack/security-web.md +5 -1
  97. package/scripts/agent-usage-census.mjs +79 -0
  98. package/scripts/apply-session-learnings.mjs +34 -6
  99. package/scripts/archive-closed-prds.mjs +21 -5
  100. package/scripts/autopilot.mjs +11 -5
  101. package/scripts/backfill-abandoned-sessions.mjs +13 -3
  102. package/scripts/backfill-evidence-digest.mjs +2 -1
  103. package/scripts/backfill-learnings-from-vault.mjs +61 -6
  104. package/scripts/backfill-sessions.mjs +16 -2
  105. package/scripts/check-package-manager.mjs +26 -8
  106. package/scripts/check-sessions-integrity.mjs +4 -1
  107. package/scripts/ci/assert-vitest-green.mjs +3 -0
  108. package/scripts/ci/windows-smoke.mjs +201 -0
  109. package/scripts/close-precheck.mjs +55 -0
  110. package/scripts/dialectic-deriver.mjs +20 -12
  111. package/scripts/emit-event.mjs +2 -2
  112. package/scripts/emit-session.mjs +239 -20
  113. package/scripts/eval-session.mjs +17 -3
  114. package/scripts/export-hw-learnings.mjs +29 -2
  115. package/scripts/fleet-checkin-audit.mjs +8 -4
  116. package/scripts/fleet-checkin.mjs +39 -27
  117. package/scripts/gc-stale-worktrees.mjs +6 -1
  118. package/scripts/github-export.mjs +128 -0
  119. package/scripts/github-protection-audit.mjs +3 -1
  120. package/scripts/handover-queue-check.mjs +209 -0
  121. package/scripts/harness-audit.mjs +6 -4
  122. package/scripts/lib/agent-frontmatter.mjs +57 -10
  123. package/scripts/lib/agent-status.mjs +125 -7
  124. package/scripts/lib/agent-usage-census.mjs +394 -0
  125. package/scripts/lib/auto-dialectic.mjs +17 -10
  126. package/scripts/lib/auto-dream.mjs +22 -14
  127. package/scripts/lib/autopilot/loop.mjs +3 -1
  128. package/scripts/lib/autopilot/recent-runs.mjs +4 -2
  129. package/scripts/lib/autopilot/stall-sampler.mjs +2 -1
  130. package/scripts/lib/autopilot/telemetry.mjs +5 -1
  131. package/scripts/lib/autopilot/worktree-pipeline.mjs +5 -5
  132. package/scripts/lib/baseline-archetypes.mjs +10 -2
  133. package/scripts/lib/blocked-commands-policy.mjs +4 -3
  134. package/scripts/lib/build-live-signals.mjs +13 -9
  135. package/scripts/lib/ci-status-banner.mjs +329 -24
  136. package/scripts/lib/codex/plugin-contract.mjs +8 -0
  137. package/scripts/lib/cold-start-detector.mjs +5 -2
  138. package/scripts/lib/command-blocker.mjs +603 -43
  139. package/scripts/lib/common.mjs +3 -2
  140. package/scripts/lib/config/cross-repo.mjs +74 -7
  141. package/scripts/lib/config/host-paths.mjs +6 -2
  142. package/scripts/lib/config/section-extractor.mjs +65 -11
  143. package/scripts/lib/config/template-keys.mjs +153 -0
  144. package/scripts/lib/config/vault-integration.mjs +1 -0
  145. package/scripts/lib/config.mjs +2 -2
  146. package/scripts/lib/coordinator-snapshot.mjs +1 -1
  147. package/scripts/lib/discovery/triage-state.mjs +2 -1
  148. package/scripts/lib/dispatcher/rank.mjs +5 -7
  149. package/scripts/lib/ecosystem-health.mjs +2 -2
  150. package/scripts/lib/eval/engine.mjs +3 -2
  151. package/scripts/lib/eval/session-resolve.mjs +6 -2
  152. package/scripts/lib/eval/sink.mjs +4 -3
  153. package/scripts/lib/events-retention-banner.mjs +3 -2
  154. package/scripts/lib/events-schema.mjs +10 -0
  155. package/scripts/lib/events.mjs +23 -12
  156. package/scripts/lib/evolve/autonomy-verdict.mjs +4 -9
  157. package/scripts/lib/evolve/autopilot-effectiveness.mjs +8 -18
  158. package/scripts/lib/fleet-protocol.mjs +4 -0
  159. package/scripts/lib/gates/gate-full.mjs +172 -11
  160. package/scripts/lib/gates/gate-helpers.mjs +236 -23
  161. package/scripts/lib/git-config-drift.mjs +141 -7
  162. package/scripts/lib/github-export.mjs +447 -0
  163. package/scripts/lib/gitlab-portfolio/cli.mjs +16 -5
  164. package/scripts/lib/handover-queue-marks.mjs +159 -0
  165. package/scripts/lib/hardware-pattern-detector.mjs +103 -13
  166. package/scripts/lib/harness-audit/categories/category1.mjs +16 -4
  167. package/scripts/lib/harness-audit/categories/category4.mjs +11 -8
  168. package/scripts/lib/harness-audit/categories/category6.mjs +25 -5
  169. package/scripts/lib/harness-audit/categories/category9.mjs +10 -4
  170. package/scripts/lib/host-identity.mjs +9 -5
  171. package/scripts/lib/http-request.mjs +64 -0
  172. package/scripts/lib/instruction-budget-guard.mjs +30 -22
  173. package/scripts/lib/io.mjs +6 -3
  174. package/scripts/lib/issue-budget-reconcile.mjs +3 -2
  175. package/scripts/lib/issue-budget.mjs +36 -7
  176. package/scripts/lib/learnings/evidence-candidates.mjs +154 -0
  177. package/scripts/lib/learnings/expiry-sweep.mjs +99 -7
  178. package/scripts/lib/learnings/io.mjs +289 -15
  179. package/scripts/lib/learnings/select.mjs +53 -4
  180. package/scripts/lib/learnings/store-role.mjs +209 -0
  181. package/scripts/lib/learnings/surface.mjs +46 -7
  182. package/scripts/lib/ledger-path.mjs +113 -0
  183. package/scripts/lib/maintenance-due-banner.mjs +63 -12
  184. package/scripts/lib/memory-banner.mjs +5 -6
  185. package/scripts/lib/memory-proposals/collector.mjs +5 -2
  186. package/scripts/lib/memory-proposals/sink.mjs +7 -4
  187. package/scripts/lib/memory-proposals/store.mjs +22 -5
  188. package/scripts/lib/mode-selector-accuracy.mjs +2 -1
  189. package/scripts/lib/no-follow-open.mjs +57 -0
  190. package/scripts/lib/orphan-reaper/reaper-audit.mjs +4 -2
  191. package/scripts/lib/own-lock-root.mjs +95 -0
  192. package/scripts/lib/owner-interview.mjs +2 -1
  193. package/scripts/lib/owner-yaml.mjs +70 -7
  194. package/scripts/lib/platform.mjs +161 -9
  195. package/scripts/lib/plugin-update-banner.mjs +15 -11
  196. package/scripts/lib/pre-push-local-partial.mjs +117 -0
  197. package/scripts/lib/pre-push-remote-gate.mjs +151 -25
  198. package/scripts/lib/process-group.mjs +270 -34
  199. package/scripts/lib/project-hygiene.mjs +28 -0
  200. package/scripts/lib/quality-gate.mjs +33 -9
  201. package/scripts/lib/reconcile/backlog.mjs +29 -15
  202. package/scripts/lib/reconcile/engine.mjs +26 -2
  203. package/scripts/lib/reconcile/idempotency.mjs +65 -3
  204. package/scripts/lib/reconcile/rule-expiry-sweep.mjs +53 -12
  205. package/scripts/lib/reconcile/verdict-ledger.mjs +224 -0
  206. package/scripts/lib/reconcile-nudge-banner.mjs +40 -6
  207. package/scripts/lib/resource-probe/evaluate.mjs +32 -9
  208. package/scripts/lib/resource-probe/probe-platform.mjs +3 -1
  209. package/scripts/lib/rule-loader.mjs +20 -10
  210. package/scripts/lib/scope-baseline.mjs +123 -8
  211. package/scripts/lib/scope-echo.mjs +5 -2
  212. package/scripts/lib/scope-gate.mjs +55 -20
  213. package/scripts/lib/session-close-backfill.mjs +75 -7
  214. package/scripts/lib/session-end/close-precheck.mjs +151 -0
  215. package/scripts/lib/session-end/phase-skip.mjs +8 -7
  216. package/scripts/lib/session-end/tail-runner.mjs +7 -2
  217. package/scripts/lib/session-id.mjs +9 -1
  218. package/scripts/lib/session-identity/own-session.mjs +63 -0
  219. package/scripts/lib/session-lock.mjs +114 -0
  220. package/scripts/lib/session-record-repair.mjs +245 -35
  221. package/scripts/lib/session-registry.mjs +72 -9
  222. package/scripts/lib/session-schema/constants.mjs +9 -0
  223. package/scripts/lib/session-schema/filters.mjs +56 -1
  224. package/scripts/lib/session-schema/validator.mjs +15 -5
  225. package/scripts/lib/session-start-probes.mjs +149 -22
  226. package/scripts/lib/session-token-rollup.mjs +2 -1
  227. package/scripts/lib/session-work-trees.mjs +166 -0
  228. package/scripts/lib/sessions-canonical.mjs +61 -3
  229. package/scripts/lib/sessions-integrity-banner.mjs +17 -39
  230. package/scripts/lib/sessions-staleness-banner.mjs +8 -5
  231. package/scripts/lib/sh-quote.mjs +1 -0
  232. package/scripts/lib/skill-evidence-window.mjs +5 -1
  233. package/scripts/lib/skill-health/join.mjs +10 -9
  234. package/scripts/lib/skill-invocations-schema.mjs +13 -0
  235. package/scripts/lib/skill-judgments-schema.mjs +6 -2
  236. package/scripts/lib/snapshot-probe.mjs +414 -0
  237. package/scripts/lib/so-hud/collect.mjs +49 -5
  238. package/scripts/lib/so-hud/runtime.mjs +15 -4
  239. package/scripts/lib/spiral-carryover.mjs +8 -1
  240. package/scripts/lib/state-md/frontmatter-mutators.mjs +266 -8
  241. package/scripts/lib/state-md/idle-reset.mjs +14 -5
  242. package/scripts/lib/state-md/mission-status.mjs +5 -1
  243. package/scripts/lib/state-md-peer-guard.mjs +2 -0
  244. package/scripts/lib/state-md.mjs +31 -8
  245. package/scripts/lib/sunset/walker.mjs +4 -3
  246. package/scripts/lib/telemetry/consent.mjs +4 -2
  247. package/scripts/lib/telemetry/queue.mjs +3 -3
  248. package/scripts/lib/telemetry/sync.mjs +45 -9
  249. package/scripts/lib/test-runner/artifact-paths.mjs +10 -2
  250. package/scripts/lib/tmux-layout/layouts.mjs +20 -3
  251. package/scripts/lib/ux-grill/paths.mjs +5 -1
  252. package/scripts/lib/validate/check-agents.mjs +37 -6
  253. package/scripts/lib/validate/check-component-paths.mjs +25 -1
  254. package/scripts/lib/validate/check-guard-requires-parity.mjs +3 -3
  255. package/scripts/lib/validate/check-hooks-symmetry.mjs +53 -32
  256. package/scripts/lib/validate/check-json-files.mjs +3 -1
  257. package/scripts/lib/validate/check-learning-provenance.mjs +3 -2
  258. package/scripts/lib/validate/check-learnings-shell-writes.mjs +10 -4
  259. package/scripts/lib/validate/check-metrics-ledger-root.mjs +234 -0
  260. package/scripts/lib/validate/check-owner-leakage.mjs +159 -11
  261. package/scripts/lib/validate/check-test-posix-shell.mjs +246 -0
  262. package/scripts/lib/validate/check-unwired-features.mjs +4 -2
  263. package/scripts/lib/validate/check-vcs-repo-flag-positional.mjs +58 -0
  264. package/scripts/lib/validate/check-vcs-repo-flag.mjs +259 -73
  265. package/scripts/lib/validate/check-workflow-continue-on-error.mjs +63 -0
  266. package/scripts/lib/validate/confidential-names.mjs +3 -1
  267. package/scripts/lib/vault-mirror/migrate-ids.mjs +321 -0
  268. package/scripts/lib/vault-mirror/namespace.mjs +19 -7
  269. package/scripts/lib/vault-mirror/process.mjs +56 -27
  270. package/scripts/lib/vault-mirror/prune.mjs +5 -2
  271. package/scripts/lib/vault-mirror/render-learnings.mjs +3 -3
  272. package/scripts/lib/vault-mirror/render-sessions.mjs +36 -53
  273. package/scripts/lib/vault-mirror/retention.mjs +2 -2
  274. package/scripts/lib/vault-mirror/utils.mjs +79 -0
  275. package/scripts/lib/vault-staleness-banner.mjs +4 -7
  276. package/scripts/lib/vault-status/board-writer.mjs +2 -1
  277. package/scripts/lib/vault-status/narrative-mirror.mjs +66 -7
  278. package/scripts/lib/wave-executor/foreign-dispatch.mjs +20 -0
  279. package/scripts/lib/win-process-tree.mjs +137 -0
  280. package/scripts/lib/workspace.mjs +1 -1
  281. package/scripts/lib/worktree/constants.mjs +1 -1
  282. package/scripts/lib/worktree/lifecycle.mjs +1 -1
  283. package/scripts/lib/worktree/listing.mjs +1 -1
  284. package/scripts/lib/zx.mjs +50 -0
  285. package/scripts/mcp-server.mjs +16 -7
  286. package/scripts/mcp-server.sh +13 -83
  287. package/scripts/measure-policy-cache-effectiveness.mjs +7 -5
  288. package/scripts/memory-propose.mjs +10 -3
  289. package/scripts/migrate-cold-start-seed.mjs +7 -0
  290. package/scripts/migrate-legacy-learnings.sh +22 -0
  291. package/scripts/migrate-sessions-jsonl.mjs +16 -2
  292. package/scripts/migrate-vault-paths.mjs +29 -13
  293. package/scripts/parse-config.mjs +71 -14
  294. package/scripts/print-learnings-index.mjs +25 -2
  295. package/scripts/release-session-lock.mjs +94 -7
  296. package/scripts/release.mjs +451 -24
  297. package/scripts/relocate-vault-corpus.mjs +11 -7
  298. package/scripts/repair-invalid-sessions.mjs +68 -3
  299. package/scripts/resolve-session-invocation.mjs +10 -17
  300. package/scripts/run-migrate-v2-cross-repo.mjs +56 -1
  301. package/scripts/run-quality-gate.mjs +33 -7
  302. package/scripts/self-update.mjs +56 -7
  303. package/scripts/session-commit-files.mjs +133 -0
  304. package/scripts/site-numbers.mjs +52 -9
  305. package/scripts/snapshot-probe.mjs +156 -0
  306. package/scripts/so-hud.mjs +29 -6
  307. package/scripts/state-md-idle-reset.mjs +2 -1
  308. package/scripts/sweep-expired-learnings.mjs +54 -6
  309. package/scripts/sweep-expired-rules.mjs +4 -1
  310. package/scripts/validate-plugin.mjs +22 -0
  311. package/scripts/vault-integration-watcher.mjs +54 -6
  312. package/scripts/vault-mirror.mjs +9 -0
  313. package/skills/_shared/fleet-protocol.md +142 -1
  314. package/skills/_shared/instruction-file-resolution.md +1 -1
  315. package/skills/_shared/monitor-patterns.md +44 -25
  316. package/skills/_shared/platform-tools.md +7 -0
  317. package/skills/_shared/state-ownership.md +3 -2
  318. package/skills/architecture/references/domain-model.md +1 -1
  319. package/skills/bootstrap/SKILL.md +3 -1
  320. package/skills/bootstrap/_shared-template.md +4 -4
  321. package/skills/bootstrap/fast-template.md +1 -1
  322. package/skills/bootstrap/private-contract.md +1 -1
  323. package/skills/bootstrap/references/bootstrap-retroactive-flow.md +17 -9
  324. package/skills/bootstrap/templates/agents/project-code-review.md +5 -1
  325. package/skills/bootstrap/templates/agents/project-discovery.md +5 -1
  326. package/skills/bootstrap/templates/agents/project-quality-gate.md +5 -1
  327. package/skills/claude-md-drift-check/SKILL.md +3 -3
  328. package/skills/claude-md-drift-check/checker.mjs +61 -101
  329. package/skills/close/SKILL.md +20 -7
  330. package/skills/discovery/probes/docs-staleness.mjs +7 -5
  331. package/skills/discovery/probes/frontend-slop.mjs +7 -3
  332. package/skills/discovery/probes/ssot-code-diff.mjs +5 -3
  333. package/skills/discovery/probes/supply-chain-slopcheck.mjs +10 -8
  334. package/skills/discovery/probes/vault-narrative-staleness.mjs +30 -10
  335. package/skills/discovery/probes/vault-staleness.mjs +5 -3
  336. package/skills/discovery/probes-session.md +3 -0
  337. package/skills/discovery/probes-vault.md +2 -0
  338. package/skills/dispatcher/SKILL.md +1 -1
  339. package/skills/eval/SKILL.md +3 -1
  340. package/skills/evolve/SKILL.md +2 -0
  341. package/skills/evolve/references/evolve-analyze-mode.md +3 -3
  342. package/skills/evolve/references/evolve-dialectic-mode.md +1 -1
  343. package/skills/gitlab-ops/SKILL.md +7 -6
  344. package/skills/gitlab-portfolio/SKILL.md +2 -2
  345. package/skills/go/SKILL.md +13 -1
  346. package/skills/npm-publish/SKILL.md +5 -2
  347. package/skills/plan/SKILL.md +23 -10
  348. package/skills/plan/mode-feature.md +13 -8
  349. package/skills/plan/mode-new.md +6 -14
  350. package/skills/plan/prd-feature-template.md +19 -0
  351. package/skills/plan/prd-full-template.md +12 -5
  352. package/skills/plan/prd-premortem-panel.md +48 -0
  353. package/skills/plan/prd-reviewer-prompt.md +11 -3
  354. package/skills/plan/soul.md +1 -1
  355. package/skills/portfolio/SKILL.md +5 -6
  356. package/skills/quality-gates/SKILL.md +2 -4
  357. package/skills/reconcile/SKILL.md +27 -4
  358. package/skills/release/SKILL.md +16 -8
  359. package/skills/session-end/SKILL.md +94 -11
  360. package/skills/session-end/phase-3-2-docs-verification.md +1 -0
  361. package/skills/session-end/phase-3-6-tail.md +11 -7
  362. package/skills/session-end/phase-3-7a-recommendations.md +9 -2
  363. package/skills/session-end/plan-verification.md +16 -1
  364. package/skills/session-end/references/phase-3-documentation-updates.md +14 -12
  365. package/skills/session-end/references/phase-5-issue-cleanup.md +1 -1
  366. package/skills/session-end/references/session-summary-template.md +4 -0
  367. package/skills/session-end/session-metrics-write.md +7 -4
  368. package/skills/session-plan/SKILL.md +5 -3
  369. package/skills/session-start/SKILL.md +9 -3
  370. package/skills/session-start/phase-4-5-resource-health.md +11 -5
  371. package/skills/session-start/phase-8-5-express-path.md +4 -3
  372. package/skills/session-start/references/phase-1-2-session-lock.md +7 -5
  373. package/skills/session-start/references/phase-1-5-session-continuity.md +2 -2
  374. package/skills/session-start/references/phase-1-7-vault-status-board.md +1 -1
  375. package/skills/session-start/references/phase-4-ssot-environment-check.md +3 -2
  376. package/skills/tmux-layout/SKILL.md +2 -2
  377. package/skills/vault-sync/validator.mjs +3 -2
  378. package/skills/wave-executor/SKILL.md +5 -4
  379. package/skills/wave-executor/references/wave-executor-state-init.md +3 -3
  380. package/skills/wave-executor/references/wave-loop-dispatch.md +11 -5
  381. package/skills/wave-executor/references/wave-loop-review.md +13 -5
  382. package/skills/wave-executor/references/wave-loop-scope-manifest.md +1 -1
  383. package/assets/og-card.png +0 -0
  384. package/assets/og-card.svg +0 -47
  385. package/assets/wave-lifecycle.svg +0 -98
@@ -35,6 +35,7 @@
35
35
 
36
36
  import { existsSync, readFileSync } from 'node:fs';
37
37
  import { join } from 'node:path';
38
+ import { fileURLToPath, pathToFileURL } from 'node:url';
38
39
 
39
40
  // ---------------------------------------------------------------------------
40
41
  // Constants
@@ -188,15 +189,16 @@ function extractCargoPackages(filePath) {
188
189
  * Attempt to dynamically import classifyPackages from slopcheck.mjs.
189
190
  * Returns null if the module is unavailable (Agent A not yet committed).
190
191
  *
191
- * @param {string} repoRoot
192
192
  * @returns {Promise<Function|null>}
193
193
  */
194
- async function loadClassifyPackages(repoRoot) {
195
- const slopcheckPath = join(repoRoot, 'scripts', 'lib', 'slopcheck.mjs');
194
+ async function loadClassifyPackages() {
195
+ // slopcheck.mjs ships with the PLUGIN: resolve it from this module, never
196
+ // from the scanned repoRoot (#1653 — absent in every consumer repo).
197
+ const slopcheckPath = fileURLToPath(new URL('../../../scripts/lib/slopcheck.mjs', import.meta.url));
196
198
  if (!existsSync(slopcheckPath)) return null;
197
199
 
198
200
  try {
199
- const mod = await import(slopcheckPath);
201
+ const mod = await import(pathToFileURL(slopcheckPath).href);
200
202
  if (typeof mod.classifyPackages !== 'function') {
201
203
  return null;
202
204
  }
@@ -319,7 +321,7 @@ export default async function supplyChainSlopcheck({ repoRoot }) {
319
321
 
320
322
  // ── 4. Load classifyPackages (defensive) ──────────────────────────────────
321
323
 
322
- const classifyPackages = await loadClassifyPackages(repoRoot);
324
+ const classifyPackages = await loadClassifyPackages();
323
325
 
324
326
  if (!classifyPackages) {
325
327
  return {
@@ -333,11 +335,11 @@ export default async function supplyChainSlopcheck({ repoRoot }) {
333
335
  registry: 'internal',
334
336
  classification: 'SKIPPED',
335
337
  evidence: null,
336
- file: join(repoRoot, 'scripts', 'lib', 'slopcheck.mjs'),
338
+ file: 'scripts/lib/slopcheck.mjs',
337
339
  },
338
340
  recommendation:
339
- 'scripts/lib/slopcheck.mjs has not been committed yet. ' +
340
- 'Re-run /discovery after the slopcheck module is available.',
341
+ 'scripts/lib/slopcheck.mjs is missing from the plugin install. ' +
342
+ 'Reinstall or update the plugin.',
341
343
  },
342
344
  ],
343
345
  summary: {
@@ -18,13 +18,17 @@
18
18
  * age_days > T * 2 → medium
19
19
  * age_days > T → low
20
20
  *
21
+ * Passive projects (`_passive.md` marker, #1690) are skipped entirely and
22
+ * counted in `metrics.passive_skipped` (also in the JSONL record).
23
+ *
21
24
  * Missing `updated` field → low / confidence 0.7.
22
25
  * Parse errors → low / confidence 0.6 (errors counter incremented).
23
26
  */
24
27
 
25
28
  import { existsSync, readFileSync, readdirSync, mkdirSync, appendFileSync } from 'node:fs';
26
- import { join } from 'node:path';
29
+ import { dirname, join } from 'node:path';
27
30
  import { expandTilde } from '../../../scripts/lib/common.mjs';
31
+ import { resolveLedgerPath } from '../../../scripts/lib/ledger-path.mjs';
28
32
 
29
33
  // ---------------------------------------------------------------------------
30
34
  // Constants
@@ -32,6 +36,10 @@ import { expandTilde } from '../../../scripts/lib/common.mjs';
32
36
 
33
37
  const NARRATIVE_FILES = ['context.md', 'decisions.md', 'people.md'];
34
38
 
39
+ // Vault convention: `01-projects/<slug>/_passive.md` = no narrative duty.
40
+ // Same marker the vault-staleness probe (#1238) and vault-lint honour.
41
+ const PASSIVE_MARKER = '_passive.md';
42
+
35
43
  const TIER_THRESHOLDS = {
36
44
  top: 30,
37
45
  active: 60,
@@ -109,8 +117,8 @@ function computeSeverity(ageDays, threshold) {
109
117
  return 'low';
110
118
  }
111
119
 
112
- function makeMetricsPath(projectRoot) {
113
- return join(projectRoot, '.orchestrator', 'metrics');
120
+ function makeLedgerPath(projectRoot) {
121
+ return resolveLedgerPath('.orchestrator/metrics/vault-narrative-staleness.jsonl', projectRoot);
114
122
  }
115
123
 
116
124
  // ---------------------------------------------------------------------------
@@ -131,7 +139,7 @@ export async function runProbe(projectRoot, config) {
131
139
  if (!vaultDir) {
132
140
  return {
133
141
  findings: [],
134
- metrics: { scanned_projects: 0, scanned_narratives: 0, stale_narratives: 0, errors: 0 },
142
+ metrics: { scanned_projects: 0, scanned_narratives: 0, stale_narratives: 0, errors: 0, passive_skipped: 0 },
135
143
  duration_ms: Date.now() - startMs,
136
144
  skipped_reason: 'vault-dir not configured',
137
145
  };
@@ -141,7 +149,7 @@ export async function runProbe(projectRoot, config) {
141
149
  if (!existsSync(vaultDir)) {
142
150
  return {
143
151
  findings: [],
144
- metrics: { scanned_projects: 0, scanned_narratives: 0, stale_narratives: 0, errors: 0 },
152
+ metrics: { scanned_projects: 0, scanned_narratives: 0, stale_narratives: 0, errors: 0, passive_skipped: 0 },
145
153
  duration_ms: Date.now() - startMs,
146
154
  skipped_reason: 'vault-dir not found on disk',
147
155
  };
@@ -153,7 +161,7 @@ export async function runProbe(projectRoot, config) {
153
161
  if (!existsSync(projectsDir)) {
154
162
  return {
155
163
  findings: [],
156
- metrics: { scanned_projects: 0, scanned_narratives: 0, stale_narratives: 0, errors: 0 },
164
+ metrics: { scanned_projects: 0, scanned_narratives: 0, stale_narratives: 0, errors: 0, passive_skipped: 0 },
157
165
  duration_ms: Date.now() - startMs,
158
166
  skipped_reason: '01-projects not found in vault',
159
167
  };
@@ -166,6 +174,7 @@ export async function runProbe(projectRoot, config) {
166
174
  let scannedNarratives = 0;
167
175
  let staleNarratives = 0;
168
176
  let errors = 0;
177
+ let passiveSkipped = 0;
169
178
 
170
179
  let projectEntries;
171
180
  try {
@@ -173,7 +182,7 @@ export async function runProbe(projectRoot, config) {
173
182
  } catch (err) {
174
183
  return {
175
184
  findings: [],
176
- metrics: { scanned_projects: 0, scanned_narratives: 0, stale_narratives: 0, errors: 1 },
185
+ metrics: { scanned_projects: 0, scanned_narratives: 0, stale_narratives: 0, errors: 1, passive_skipped: 0 },
177
186
  duration_ms: Date.now() - startMs,
178
187
  skipped_reason: `cannot read 01-projects: ${err.message || err}`,
179
188
  };
@@ -184,6 +193,14 @@ export async function runProbe(projectRoot, config) {
184
193
  const slug = entry.name;
185
194
  const projectDir = join(projectsDir, slug);
186
195
 
196
+ // #1690 — a passive project carries no narrative duty, so its narratives
197
+ // are not findings. Skipped before any read, but COUNTED so the skip is
198
+ // visible rather than indistinguishable from a healthy project.
199
+ if (existsSync(join(projectDir, PASSIVE_MARKER))) {
200
+ passiveSkipped++;
201
+ continue;
202
+ }
203
+
187
204
  scannedProjects++;
188
205
 
189
206
  const tier = readTier(projectDir, slug);
@@ -310,11 +327,13 @@ export async function runProbe(projectRoot, config) {
310
327
  scanned_narratives: scannedNarratives,
311
328
  stale_narratives: staleNarratives,
312
329
  errors,
330
+ passive_skipped: passiveSkipped,
313
331
  };
314
332
 
315
333
  // ── JSONL append ──────────────────────────────────────────────────────────
316
334
  try {
317
- const metricsDir = makeMetricsPath(projectRoot);
335
+ const ledgerPath = makeLedgerPath(projectRoot);
336
+ const metricsDir = dirname(ledgerPath);
318
337
  if (!existsSync(metricsDir)) mkdirSync(metricsDir, { recursive: true });
319
338
  const record = {
320
339
  timestamp: new Date().toISOString(),
@@ -325,6 +344,7 @@ export async function runProbe(projectRoot, config) {
325
344
  scanned_narratives: scannedNarratives,
326
345
  stale_narratives: staleNarratives,
327
346
  errors,
347
+ passive_skipped: passiveSkipped,
328
348
  duration_ms: durationMs,
329
349
  findings: findings.map((f) => ({
330
350
  slug: f.evidence.slug,
@@ -336,7 +356,7 @@ export async function runProbe(projectRoot, config) {
336
356
  })),
337
357
  };
338
358
  appendFileSync(
339
- join(metricsDir, 'vault-narrative-staleness.jsonl'),
359
+ ledgerPath,
340
360
  JSON.stringify(record) + '\n',
341
361
  'utf8',
342
362
  );
@@ -349,7 +369,7 @@ export async function runProbe(projectRoot, config) {
349
369
  // Top-level safety net — probe must never throw
350
370
  return {
351
371
  findings: [],
352
- metrics: { scanned_projects: 0, scanned_narratives: 0, stale_narratives: 0, errors: 1 },
372
+ metrics: { scanned_projects: 0, scanned_narratives: 0, stale_narratives: 0, errors: 1, passive_skipped: 0 },
353
373
  duration_ms: Date.now() - startMs,
354
374
  skipped_reason: `probe error: ${err.message || err}`,
355
375
  };
@@ -37,8 +37,9 @@
37
37
  */
38
38
 
39
39
  import { existsSync, readFileSync, readdirSync, mkdirSync, appendFileSync } from 'node:fs';
40
- import { join } from 'node:path';
40
+ import { dirname, join } from 'node:path';
41
41
  import { expandTilde } from '../../../scripts/lib/common.mjs';
42
+ import { resolveLedgerPath } from '../../../scripts/lib/ledger-path.mjs';
42
43
 
43
44
  // ---------------------------------------------------------------------------
44
45
  // Minimal YAML frontmatter parser — top-level scalar fields only (<30 lines).
@@ -302,9 +303,10 @@ export async function runProbe(projectRoot, config) {
302
303
  })),
303
304
  };
304
305
  try {
305
- mkdirSync(join(projectRoot, '.orchestrator/metrics'), { recursive: true });
306
+ const ledgerPath = resolveLedgerPath('.orchestrator/metrics/vault-staleness.jsonl', projectRoot);
307
+ mkdirSync(dirname(ledgerPath), { recursive: true });
306
308
  appendFileSync(
307
- join(projectRoot, '.orchestrator/metrics/vault-staleness.jsonl'),
309
+ ledgerPath,
308
310
  JSON.stringify(record) + '\n'
309
311
  );
310
312
  } catch {
@@ -485,6 +485,9 @@ const files = readdirSync(dir).filter(f => f.endsWith('.md'));
485
485
  let hasErrors = false;
486
486
  for (const f of files) {
487
487
  const result = validateAgentFile(join(dir, f));
488
+ for (const w of result.warnings ?? []) {
489
+ console.log('WARN: ' + f + ' - ' + w.path + ' (' + w.rule + '): ' + w.message);
490
+ }
488
491
  if (!result.ok) {
489
492
  hasErrors = true;
490
493
  console.log('INVALID: ' + f);
@@ -67,6 +67,8 @@ if (r.skipped_reason) console.log('SKIPPED:', r.skipped_reason);
67
67
 
68
68
  **Tier thresholds (days):** top=30, active=60, archived=180. Tier sourced from `_overview.md` frontmatter; defaults to `active` if missing.
69
69
 
70
+ **Passive skip (#1690):** same marker and form as vault-staleness — a `01-projects/<slug>/` carrying `_passive.md` is skipped BEFORE any narrative is read, excluded from `scanned_projects` and counted in `metrics.passive_skipped` (same key in the JSONL record), so the skip stays visible.
71
+
70
72
  ---
71
73
 
72
74
  **Session-end integration:** When `vault-staleness.enabled: true` in Session Config, these same probes are also invoked at session-end Phase 2.3 — see `skills/session-end/SKILL.md` for the gating logic and strict-mode override behavior. The `/discovery vault` invocation here is the on-demand discovery path; Phase 2.3 is the close-time gate.
@@ -161,7 +161,7 @@ With the lease held, routing splits on whether the chosen entry is model-invocab
161
161
  ## Phase 5: Edge cases
162
162
 
163
163
  - **No free candidate** (`recommended === null` / `free` empty) → report "all repos busy", and offer `resume` (an in-progress session) or `wait` via AUQ. **Never force a selection** of a busy repo.
164
- - **vault off / glab missing** → degrade per the `warnings` array: rank on staleness × readiness only, surface the warning, continue. A missing CLI is never fatal.
164
+ - **glab/gh missing or timed out** → the PRIORITY signal (open critical/high backlog counts via `scanBacklog`, `scripts/lib/dispatcher/rank.mjs`) falls back to a neutral 1 and a `warnings` entry says so: the repo is ranked on staleness × readiness only, surface the warning, continue. A missing CLI is never fatal. Ranking does not read the vault, so `vault-integration` off changes nothing here.
165
165
  - **Host resource probe failed** → readiness is scored without resource dampening (a warning says so); ranking still completes.
166
166
  - **Bad `--start-dir`** → CLI exits 1 (user/input error); fix the path and re-run.
167
167
 
@@ -177,6 +177,7 @@ coordinator thread using the read-only agent `session-orchestrator:eval-judge`
177
177
  ```javascript
178
178
  import { runEvalJudge, mergeJudgeDimensions } from '$PLUGIN_ROOT/scripts/lib/eval/judge.mjs';
179
179
  import { appendEvalRecord } from '$PLUGIN_ROOT/scripts/lib/eval/sink.mjs';
180
+ import { resolveLedgerPath } from '$PLUGIN_ROOT/scripts/lib/ledger-path.mjs';
180
181
 
181
182
  // dispatchAgent = the coordinator's Agent-tool dispatch closure targeting
182
183
  // subagent_type 'session-orchestrator:eval-judge'.
@@ -191,7 +192,8 @@ const { status, dimensions } = await runEvalJudge({
191
192
  const merged = mergeJudgeDimensions(record, dimensions);
192
193
 
193
194
  // The COORDINATOR appends the enriched record (subagents never write the journal).
194
- appendEvalRecord(merged, { path: '.orchestrator/metrics/eval.jsonl' });
195
+ // In a linked worktree the main checkout's journal when it is gitignored there (#1722).
196
+ appendEvalRecord(merged, { path: resolveLedgerPath('.orchestrator/metrics/eval.jsonl', process.cwd()) });
195
197
  ```
196
198
 
197
199
  - The judge dimension arrives `advisory: true` + `calibration_status:
@@ -100,6 +100,8 @@ Route based on mode:
100
100
 
101
101
  Extracts learnings from session history: pattern extraction across the 9 built-in analyzer types plus `evolve.extra-sources`, deduplication, relation judgment (#1016), the AskUserQuestion confirmation gate, and the archive-safe write pipeline (through the C2 auto-repair feeder). See [references/evolve-analyze-mode.md](references/evolve-analyze-mode.md). **Read WHEN:** Phase 2's Mode Dispatch routes to `analyze` (the default mode).
102
102
 
103
+ **Agent-usage census (#1617).** Before extraction, run `node "${CLAUDE_PLUGIN_ROOT:-${CODEX_PLUGIN_ROOT:-$PLUGIN_ROOT}}/scripts/agent-usage-census.mjs" --days 14` (read-only over `~/.claude/projects` subagent transcripts, ~20 s for 14 days). Report the model shares and the top agent types (runs, turns/run, output/run, cache rebuilds, start context) in the analyze summary, and quote `malformed_lines`. It is an observation, not a learning source: nothing is written from it, and a shift (a type moving model, a new dominant type) goes to the operator as a finding. Housekeeping step 4 runs `/evolve analyze`, so the weekly maintenance loop carries the census without a second entry.
104
+
103
105
  ---
104
106
 
105
107
  ## Phase 4: Review Mode
@@ -51,7 +51,7 @@ For each of the 9 built-in analyzer learning types, apply these heuristics.
51
51
 
52
52
  - `waves[].files_changed` is a COUNT (a number), never a list of paths — do not iterate it (#1321). File identity comes from git, the method of `skills/session-end/learning-patterns.md:13`, run per session over its commit range:
53
53
  `git log --name-only --format="" <session_start_ref>..<end_ref> | sort | uniq -c | sort -rn`
54
- with `<end_ref>` = the record's `end_ref` / `session_end_ref`; when neither exists use `HEAD` plus `--until=<completed_at>`. Records without `session_start_ref` fall back to `git log --name-only --format="" --since=<started_at> --until=<completed_at>`.
54
+ with `<end_ref>` = the record's `end_ref` / `session_end_ref`; when neither exists use `HEAD` plus `--until=<completed_at>`. When the record carries `session_work_trees: [{tree, start_ref}]`, run the same log once per entry, each inside its own tree (`git -C <tree> log …`) with its own ref — never apply one tree's ref in another tree — and add the results to the counts. Records without `session_start_ref` fall back to `git log --name-only --format="" --since=<started_at> --until=<completed_at>`.
55
55
  - **Prefer the ref range; label the fallback.** Only 26 of 201 real records carry `session_start_ref` (measured 2026-09-12), so most analyses land on the time-window fallback. That window also picks up commits a PARALLEL session made on the same branch in the same hours — it attributes foreign commits to this session. Use the ref range wherever the record has one, and mark every candidate whose evidence came from the fallback as `window: time (unattributed)` in its `evidence`.
56
56
  - Within a session: a file changed in 3+ commits of that session's range is fragile. Here the population rule's `n` counts the **commits in that session's range**, not records — one session is always one record, so counting records would WARN on every within-session check
57
57
  - Cross-session: if a file appears in 3+ different sessions' ranges, flag it
@@ -60,7 +60,7 @@ For each of the 9 built-in analyzer learning types, apply these heuristics.
60
60
  #### 2. effective-sizing (type: `effective-sizing`)
61
61
 
62
62
  - Compare `total_agents` and `total_waves` across session types
63
- - Calculate average agents per wave for each session type. Read a wave's agent count defensively — older records use other keys: `agent_count`, else `agents` when it is a number, else the length of `agents` when it is an array (of descriptions), else `agents_dispatched`. A record with `total_waves: 0` contributes no per-wave ratio — skip it rather than divide by zero. Exclude coordinator-direct waves (`coordinator_direct: true`, which dispatched no agents) from the ratio. In particular, a record whose waves are all coordinator-direct `Housekeeping` waves (predicate `isCoordinatorDirectHousekeeping` in `scripts/lib/session-schema/filters.mjs`, the session-end writer shape since #1321) contributes no per-wave ratio, same as `total_waves: 0`. Counting it would log a false 0.0 agents-per-wave observation.
63
+ - Calculate average agents per wave for each session type. Read a wave's agent count with `waveAgentCount(wave)` (`scripts/lib/session-schema/filters.mjs`) — older records use other keys: `agent_count`, else `agents` when it is a number, else the length of `agents` when it is an array (of descriptions), else `agents_dispatched`, else `agent_count_started` / `agents_started`; no key → unmeasured, skip the wave. A record with `total_waves: 0` contributes no per-wave ratio — skip it rather than divide by zero. Exclude coordinator-direct waves from the ratio with `isCoordinatorDirectWave(wave)`: `coordinator_direct: true` OR a measured count of 0 without the flag (#1652 — 222 of 238 0-agent waves in this ledger carry no flag, measured 2026-10-17; excluding only flagged waves lowered the average from 3.92 to 2.96). When a candidate reports per-role numbers, group roles by `normalizeWaveRole(role)` (case- and separator-insensitive: `Finalization`/`finalization`, `Express-Path`/`Express Path` are one role). In particular, a record whose waves are all coordinator-direct `Housekeeping` waves (predicate `isCoordinatorDirectHousekeeping` in `scripts/lib/session-schema/filters.mjs`, the session-end writer shape since #1321) contributes no per-wave ratio, same as `total_waves: 0`. Counting it would log a false 0.0 agents-per-wave observation.
64
64
  - **Group by `(session_type, session_profile)` (#1247), never by `session_type` alone.** `ultradeep` is a PROFILE over `session_type: deep` (7 waves vs. deep's 4-5, STATE.md frontmatter key `session-profile` — see `scripts/lib/state-md.mjs`), not a distinct type, so a bare `session_type` grouping folds a 7-wave ultradeep session and a 5-wave deep session into the same row and silently averages their agents-per-wave numbers together.
65
65
  - Subject = `sizingSubject({ session_type, session_profile })` from `scripts/lib/learnings/sizing-subject.mjs` — e.g. `deep-session-sizing` (no profile, byte-identical to the pre-#1247 literal), `deep-ultradeep-session-sizing` (profile `ultradeep`), or `feature-session-sizing`. Always derive via this helper; do not hand-concatenate the subject string.
66
66
  - Insight = "Deep sessions average X agents across Y waves" or "Ultradeep sessions average X agents across Y waves" (name the profile in the insight whenever `session_profile` is present, so the two rows read as distinct sizing observations, not variants of one sentence)
@@ -105,7 +105,7 @@ For each of the 9 built-in analyzer learning types, apply these heuristics.
105
105
  - Five detection signals (aggregated per `(signal, host_class)` pair, ≥2 occurrences required):
106
106
  - **oom-kill** — `orchestrator.turn.stopped` (or its deprecated alias `orchestrator.session.stopped`, which `hooks/on-stop.mjs` still emits with `deprecated: true` until **2027-03-06**) with `exit_code: 137` or OOM-marker in `error`. Both names are accepted for the deprecation window because every OOM record already on disk carries only the legacy name; the detector's set lives in `OOM_TERMINAL_EVENTS` (`scripts/lib/hardware-pattern-detector.mjs`) and drops the alias on that date.
107
107
  - **heartbeat-gap** — registry sweep-log entries with `gap_minutes` above `resource-thresholds.zombie-threshold-min`
108
- - **concurrent-session-pressure** — session-start events with `peer_count ≥ concurrent-sessions-warn`
108
+ - **concurrent-session-pressure** — session-start events inside a start wave: `recent_starts_count ≥ 5` foreign starts in the preceding 5 min (`DEFAULT_THRESHOLDS.startWaveMin`, mirrors `START_WAVE_MIN` in `hooks/on-session-start.mjs`). Re-aimed in #1654 off `peer_count ≥ concurrent-sessions-warn`, which held on 67.4% of M4 starts (a standing condition, HR-101). Events without a numeric `recent_starts_count` (all pre-#1650 records) are skipped, never counted. Not fed from `concurrent-sessions-warn`.
109
109
  - **disk-full** — events whose `error` matches `ENOSPC` / "no space left"
110
110
  - **thermal-throttle** — events whose `resource_snapshot.cpu_load_pct` crosses `cpu-load-max-pct`
111
111
  - Each candidate is piped through `candidateToLearning()` → `validateLearning()`. Default `scope` is `private` (in-repo only). To promote to `public`, the user runs `npm run share:hw-learnings -- --promote` (C3 export). This anonymizes each `private` hardware-pattern entry, validates via the privacy contract, and appends a `public` twin to `learnings.jsonl` (original preserved). Use `--dry-run` to preview without writing.
@@ -103,7 +103,7 @@ const result = await runDialecticDeriver({
103
103
  | Text before the first `## ` heading | — | NOT applied | `preamble` + a `{ type: 'unmapped-preamble' }` entry in `conflicts[]` |
104
104
  | Falls inside an existing managed region that wraps MORE than one `## ` heading | — | NOT applied — the region stays byte-unchanged (no replace, which would delete its sibling headings' hand-written text; no append, which would duplicate the heading) | `{ type: 'multi-heading-region', region, headings, skipped }` in `conflicts[]` — `region` is the region's section name, `headings` the `## ` headings it wraps, `skipped` the proposed headings dropped. Operator action: split the region by hand into one managed region per heading, then re-run — or discard the proposal for those headings |
105
105
 
106
- Existing names are read back out of the card rather than re-derived because the live names are not a pure function of their headings — measured 2026-09-11 in `.orchestrator/peers/AGENT.md`: `## Guard and protocol-migration discipline` → `guard-and-protocol-migration`. Re-slugifying would APPEND a duplicate section instead of replacing one.
106
+ Existing names are read back out of the card rather than re-derived because the live names are not a pure function of their headings — measured 2026-09-11 in this repo's `AGENT.md` peer card: `## Guard and protocol-migration discipline` → `guard-and-protocol-migration`. Re-slugifying would APPEND a duplicate section instead of replacing one.
107
107
 
108
108
  **Present `conflicts[]` before writing.** A non-empty `conflicts[]` (`duplicate-section`, `orphan-begin`, `unmapped-preamble`, `multi-heading-region`) is operator-visible content that the merge did not place — report it beside the delta line rather than writing silently.
109
109
  - **Close the loop — after a successful `--apply` AND after the operator explicitly discards a reviewed proposal** (never after a dry-run, a failure, a skip, or the drift-check's "keep the sidecar for another review" branch above): record the run and consume the sidecar, both from `scripts/lib/auto-dialectic.mjs`. Without these two calls the maintenance-due probe keeps `dialectic` (measured against `.orchestrator/dialectic-last-run`) and `pending-sidecar` (`.orchestrator/dialectic-pending.md` younger than 14 days) due forever — nothing else writes the one or moves the other (#1380). Both return `{ ok, error? }` and never throw; log a failure and continue. Since #1388 `consumeDialecticPending` MOVES the sidecar to `.orchestrator/consumed/<timestamp>-dialectic-pending.md` (newest 10 retained) instead of deleting it, so the reviewed text survives the apply; `archivedTo` on the result names the file. <!-- path-check: example -->
@@ -111,8 +111,8 @@ done
111
111
  **Taxonomy convention — `priority` REVERSED to scoped `::` (supersedes #727 for this one axis).**
112
112
 
113
113
  - **`priority::<level>` is canonical.** #727's stated rationale was that "this repo mirrors to GitHub, which has no scoped-label semantics … while a migration would break every existing label reference and issue." Both halves were checked on 2026-07-25 and neither holds:
114
- - **Issues are not mirrored at all.** `aiat-poc-infra/docs/github-mirror-runbook.md:1,5` describes a git **push-mirror** with GitHub as "read-only downstream"; the external team-organization audit `docs/gitlab-team-org-2026-06-21.md:45` confirms there is no two-way GitLab issue sync. Nothing crosses the boundary that a label rename could break. <!-- path-check: example -->
115
- - **GitHub already uses the scoped form.** `gh api "repos/AIAT-AIandBusinessgrowth/aiat-barrierefrei-engine/labels"` returns `priority::high`, `priority::low`, `priority::med`, `priority::medium` across 77 open issues, and **zero** `priority:high`. Same pattern on `aiat-doc-vlm`. GitHub treats `::` as an ordinary string; it merely does not enforce mutual exclusion.
114
+ - **Issues are not mirrored at all.** A consumer infra repo's GitHub-mirror runbook describes a git **push-mirror** with GitHub as "read-only downstream"; the external team-organization audit `docs/gitlab-team-org-2026-06-21.md:45` confirms there is no two-way GitLab issue sync. Nothing crosses the boundary that a label rename could break. <!-- path-check: example -->
115
+ - **GitHub already uses the scoped form.** On a GitHub consumer repo, `gh api "repos/<owner>/<repo>/labels"` returns `priority::high`, `priority::low`, `priority::med`, `priority::medium` across 77 open issues, and **zero** `priority:high`. Same pattern on a second consumer repo. GitHub treats `::` as an ordinary string; it merely does not enforce mutual exclusion.
116
116
  - Volume agrees independently: **416 `priority::` against 249 `priority:` and 7 bare** at the time of the decision. Chasing the minority spelling would mean re-labelling the majority.
117
117
  Producers were migrated FIRST (this change); the label-data migration follows separately, because migrating data before producers means the divergence returns within a day.
118
118
  - **`area:` / `type:` / `status:` / `from:` stay SINGLE-COLON** — but NOT on #727's rationale, which is disproven above. They stay because nothing measured argues for flipping them, and because each axis is its own migration cost. Flipping them is a separate decision and is explicitly NOT made here. Note that `status` in particular is the worst-disciplined axis on the instance (354 assignments, only 48 percent scoped, 5 genuine value conflicts), so any future flip there needs a conflict-resolution pass first.
@@ -355,9 +355,10 @@ Accepted template paths are configured in `.orchestrator/policy/templates-policy
355
355
 
356
356
  1. **Read the template first** — re-run the `create` call after a `Read` on the template
357
357
  path; the hook re-evaluates and sees the Read.
358
- 2. **Session acknowledgement** — write `.orchestrator/runtime/templates-acknowledged.json`
359
- containing `{ sessionId, acknowledgedAt }`; the hook allows all subsequent `create`
360
- calls in this session.
358
+ 2. **Session acknowledgement** — run `/templates-ack [reason]` (`commands/templates-ack.md`);
359
+ it verifies the invoking session before recording the acknowledgement, and the hook
360
+ then allows all subsequent `create` calls in this session. Never write the
361
+ acknowledgement file by hand — that skips the command's session check.
361
362
 
362
363
  **What the hook mechanically enforces** (what this skill previously documented as convention only):
363
364
 
@@ -391,6 +392,6 @@ gh pr create -R <OWNER>/<REPO> --title "..." --body "..."
391
392
  - Hook implementation: `hooks/pre-bash-templates-first.mjs`
392
393
  - Read-history helper: `hooks/_lib/transcript-history.mjs` (checks session transcript for prior Reads)
393
394
  - Enforcement policy: `.orchestrator/policy/templates-policy.json`
394
- - Session acknowledgement: `.orchestrator/runtime/templates-acknowledged.json`
395
+ - Session acknowledgement: `/templates-ack` (`commands/templates-ack.md`), the only sanctioned writer
395
396
  - Sister hook (destructive-command model): `hooks/pre-bash-destructive-guard.mjs`
396
397
  - PRD: "gsd Pattern Adoption Quick-Wins" (#519; archived in the private Meta-Vault) § Pattern 3 + § 3 Gherkin Pattern 3
@@ -185,9 +185,9 @@ repos: 2
185
185
 
186
186
  ## Error handling
187
187
 
188
- Behaviour is governed by `mode`. `warn`: emit warning to stderr, continue with partial data; repo rows show `(fetch failed)`. `strict`: any repo fetch failure or missing vault-dir exits 3 immediately. `off`: all errors are silently swallowed, partial data written.
188
+ Behaviour is governed by `mode`. `warn`: emit warning to stderr, continue with partial data; repo rows show `(fetch failed)`. `strict`: any repo fetch failure exits 2 after the scan. `off`: the CLI exits 0 with one line before resolving the vault-dir or scanning any repo, and writes nothing (#1619).
189
189
 
190
- `--vault-dir` not found and write errors always exit 2 regardless of `mode`. `_PORTFOLIO.md` with no `_generator` key always results in `skipped-handwritten` (all modes). No repos discovered: `warn` → exit 0 (no file written); `strict` → exit 3.
190
+ `--vault-dir` not found and write errors always exit 2 regardless of `mode`. `_PORTFOLIO.md` with no `_generator` key always results in `skipped-handwritten` (all modes). No repos discovered: exit 0 in every mode (no file written).
191
191
 
192
192
  ## Anti-Patterns
193
193
 
@@ -10,6 +10,17 @@ model: inherit
10
10
 
11
11
  The user has approved the session plan. Begin execution immediately.
12
12
 
13
+ ## No plan to execute
14
+
15
+ Before executing either path below, check for a plan. A plan exists when either holds:
16
+
17
+ - the conversation — including a context-compaction summary — contains a session-plan result that offers `Use /go to begin.` (wave plan or Express Path plan);
18
+ - `<state-dir>/STATE.md` has `status: active` or `status: paused` and its frontmatter `session-id` (the raw harness id) equals this process's own raw id — `readProcessLocalSessionIds()` in `scripts/lib/session-identity/own-session.mjs` (Claude Code: `$CLAUDE_CODE_SESSION_ID`; `readInvocationSessionId()` there is the ancestor-process proof). That is an interrupted wave execution of this session; the raw id survives a context compaction.
19
+
20
+ Never decide this by the labels STATE.md `session`, `semantic_session_id` or `.orchestrator/current-session.json`: they are repo-wide, and a peer session started later in the same repo owns them (`skills/_shared/state-ownership.md` § Session Identity and Lock Ownership). A STATE.md without `session-id`, without a measurable own id, or not `active`/`paused` proves nothing: session-plan does not write it, and the wave-executor sets `status: active` only when execution starts. If neither holds, print the line `/go: kein Plan vorhanden – nichts ausgeführt` and end the answer with the wait sentence `Ich warte auf den nächsten Auftrag.` (or `Bereit zum Schließen.` when the fleet handover applies) — the status line alone is not recognised as a waiting answer (`skills/_shared/fleet-protocol.md` § Rücklauf an den Navigator, Wartesatz). Do not re-plan or start a new session.
21
+
22
+ In this no-plan case apply `skills/_shared/fleet-protocol.md` § Rücklauf an den Navigator (Pflicht) with the wait case `go-ohne-plan`: measure fleet and lease read-only (no check-in) and send exactly ONE report in this turn, even if an earlier turn already reported the same case (`SendMessage` with an active, reachable lease; on failure or otherwise a Lead-Todo; if that fails too, `Meldung gescheitert: <Grund>` in the last paragraph) — the session, `/go ohne Plan`, the time from `date`, and what the session needs next. Never wait for a reply (CSM-004). Return without executing work.
23
+
13
24
  ## Invocation
14
25
 
15
26
  Invoked as `/go [optional instructions]` with arguments: **$ARGUMENTS**. The user has approved the session plan; begin execution immediately.
@@ -38,7 +49,8 @@ If the banner is present (and the session-plan output emitted a 1-wave Express P
38
49
  await appendDeviationOnDisk(repoRoot, new Date().toISOString(), 'Express path: <N> tasks executed coord-direct (express-path.enabled: true, session-type: housekeeping, scope: <N> issues)');
39
50
  "
40
51
  ```
41
- 3. **Invoke `session-orchestrator:session-end`** directly via the `Skill` tool. Session-end finalizes STATE.md (sets `status: completed`, writes `.orchestrator/metrics/sessions.jsonl`, runs vault-mirror if enabled). Without this auto-invocation, every Express Path run leaves no audit trail (issue #320).
52
+ 3. **Fleet check (#1620), then close.** Measure fleet integration first with the read-only one-liner in `skills/_shared/fleet-protocol.md` § Rücklauf an den Navigator. On `flotte: true` (fleet integration on this host, with or without an active lease) the session does NOT close itself (fleet-protocol § Übergabe Punkt 4): skip the rest of this step and steps 4–5. Instead give the session summary first, then report the wait case `fertig`, write the hand-over and end the reply with `Bereit zum Schließen.` as its last sentence, per fleet-protocol § Übergabe und Zug-Manifest (the coordinator only reads the last 600 characters). The deviation from step 2 is already on disk; the coordinator triggers `/close`, and the regular session-end flow finalizes STATE.md — the step-4 persistence check does not run on this path. On `flotte: false` continue:
53
+ **Invoke `session-orchestrator:session-end`** directly via the `Skill` tool. Session-end finalizes STATE.md (sets `status: completed`, writes `.orchestrator/metrics/sessions.jsonl`, runs vault-mirror if enabled). Without this auto-invocation, every Express Path run leaves no audit trail (issue #320).
42
54
  4. **Verify persistence after session-end completes:** read `<state-dir>/STATE.md` and confirm `frontmatter.status === 'completed'` and the body's `## Deviations` section contains an `Express path:` entry. If either is missing, warn the user inline with: `⚠ Express Path persistence verification failed — STATE.md not finalized. Re-run /close manually.` Then return the final summary.
43
55
  5. **Return** the session summary to the user. The express-path execution is complete.
44
56
 
@@ -7,7 +7,7 @@ description: Use when publishing this package to npm — a version release (npm
7
7
 
8
8
  # npm-publish — token auth, and the calls the script cannot make
9
9
 
10
- > **The release itself is `/release` → `scripts/release.mjs`.** That script mechanizes the whole sequence: version surfaces, CHANGELOG gate, drift sweep, tag/registry collision, CI, leakage gate, publish, the target-confirmed npm receipt boundary, tag-after-receipt, push to both remotes, GitHub-release handling, and live-site poll. This skill does not restate it.
10
+ > **The release itself is `/release` → `scripts/release.mjs`.** That script mechanizes the whole sequence: version surfaces, CHANGELOG gate, drift sweep, tag/registry collision, CI, leakage gate, publish, the target-confirmed npm receipt boundary, tag-after-receipt, push to both remotes (under `mirror: curated` the GitHub side gets the verified export snapshot as main and the tag on that snapshot, never the release commit — `docs/github-mirror-protection.md` § Releases under `mirror: curated`), GitHub-release handling, and live-site poll. This skill does not restate it.
11
11
  >
12
12
  > What lives here is the half a script cannot own: the **token setup**, the **auth failure diagnosis**, and the **judgement calls** — which version, what a leak means, when to abort rather than repair.
13
13
 
@@ -29,6 +29,8 @@ Create at https://www.npmjs.com/settings/<user>/tokens → Generate New Token
29
29
  1. `NPM_TOKEN` in `.env.local` at the repo root (gitignored — verify with `git check-ignore .env.local` before writing; also confirm no `.env` pattern in the `files` whitelist of package.json). `scripts/release.mjs` refuses to read the token if that ignore check fails.
30
30
  2. Interactive fallback: operator runs `npm publish --access public` in a real terminal (only works when account 2FA is enrolled — OTP prompt appears).
31
31
 
32
+ `release --check` verifies the token before any publish: `npm-token-live` (`npm whoami`) proves it authenticates, `npm-token-publish` reads `npm token list --json`, finds the token in use by its abbreviated `npm_xxxx...xxxx` form, and goes red when it lacks `bypass_2fa`, write `permissions`, a matching `scopes` entry, or has passed `expiry`/been `revoked` — the 5.13.0 EOTP case, where `whoami` was green. `npm token list` works with a granular token; `npm profile get` does not (npm 11.19.1, 2026-10-21).
33
+
32
34
  **Never** put the token in the tracked `.npmrc` (it holds `ignore-scripts=true` per SEC-020 and is committed), never persist it into `~/.npmrc`, never echo it into logs.
33
35
 
34
36
  ## The three judgement calls
@@ -39,7 +41,7 @@ The script gates mechanics. These three are yours, and it will not make them for
39
41
 
40
42
  **2. What a leak means when one is found.** A hit from the leakage gate is not a pattern to silence. Decide which of two it is: a real leak (fix `package.json` `files`, re-pack, re-check) or genuine over-matching (fix `LEAKAGE_PATTERNS` in `scripts/release.mjs` **with a test**). There is no third option, and neither is "publish anyway and clean it up in the next version" — an npm publish is not revocable, and unpublishing burns the version number permanently. Operator handling detail: `docs/distribution/npm-publish-checklist.md` § 3.
41
43
 
42
- **3. When to abort instead of repair.** Abort — do not patch forward — when the failure is upstream of the target-confirmed npm receipt: a red preflight row, a lagging `github` mirror, CI not green on the exact commit **on either platform** (`--check` carries both `ci-green-on-head` for GitLab and `ci-green-on-head-github` for the mirror, whose macOS matrix leg has no GitLab equivalent), a dead token, or a publish that did not issue the target receipt. These are cheap to fix and re-run from the top. Repair-in-place is only appropriate *after* that receipt, where the version is already immutable: registry availability (`--reconcile`), a missing GitHub release, or a lagging site deploy can be reconciled because npm already has the correct artifact. When `--publish` reports **Post-publish reconciliation required**, **do not rerun `--publish`**; repair the listed state directly. `skills/release/SKILL.md` § Abort criteria is the operative list.
44
+ **3. When to abort instead of repair.** Abort — do not patch forward — when the failure is upstream of the target-confirmed npm receipt: a red preflight row, a lagging `github` mirror (under `mirror: curated`: github/main is not yet the snapshot of the release commit — run `/close` first), CI not green on the exact commit **on either platform** (`--check` carries both `ci-green-on-head` for GitLab and `ci-green-on-head-github` for the mirror, whose macOS matrix leg has no GitLab equivalent), a dead token, or a publish that did not issue the target receipt. These are cheap to fix and re-run from the top. Repair-in-place is only appropriate *after* that receipt, where the version is already immutable: registry availability (`--reconcile`), a missing GitHub release, or a lagging site deploy can be reconciled because npm already has the correct artifact. When `--publish` reports **Post-publish reconciliation required**, **do not rerun `--publish`**; repair the listed state directly. `skills/release/SKILL.md` § Abort criteria is the operative list.
43
45
 
44
46
  ## Failure-mode table
45
47
 
@@ -47,6 +49,7 @@ The script gates mechanics. These three are yours, and it will not make them for
47
49
  |---|---|---|
48
50
  | `E403 ... Two-factor authentication or granular access token with bypass 2fa enabled is required` — no OTP prompt | Account has no 2FA enrolled AND token (if any) lacks Bypass-2FA | Create granular token with all four requirements above, or enroll 2FA |
49
51
  | Same E403 despite a fresh token | Token created without the Bypass-2FA checkbox, or Read-only, or package-scoped on a first publish | Re-create: RW + All packages + Bypass-2FA |
52
+ | `EOTP` from `npm publish` while `npm whoami` is green | Granular token without Bypass-2FA (5.13.0) | Re-create with Bypass-2FA; `release --check` row `npm-token-publish` now catches it before the publish |
50
53
  | `npm whoami` silent or non-zero | Token expired, or `.env.local` missing | Re-create the token; do not proceed — the preflight fails this row on purpose |
51
54
  | `E404` on `npm view <pkg>@<target>` after a target-confirmed publish receipt (npm answered HTTP 202) | The upload is **accepted, not yet available**. npm scans every new publish before it becomes installable: "typically around five minutes", "up to 15 minutes or more" at peak or depending on content/size, no service guarantee; the outcome may be published, **held for manual review**, or **blocked** (GitHub changelog 2026-07-28, read 2026-10-08, npm CLI 11.19.0). 5.10.0 stayed 404 for more than 25 minutes. A 404 alone does **not** tell you which of these applies — the package token cannot see the scan state | Let the script finish its tag/push/GitHub/site tail, then run `node scripts/release.mjs --reconcile --target <target>` (read-only, resumable; exit 0 only once installable). While still `pending`, check the owner-visible side: npm says a blocked package's publisher "may receive a notification with the option to appeal" — look at the npm account notifications/e-mail of the publishing account and the package page on npmjs.com. Do **not** rerun `--publish` and do not declare it blocked from the 404 |
52
55
  | `ENEEDAUTH` | No login/token at all | Token flow above, or `npm login` |
@@ -46,6 +46,7 @@ Interactive sessions are unaffected — `/plan` works there as it always has.
46
46
  - `mode-feature.md` — Feature PRD: 2 Q&A waves, compact scope, acceptance criteria
47
47
  - `mode-retro.md` — Retrospective: metrics analysis, reflection waves, improvement actions
48
48
  - `soul.md` — Product Strategist identity and behavioral anchor
49
+ - `prd-premortem-panel.md` — Phase 4.5 Refute + Deepen briefs (pre-mortem against the code)
49
50
 
50
51
  ## Soul Reference
51
52
 
@@ -125,6 +126,10 @@ Before each Q&A wave, dispatch 2-3 `Agent()` tool calls in a single message (par
125
126
  2. **Baseline analysis agent** — reads projects-baseline templates, rules, and scripts at `$BASELINE_PATH` to discover available options (archetypes, styles, configurations). Tools: Read, Glob, Grep.
126
127
  3. **Repo context agent** (skip for `/plan new` wave 1) — analyzes the current repository for existing patterns, file structure, dependencies, and conventions. Tools: Read, Glob, Grep.
127
128
 
129
+ **Raw material before digest.** Brief the repo and baseline agents to start from the rawest reachable material, not from what has already been summarised: the code path that actually runs (caller census), the installed artifact or platform contract, live event or process data, a real run's output, the git history of the area. Issue text and docs come second. Two asks are mandatory in Wave 1:
130
+ - **Reproduce the premise.** Re-measure the stated problem with a quoted command. If it does not reproduce, record it as a hypothesis in PRD § Evidence Baseline.
131
+ - **Census local equivalents.** What already exists for this need (`build-value.md` BV-001 rung 2)? In 12 measured `/plan` runs the operator corrected 3 options with "that already exists".
132
+
128
133
  Example dispatch:
129
134
 
130
135
  ```
@@ -138,15 +143,9 @@ Agent({ subagent_type: "Explore", description: "Analyze repo context",
138
143
 
139
144
  Wait for ALL agents to complete before proceeding. Use `run_in_background: false` for all agents.
140
145
 
141
- ### Opportunity Score (Ranking Candidate Subfeatures)
142
-
143
- When a Wave 1 "what to build" question surfaces multiple candidate subfeatures (rather than one clear scope), rank the candidates before recommending one. Score each candidate:
144
-
145
- ```
146
- Opportunity Score = Importance × (1 − Satisfaction)
147
- ```
146
+ ### Ranking Candidate Subfeatures
148
147
 
149
- Both `Importance` and `Satisfaction` are estimated on a 0..1 scale from the Wave 1 research/Explore agent findings (market signal, existing-issue signal, repo-pattern signal) — not asked of the user directly. Rank candidates descending by score; the top-ranked candidate becomes the `(Recommended)` Option 1 in the AskUserQuestion payload for that question. Apply this only when genuinely multiple candidates are surfaced — a single well-defined feature needs no ranking.
148
+ When a Wave 1 "what to build" question surfaces several candidate subfeatures, rank them by measured signal: how often the problem shows up in events, issues or transcripts, and how much each one blocks. Cite the count and the command that produced it. With no measured signal, rank ordinally and say so. Never invent a score. The top candidate becomes the `(Recommended)` Option 1.
150
149
 
151
150
  ### 3.2 Question Presentation
152
151
 
@@ -157,6 +156,7 @@ Synthesize research results into 5 questions per wave. Split across 2 AskUserQue
157
156
  - Each option includes a `description` with Pros/Cons drawn from the research
158
157
  - Include an "Other" option when custom input makes sense
159
158
  - Use `multiSelect: false` unless the question genuinely requires multiple selections
159
+ - If two options are not mutually exclusive (a default plus an opt-in, or both modes behind one switch), offer that combination as an option of its own. In 12 measured runs, 50 of 156 answers were free text, and 17 of those read "as recommended, but …".
160
160
 
161
161
  Example payload:
162
162
 
@@ -237,6 +237,12 @@ Use today's date. Derive the name slug from the project name (for new) or featur
237
237
 
238
238
  Ensure the target directory exists (create with `mkdir -p` if needed) before writing.
239
239
 
240
+ ## Phase 4.5: Pre-Mortem Panel (skip for retro mode)
241
+
242
+ Dispatch the two read-only briefs in `prd-premortem-panel.md`, Refute and Deepen, as two `Agent()` calls in one message. Pass each the PRD path and its brief verbatim. Then merge their reports into the PRD per that file's § Coordinator merge: re-checked predictions go into § Risks, every acceptance criterion gets an `Oracle:` line, and criteria whose oracle cannot run in the implementing session go into § External Acceptance. A raw-material finding that contradicts the PRD's premise goes to the operator before Phase 5.
243
+
244
+ Why this phase exists: replayed against their later history, three shipped PRDs anticipated 0 of 43 recorded surprises. The two briefs together hit 11 and found different classes (`prd-premortem-panel.md` § Why two briefs). The PRD reviewer below checks form; this panel checks the plan against the code.
245
+
240
246
  ## Phase 3.5: Package Legitimacy Audit (Slopcheck — #520)
241
247
 
242
248
  > Despite the name, this phase runs *after* Phase 4 (Document Generation) and *before* Phase 5 (PRD Review). The "3.5" identifier is historical, anchored to the PRD's Pattern-2 specification so cross-references stay searchable.
@@ -292,7 +298,7 @@ generation due to slopcheck failure — log + continue.
292
298
 
293
299
  Dispatch a reviewer subagent: read `prd-reviewer-prompt.md` in this skill directory for review instructions. Pass the full PRD content to the reviewer.
294
300
 
295
- The reviewer checks 7 criteria:
301
+ The reviewer checks 8 criteria:
296
302
  1. **Completeness** — all sections filled, no TBD or placeholder content
297
303
  2. **Consistency** — no internal contradictions between sections
298
304
  3. **Clarity** — unambiguous enough that a developer could implement from this document alone
@@ -300,6 +306,7 @@ The reviewer checks 7 criteria:
300
306
  5. **YAGNI** — no unrequested features or gold-plating
301
307
  6. **SMART metrics** — success criteria are Specific, Measurable, Achievable, Relevant, Time-bound
302
308
  7. **User Stories** (gated — active only when a populated ## User Stories section is present) — section present, every story in one complete form (either the Als/möchte/damit persona form, or the job-story form: "When [situation], I want [motivation], so I can [outcome]"), each story links ≥1 acceptance criterion; SKIP when no User Stories section. No INVEST checks.
309
+ 8. **Verifiability**: every acceptance criterion names an `Oracle:` that is not the author's own unit test against a fake. Every External Acceptance row has an owner, a not-before date, a pass condition and a fallback. The Evidence Baseline quotes the command that measured the premise.
303
310
 
304
311
  ### 5.2 Revision Loop
305
312
 
@@ -353,6 +360,8 @@ Do NOT proceed to Phase 6 (Issue Creation) until the generated document (PRD or
353
360
 
354
361
  Two prior `/plan` sessions filed issues referencing a PRD path that no downstream session could find, because the document was written to disk (Phase 4.3) but never committed (issue #784). This gate closes that gap mechanically, right after user approval (Phase 5) and before any issue is filed (Phase 6). It applies to every mode that reaches Phase 6 — including `/plan retro`, which skips Phase 5's review loop but still saves a document and (conditionally) files issues.
355
362
 
363
+ **`/plan new`:** the target repo does not exist until `mode-new.md` Phase 3 creates it, and the directory the planning ran from may not be a repo at all. There, `mode-new.md` Phase 3 Step 6 meets this gate: it copies the PRD into the new repo and commits it, then § 5.5.2 runs against that repo. Phase 6 files issues only after that.
364
+
356
365
  ### 5.5.1 Commit the Document
357
366
 
358
367
  The Epic issue does not exist yet at this point in the flow — do NOT reference an issue number in the commit message. Use a session-dated message instead:
@@ -399,6 +408,8 @@ The Epic issue's number is not known during § 5.5.1. Once Phase 6 creates it, s
399
408
  - **`/plan feature`** — derive from PRD Section 3 (Acceptance Criteria). Each Given/When/Then block becomes a sub-issue. Group under an Epic named after the feature.
400
409
  - **`/plan retro`** — derive from the improvement actions in the reflection phase. Each action becomes an issue (no Epic wrapper unless 5+ actions).
401
410
 
411
+ **External Acceptance (all PRD modes).** Each row of the PRD's § External Acceptance becomes its own issue, titled `[Abnahme] <criterion>`. Its body carries the owner, the not-before date, the pass condition, the fallback and the oracle command. The issue that implements the criterion links to it and must not close it, so "implemented" and "accepted" stay separate states. Measured basis: 68 of 85 closed `[Plan]` issues were closed the day they were filed, and the real-world acceptance stayed undone in all three back-tested PRDs.
412
+
402
413
  ### 6.2 Auto-Prioritize
403
414
 
404
415
  Score each issue using three factors:
@@ -504,6 +515,7 @@ Skip this step if issue creation was cancelled at § 6.3 ("Cancel") — there is
504
515
  - **ALWAYS research before asking** — dispatch Explore agents before every Q&A wave. Questions without research backing are guesses.
505
516
  - **ALWAYS mark Option 1 as recommended** — with `(Recommended)` in the label. Every question must have a clear recommendation.
506
517
  - **ALWAYS use AskUserQuestion** — never present options as plain text. The structured UI is mandatory.
518
+ - **Autonomous runs**: headless, autopilot, or a session the operator has told to decide on its own. Do not stop at an AUQ there. Answer each question with Option 1 when its evidence holds, and record the decision, its reasons and the rejected options as a comment on the Epic. Decisions the operator reserves (external effect, money, accounts, deleting data, security exceptions, irreversible product calls) go to the operator's decision queue and are marked "waits on owner" on the Epic. The Q&A still runs: the research, the recap and the recorded answers are the audit trail.
507
519
  - **ALWAYS save documents before creating issues** — the PRD/retro document is the source of truth. Issues reference it.
508
520
  - **ALWAYS commit the PRD before creating issues** — see Phase 5.5 (HARD-GATE). A saved-but-uncommitted document is unverifiable by any downstream session; commit to HEAD is the trust boundary, not disk-write.
509
521
  - **Security** — never include internal paths, IPs, or infrastructure details in output documents. Read sensitive baseline areas for context but filter from outputs.
@@ -511,7 +523,7 @@ Skip this step if issue creation was cancelled at § 6.3 ("Cancel") — there is
511
523
 
512
524
  ## Sub-File Reference
513
525
 
514
- This skill uses 8 sub-files in the same directory:
526
+ This skill uses 9 sub-files in the same directory:
515
527
 
516
528
  | File | Purpose |
517
529
  |------|---------|
@@ -523,3 +535,4 @@ This skill uses 8 sub-files in the same directory:
523
535
  | `prd-feature-template.md` | 5-section compact PRD template for `/plan feature` |
524
536
  | `retro-template.md` | Retrospective document template for `/plan retro` |
525
537
  | `prd-reviewer-prompt.md` | PRD quality review instructions for the reviewer subagent |
538
+ | `prd-premortem-panel.md` | Phase 4.5: Refute + Deepen briefs and the coordinator merge rules |