oh-my-codex 0.18.12 → 0.18.14

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 (317) hide show
  1. package/Cargo.lock +6 -6
  2. package/Cargo.toml +1 -1
  3. package/README.md +38 -11
  4. package/dist/agents/__tests__/native-config.test.js +25 -0
  5. package/dist/agents/__tests__/native-config.test.js.map +1 -1
  6. package/dist/agents/native-config.d.ts.map +1 -1
  7. package/dist/agents/native-config.js +5 -1
  8. package/dist/agents/native-config.js.map +1 -1
  9. package/dist/autopilot/__tests__/fsm.test.js +7 -0
  10. package/dist/autopilot/__tests__/fsm.test.js.map +1 -1
  11. package/dist/autopilot/__tests__/planner-routing.test.d.ts +2 -0
  12. package/dist/autopilot/__tests__/planner-routing.test.d.ts.map +1 -0
  13. package/dist/autopilot/__tests__/planner-routing.test.js +74 -0
  14. package/dist/autopilot/__tests__/planner-routing.test.js.map +1 -0
  15. package/dist/autopilot/__tests__/ralplan-gate.test.js +936 -0
  16. package/dist/autopilot/__tests__/ralplan-gate.test.js.map +1 -1
  17. package/dist/autopilot/completion-gate.js +1 -1
  18. package/dist/autopilot/completion-gate.js.map +1 -1
  19. package/dist/autopilot/fsm.d.ts +2 -2
  20. package/dist/autopilot/fsm.d.ts.map +1 -1
  21. package/dist/autopilot/fsm.js +3 -0
  22. package/dist/autopilot/fsm.js.map +1 -1
  23. package/dist/autopilot/planner-routing.d.ts +21 -0
  24. package/dist/autopilot/planner-routing.d.ts.map +1 -0
  25. package/dist/autopilot/planner-routing.js +59 -0
  26. package/dist/autopilot/planner-routing.js.map +1 -0
  27. package/dist/autopilot/ralplan-gate.d.ts.map +1 -1
  28. package/dist/autopilot/ralplan-gate.js +62 -18
  29. package/dist/autopilot/ralplan-gate.js.map +1 -1
  30. package/dist/autoresearch/goal.d.ts.map +1 -1
  31. package/dist/autoresearch/goal.js +10 -1
  32. package/dist/autoresearch/goal.js.map +1 -1
  33. package/dist/cli/__tests__/autoresearch-goal.test.js +33 -0
  34. package/dist/cli/__tests__/autoresearch-goal.test.js.map +1 -1
  35. package/dist/cli/__tests__/codex-plugin-layout.test.js +30 -0
  36. package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
  37. package/dist/cli/__tests__/doctor-artifact-ownership.test.d.ts +2 -0
  38. package/dist/cli/__tests__/doctor-artifact-ownership.test.d.ts.map +1 -0
  39. package/dist/cli/__tests__/doctor-artifact-ownership.test.js +158 -0
  40. package/dist/cli/__tests__/doctor-artifact-ownership.test.js.map +1 -0
  41. package/dist/cli/__tests__/doctor-invalid-config.test.js +35 -0
  42. package/dist/cli/__tests__/doctor-invalid-config.test.js.map +1 -1
  43. package/dist/cli/__tests__/doctor-spark-routing.test.js +13 -0
  44. package/dist/cli/__tests__/doctor-spark-routing.test.js.map +1 -1
  45. package/dist/cli/__tests__/doctor-warning-copy.test.js +1 -0
  46. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
  47. package/dist/cli/__tests__/index.test.js +59 -1
  48. package/dist/cli/__tests__/index.test.js.map +1 -1
  49. package/dist/cli/__tests__/nested-help-routing.test.js +4 -0
  50. package/dist/cli/__tests__/nested-help-routing.test.js.map +1 -1
  51. package/dist/cli/__tests__/package-bin-contract.test.js +7 -1
  52. package/dist/cli/__tests__/package-bin-contract.test.js.map +1 -1
  53. package/dist/cli/__tests__/performance-goal.test.js +22 -0
  54. package/dist/cli/__tests__/performance-goal.test.js.map +1 -1
  55. package/dist/cli/__tests__/resume.test.js +313 -1
  56. package/dist/cli/__tests__/resume.test.js.map +1 -1
  57. package/dist/cli/__tests__/session-scoped-runtime.test.js +162 -0
  58. package/dist/cli/__tests__/session-scoped-runtime.test.js.map +1 -1
  59. package/dist/cli/__tests__/session-search-help.test.js +3 -2
  60. package/dist/cli/__tests__/session-search-help.test.js.map +1 -1
  61. package/dist/cli/__tests__/session-search.test.js +100 -2
  62. package/dist/cli/__tests__/session-search.test.js.map +1 -1
  63. package/dist/cli/__tests__/setup-agents-overwrite.test.js +35 -1
  64. package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
  65. package/dist/cli/__tests__/setup-install-mode.test.js +39 -5
  66. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
  67. package/dist/cli/__tests__/setup-prompts-overwrite.test.js +74 -0
  68. package/dist/cli/__tests__/setup-prompts-overwrite.test.js.map +1 -1
  69. package/dist/cli/__tests__/setup-scope.test.js +45 -0
  70. package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
  71. package/dist/cli/__tests__/team.test.js +17 -3
  72. package/dist/cli/__tests__/team.test.js.map +1 -1
  73. package/dist/cli/__tests__/ultragoal.test.js +37 -0
  74. package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
  75. package/dist/cli/__tests__/update.test.js +6 -2
  76. package/dist/cli/__tests__/update.test.js.map +1 -1
  77. package/dist/cli/autoresearch-goal.d.ts.map +1 -1
  78. package/dist/cli/autoresearch-goal.js +2 -1
  79. package/dist/cli/autoresearch-goal.js.map +1 -1
  80. package/dist/cli/doctor.d.ts +22 -0
  81. package/dist/cli/doctor.d.ts.map +1 -1
  82. package/dist/cli/doctor.js +272 -5
  83. package/dist/cli/doctor.js.map +1 -1
  84. package/dist/cli/index.d.ts +10 -2
  85. package/dist/cli/index.d.ts.map +1 -1
  86. package/dist/cli/index.js +274 -11
  87. package/dist/cli/index.js.map +1 -1
  88. package/dist/cli/performance-goal.d.ts.map +1 -1
  89. package/dist/cli/performance-goal.js +4 -2
  90. package/dist/cli/performance-goal.js.map +1 -1
  91. package/dist/cli/plugin-marketplace.d.ts +1 -0
  92. package/dist/cli/plugin-marketplace.d.ts.map +1 -1
  93. package/dist/cli/plugin-marketplace.js +67 -5
  94. package/dist/cli/plugin-marketplace.js.map +1 -1
  95. package/dist/cli/project-runtime-codex-homes.d.ts +8 -0
  96. package/dist/cli/project-runtime-codex-homes.d.ts.map +1 -0
  97. package/dist/cli/project-runtime-codex-homes.js +134 -0
  98. package/dist/cli/project-runtime-codex-homes.js.map +1 -0
  99. package/dist/cli/session-search.d.ts.map +1 -1
  100. package/dist/cli/session-search.js +8 -1
  101. package/dist/cli/session-search.js.map +1 -1
  102. package/dist/cli/setup.d.ts +1 -0
  103. package/dist/cli/setup.d.ts.map +1 -1
  104. package/dist/cli/setup.js +183 -10
  105. package/dist/cli/setup.js.map +1 -1
  106. package/dist/cli/ultragoal.d.ts.map +1 -1
  107. package/dist/cli/ultragoal.js +5 -1
  108. package/dist/cli/ultragoal.js.map +1 -1
  109. package/dist/cli/update.d.ts.map +1 -1
  110. package/dist/cli/update.js +5 -0
  111. package/dist/cli/update.js.map +1 -1
  112. package/dist/config/__tests__/codex-hooks.test.js +38 -24
  113. package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
  114. package/dist/config/__tests__/models.test.js +21 -1
  115. package/dist/config/__tests__/models.test.js.map +1 -1
  116. package/dist/config/codex-hooks.d.ts +6 -0
  117. package/dist/config/codex-hooks.d.ts.map +1 -1
  118. package/dist/config/codex-hooks.js +34 -49
  119. package/dist/config/codex-hooks.js.map +1 -1
  120. package/dist/config/models.d.ts +5 -0
  121. package/dist/config/models.d.ts.map +1 -1
  122. package/dist/config/models.js +23 -0
  123. package/dist/config/models.js.map +1 -1
  124. package/dist/goal-workflows/codex-goal-snapshot.d.ts +2 -0
  125. package/dist/goal-workflows/codex-goal-snapshot.d.ts.map +1 -1
  126. package/dist/goal-workflows/codex-goal-snapshot.js +10 -0
  127. package/dist/goal-workflows/codex-goal-snapshot.js.map +1 -1
  128. package/dist/hooks/__tests__/autopilot-skill-contract.test.js +7 -0
  129. package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
  130. package/dist/hooks/__tests__/keyword-detector.test.js +46 -0
  131. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  132. package/dist/hooks/__tests__/notify-fallback-watcher.test.js +100 -0
  133. package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
  134. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +75 -0
  135. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +1 -1
  136. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +225 -0
  137. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
  138. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +75 -0
  139. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
  140. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +200 -0
  141. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
  142. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js +187 -12
  143. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +1 -1
  144. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +225 -0
  145. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
  146. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js +0 -0
  147. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js.map +1 -1
  148. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js +75 -0
  149. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -1
  150. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  151. package/dist/hooks/keyword-detector.js +4 -0
  152. package/dist/hooks/keyword-detector.js.map +1 -1
  153. package/dist/hud/__tests__/reconcile.test.js +137 -2
  154. package/dist/hud/__tests__/reconcile.test.js.map +1 -1
  155. package/dist/hud/__tests__/state.test.js +107 -0
  156. package/dist/hud/__tests__/state.test.js.map +1 -1
  157. package/dist/hud/__tests__/tmux.test.js +17 -0
  158. package/dist/hud/__tests__/tmux.test.js.map +1 -1
  159. package/dist/hud/reconcile.d.ts.map +1 -1
  160. package/dist/hud/reconcile.js +21 -7
  161. package/dist/hud/reconcile.js.map +1 -1
  162. package/dist/hud/render.d.ts.map +1 -1
  163. package/dist/hud/render.js +9 -0
  164. package/dist/hud/render.js.map +1 -1
  165. package/dist/hud/state.d.ts.map +1 -1
  166. package/dist/hud/state.js +43 -5
  167. package/dist/hud/state.js.map +1 -1
  168. package/dist/hud/types.d.ts +6 -0
  169. package/dist/hud/types.d.ts.map +1 -1
  170. package/dist/hud/types.js.map +1 -1
  171. package/dist/modes/__tests__/base-autopilot-gates.test.js +48 -0
  172. package/dist/modes/__tests__/base-autopilot-gates.test.js.map +1 -1
  173. package/dist/modes/base.d.ts.map +1 -1
  174. package/dist/modes/base.js +1 -0
  175. package/dist/modes/base.js.map +1 -1
  176. package/dist/performance-goal/artifacts.d.ts.map +1 -1
  177. package/dist/performance-goal/artifacts.js +10 -1
  178. package/dist/performance-goal/artifacts.js.map +1 -1
  179. package/dist/pipeline/__tests__/orchestrator.test.js +125 -0
  180. package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
  181. package/dist/pipeline/__tests__/stages.test.js +109 -0
  182. package/dist/pipeline/__tests__/stages.test.js.map +1 -1
  183. package/dist/pipeline/orchestrator.d.ts.map +1 -1
  184. package/dist/pipeline/orchestrator.js +7 -0
  185. package/dist/pipeline/orchestrator.js.map +1 -1
  186. package/dist/ralplan/__tests__/consensus-gate.test.js +552 -1
  187. package/dist/ralplan/__tests__/consensus-gate.test.js.map +1 -1
  188. package/dist/ralplan/consensus-gate.d.ts +25 -0
  189. package/dist/ralplan/consensus-gate.d.ts.map +1 -1
  190. package/dist/ralplan/consensus-gate.js +289 -75
  191. package/dist/ralplan/consensus-gate.js.map +1 -1
  192. package/dist/scripts/__tests__/codex-native-hook.test.js +1149 -47
  193. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  194. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  195. package/dist/scripts/codex-native-hook.js +542 -33
  196. package/dist/scripts/codex-native-hook.js.map +1 -1
  197. package/dist/scripts/codex-native-pre-post.d.ts +1 -0
  198. package/dist/scripts/codex-native-pre-post.d.ts.map +1 -1
  199. package/dist/scripts/codex-native-pre-post.js +130 -0
  200. package/dist/scripts/codex-native-pre-post.js.map +1 -1
  201. package/dist/scripts/notify-hook/team-tmux-guard.d.ts.map +1 -1
  202. package/dist/scripts/notify-hook/team-tmux-guard.js +87 -8
  203. package/dist/scripts/notify-hook/team-tmux-guard.js.map +1 -1
  204. package/dist/scripts/notify-hook/tmux-injection.js +1 -1
  205. package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
  206. package/dist/scripts/run-compiled-ci.d.ts +2 -0
  207. package/dist/scripts/run-compiled-ci.d.ts.map +1 -0
  208. package/dist/scripts/run-compiled-ci.js +77 -0
  209. package/dist/scripts/run-compiled-ci.js.map +1 -0
  210. package/dist/scripts/sync-plugin-mirror.d.ts.map +1 -1
  211. package/dist/scripts/sync-plugin-mirror.js +1 -0
  212. package/dist/scripts/sync-plugin-mirror.js.map +1 -1
  213. package/dist/session-history/__tests__/search.test.js +166 -0
  214. package/dist/session-history/__tests__/search.test.js.map +1 -1
  215. package/dist/session-history/search.d.ts +7 -0
  216. package/dist/session-history/search.d.ts.map +1 -1
  217. package/dist/session-history/search.js +99 -25
  218. package/dist/session-history/search.js.map +1 -1
  219. package/dist/sidecar/__tests__/collector.test.js +60 -0
  220. package/dist/sidecar/__tests__/collector.test.js.map +1 -1
  221. package/dist/sidecar/collector.d.ts.map +1 -1
  222. package/dist/sidecar/collector.js +3 -6
  223. package/dist/sidecar/collector.js.map +1 -1
  224. package/dist/state/__tests__/operations.test.js +107 -3
  225. package/dist/state/__tests__/operations.test.js.map +1 -1
  226. package/dist/state/operations.d.ts.map +1 -1
  227. package/dist/state/operations.js +57 -2
  228. package/dist/state/operations.js.map +1 -1
  229. package/dist/team/__tests__/delivery-e2e-smoke.test.js +22 -1
  230. package/dist/team/__tests__/delivery-e2e-smoke.test.js.map +1 -1
  231. package/dist/team/__tests__/model-contract.test.js +57 -1
  232. package/dist/team/__tests__/model-contract.test.js.map +1 -1
  233. package/dist/team/__tests__/runtime.test.js +1468 -110
  234. package/dist/team/__tests__/runtime.test.js.map +1 -1
  235. package/dist/team/__tests__/scaling.test.js +63 -0
  236. package/dist/team/__tests__/scaling.test.js.map +1 -1
  237. package/dist/team/__tests__/state.test.js +24 -1
  238. package/dist/team/__tests__/state.test.js.map +1 -1
  239. package/dist/team/__tests__/tmux-session.test.js +512 -0
  240. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  241. package/dist/team/__tests__/worker-bootstrap.test.js +42 -9
  242. package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
  243. package/dist/team/model-contract.d.ts +16 -0
  244. package/dist/team/model-contract.d.ts.map +1 -1
  245. package/dist/team/model-contract.js +41 -1
  246. package/dist/team/model-contract.js.map +1 -1
  247. package/dist/team/runtime.d.ts.map +1 -1
  248. package/dist/team/runtime.js +116 -30
  249. package/dist/team/runtime.js.map +1 -1
  250. package/dist/team/scaling.d.ts.map +1 -1
  251. package/dist/team/scaling.js +9 -1
  252. package/dist/team/scaling.js.map +1 -1
  253. package/dist/team/state/types.d.ts +2 -0
  254. package/dist/team/state/types.d.ts.map +1 -1
  255. package/dist/team/state/types.js.map +1 -1
  256. package/dist/team/state.d.ts +3 -0
  257. package/dist/team/state.d.ts.map +1 -1
  258. package/dist/team/state.js +20 -0
  259. package/dist/team/state.js.map +1 -1
  260. package/dist/team/tmux-session.d.ts +38 -3
  261. package/dist/team/tmux-session.d.ts.map +1 -1
  262. package/dist/team/tmux-session.js +275 -36
  263. package/dist/team/tmux-session.js.map +1 -1
  264. package/dist/team/worker-bootstrap.d.ts.map +1 -1
  265. package/dist/team/worker-bootstrap.js +26 -1
  266. package/dist/team/worker-bootstrap.js.map +1 -1
  267. package/dist/ultragoal/__tests__/artifacts.test.js +238 -0
  268. package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
  269. package/dist/ultragoal/__tests__/docs-contract.test.js +3 -0
  270. package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -1
  271. package/dist/ultragoal/artifacts.d.ts +15 -0
  272. package/dist/ultragoal/artifacts.d.ts.map +1 -1
  273. package/dist/ultragoal/artifacts.js +167 -4
  274. package/dist/ultragoal/artifacts.js.map +1 -1
  275. package/dist/utils/__tests__/agents-md.test.js +39 -1
  276. package/dist/utils/__tests__/agents-md.test.js.map +1 -1
  277. package/dist/utils/__tests__/agents-model-table.test.js +28 -0
  278. package/dist/utils/__tests__/agents-model-table.test.js.map +1 -1
  279. package/dist/utils/agents-md.d.ts +4 -0
  280. package/dist/utils/agents-md.d.ts.map +1 -1
  281. package/dist/utils/agents-md.js +25 -0
  282. package/dist/utils/agents-md.js.map +1 -1
  283. package/dist/utils/agents-model-table.d.ts +7 -3
  284. package/dist/utils/agents-model-table.d.ts.map +1 -1
  285. package/dist/utils/agents-model-table.js +16 -8
  286. package/dist/utils/agents-model-table.js.map +1 -1
  287. package/dist/verification/__tests__/ci-rust-gates.test.js +8 -2
  288. package/dist/verification/__tests__/ci-rust-gates.test.js.map +1 -1
  289. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js +71 -3
  290. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js.map +1 -1
  291. package/package.json +2 -2
  292. package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
  293. package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +59 -8
  294. package/plugins/oh-my-codex/skills/autopilot/SKILL.md +9 -5
  295. package/plugins/oh-my-codex/skills/autoresearch-goal/SKILL.md +3 -0
  296. package/plugins/oh-my-codex/skills/performance-goal/SKILL.md +3 -0
  297. package/plugins/oh-my-codex/skills/ralplan/SKILL.md +1 -1
  298. package/plugins/oh-my-codex/skills/ultragoal/SKILL.md +22 -4
  299. package/plugins/oh-my-codex/skills/ultrawork/SKILL.md +2 -2
  300. package/plugins/oh-my-codex/skills/ultrawork/references/agent-tiers.md +61 -0
  301. package/skills/autopilot/SKILL.md +9 -5
  302. package/skills/autoresearch-goal/SKILL.md +3 -0
  303. package/skills/ecomode/SKILL.md +1 -1
  304. package/skills/ecomode/references/agent-tiers.md +61 -0
  305. package/skills/performance-goal/SKILL.md +3 -0
  306. package/skills/ralplan/SKILL.md +1 -1
  307. package/skills/ultragoal/SKILL.md +22 -4
  308. package/skills/ultrawork/SKILL.md +2 -2
  309. package/skills/ultrawork/references/agent-tiers.md +61 -0
  310. package/src/scripts/__tests__/codex-native-hook.test.ts +1417 -119
  311. package/src/scripts/codex-native-hook.ts +597 -40
  312. package/src/scripts/codex-native-pre-post.ts +137 -0
  313. package/src/scripts/notify-hook/team-tmux-guard.ts +92 -8
  314. package/src/scripts/notify-hook/tmux-injection.ts +1 -1
  315. package/src/scripts/run-compiled-ci.ts +85 -0
  316. package/src/scripts/sync-plugin-mirror.ts +1 -0
  317. package/templates/AGENTS.md +6 -0
