session-orchestrator 3.21.0 → 3.23.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 (345) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/.cursor/commands/autopilot-multi.md +14 -0
  5. package/.cursor/commands/autopilot.md +14 -0
  6. package/.cursor/commands/bootstrap.md +14 -0
  7. package/.cursor/commands/brainstorm.md +14 -0
  8. package/.cursor/commands/close.md +13 -0
  9. package/.cursor/commands/contract-version-bump.md +14 -0
  10. package/.cursor/commands/debug.md +14 -0
  11. package/.cursor/commands/discovery.md +14 -0
  12. package/.cursor/commands/dispatcher.md +14 -0
  13. package/.cursor/commands/eli5.md +14 -0
  14. package/.cursor/commands/eval.md +14 -0
  15. package/.cursor/commands/evolve.md +14 -0
  16. package/.cursor/commands/go.md +14 -0
  17. package/.cursor/commands/grill.md +14 -0
  18. package/.cursor/commands/harness-audit.md +13 -0
  19. package/.cursor/commands/journey-audit.md +14 -0
  20. package/.cursor/commands/memory-cleanup.md +14 -0
  21. package/.cursor/commands/persona-panel.md +14 -0
  22. package/.cursor/commands/plan.md +14 -0
  23. package/.cursor/commands/portfolio.md +14 -0
  24. package/.cursor/commands/reconcile.md +14 -0
  25. package/.cursor/commands/release.md +14 -0
  26. package/.cursor/commands/repo-audit.md +13 -0
  27. package/.cursor/commands/session.md +14 -0
  28. package/.cursor/commands/spinout.md +14 -0
  29. package/.cursor/commands/sunset-review.md +14 -0
  30. package/.cursor/commands/templates-ack.md +14 -0
  31. package/.cursor/commands/test.md +14 -0
  32. package/.cursor/hooks.json +60 -0
  33. package/.cursor/rules/000-session-orchestrator.mdc +11 -2
  34. package/.cursor/rules/010-session-workflow.mdc +9 -1
  35. package/.cursor/rules/020-quality-gates.mdc +1 -1
  36. package/.cursor/rules/030-wave-execution.mdc +1 -1
  37. package/.cursor/rules/040-discovery.mdc +6 -6
  38. package/.cursor/rules/050-plan.mdc +10 -10
  39. package/.cursor/rules/070-gitlab-ops.mdc +73 -57
  40. package/.cursor/rules/080-ecosystem-health.mdc +7 -7
  41. package/.cursor/skills/architecture/SKILL.md +13 -0
  42. package/.cursor/skills/autopilot/SKILL.md +12 -0
  43. package/.cursor/skills/bootstrap/SKILL.md +12 -0
  44. package/.cursor/skills/brainstorm/SKILL.md +13 -0
  45. package/.cursor/skills/claude-md-drift-check/SKILL.md +13 -0
  46. package/.cursor/skills/contract-version-bump/SKILL.md +12 -0
  47. package/.cursor/skills/convergence-monitoring/SKILL.md +12 -0
  48. package/.cursor/skills/daily/SKILL.md +12 -0
  49. package/.cursor/skills/debug/SKILL.md +13 -0
  50. package/.cursor/skills/discovery/SKILL.md +13 -0
  51. package/.cursor/skills/dispatcher/SKILL.md +13 -0
  52. package/.cursor/skills/docs-orchestrator/SKILL.md +13 -0
  53. package/.cursor/skills/domain-model/SKILL.md +13 -0
  54. package/.cursor/skills/ecosystem-health/SKILL.md +13 -0
  55. package/.cursor/skills/eli5/SKILL.md +13 -0
  56. package/.cursor/skills/eval/SKILL.md +12 -0
  57. package/.cursor/skills/evolve/SKILL.md +13 -0
  58. package/.cursor/skills/frontmatter-guard/SKILL.md +13 -0
  59. package/.cursor/skills/gitlab-ops/SKILL.md +13 -0
  60. package/.cursor/skills/gitlab-portfolio/SKILL.md +13 -0
  61. package/.cursor/skills/grill/SKILL.md +13 -0
  62. package/.cursor/skills/hook-development/SKILL.md +13 -0
  63. package/.cursor/skills/journey-audit/SKILL.md +13 -0
  64. package/.cursor/skills/mcp-builder/SKILL.md +13 -0
  65. package/.cursor/skills/memory-cleanup/SKILL.md +12 -0
  66. package/.cursor/skills/mode-selector/SKILL.md +13 -0
  67. package/.cursor/skills/npm-publish/SKILL.md +12 -0
  68. package/.cursor/skills/peekaboo-driver/SKILL.md +13 -0
  69. package/.cursor/skills/persona-panel/SKILL.md +12 -0
  70. package/.cursor/skills/plan/SKILL.md +13 -0
  71. package/.cursor/skills/playwright-driver/SKILL.md +13 -0
  72. package/.cursor/skills/quality-gates/SKILL.md +13 -0
  73. package/.cursor/skills/reconcile/SKILL.md +12 -0
  74. package/.cursor/skills/repo-audit/SKILL.md +13 -0
  75. package/.cursor/skills/session-end/SKILL.md +13 -0
  76. package/.cursor/skills/session-plan/SKILL.md +13 -0
  77. package/.cursor/skills/session-start/SKILL.md +13 -0
  78. package/.cursor/skills/skill-creator/SKILL.md +13 -0
  79. package/.cursor/skills/spinout/SKILL.md +12 -0
  80. package/.cursor/skills/sunset-review/SKILL.md +13 -0
  81. package/.cursor/skills/test-runner/SKILL.md +13 -0
  82. package/.cursor/skills/tmux-layout/SKILL.md +13 -0
  83. package/.cursor/skills/ubiquitous-language/SKILL.md +13 -0
  84. package/.cursor/skills/using-orchestrator/SKILL.md +13 -0
  85. package/.cursor/skills/vault-mirror/SKILL.md +13 -0
  86. package/.cursor/skills/vault-sync/SKILL.md +13 -0
  87. package/.cursor/skills/wave-executor/SKILL.md +13 -0
  88. package/.cursor/skills/write-executable-plan/SKILL.md +13 -0
  89. package/.mcp.json +4 -1
  90. package/CHANGELOG.md +269 -0
  91. package/README.md +18 -15
  92. package/agents/AGENTS.md +23 -4
  93. package/agents/code-implementer.md +2 -1
  94. package/agents/db-specialist.md +2 -1
  95. package/agents/docs-writer.md +3 -1
  96. package/agents/eval-judge.md +1 -1
  97. package/agents/memory-proposal-collector.md +6 -4
  98. package/agents/session-reviewer.md +7 -1
  99. package/agents/test-writer.md +2 -1
  100. package/agents/ui-developer.md +2 -1
  101. package/commands/bootstrap.md +2 -2
  102. package/commands/close.md +3 -1
  103. package/commands/eli5.md +33 -0
  104. package/commands/go.md +1 -1
  105. package/commands/journey-audit.md +43 -0
  106. package/commands/release.md +5 -3
  107. package/commands/test.md +2 -2
  108. package/docs/USER-GUIDE.md +2 -2
  109. package/docs/ci-setup.md +14 -0
  110. package/docs/codex-setup.md +64 -0
  111. package/docs/components.md +7 -6
  112. package/docs/cursor-setup.md +26 -47
  113. package/docs/events-schema.md +76 -4
  114. package/docs/github-mirror-protection.md +197 -0
  115. package/docs/pi-setup.md +2 -0
  116. package/docs/rule-authoring.md +3 -1
  117. package/docs/scope-collision-guard.md +52 -5
  118. package/docs/session-config-reference.md +57 -12
  119. package/docs/session-config-template.md +4 -3
  120. package/docs/telemetry.md +22 -0
  121. package/hooks/_lib/lock-bootstrap.mjs +26 -16
  122. package/hooks/_lib/vcs-create-matcher.mjs +397 -38
  123. package/hooks/enforce-scope.mjs +64 -0
  124. package/hooks/hooks-codex.json +1 -1
  125. package/hooks/hooks-cursor.json +201 -20
  126. package/hooks/hooks-pi.json +1 -1
  127. package/hooks/hooks.json +12 -2
  128. package/hooks/on-session-end.mjs +237 -104
  129. package/hooks/on-session-start.mjs +404 -110
  130. package/hooks/on-stop.mjs +48 -9
  131. package/hooks/post-subagent-discovery-validator.mjs +34 -3
  132. package/hooks/post-tool-batch-wave-signal.mjs +11 -2
  133. package/hooks/pre-auq-clarity.mjs +787 -0
  134. package/hooks/pre-bash-issue-budget.mjs +133 -21
  135. package/hooks/pre-bash-sessions-ledger-guard.mjs +159 -0
  136. package/hooks/pre-bash-staging-fence.mjs +4 -0
  137. package/hooks/pre-task-scope-disjoint.mjs +368 -35
  138. package/hooks/skill-invocation-telemetry.mjs +21 -10
  139. package/monitors/monitors.json +6 -0
  140. package/package.json +3 -1
  141. package/pi/prompts/eli5.md +12 -0
  142. package/pi/prompts/journey-audit.md +12 -0
  143. package/rules/_index.md +9 -1
  144. package/rules/always-on/ask-via-tool.md +62 -0
  145. package/rules/always-on/bash-harness-pitfalls.md +168 -0
  146. package/rules/always-on/build-value.md +47 -0
  147. package/rules/always-on/cross-session-messaging.md +59 -0
  148. package/rules/always-on/loop-and-monitor.md +221 -0
  149. package/rules/always-on/parallel-sessions.md +142 -12
  150. package/rules/always-on/receiving-review.md +108 -0
  151. package/rules/always-on/test-value.md +40 -0
  152. package/rules/always-on/verification-before-completion.md +77 -0
  153. package/scripts/archive-closed-prds.mjs +258 -18
  154. package/scripts/auq-audit.mjs +825 -0
  155. package/scripts/autopilot.mjs +12 -8
  156. package/scripts/backfill-evidence-digest.mjs +376 -0
  157. package/scripts/cursor-install.mjs +89 -48
  158. package/scripts/export-hw-learnings.mjs +143 -2
  159. package/scripts/express-path.mjs +299 -0
  160. package/scripts/generate-cursor-adapter.mjs +253 -0
  161. package/scripts/github-protection-audit.mjs +358 -0
  162. package/scripts/lib/auq/clarity.mjs +1314 -0
  163. package/scripts/lib/auq/parse.mjs +1006 -0
  164. package/scripts/lib/auq/schema.mjs +1457 -0
  165. package/scripts/lib/autopilot/worktree-pipeline.mjs +240 -16
  166. package/scripts/lib/build-live-signals.mjs +24 -5
  167. package/scripts/lib/ci-status-banner.mjs +221 -68
  168. package/scripts/lib/command-blocker.mjs +70 -0
  169. package/scripts/lib/config/dispatcher-autonomy-capture.mjs +32 -9
  170. package/scripts/lib/config/reconcile.mjs +79 -4
  171. package/scripts/lib/config/section-extractor.mjs +235 -36
  172. package/scripts/lib/config/vault-integration.mjs +12 -1
  173. package/scripts/lib/config-schema.mjs +9 -1
  174. package/scripts/lib/config.mjs +57 -6
  175. package/scripts/lib/convergence-monitor.mjs +13 -2
  176. package/scripts/lib/cursor-hook-bridge.mjs +443 -0
  177. package/scripts/lib/dispatcher/cli.mjs +2 -2
  178. package/scripts/lib/dispatcher/rank.mjs +4 -7
  179. package/scripts/lib/express-path.mjs +327 -0
  180. package/scripts/lib/file-lock.mjs +22 -4
  181. package/scripts/lib/gates/gate-full.mjs +84 -11
  182. package/scripts/lib/gates/gate-helpers.mjs +93 -21
  183. package/scripts/lib/git-config-drift.mjs +134 -5
  184. package/scripts/lib/host-identity.mjs +247 -2
  185. package/scripts/lib/instruction-budget-guard.mjs +31 -1
  186. package/scripts/lib/io.mjs +239 -0
  187. package/scripts/lib/issue-budget.mjs +284 -31
  188. package/scripts/lib/learnings/io.mjs +55 -10
  189. package/scripts/lib/learnings/schema.mjs +95 -28
  190. package/scripts/lib/lock-reaper.mjs +7 -1
  191. package/scripts/lib/locks/staging-fence-lock.mjs +5 -1
  192. package/scripts/lib/locks/state-md-lock.mjs +8 -1
  193. package/scripts/lib/memory-banner.mjs +5 -2
  194. package/scripts/lib/memory-paths.mjs +15 -6
  195. package/scripts/lib/mode-selector/scoring.mjs +53 -6
  196. package/scripts/lib/owner-interview.mjs +78 -32
  197. package/scripts/lib/peer-discovery.mjs +73 -22
  198. package/scripts/lib/platform.mjs +72 -9
  199. package/scripts/lib/plugin-root.mjs +143 -19
  200. package/scripts/lib/project-hygiene.mjs +104 -4
  201. package/scripts/lib/quality-gate.mjs +271 -13
  202. package/scripts/lib/reconcile/emitter.mjs +87 -19
  203. package/scripts/lib/reconcile/engine.mjs +281 -13
  204. package/scripts/lib/reconcile/idempotency.mjs +102 -1
  205. package/scripts/lib/reconcile/renderer.mjs +165 -7
  206. package/scripts/lib/reconcile/sanitize.mjs +40 -17
  207. package/scripts/lib/reconcile/writer.mjs +415 -84
  208. package/scripts/lib/resource-probe/evaluate.mjs +330 -149
  209. package/scripts/lib/resource-probe/probe-platform.mjs +35 -0
  210. package/scripts/lib/resource-probe.mjs +18 -2
  211. package/scripts/lib/rule-loader.mjs +37 -2
  212. package/scripts/lib/rules-sync.mjs +51 -8
  213. package/scripts/lib/scope-gate.mjs +90 -0
  214. package/scripts/lib/session-close-backfill.mjs +369 -28
  215. package/scripts/lib/session-discovery.mjs +13 -3
  216. package/scripts/lib/session-end/phase-skip.mjs +37 -4
  217. package/scripts/lib/session-end/worktree-cleanup.mjs +154 -7
  218. package/scripts/lib/session-id.mjs +30 -14
  219. package/scripts/lib/session-identity/own-session.mjs +159 -0
  220. package/scripts/lib/session-lock.mjs +85 -30
  221. package/scripts/lib/session-schema/normalizer.mjs +70 -3
  222. package/scripts/lib/session-schema/validator.mjs +40 -0
  223. package/scripts/lib/session-start-probes.mjs +608 -0
  224. package/scripts/lib/session-transition.mjs +277 -0
  225. package/scripts/lib/sessions-staleness-banner.mjs +124 -57
  226. package/scripts/lib/spiral-carryover.mjs +111 -9
  227. package/scripts/lib/state-md/frontmatter-mutators.mjs +41 -8
  228. package/scripts/lib/state-md/mission-status.mjs +467 -72
  229. package/scripts/lib/state-md/yaml-parser.mjs +145 -16
  230. package/scripts/lib/state-md.mjs +12 -2
  231. package/scripts/lib/telemetry/sync.mjs +46 -8
  232. package/scripts/lib/validate/check-agents.mjs +66 -0
  233. package/scripts/lib/validate/check-auq-clarity.mjs +274 -0
  234. package/scripts/lib/validate/check-cursor-adapter.mjs +102 -0
  235. package/scripts/lib/validate/check-dead-bridge.mjs +24 -2
  236. package/scripts/lib/validate/check-doc-cli-commands.mjs +16 -32
  237. package/scripts/lib/validate/check-hooks-symmetry.mjs +59 -63
  238. package/scripts/lib/validate/check-playwright-mcp-canary.mjs +13 -22
  239. package/scripts/lib/validate/check-plugin-monitors.mjs +10 -4
  240. package/scripts/lib/validate/check-rules.mjs +153 -9
  241. package/scripts/lib/validate/check-test-value-bans.mjs +165 -17
  242. package/scripts/lib/validate/check-unwired-features.mjs +340 -32
  243. package/scripts/lib/validate/repo-files.mjs +275 -0
  244. package/scripts/lib/validate-vendored-rules.mjs +229 -7
  245. package/scripts/lib/vault-backfill/glab.mjs +91 -58
  246. package/scripts/lib/vault-backfill/manifest.mjs +28 -8
  247. package/scripts/lib/vault-mirror/process.mjs +99 -43
  248. package/scripts/lib/vault-mirror/telemetry.mjs +210 -0
  249. package/scripts/lib/vault-staleness-banner.mjs +76 -6
  250. package/scripts/lib/vault-status/board-writer.mjs +211 -10
  251. package/scripts/lib/vault-status/narrative-mirror.mjs +188 -8
  252. package/scripts/lib/vcs-repo-spec.mjs +182 -13
  253. package/scripts/lib/wave-executor/foreign-dispatch.mjs +832 -0
  254. package/scripts/lib/wave-resource-gate.mjs +67 -73
  255. package/scripts/lib/wave-transcript-tail.mjs +869 -0
  256. package/scripts/materialize-wave-scope.mjs +478 -0
  257. package/scripts/mcp-server.sh +11 -2
  258. package/scripts/parse-config.mjs +65 -0
  259. package/scripts/release.mjs +443 -122
  260. package/scripts/run-quality-gate.mjs +14 -0
  261. package/scripts/token-audit.sh +9 -2
  262. package/scripts/validate-plugin.mjs +6 -0
  263. package/scripts/validate-wave-scope.mjs +73 -1
  264. package/scripts/vault-backfill.mjs +32 -5
  265. package/scripts/vault-mirror.mjs +203 -34
  266. package/skills/_shared/monitor-patterns.md +31 -5
  267. package/skills/_shared/parallel-aware-auq.md +31 -25
  268. package/skills/_shared/parallel-aware-preamble.md +35 -4
  269. package/skills/_shared/platform-tools.md +11 -5
  270. package/skills/_shared/state-ownership.md +61 -8
  271. package/skills/autopilot/SKILL.md +5 -1
  272. package/skills/bootstrap/SKILL.md +5 -4
  273. package/skills/bootstrap/_shared-template.md +18 -10
  274. package/skills/bootstrap/deep-template.md +10 -6
  275. package/skills/bootstrap/fast-template.md +15 -8
  276. package/skills/bootstrap/standard-template.md +10 -6
  277. package/skills/brainstorm/SKILL.md +18 -18
  278. package/skills/brainstorm/soul.md +12 -0
  279. package/skills/claude-md-drift-check/checker.mjs +39 -11
  280. package/skills/discovery/SKILL.md +28 -24
  281. package/skills/dispatcher/SKILL.md +1 -1
  282. package/skills/eli5/SKILL.md +43 -0
  283. package/skills/evolve/SKILL.md +8 -9
  284. package/skills/gitlab-ops/SKILL.md +30 -26
  285. package/skills/grill/SKILL.md +6 -6
  286. package/skills/grill/soul.md +16 -0
  287. package/skills/journey-audit/SKILL.md +269 -0
  288. package/skills/memory-cleanup/SKILL.md +2 -2
  289. package/skills/npm-publish/SKILL.md +4 -4
  290. package/skills/peekaboo-driver/SKILL.md +18 -6
  291. package/skills/persona-panel/SKILL.md +1 -1
  292. package/skills/plan/SKILL.md +18 -16
  293. package/skills/plan/mode-feature.md +1 -1
  294. package/skills/plan/mode-new.md +35 -23
  295. package/skills/plan/soul.md +12 -0
  296. package/skills/reconcile/SKILL.md +44 -4
  297. package/skills/session-end/SKILL.md +70 -24
  298. package/skills/session-end/metrics-collection.md +7 -4
  299. package/skills/session-end/phase-3-6-tail.md +48 -5
  300. package/skills/session-end/phase-3-7a-recommendations.md +16 -2
  301. package/skills/session-plan/SKILL.md +6 -1
  302. package/skills/session-plan/wave-template.md +1 -0
  303. package/skills/session-start/SKILL.md +96 -48
  304. package/skills/session-start/phase-2-5-docs-planning.md +8 -8
  305. package/skills/session-start/phase-4-5-resource-health.md +82 -19
  306. package/skills/session-start/phase-7-5-mode-selector.md +15 -3
  307. package/skills/session-start/phase-8-5-express-path.md +77 -12
  308. package/skills/session-start/soul.md +110 -0
  309. package/skills/test-runner/SKILL.md +2 -2
  310. package/skills/using-orchestrator/SKILL.md +1 -1
  311. package/skills/vault-sync/validator.mjs +31 -0
  312. package/skills/wave-executor/SKILL.md +4 -2
  313. package/skills/wave-executor/circuit-breaker.md +34 -9
  314. package/skills/wave-executor/wave-loop.md +129 -24
  315. package/skills/write-executable-plan/SKILL.md +6 -6
  316. package/templates/_shared/journey-manifest.md +110 -0
  317. package/scripts/tests/fixtures/fetch-baseline/sample-rule.md +0 -8
  318. package/skills/vault-sync/tests/fixtures/archive-test-vault/90-archive/bad-archived.md +0 -8
  319. package/skills/vault-sync/tests/fixtures/archive-test-vault/_meta/.gitkeep +0 -0
  320. package/skills/vault-sync/tests/fixtures/archive-test-vault/live-note.md +0 -8
  321. package/skills/vault-sync/tests/fixtures/broken-frontmatter-vault/_meta/.gitkeep +0 -0
  322. package/skills/vault-sync/tests/fixtures/broken-frontmatter-vault/bad-type.md +0 -8
  323. package/skills/vault-sync/tests/fixtures/broken-frontmatter-vault/good-note.md +0 -8
  324. package/skills/vault-sync/tests/fixtures/clean-vault/.obsidian/config.md +0 -8
  325. package/skills/vault-sync/tests/fixtures/clean-vault/01-projects/foo/projects-baseline.md +0 -10
  326. package/skills/vault-sync/tests/fixtures/clean-vault/03-daily/daily-2026-04-13.md +0 -8
  327. package/skills/vault-sync/tests/fixtures/clean-vault/README.md +0 -3
  328. package/skills/vault-sync/tests/fixtures/clean-vault/hello-world.md +0 -11
  329. package/skills/vault-sync/tests/fixtures/dangling-link-vault/_meta/.gitkeep +0 -0
  330. package/skills/vault-sync/tests/fixtures/dangling-link-vault/has-dangling.md +0 -9
  331. package/skills/vault-sync/tests/fixtures/dangling-link-vault/real-target.md +0 -8
  332. package/skills/vault-sync/tests/fixtures/empty-vault/_meta/.gitkeep +0 -0
  333. package/skills/vault-sync/tests/fixtures/missing-field-vault/_meta/.gitkeep +0 -0
  334. package/skills/vault-sync/tests/fixtures/missing-field-vault/missing-id.md +0 -7
  335. package/skills/vault-sync/tests/fixtures/nested-tag-vault/03-daily/daily-2026-04-13.md +0 -9
  336. package/skills/vault-sync/tests/fixtures/nested-tag-vault/_meta/.gitkeep +0 -0
  337. package/skills/vault-sync/tests/fixtures/nested-tag-vault/nested-tags-note.md +0 -11
  338. package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/README.md +0 -3
  339. package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/_MOC.md +0 -3
  340. package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/_meta/.gitkeep +0 -0
  341. package/skills/vault-sync/tests/fixtures/with-moc-vault/_MOC.md +0 -11
  342. package/skills/vault-sync/tests/fixtures/with-moc-vault/_meta/.gitkeep +0 -0
  343. package/skills/vault-sync/tests/fixtures/with-moc-vault/hello-world.md +0 -11
  344. package/skills/vault-sync/tests/schema-drift.test.mjs +0 -133
  345. package/templates/_shared/rules/parallel-sessions.md +0 -77