@@ -5,7 +5,422 @@ import { join } from 'node:path';
5
5
  import { tmpdir } from 'node:os';
6
6
  import { subagentTrackingPath } from '../../subagents/tracker.js';
7
7
  import { buildAutopilotRalplanUltragoalGateError, canAdvanceAutopilotRalplanToUltragoal, } from '../ralplan-gate.js';
8
+ import { buildRalplanConsensusGateFromSources } from '../../ralplan/consensus-gate.js';
8
9
  describe('autopilot ralplan gate', () => {
10
+ it('rejects direct consensus when architect review is not approving', () => {
11
+ const evidence = buildRalplanConsensusGateFromSources([{
12
+ source: 'direct-architect-comment',
13
+ value: {
14
+ ralplan_consensus_gate: {
15
+ complete: true,
16
+ sequence: ['architect-review', 'critic-review'],
17
+ ralplan_architect_review: {
18
+ agent_role: 'architect',
19
+ verdict: 'comment',
20
+ },
21
+ ralplan_critic_review: {
22
+ agent_role: 'critic',
23
+ verdict: 'approve',
24
+ },
25
+ },
26
+ },
27
+ }]);
28
+ assert.equal(evidence.complete, false);
29
+ assert.equal(evidence.blockedReason, 'non_approving_ralplan_consensus_review');
30
+ assert.match(evidence.blockedDetails?.join('\n') ?? '', /architect review verdict=comment is not approve/);
31
+ });
32
+ it('rejects direct consensus when critic review is not approving', () => {
33
+ const evidence = buildRalplanConsensusGateFromSources([{
34
+ source: 'direct-critic-reject',
35
+ value: {
36
+ ralplan_consensus_gate: {
37
+ complete: true,
38
+ sequence: ['architect-review', 'critic-review'],
39
+ ralplan_architect_review: {
40
+ agent_role: 'architect',
41
+ verdict: 'approve',
42
+ },
43
+ ralplan_critic_review: {
44
+ agent_role: 'critic',
45
+ verdict: 'reject',
46
+ },
47
+ },
48
+ },
49
+ }]);
50
+ assert.equal(evidence.complete, false);
51
+ assert.equal(evidence.blockedReason, 'non_approving_ralplan_consensus_review');
52
+ assert.match(evidence.blockedDetails?.join('\n') ?? '', /critic review verdict=reject is not approve/);
53
+ });
54
+ it('accepts direct consensus when architect and critic reviews approve in order', () => {
55
+ const evidence = buildRalplanConsensusGateFromSources([{
56
+ source: 'direct-approval',
57
+ value: {
58
+ ralplan_consensus_gate: {
59
+ complete: true,
60
+ sequence: ['architect-review', 'critic-review'],
61
+ ralplan_architect_review: {
62
+ agent_role: 'architect',
63
+ verdict: 'approve',
64
+ completed_at: '2026-06-12T10:02:00.000Z',
65
+ },
66
+ ralplan_critic_review: {
67
+ agent_role: 'critic',
68
+ verdict: 'approve',
69
+ completed_at: '2026-06-12T10:03:00.000Z',
70
+ },
71
+ },
72
+ },
73
+ }]);
74
+ assert.equal(evidence.complete, true);
75
+ assert.equal(evidence.blockedReason, null);
76
+ assert.equal(evidence.source, 'direct-approval');
77
+ });
78
+ it('accepts fresh valid consensus before stale invalid consensus', () => {
79
+ const evidence = buildRalplanConsensusGateFromSources([
80
+ {
81
+ source: 'fresh-valid',
82
+ value: {
83
+ ralplan_consensus_gate: {
84
+ complete: true,
85
+ sequence: ['architect-review', 'critic-review'],
86
+ ralplan_architect_review: {
87
+ agent_role: 'architect',
88
+ verdict: 'approve',
89
+ completed_at: '2026-06-12T10:02:00.000Z',
90
+ },
91
+ ralplan_critic_review: {
92
+ agent_role: 'critic',
93
+ verdict: 'approve',
94
+ completed_at: '2026-06-12T10:03:00.000Z',
95
+ },
96
+ },
97
+ },
98
+ },
99
+ {
100
+ source: 'stale-invalid',
101
+ value: {
102
+ ralplan_consensus_gate: {
103
+ complete: true,
104
+ sequence: ['architect-review', 'critic-review'],
105
+ ralplan_architect_review: {
106
+ agent_role: 'architect',
107
+ verdict: 'iterate',
108
+ completed_at: '2026-06-12T09:58:00.000Z',
109
+ },
110
+ ralplan_critic_review: {
111
+ agent_role: 'critic',
112
+ verdict: 'approve',
113
+ completed_at: '2026-06-12T09:59:00.000Z',
114
+ },
115
+ },
116
+ },
117
+ },
118
+ ]);
119
+ assert.equal(evidence.complete, true);
120
+ assert.equal(evidence.blockedReason, null);
121
+ assert.equal(evidence.source, 'fresh-valid');
122
+ });
123
+ it('rejects invalid next-state complete consensus before falling back to older valid current state', async () => {
124
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-autopilot-ralplan-next-invalid-terminal-'));
125
+ const sessionId = 'sess-autopilot-next-invalid-terminal';
126
+ const trackingPath = subagentTrackingPath(cwd);
127
+ try {
128
+ await mkdir(join(trackingPath, '..'), { recursive: true });
129
+ await writeFile(trackingPath, JSON.stringify({
130
+ schemaVersion: 1,
131
+ sessions: {
132
+ [sessionId]: {
133
+ session_id: sessionId,
134
+ leader_thread_id: 'thread-leader',
135
+ updated_at: '2026-06-12T10:00:00.000Z',
136
+ threads: {
137
+ 'thread-leader': { thread_id: 'thread-leader', kind: 'leader', first_seen_at: '2026-06-12T09:59:00.000Z', last_seen_at: '2026-06-12T09:59:00.000Z', turn_count: 1 },
138
+ 'thread-architect-old': { thread_id: 'thread-architect-old', kind: 'subagent', first_seen_at: '2026-06-12T09:59:30.000Z', last_seen_at: '2026-06-12T09:59:30.000Z', completed_at: '2026-06-12T09:59:30.000Z', turn_count: 1 },
139
+ 'thread-critic-old': { thread_id: 'thread-critic-old', kind: 'subagent', first_seen_at: '2026-06-12T10:00:00.000Z', last_seen_at: '2026-06-12T10:00:00.000Z', completed_at: '2026-06-12T10:00:00.000Z', turn_count: 1 },
140
+ },
141
+ },
142
+ },
143
+ }, null, 2));
144
+ const nextState = {
145
+ current_phase: 'ralplan',
146
+ return_to_ralplan_reason: 'Code review requested a plan update.',
147
+ handoff_artifacts: {
148
+ ralplan_consensus_gate: {
149
+ complete: true,
150
+ sequence: ['architect-review', 'critic-review'],
151
+ ralplan_architect_review: {
152
+ agent_role: 'architect',
153
+ provenance_kind: 'native_subagent',
154
+ verdict: 'iterate',
155
+ session_id: sessionId,
156
+ thread_id: 'thread-architect-new',
157
+ artifact_path: '.omx/artifacts/architect-new.md',
158
+ tracker_path: '.omx/state/subagent-tracking.json',
159
+ completed_at: '2026-06-12T10:01:00.000Z',
160
+ },
161
+ ralplan_critic_review: {
162
+ agent_role: 'critic',
163
+ provenance_kind: 'native_subagent',
164
+ verdict: 'approve',
165
+ session_id: sessionId,
166
+ thread_id: 'thread-critic-new',
167
+ artifact_path: '.omx/artifacts/critic-new.md',
168
+ tracker_path: '.omx/state/subagent-tracking.json',
169
+ completed_at: '2026-06-12T10:02:00.000Z',
170
+ },
171
+ },
172
+ },
173
+ };
174
+ const currentState = {
175
+ current_phase: 'ralplan',
176
+ handoff_artifacts: {
177
+ ralplan_consensus_gate: {
178
+ complete: true,
179
+ sequence: ['architect-review', 'critic-review'],
180
+ ralplan_architect_review: {
181
+ agent_role: 'architect',
182
+ provenance_kind: 'native_subagent',
183
+ verdict: 'approve',
184
+ session_id: sessionId,
185
+ thread_id: 'thread-architect-old',
186
+ artifact_path: '.omx/artifacts/architect-old.md',
187
+ tracker_path: '.omx/state/subagent-tracking.json',
188
+ completed_at: '2026-06-12T09:59:30.000Z',
189
+ },
190
+ ralplan_critic_review: {
191
+ agent_role: 'critic',
192
+ provenance_kind: 'native_subagent',
193
+ verdict: 'approve',
194
+ session_id: sessionId,
195
+ thread_id: 'thread-critic-old',
196
+ artifact_path: '.omx/artifacts/critic-old.md',
197
+ tracker_path: '.omx/state/subagent-tracking.json',
198
+ completed_at: '2026-06-12T10:00:00.000Z',
199
+ },
200
+ },
201
+ },
202
+ };
203
+ const decision = canAdvanceAutopilotRalplanToUltragoal({ cwd, sessionId, nextState, currentState });
204
+ assert.equal(decision.allowed, false);
205
+ assert.equal(decision.evidence?.source, 'next-autopilot-state:handoff_artifacts');
206
+ assert.equal(decision.evidence?.blockedReason, 'non_approving_ralplan_consensus_review');
207
+ assert.match(buildAutopilotRalplanUltragoalGateError(decision), /architect.*verdict=iterate/i);
208
+ }
209
+ finally {
210
+ await rm(cwd, { recursive: true, force: true });
211
+ }
212
+ });
213
+ it('rejects ordered invalid next-state direct consensus before older valid current state', async () => {
214
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-autopilot-ralplan-next-invalid-direct-'));
215
+ const sessionId = 'sess-autopilot-next-invalid-direct';
216
+ const trackingPath = subagentTrackingPath(cwd);
217
+ try {
218
+ await mkdir(join(trackingPath, '..'), { recursive: true });
219
+ await writeFile(trackingPath, JSON.stringify({
220
+ schemaVersion: 1,
221
+ sessions: {
222
+ [sessionId]: {
223
+ session_id: sessionId,
224
+ leader_thread_id: 'thread-leader',
225
+ updated_at: '2026-06-12T10:05:00.000Z',
226
+ threads: {
227
+ 'thread-leader': { thread_id: 'thread-leader', kind: 'leader', first_seen_at: '2026-06-12T09:59:00.000Z', last_seen_at: '2026-06-12T09:59:00.000Z', turn_count: 1 },
228
+ 'thread-architect-old': { thread_id: 'thread-architect-old', kind: 'subagent', first_seen_at: '2026-06-12T09:59:30.000Z', last_seen_at: '2026-06-12T09:59:30.000Z', completed_at: '2026-06-12T09:59:30.000Z', turn_count: 1 },
229
+ 'thread-critic-old': { thread_id: 'thread-critic-old', kind: 'subagent', first_seen_at: '2026-06-12T10:00:00.000Z', last_seen_at: '2026-06-12T10:00:00.000Z', completed_at: '2026-06-12T10:00:00.000Z', turn_count: 1 },
230
+ },
231
+ },
232
+ },
233
+ }, null, 2));
234
+ const nextState = {
235
+ current_phase: 'ralplan',
236
+ return_to_ralplan_reason: 'Code review requested a plan update.',
237
+ ralplan_consensus_gate: {
238
+ complete: true,
239
+ sequence: ['architect-review', 'critic-review'],
240
+ ralplan_architect_review: {
241
+ agent_role: 'architect',
242
+ provenance_kind: 'native_subagent',
243
+ verdict: 'iterate',
244
+ session_id: sessionId,
245
+ thread_id: 'thread-architect-new',
246
+ artifact_path: '.omx/artifacts/architect-new.md',
247
+ tracker_path: '.omx/state/subagent-tracking.json',
248
+ completed_at: '2026-06-12T10:04:00.000Z',
249
+ },
250
+ ralplan_critic_review: {
251
+ agent_role: 'critic',
252
+ provenance_kind: 'native_subagent',
253
+ verdict: 'approve',
254
+ session_id: sessionId,
255
+ thread_id: 'thread-critic-new',
256
+ artifact_path: '.omx/artifacts/critic-new.md',
257
+ tracker_path: '.omx/state/subagent-tracking.json',
258
+ completed_at: '2026-06-12T10:05:00.000Z',
259
+ },
260
+ },
261
+ };
262
+ const currentState = {
263
+ current_phase: 'ralplan',
264
+ handoff_artifacts: {
265
+ ralplan_consensus_gate: {
266
+ complete: true,
267
+ sequence: ['architect-review', 'critic-review'],
268
+ ralplan_architect_review: {
269
+ agent_role: 'architect',
270
+ provenance_kind: 'native_subagent',
271
+ verdict: 'approve',
272
+ session_id: sessionId,
273
+ thread_id: 'thread-architect-old',
274
+ artifact_path: '.omx/artifacts/architect-old.md',
275
+ tracker_path: '.omx/state/subagent-tracking.json',
276
+ completed_at: '2026-06-12T09:59:30.000Z',
277
+ },
278
+ ralplan_critic_review: {
279
+ agent_role: 'critic',
280
+ provenance_kind: 'native_subagent',
281
+ verdict: 'approve',
282
+ session_id: sessionId,
283
+ thread_id: 'thread-critic-old',
284
+ artifact_path: '.omx/artifacts/critic-old.md',
285
+ tracker_path: '.omx/state/subagent-tracking.json',
286
+ completed_at: '2026-06-12T10:00:00.000Z',
287
+ },
288
+ },
289
+ },
290
+ };
291
+ const decision = canAdvanceAutopilotRalplanToUltragoal({ cwd, sessionId, nextState, currentState });
292
+ assert.equal(decision.allowed, false);
293
+ assert.equal(decision.evidence?.source, 'next-autopilot-state');
294
+ assert.equal(decision.evidence?.blockedReason, 'non_approving_ralplan_consensus_review');
295
+ assert.match(buildAutopilotRalplanUltragoalGateError(decision), /architect.*verdict=iterate/i);
296
+ }
297
+ finally {
298
+ await rm(cwd, { recursive: true, force: true });
299
+ }
300
+ });
301
+ it('rejects stale nested ralplan handoff consensus when parent state returned to ralplan', async () => {
302
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-autopilot-ralplan-stale-nested-'));
303
+ const sessionId = 'sess-autopilot-stale-nested';
304
+ const trackingPath = subagentTrackingPath(cwd);
305
+ try {
306
+ await mkdir(join(trackingPath, '..'), { recursive: true });
307
+ await writeFile(trackingPath, JSON.stringify({
308
+ schemaVersion: 1,
309
+ sessions: {
310
+ [sessionId]: {
311
+ session_id: sessionId,
312
+ leader_thread_id: 'thread-leader',
313
+ updated_at: '2026-06-12T10:00:00.000Z',
314
+ threads: {
315
+ 'thread-leader': { thread_id: 'thread-leader', kind: 'leader', first_seen_at: '2026-06-12T09:59:00.000Z', last_seen_at: '2026-06-12T09:59:00.000Z', turn_count: 1 },
316
+ 'thread-architect-stale': { thread_id: 'thread-architect-stale', kind: 'subagent', first_seen_at: '2026-06-12T09:59:30.000Z', last_seen_at: '2026-06-12T09:59:30.000Z', completed_at: '2026-06-12T09:59:30.000Z', turn_count: 1 },
317
+ 'thread-critic-stale': { thread_id: 'thread-critic-stale', kind: 'subagent', first_seen_at: '2026-06-12T10:00:00.000Z', last_seen_at: '2026-06-12T10:00:00.000Z', completed_at: '2026-06-12T10:00:00.000Z', turn_count: 1 },
318
+ },
319
+ },
320
+ },
321
+ }, null, 2));
322
+ const nextState = {
323
+ current_phase: 'ralplan',
324
+ return_to_ralplan_reason: 'Code review requested a plan update.',
325
+ review_cycle: 2,
326
+ handoff_artifacts: {
327
+ ralplan: {
328
+ review_cycle: 2,
329
+ ralplanConsensusGate: {
330
+ complete: true,
331
+ sequence: ['architect-review', 'critic-review'],
332
+ ralplan_architect_review: {
333
+ agent_role: 'architect',
334
+ provenance_kind: 'native_subagent',
335
+ verdict: 'approve',
336
+ session_id: sessionId,
337
+ thread_id: 'thread-architect-stale',
338
+ artifact_path: '.omx/artifacts/architect-stale.md',
339
+ tracker_path: '.omx/state/subagent-tracking.json',
340
+ completed_at: '2026-06-12T09:59:30.000Z',
341
+ },
342
+ ralplan_critic_review: {
343
+ agent_role: 'critic',
344
+ provenance_kind: 'native_subagent',
345
+ verdict: 'approve',
346
+ session_id: sessionId,
347
+ thread_id: 'thread-critic-stale',
348
+ artifact_path: '.omx/artifacts/critic-stale.md',
349
+ tracker_path: '.omx/state/subagent-tracking.json',
350
+ completed_at: '2026-06-12T10:00:00.000Z',
351
+ },
352
+ },
353
+ },
354
+ },
355
+ };
356
+ const decision = canAdvanceAutopilotRalplanToUltragoal({ cwd, sessionId, nextState });
357
+ assert.equal(decision.allowed, false);
358
+ assert.equal(decision.evidence?.blockedReason, 'missing_sequential_architect_then_critic_approval');
359
+ }
360
+ finally {
361
+ await rm(cwd, { recursive: true, force: true });
362
+ }
363
+ });
364
+ it('rejects stale raw handoff consensus when parent state returned to ralplan', async () => {
365
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-autopilot-ralplan-stale-raw-handoff-'));
366
+ const sessionId = 'sess-autopilot-stale-raw-handoff';
367
+ const trackingPath = subagentTrackingPath(cwd);
368
+ try {
369
+ await mkdir(join(trackingPath, '..'), { recursive: true });
370
+ await writeFile(trackingPath, JSON.stringify({
371
+ schemaVersion: 1,
372
+ sessions: {
373
+ [sessionId]: {
374
+ session_id: sessionId,
375
+ leader_thread_id: 'thread-leader',
376
+ updated_at: '2026-06-12T10:00:00.000Z',
377
+ threads: {
378
+ 'thread-leader': { thread_id: 'thread-leader', kind: 'leader', first_seen_at: '2026-06-12T09:59:00.000Z', last_seen_at: '2026-06-12T09:59:00.000Z', turn_count: 1 },
379
+ 'thread-architect-stale': { thread_id: 'thread-architect-stale', kind: 'subagent', first_seen_at: '2026-06-12T09:59:30.000Z', last_seen_at: '2026-06-12T09:59:30.000Z', completed_at: '2026-06-12T09:59:30.000Z', turn_count: 1 },
380
+ 'thread-critic-stale': { thread_id: 'thread-critic-stale', kind: 'subagent', first_seen_at: '2026-06-12T10:00:00.000Z', last_seen_at: '2026-06-12T10:00:00.000Z', completed_at: '2026-06-12T10:00:00.000Z', turn_count: 1 },
381
+ },
382
+ },
383
+ },
384
+ }, null, 2));
385
+ const currentState = {
386
+ current_phase: 'ralplan',
387
+ return_to_ralplan_reason: 'Code review requested a plan update.',
388
+ review_cycle: 1,
389
+ handoff_artifacts: {
390
+ ralplan_consensus_gate: {
391
+ complete: true,
392
+ sequence: ['architect-review', 'critic-review'],
393
+ ralplan_architect_review: {
394
+ agent_role: 'architect',
395
+ provenance_kind: 'native_subagent',
396
+ verdict: 'approve',
397
+ session_id: sessionId,
398
+ thread_id: 'thread-architect-stale',
399
+ artifact_path: '.omx/artifacts/architect-stale.md',
400
+ tracker_path: '.omx/state/subagent-tracking.json',
401
+ completed_at: '2026-06-12T09:59:30.000Z',
402
+ },
403
+ ralplan_critic_review: {
404
+ agent_role: 'critic',
405
+ provenance_kind: 'native_subagent',
406
+ verdict: 'approve',
407
+ session_id: sessionId,
408
+ thread_id: 'thread-critic-stale',
409
+ artifact_path: '.omx/artifacts/critic-stale.md',
410
+ tracker_path: '.omx/state/subagent-tracking.json',
411
+ completed_at: '2026-06-12T10:00:00.000Z',
412
+ },
413
+ },
414
+ },
415
+ };
416
+ const decision = canAdvanceAutopilotRalplanToUltragoal({ cwd, sessionId, currentState });
417
+ assert.equal(decision.allowed, false);
418
+ assert.equal(decision.evidence?.blockedReason, 'missing_sequential_architect_then_critic_approval');
419
+ }
420
+ finally {
421
+ await rm(cwd, { recursive: true, force: true });
422
+ }
423
+ });
9
424
  for (const { lane, architectVerdict, criticVerdict } of [
10
425
  { lane: 'architect', architectVerdict: 'iterate', criticVerdict: 'approve' },
11
426
  { lane: 'critic', architectVerdict: 'approve', criticVerdict: 'iterate' },
@@ -53,6 +468,525 @@ describe('autopilot ralplan gate', () => {
53
468
  assert.match(error, new RegExp(`${lane}.*verdict=iterate`, 'i'));
54
469
  });
55
470
  }
471
+ it('accepts fresh next-state consensus over stale invalid current-state consensus', async () => {
472
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-autopilot-ralplan-fresh-next-valid-'));
473
+ const sessionId = 'sess-autopilot-fresh-next-valid';
474
+ const trackingPath = subagentTrackingPath(cwd);
475
+ try {
476
+ await mkdir(join(trackingPath, '..'), { recursive: true });
477
+ await writeFile(trackingPath, JSON.stringify({
478
+ schemaVersion: 1,
479
+ sessions: {
480
+ [sessionId]: {
481
+ session_id: sessionId,
482
+ leader_thread_id: 'thread-leader',
483
+ updated_at: '2026-06-12T10:03:00.000Z',
484
+ threads: {
485
+ 'thread-leader': { thread_id: 'thread-leader', kind: 'leader', first_seen_at: '2026-06-12T09:59:00.000Z', last_seen_at: '2026-06-12T09:59:00.000Z', turn_count: 1 },
486
+ 'thread-architect-fresh': { thread_id: 'thread-architect-fresh', kind: 'subagent', first_seen_at: '2026-06-12T10:02:00.000Z', last_seen_at: '2026-06-12T10:02:00.000Z', completed_at: '2026-06-12T10:02:00.000Z', turn_count: 1 },
487
+ 'thread-critic-fresh': { thread_id: 'thread-critic-fresh', kind: 'subagent', first_seen_at: '2026-06-12T10:03:00.000Z', last_seen_at: '2026-06-12T10:03:00.000Z', completed_at: '2026-06-12T10:03:00.000Z', turn_count: 1 },
488
+ },
489
+ },
490
+ },
491
+ }, null, 2));
492
+ const nextState = {
493
+ current_phase: 'ralplan',
494
+ review_cycle: 2,
495
+ handoff_artifacts: {
496
+ ralplan_consensus_gate: {
497
+ complete: true,
498
+ sequence: ['architect-review', 'critic-review'],
499
+ ralplan_architect_review: {
500
+ agent_role: 'architect',
501
+ provenance_kind: 'native_subagent',
502
+ verdict: 'approve',
503
+ review_cycle: 2,
504
+ session_id: sessionId,
505
+ thread_id: 'thread-architect-fresh',
506
+ artifact_path: '.omx/artifacts/architect-fresh.md',
507
+ tracker_path: '.omx/state/subagent-tracking.json',
508
+ completed_at: '2026-06-12T10:02:00.000Z',
509
+ },
510
+ ralplan_critic_review: {
511
+ agent_role: 'critic',
512
+ provenance_kind: 'native_subagent',
513
+ verdict: 'approve',
514
+ review_cycle: 2,
515
+ session_id: sessionId,
516
+ thread_id: 'thread-critic-fresh',
517
+ artifact_path: '.omx/artifacts/critic-fresh.md',
518
+ tracker_path: '.omx/state/subagent-tracking.json',
519
+ completed_at: '2026-06-12T10:03:00.000Z',
520
+ },
521
+ },
522
+ },
523
+ };
524
+ const currentState = {
525
+ current_phase: 'ralplan',
526
+ return_to_ralplan_reason: 'Code review requested a plan update.',
527
+ review_cycle: 1,
528
+ handoff_artifacts: {
529
+ ralplan_consensus_gate: {
530
+ complete: true,
531
+ sequence: ['architect-review', 'critic-review'],
532
+ ralplan_architect_review: {
533
+ agent_role: 'architect',
534
+ provenance_kind: 'native_subagent',
535
+ verdict: 'block',
536
+ review_cycle: 1,
537
+ session_id: sessionId,
538
+ thread_id: 'thread-architect-stale',
539
+ artifact_path: '.omx/artifacts/architect-stale.md',
540
+ tracker_path: '.omx/state/subagent-tracking.json',
541
+ completed_at: '2026-06-12T10:00:00.000Z',
542
+ },
543
+ ralplan_critic_review: {
544
+ agent_role: 'critic',
545
+ provenance_kind: 'native_subagent',
546
+ verdict: 'approve',
547
+ review_cycle: 1,
548
+ session_id: sessionId,
549
+ thread_id: 'thread-critic-stale',
550
+ artifact_path: '.omx/artifacts/critic-stale.md',
551
+ tracker_path: '.omx/state/subagent-tracking.json',
552
+ completed_at: '2026-06-12T10:01:00.000Z',
553
+ },
554
+ },
555
+ },
556
+ };
557
+ const decision = canAdvanceAutopilotRalplanToUltragoal({ cwd, sessionId, nextState, currentState });
558
+ assert.equal(decision.allowed, true);
559
+ assert.equal(decision.evidence?.source, 'next-autopilot-state');
560
+ assert.equal(decision.evidence?.blockedReason, null);
561
+ }
562
+ finally {
563
+ await rm(cwd, { recursive: true, force: true });
564
+ }
565
+ });
566
+ it('accepts tracker-backed native reviews without duplicated session, tracker, or artifact fields', async () => {
567
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-autopilot-ralplan-tracker-resolved-'));
568
+ const sessionId = 'sess-autopilot-tracker-resolved';
569
+ const trackingPath = subagentTrackingPath(cwd);
570
+ try {
571
+ await mkdir(join(trackingPath, '..'), { recursive: true });
572
+ await writeFile(trackingPath, JSON.stringify({
573
+ schemaVersion: 1,
574
+ sessions: {
575
+ [sessionId]: {
576
+ session_id: sessionId,
577
+ leader_thread_id: 'thread-leader',
578
+ updated_at: '2026-06-12T10:03:00.000Z',
579
+ threads: {
580
+ 'thread-leader': { thread_id: 'thread-leader', kind: 'leader', first_seen_at: '2026-06-12T09:59:00.000Z', last_seen_at: '2026-06-12T09:59:00.000Z', turn_count: 1 },
581
+ 'thread-architect': { thread_id: 'thread-architect', kind: 'subagent', first_seen_at: '2026-06-12T10:02:00.000Z', last_seen_at: '2026-06-12T10:02:00.000Z', completed_at: '2026-06-12T10:02:00.000Z', turn_count: 1 },
582
+ 'thread-critic': { thread_id: 'thread-critic', kind: 'subagent', first_seen_at: '2026-06-12T10:03:00.000Z', last_seen_at: '2026-06-12T10:03:00.000Z', completed_at: '2026-06-12T10:03:00.000Z', turn_count: 1 },
583
+ },
584
+ },
585
+ },
586
+ }, null, 2));
587
+ const state = {
588
+ current_phase: 'ralplan',
589
+ handoff_artifacts: {
590
+ ralplan_consensus_gate: {
591
+ complete: true,
592
+ sequence: ['architect-review', 'critic-review'],
593
+ ralplan_architect_review: {
594
+ agent_role: 'architect',
595
+ provenance_kind: 'native_subagent',
596
+ verdict: 'approve',
597
+ thread_id: 'thread-architect',
598
+ completed_at: '2026-06-12T10:02:00.000Z',
599
+ },
600
+ ralplan_critic_review: {
601
+ agent_role: 'critic',
602
+ provenance_kind: 'native_subagent',
603
+ verdict: 'approve',
604
+ thread_id: 'thread-critic',
605
+ completed_at: '2026-06-12T10:03:00.000Z',
606
+ },
607
+ },
608
+ },
609
+ };
610
+ const decision = canAdvanceAutopilotRalplanToUltragoal({ cwd, sessionId, currentState: state });
611
+ assert.equal(decision.allowed, true);
612
+ assert.equal(decision.evidence?.blockedReason, null);
613
+ }
614
+ finally {
615
+ await rm(cwd, { recursive: true, force: true });
616
+ }
617
+ });
618
+ it('rejects omitted review session ids when no transition session context exists', async () => {
619
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-autopilot-ralplan-no-session-context-'));
620
+ const trackingPath = subagentTrackingPath(cwd);
621
+ try {
622
+ await mkdir(join(trackingPath, '..'), { recursive: true });
623
+ await writeFile(trackingPath, JSON.stringify({
624
+ schemaVersion: 1,
625
+ sessions: {},
626
+ }, null, 2));
627
+ const state = {
628
+ current_phase: 'ralplan',
629
+ handoff_artifacts: {
630
+ ralplan_consensus_gate: {
631
+ complete: true,
632
+ sequence: ['architect-review', 'critic-review'],
633
+ ralplan_architect_review: {
634
+ agent_role: 'architect',
635
+ provenance_kind: 'native_subagent',
636
+ verdict: 'approve',
637
+ thread_id: 'thread-architect',
638
+ },
639
+ ralplan_critic_review: {
640
+ agent_role: 'critic',
641
+ provenance_kind: 'native_subagent',
642
+ verdict: 'approve',
643
+ thread_id: 'thread-critic',
644
+ },
645
+ },
646
+ },
647
+ };
648
+ const decision = canAdvanceAutopilotRalplanToUltragoal({ cwd, currentState: state });
649
+ assert.equal(decision.allowed, false);
650
+ assert.match(buildAutopilotRalplanUltragoalGateError(decision), /cannot resolve session_id/);
651
+ }
652
+ finally {
653
+ await rm(cwd, { recursive: true, force: true });
654
+ }
655
+ });
656
+ it('rejects architect and critic reviews that reuse the same native tracker thread', async () => {
657
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-autopilot-ralplan-duplicate-thread-'));
658
+ const sessionId = 'sess-autopilot-duplicate-thread';
659
+ const trackingPath = subagentTrackingPath(cwd);
660
+ try {
661
+ await mkdir(join(trackingPath, '..'), { recursive: true });
662
+ await writeFile(trackingPath, JSON.stringify({
663
+ schemaVersion: 1,
664
+ sessions: {
665
+ [sessionId]: {
666
+ session_id: sessionId,
667
+ leader_thread_id: 'thread-leader',
668
+ updated_at: '2026-06-12T10:03:00.000Z',
669
+ threads: {
670
+ 'thread-leader': { thread_id: 'thread-leader', kind: 'leader', first_seen_at: '2026-06-12T09:59:00.000Z', last_seen_at: '2026-06-12T09:59:00.000Z', turn_count: 1 },
671
+ 'thread-reviewer': { thread_id: 'thread-reviewer', kind: 'subagent', first_seen_at: '2026-06-12T10:02:00.000Z', last_seen_at: '2026-06-12T10:03:00.000Z', completed_at: '2026-06-12T10:03:00.000Z', turn_count: 1 },
672
+ },
673
+ },
674
+ },
675
+ }, null, 2));
676
+ const state = {
677
+ current_phase: 'ralplan',
678
+ handoff_artifacts: {
679
+ ralplan_consensus_gate: {
680
+ complete: true,
681
+ sequence: ['architect-review', 'critic-review'],
682
+ ralplan_architect_review: {
683
+ agent_role: 'architect',
684
+ provenance_kind: 'native_subagent',
685
+ verdict: 'approve',
686
+ session_id: sessionId,
687
+ thread_id: 'thread-reviewer',
688
+ completed_at: '2026-06-12T10:02:00.000Z',
689
+ },
690
+ ralplan_critic_review: {
691
+ agent_role: 'critic',
692
+ provenance_kind: 'native_subagent',
693
+ verdict: 'approve',
694
+ session_id: sessionId,
695
+ thread_id: 'thread-reviewer',
696
+ completed_at: '2026-06-12T10:03:00.000Z',
697
+ },
698
+ },
699
+ },
700
+ };
701
+ const decision = canAdvanceAutopilotRalplanToUltragoal({ cwd, sessionId, currentState: state });
702
+ assert.equal(decision.allowed, false);
703
+ assert.match(buildAutopilotRalplanUltragoalGateError(decision), /distinct native subagent tracker threads/);
704
+ }
705
+ finally {
706
+ await rm(cwd, { recursive: true, force: true });
707
+ }
708
+ });
709
+ it('rejects tracker-backed native reviews composed from different sessions', async () => {
710
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-autopilot-ralplan-cross-session-'));
711
+ const trackingPath = subagentTrackingPath(cwd);
712
+ try {
713
+ await mkdir(join(trackingPath, '..'), { recursive: true });
714
+ await writeFile(trackingPath, JSON.stringify({
715
+ schemaVersion: 1,
716
+ sessions: {
717
+ 'sess-architect': {
718
+ session_id: 'sess-architect',
719
+ leader_thread_id: 'thread-leader-a',
720
+ updated_at: '2026-06-12T10:02:00.000Z',
721
+ threads: {
722
+ 'thread-leader-a': { thread_id: 'thread-leader-a', kind: 'leader', first_seen_at: '2026-06-12T09:59:00.000Z', last_seen_at: '2026-06-12T09:59:00.000Z', turn_count: 1 },
723
+ 'thread-architect': { thread_id: 'thread-architect', kind: 'subagent', first_seen_at: '2026-06-12T10:02:00.000Z', last_seen_at: '2026-06-12T10:02:00.000Z', completed_at: '2026-06-12T10:02:00.000Z', turn_count: 1 },
724
+ },
725
+ },
726
+ 'sess-critic': {
727
+ session_id: 'sess-critic',
728
+ leader_thread_id: 'thread-leader-c',
729
+ updated_at: '2026-06-12T10:03:00.000Z',
730
+ threads: {
731
+ 'thread-leader-c': { thread_id: 'thread-leader-c', kind: 'leader', first_seen_at: '2026-06-12T09:59:00.000Z', last_seen_at: '2026-06-12T09:59:00.000Z', turn_count: 1 },
732
+ 'thread-critic': { thread_id: 'thread-critic', kind: 'subagent', first_seen_at: '2026-06-12T10:03:00.000Z', last_seen_at: '2026-06-12T10:03:00.000Z', completed_at: '2026-06-12T10:03:00.000Z', turn_count: 1 },
733
+ },
734
+ },
735
+ },
736
+ }, null, 2));
737
+ const state = {
738
+ current_phase: 'ralplan',
739
+ handoff_artifacts: {
740
+ ralplan_consensus_gate: {
741
+ complete: true,
742
+ sequence: ['architect-review', 'critic-review'],
743
+ ralplan_architect_review: {
744
+ agent_role: 'architect',
745
+ provenance_kind: 'native_subagent',
746
+ verdict: 'approve',
747
+ session_id: 'sess-architect',
748
+ thread_id: 'thread-architect',
749
+ completed_at: '2026-06-12T10:02:00.000Z',
750
+ },
751
+ ralplan_critic_review: {
752
+ agent_role: 'critic',
753
+ provenance_kind: 'native_subagent',
754
+ verdict: 'approve',
755
+ session_id: 'sess-critic',
756
+ thread_id: 'thread-critic',
757
+ completed_at: '2026-06-12T10:03:00.000Z',
758
+ },
759
+ },
760
+ },
761
+ };
762
+ const decision = canAdvanceAutopilotRalplanToUltragoal({ cwd, currentState: state });
763
+ assert.equal(decision.allowed, false);
764
+ assert.match(buildAutopilotRalplanUltragoalGateError(decision), /same native subagent tracker session/);
765
+ }
766
+ finally {
767
+ await rm(cwd, { recursive: true, force: true });
768
+ }
769
+ });
770
+ it('rejects stale review session ids even when transition session context exists', async () => {
771
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-autopilot-ralplan-live-session-mismatch-'));
772
+ const sessionId = 'sess-autopilot-live-session';
773
+ const trackingPath = subagentTrackingPath(cwd);
774
+ try {
775
+ await mkdir(join(trackingPath, '..'), { recursive: true });
776
+ await writeFile(trackingPath, JSON.stringify({
777
+ schemaVersion: 1,
778
+ sessions: {
779
+ [sessionId]: {
780
+ session_id: sessionId,
781
+ leader_thread_id: 'thread-leader',
782
+ updated_at: '2026-06-12T10:03:00.000Z',
783
+ threads: {
784
+ 'thread-leader': { thread_id: 'thread-leader', kind: 'leader', first_seen_at: '2026-06-12T09:59:00.000Z', last_seen_at: '2026-06-12T09:59:00.000Z', turn_count: 1 },
785
+ 'thread-architect': { thread_id: 'thread-architect', kind: 'subagent', first_seen_at: '2026-06-12T10:02:00.000Z', last_seen_at: '2026-06-12T10:02:00.000Z', completed_at: '2026-06-12T10:02:00.000Z', turn_count: 1 },
786
+ 'thread-critic': { thread_id: 'thread-critic', kind: 'subagent', first_seen_at: '2026-06-12T10:03:00.000Z', last_seen_at: '2026-06-12T10:03:00.000Z', completed_at: '2026-06-12T10:03:00.000Z', turn_count: 1 },
787
+ },
788
+ },
789
+ },
790
+ }, null, 2));
791
+ const state = {
792
+ current_phase: 'ralplan',
793
+ handoff_artifacts: {
794
+ ralplan_consensus_gate: {
795
+ complete: true,
796
+ sequence: ['architect-review', 'critic-review'],
797
+ ralplan_architect_review: {
798
+ agent_role: 'architect',
799
+ provenance_kind: 'native_subagent',
800
+ verdict: 'approve',
801
+ thread_id: 'thread-architect',
802
+ completed_at: '2026-06-12T10:02:00.000Z',
803
+ },
804
+ ralplan_critic_review: {
805
+ agent_role: 'critic',
806
+ provenance_kind: 'native_subagent',
807
+ verdict: 'approve',
808
+ session_id: 'sess-stale-critic',
809
+ thread_id: 'thread-critic',
810
+ completed_at: '2026-06-12T10:03:00.000Z',
811
+ },
812
+ },
813
+ },
814
+ };
815
+ const decision = canAdvanceAutopilotRalplanToUltragoal({ cwd, sessionId, currentState: state });
816
+ assert.equal(decision.allowed, false);
817
+ assert.match(buildAutopilotRalplanUltragoalGateError(decision), /critic review session_id=sess-stale-critic does not match/);
818
+ }
819
+ finally {
820
+ await rm(cwd, { recursive: true, force: true });
821
+ }
822
+ });
823
+ it('rejects tracker-backed native reviews whose subagent threads are not completed', async () => {
824
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-autopilot-ralplan-incomplete-thread-'));
825
+ const sessionId = 'sess-autopilot-incomplete-thread';
826
+ const trackingPath = subagentTrackingPath(cwd);
827
+ try {
828
+ await mkdir(join(trackingPath, '..'), { recursive: true });
829
+ await writeFile(trackingPath, JSON.stringify({
830
+ schemaVersion: 1,
831
+ sessions: {
832
+ [sessionId]: {
833
+ session_id: sessionId,
834
+ leader_thread_id: 'thread-leader',
835
+ updated_at: '2026-06-12T10:03:00.000Z',
836
+ threads: {
837
+ 'thread-leader': { thread_id: 'thread-leader', kind: 'leader', first_seen_at: '2026-06-12T09:59:00.000Z', last_seen_at: '2026-06-12T09:59:00.000Z', turn_count: 1 },
838
+ 'thread-architect': { thread_id: 'thread-architect', kind: 'subagent', first_seen_at: '2026-06-12T10:02:00.000Z', last_seen_at: '2026-06-12T10:02:00.000Z', turn_count: 1 },
839
+ 'thread-critic': { thread_id: 'thread-critic', kind: 'subagent', first_seen_at: '2026-06-12T10:03:00.000Z', last_seen_at: '2026-06-12T10:03:00.000Z', completed_at: '2026-06-12T10:03:00.000Z', turn_count: 1 },
840
+ },
841
+ },
842
+ },
843
+ }, null, 2));
844
+ const state = {
845
+ current_phase: 'ralplan',
846
+ handoff_artifacts: {
847
+ ralplan_consensus_gate: {
848
+ complete: true,
849
+ sequence: ['architect-review', 'critic-review'],
850
+ ralplan_architect_review: {
851
+ agent_role: 'architect',
852
+ provenance_kind: 'native_subagent',
853
+ verdict: 'approve',
854
+ session_id: sessionId,
855
+ thread_id: 'thread-architect',
856
+ completed_at: '2026-06-12T10:02:00.000Z',
857
+ },
858
+ ralplan_critic_review: {
859
+ agent_role: 'critic',
860
+ provenance_kind: 'native_subagent',
861
+ verdict: 'approve',
862
+ session_id: sessionId,
863
+ thread_id: 'thread-critic',
864
+ completed_at: '2026-06-12T10:03:00.000Z',
865
+ },
866
+ },
867
+ },
868
+ };
869
+ const decision = canAdvanceAutopilotRalplanToUltragoal({ cwd, sessionId, currentState: state });
870
+ assert.equal(decision.allowed, false);
871
+ assert.match(buildAutopilotRalplanUltragoalGateError(decision), /architect tracker thread thread-architect is not completed/);
872
+ }
873
+ finally {
874
+ await rm(cwd, { recursive: true, force: true });
875
+ }
876
+ });
877
+ it('explains tracker-backed native review schema and observed missing session values', async () => {
878
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-autopilot-ralplan-diagnostic-missing-session-'));
879
+ const sessionId = 'sess-autopilot-diagnostic-missing-session';
880
+ const trackingPath = subagentTrackingPath(cwd);
881
+ try {
882
+ await mkdir(join(trackingPath, '..'), { recursive: true });
883
+ await writeFile(trackingPath, JSON.stringify({
884
+ schemaVersion: 1,
885
+ sessions: {},
886
+ }, null, 2));
887
+ const state = {
888
+ current_phase: 'ralplan',
889
+ handoff_artifacts: {
890
+ ralplan_consensus_gate: {
891
+ complete: true,
892
+ sequence: ['architect-review', 'critic-review'],
893
+ ralplan_architect_review: {
894
+ agent_role: 'architect',
895
+ provenance_kind: 'native_subagent',
896
+ verdict: 'approve',
897
+ session_id: sessionId,
898
+ thread_id: 'thread-architect',
899
+ tracker_path: '.omx/state/subagent-tracking.json',
900
+ completed_at: '2026-06-12T10:02:00.000Z',
901
+ },
902
+ ralplan_critic_review: {
903
+ agent_role: 'critic',
904
+ provenance_kind: 'native_subagent',
905
+ verdict: 'approve',
906
+ session_id: sessionId,
907
+ thread_id: 'thread-critic',
908
+ tracker_path: '.omx/state/subagent-tracking.json',
909
+ completed_at: '2026-06-12T10:03:00.000Z',
910
+ },
911
+ },
912
+ },
913
+ };
914
+ const decision = canAdvanceAutopilotRalplanToUltragoal({ cwd, sessionId, currentState: state });
915
+ assert.equal(decision.allowed, false);
916
+ assert.equal(decision.evidence?.diagnostic?.current_session_id, sessionId);
917
+ assert.equal(decision.evidence?.diagnostic?.architect.session_found, false);
918
+ assert.equal(decision.evidence?.diagnostic?.architect.thread_found, false);
919
+ assert.equal(decision.evidence?.diagnostic?.distinct_thread_ids, true);
920
+ const error = buildAutopilotRalplanUltragoalGateError(decision);
921
+ assert.match(error, /Expected:/);
922
+ assert.match(error, /sessions\["<current_session_id>"\]\.threads\["<architect_thread_id>"\]\.kind = "subagent"/);
923
+ assert.match(error, /current_session_id: sess-autopilot-diagnostic-missing-session/);
924
+ assert.match(error, /architect thread_id: thread-architect found: no kind=missing completed=no/);
925
+ assert.match(error, /session_id: sess-autopilot-diagnostic-missing-session session_found=no/);
926
+ assert.match(error, /Re-run native ralplan Architect\/Critic reviews/);
927
+ assert.match(error, /docs\/contracts\/ralplan-consensus-gate\.md/);
928
+ }
929
+ finally {
930
+ await rm(cwd, { recursive: true, force: true });
931
+ }
932
+ });
933
+ it('explains observed tracker thread kind and completion checks', async () => {
934
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-autopilot-ralplan-diagnostic-thread-values-'));
935
+ const sessionId = 'sess-autopilot-diagnostic-thread-values';
936
+ const trackingPath = subagentTrackingPath(cwd);
937
+ try {
938
+ await mkdir(join(trackingPath, '..'), { recursive: true });
939
+ await writeFile(trackingPath, JSON.stringify({
940
+ schemaVersion: 1,
941
+ sessions: {
942
+ [sessionId]: {
943
+ session_id: sessionId,
944
+ leader_thread_id: 'thread-leader',
945
+ threads: {
946
+ 'thread-architect': { thread_id: 'thread-architect', kind: 'leader', turn_count: 1 },
947
+ 'thread-critic': { thread_id: 'thread-critic', kind: 'subagent', completed_at: '2026-06-12T10:03:00.000Z', turn_count: 1 },
948
+ },
949
+ },
950
+ },
951
+ }, null, 2));
952
+ const state = {
953
+ current_phase: 'ralplan',
954
+ handoff_artifacts: {
955
+ ralplan_consensus_gate: {
956
+ complete: true,
957
+ sequence: ['architect-review', 'critic-review'],
958
+ ralplan_architect_review: {
959
+ agent_role: 'architect',
960
+ provenance_kind: 'native_subagent',
961
+ verdict: 'approve',
962
+ session_id: sessionId,
963
+ thread_id: 'thread-architect',
964
+ },
965
+ ralplan_critic_review: {
966
+ agent_role: 'critic',
967
+ provenance_kind: 'native_subagent',
968
+ verdict: 'approve',
969
+ session_id: sessionId,
970
+ thread_id: 'thread-critic',
971
+ },
972
+ },
973
+ },
974
+ };
975
+ const decision = canAdvanceAutopilotRalplanToUltragoal({ cwd, sessionId, currentState: state });
976
+ assert.equal(decision.allowed, false);
977
+ assert.equal(decision.evidence?.diagnostic?.architect.session_found, true);
978
+ assert.equal(decision.evidence?.diagnostic?.architect.thread_found, true);
979
+ assert.equal(decision.evidence?.diagnostic?.architect.kind, 'leader');
980
+ assert.equal(decision.evidence?.diagnostic?.architect.completed, false);
981
+ const error = buildAutopilotRalplanUltragoalGateError(decision);
982
+ assert.match(error, /architect thread_id: thread-architect found: yes kind=leader completed=no/);
983
+ assert.match(error, /critic thread_id: thread-critic found: yes kind=subagent completed=yes/);
984
+ assert.match(error, /distinct_thread_ids: yes/);
985
+ }
986
+ finally {
987
+ await rm(cwd, { recursive: true, force: true });
988
+ }
989
+ });
56
990
  it('rejects native review evidence from the session leader even when malformed tracking marks it as subagent', async () => {
57
991
  const cwd = await mkdtemp(join(tmpdir(), 'omx-autopilot-ralplan-leader-spoof-'));
58
992
  const sessionId = 'sess-autopilot-leader-spoof';
@@ -145,6 +1079,7 @@ describe('autopilot ralplan gate', () => {
145
1079
  kind: 'subagent',
146
1080
  first_seen_at: '2026-05-28T18:34:51.000Z',
147
1081
  last_seen_at: '2026-05-28T18:34:51.000Z',
1082
+ completed_at: '2026-05-28T18:34:51.000Z',
148
1083
  turn_count: 1,
149
1084
  mode: 'architect',
150
1085
  },
@@ -153,6 +1088,7 @@ describe('autopilot ralplan gate', () => {
153
1088
  kind: 'subagent',
154
1089
  first_seen_at: '2026-05-28T18:35:10.000Z',
155
1090
  last_seen_at: '2026-05-28T18:35:10.000Z',
1091
+ completed_at: '2026-05-28T18:35:10.000Z',
156
1092
  turn_count: 1,
157
1093
  mode: 'critic',
158
1094
  },