package/hooks/on-stop.mjs CHANGED
@@ -16,7 +16,8 @@
16
16
  * JSONL format (`.orchestrator/metrics/events.jsonl`) — emitted via the canonical
17
17
  * `emitEvent()` so the JSONL record and the optional Clank webhook always carry the
18
18
  * SAME dotted event name (was: bare `stop`/`subagent_stop` in JSONL vs dotted in webhook):
19
- * Stop: {"timestamp":<ISO>,"event":"orchestrator.session.stopped","session_id":"...","wave":<int>,"branch":"...","commit":"...","duration_ms":<int>}
19
+ * Stop: {"timestamp":<ISO>,"event":"orchestrator.session.stopped","session_id":"...","semantic_session_id":"...","wave":<int>,"branch":"...","commit":"...","duration_ms":<int>}
20
+ * (`session_id` / `semantic_session_id` are omitted when unresolvable — #1068 AC1.)
20
21
  * SubagentStop: {"timestamp":<ISO>,"event":"orchestrator.agent.stopped","agent":"<name>"}
21
22
  */
22
23
 
@@ -29,6 +30,7 @@ if (!shouldRunHook('on-stop')) process.exit(0);
29
30
 
30
31
  import { emitEvent } from '../scripts/lib/events.mjs';
31
32
  import { SO_PROJECT_DIR } from '../scripts/lib/platform.mjs';
33
+ import { parseSessionId } from '../scripts/lib/session-id.mjs';
32
34
  import { heartbeat, logSweepEvent } from '../scripts/lib/session-registry.mjs';
33
35
  import { updateHeartbeat } from '../scripts/lib/session-lock.mjs';
34
36
 
@@ -216,17 +218,39 @@ async function readWaveNumber(projectRoot) {
216
218
  // ---------------------------------------------------------------------------
217
219
 
218
220
  /**
219
- * Resolve this session's id. Stdin payload wins. If Claude Code did not pass
220
- * one (Codex / Cursor paths, or older harnesses), fall back to
221
- * `.orchestrator/current-session.json` which on-session-start.mjs writes.
221
+ * Resolve this session's id + its attested semantic id. A stdin payload id wins
222
+ * ONLY when it parses as a UUID. If Claude Code did not pass one (Codex /
223
+ * Cursor paths, or older harnesses) — or passed something that is not a UUID —
224
+ * fall back to `.orchestrator/current-session.json` which on-session-start.mjs
225
+ * writes.
226
+ *
227
+ * #1091 / Kanevry#66 — WRITER/READER SYMMETRY, same defect class as
228
+ * `hooks/on-session-end.mjs`: `on-session-start.mjs` accepts a stdin raw id
229
+ * only when `parseSessionId(fromStdin)?.format === 'uuid'` and otherwise mints
230
+ * a `randomUUID()`, so every artifact this hook then addresses by id (the host
231
+ * registry entry, `session.lock`) is keyed by a UUID. Passing a non-UUID stdin
232
+ * string through meant `heartbeat()` and `updateHeartbeat()` addressed a key
233
+ * that was never written: the registry entry silently went un-refreshed (and
234
+ * aged into the zombie sweep) while the lock heartbeat no-oped on an ownership
235
+ * mismatch.
236
+ *
237
+ * `semanticSessionId` (#1068 AC1) is read from the SAME file and is deliberately
238
+ * gated on the resolved id BEING the recorded one — `current-session.json` is a
239
+ * single repo-global file describing whichever session most recently ran
240
+ * SessionStart, so an unrelated window's turn-end must not inherit a live
241
+ * peer's semantic identity (the #863 defect (c) contamination shape, mirrored
242
+ * here from `hooks/on-session-end.mjs`).
222
243
  *
223
244
  * @param {object|null} input
224
245
  * @param {string} projectRoot
225
- * @returns {Promise<string|null>}
246
+ * @returns {Promise<{sessionId: string|null, semanticSessionId: string|null}>}
226
247
  */
227
248
  async function resolveSessionId(input, projectRoot) {
228
249
  const fromStdin = input?.session_id ?? input?.sessionId ?? null;
229
- if (typeof fromStdin === 'string' && fromStdin.length > 0) return fromStdin;
250
+ let sessionId = parseSessionId(fromStdin)?.format === 'uuid' ? fromStdin : null;
251
+
252
+ let recordedId = null;
253
+ let semanticSessionId = null;
230
254
  try {
231
255
  const raw = await fs.readFile(
232
256
  path.join(projectRoot, '.orchestrator', 'current-session.json'),
@@ -234,10 +258,20 @@ async function resolveSessionId(input, projectRoot) {
234
258
  );
235
259
  const parsed = JSON.parse(raw);
236
260
  if (typeof parsed.session_id === 'string' && parsed.session_id.length > 0) {
237
- return parsed.session_id;
261
+ recordedId = parsed.session_id;
262
+ }
263
+ if (typeof parsed.semantic_session_id === 'string' && parsed.semantic_session_id.length > 0) {
264
+ semanticSessionId = parsed.semantic_session_id;
238
265
  }
239
266
  } catch { /* missing or unparseable is fine */ }
240
- return null;
267
+
268
+ if (sessionId === null) sessionId = recordedId;
269
+
270
+ const isRecordedSession = sessionId !== null && sessionId === recordedId;
271
+ return {
272
+ sessionId,
273
+ semanticSessionId: isRecordedSession ? semanticSessionId : null,
274
+ };
241
275
  }
242
276
 
243
277
  /**
@@ -250,7 +284,7 @@ async function handleStop(input) {
250
284
  const wave = await readWaveNumber(projectRoot);
251
285
  const { commit, branch } = await gitInfo(projectRoot);
252
286
 
253
- const sessionId = await resolveSessionId(input, projectRoot);
287
+ const { sessionId, semanticSessionId } = await resolveSessionId(input, projectRoot);
254
288
 
255
289
  // v3.1.0 multi-session registry (#169), corrected in #1047 — REFRESH the
256
290
  // registry entry here; never remove it.
@@ -323,8 +357,13 @@ async function handleStop(input) {
323
357
  // Single emission path: emitEvent writes the canonical {timestamp, event, ...payload}
324
358
  // JSONL record AND fires the optional Clank webhook with the SAME event name — no
325
359
  // more bare-`stop` (JSONL) vs dotted-`stopped` (webhook) divergence.
360
+ // #1068 AC1 — carry the attested semantic id alongside the raw UUID so a
361
+ // turn-end outcome is joinable by identity from events.jsonl alone. Omitted
362
+ // (never `""`/`null`) when unattested: an unresolved identity stays visibly
363
+ // unresolved rather than becoming a guessed id.
326
364
  await emitEvent('orchestrator.session.stopped', {
327
365
  ...(sessionId !== null ? { session_id: sessionId } : {}),
366
+ ...(semanticSessionId !== null ? { semantic_session_id: semanticSessionId } : {}),
328
367
  wave,
329
368
  ...(branch !== null ? { branch } : {}),
330
369
  ...(commit !== null ? { commit } : {}),
@@ -30,6 +30,19 @@
30
30
  * Why read the transcript: the SubagentStop stdin payload has NO output_text
31
31
  * field. The agent's text lives in `input.transcript_path`.
32
32
  *
33
+ * Output channels — THREE writes, TWO different recipients:
34
+ * - `discovery_validator_violation` in .orchestrator/metrics/events.jsonl,
35
+ * and the stderr WARN → the COORDINATOR's only copy of the finding. PSA-006
36
+ * makes REJECTING the unverified claim his duty, so these two are the
37
+ * channels that carry the rule's enforcement path.
38
+ * - stdout `hookSpecificOutput.additionalContext` → the STOPPING SUBAGENT
39
+ * (which continues and may self-correct), NOT the coordinator — a hook is
40
+ * structurally unable to address him. See the measured delivery note at the
41
+ * hookSpecificOutput write below for the shipped-binary evidence.
42
+ * All three are pinned together by the "all three channels fire" test in
43
+ * tests/hooks/post-subagent-discovery-validator.test.mjs — do not collapse
44
+ * the coordinator-visible pair into additionalContext.
45
+ *
33
46
  * Exit codes: 0 always (informational, never blocking).
34
47
  */
35
48
 
@@ -594,12 +607,30 @@ async function main() {
594
607
  }
595
608
 
596
609
  if (alreadyWarned) {
597
- // Events logged above; suppress additionalContext to prevent coordinator loop.
610
+ // Events logged above; suppress the repeat additionalContext for this
611
+ // already-warned real context. (Recipient is the stopping subagent, not the
612
+ // coordinator — see the delivery note at the hookSpecificOutput write below.)
598
613
  return;
599
614
  }
600
615
 
601
- // v2.1.163+ additionalContext: feed the warning back to the coordinator turn
602
- // so the finding is visible inline, not just in stderr + events.jsonl.
616
+ // v2.1.163+ additionalContext: surface the finding inline, not just in
617
+ // stderr + events.jsonl.
618
+ //
619
+ // The recipient is the SUBAGENT that just stopped — NOT the coordinator.
620
+ // Measured in the shipped binary (Claude Code 2.1.241, 2026-08-23): the
621
+ // SubagentStop hookSpecificOutput schema reads "additionalContext is
622
+ // non-error feedback delivered to the subagent; the subagent continues so it
623
+ // can act on it", and the emitter picks its target with
624
+ // `i.agentId ? "SubagentStop" : "Stop"`, yielding a `hook_additional_context`
625
+ // message into that agent's own loop. So this text lands in the transcript of
626
+ // the agent whose claims it is about, one moment after that agent is done.
627
+ //
628
+ // Worth knowing before "fixing" the path: PSA-006 asks the COORDINATOR to
629
+ // reject unverified distributional claims, and this channel never reaches
630
+ // him. His copy of the finding is events.jsonl + stderr, not this write.
631
+ // Whether he SHOULD receive it is a product question (#1116) — changing the
632
+ // route is not a comment edit.
633
+ //
603
634
  // Non-blocking — exit 0 always. Decision:"block" must never be set here.
604
635
  process.stdout.write(JSON.stringify({
605
636
  hookSpecificOutput: {
@@ -41,6 +41,7 @@ if (!shouldRunHook('post-tool-batch-wave-signal')) process.exit(0);
41
41
 
42
42
  import { SO_PROJECT_DIR } from '../scripts/lib/platform.mjs';
43
43
  import { emitEvent } from '../scripts/lib/events.mjs';
44
+ import { findScopeFile } from '../scripts/lib/scope-gate.mjs';
44
45
 
45
46
  // ---------------------------------------------------------------------------
46
47
  // Helpers
@@ -135,17 +136,25 @@ async function resolveSessionIdForHeartbeat(input, sessionFile) {
135
136
  }
136
137
 
137
138
  /**
138
- * Resolve the current wave number from .claude/wave-scope.json `.wave`.
139
+ * Resolve the current wave number from the wave-scope manifest's `.wave`.
139
140
  * Returns 0 when the file is absent or unparseable, mirroring the
140
141
  * pre-bash-memory-propose-audit.mjs G5 precedent ("wave defaults to 0 when
141
142
  * wave-scope.json absent"). The file is deleted mid-session at Quality phase
142
143
  * transitions and final cleanup, so absence is an expected, non-error state.
143
144
  *
145
+ * The manifest is located via `findScopeFile()` (#1082), the same precedence
146
+ * every other consumer uses — `.pi` > `.cursor` > `.codex` > `.claude`. The
147
+ * previous hard-coded `.claude/` path made this hook's whole wave-lifecycle
148
+ * fallback structurally dead on Codex CLI, Cursor and pi: the manifest exists,
149
+ * it just is not under `.claude/`, so every batch read 0 and no
150
+ * `orchestrator.wave.started`/`completed` event was ever emitted there.
151
+ *
144
152
  * @param {string} projectDir
145
153
  * @returns {Promise<number>}
146
154
  */
147
155
  async function resolveWaveNumber(projectDir) {
148
- const waveFile = path.join(projectDir, '.claude', 'wave-scope.json');
156
+ const waveFile = findScopeFile(projectDir);
157
+ if (waveFile === null) return 0;
149
158
  try {
150
159
  const raw = await readFile(waveFile, 'utf8');
151
160
  const data = JSON.parse(raw);