oh-my-codex 0.18.11 → 0.18.13

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 (196) hide show
  1. package/Cargo.lock +6 -6
  2. package/Cargo.toml +1 -1
  3. package/README.md +9 -1
  4. package/dist/autopilot/__tests__/ralplan-gate.test.js +668 -0
  5. package/dist/autopilot/__tests__/ralplan-gate.test.js.map +1 -1
  6. package/dist/autopilot/completion-gate.d.ts +10 -0
  7. package/dist/autopilot/completion-gate.d.ts.map +1 -0
  8. package/dist/autopilot/completion-gate.js +154 -0
  9. package/dist/autopilot/completion-gate.js.map +1 -0
  10. package/dist/autopilot/ralplan-gate.d.ts.map +1 -1
  11. package/dist/autopilot/ralplan-gate.js +42 -21
  12. package/dist/autopilot/ralplan-gate.js.map +1 -1
  13. package/dist/cli/__tests__/codex-plugin-layout.test.js +46 -3
  14. package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
  15. package/dist/cli/__tests__/doctor-invalid-config.test.js +35 -0
  16. package/dist/cli/__tests__/doctor-invalid-config.test.js.map +1 -1
  17. package/dist/cli/__tests__/doctor-warning-copy.test.js +317 -0
  18. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
  19. package/dist/cli/__tests__/index.test.js +120 -2
  20. package/dist/cli/__tests__/index.test.js.map +1 -1
  21. package/dist/cli/__tests__/launch-fallback.test.js +1 -1
  22. package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
  23. package/dist/cli/__tests__/resume.test.js +217 -1
  24. package/dist/cli/__tests__/resume.test.js.map +1 -1
  25. package/dist/cli/__tests__/session-scoped-runtime.test.js +101 -0
  26. package/dist/cli/__tests__/session-scoped-runtime.test.js.map +1 -1
  27. package/dist/cli/__tests__/session-search-help.test.js +3 -2
  28. package/dist/cli/__tests__/session-search-help.test.js.map +1 -1
  29. package/dist/cli/__tests__/session-search.test.js +64 -2
  30. package/dist/cli/__tests__/session-search.test.js.map +1 -1
  31. package/dist/cli/__tests__/setup-agents-overwrite.test.js +289 -1
  32. package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
  33. package/dist/cli/__tests__/setup-install-mode.test.js +290 -17
  34. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
  35. package/dist/cli/__tests__/setup-prompts-overwrite.test.js +74 -0
  36. package/dist/cli/__tests__/setup-prompts-overwrite.test.js.map +1 -1
  37. package/dist/cli/__tests__/setup-scope.test.js +45 -0
  38. package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
  39. package/dist/cli/__tests__/state.test.js +93 -0
  40. package/dist/cli/__tests__/state.test.js.map +1 -1
  41. package/dist/cli/__tests__/update.test.js +157 -3
  42. package/dist/cli/__tests__/update.test.js.map +1 -1
  43. package/dist/cli/__tests__/version-sync-contract.test.js +2 -0
  44. package/dist/cli/__tests__/version-sync-contract.test.js.map +1 -1
  45. package/dist/cli/doctor.d.ts.map +1 -1
  46. package/dist/cli/doctor.js +90 -12
  47. package/dist/cli/doctor.js.map +1 -1
  48. package/dist/cli/index.d.ts +13 -4
  49. package/dist/cli/index.d.ts.map +1 -1
  50. package/dist/cli/index.js +439 -46
  51. package/dist/cli/index.js.map +1 -1
  52. package/dist/cli/project-runtime-codex-homes.d.ts +6 -0
  53. package/dist/cli/project-runtime-codex-homes.d.ts.map +1 -0
  54. package/dist/cli/project-runtime-codex-homes.js +27 -0
  55. package/dist/cli/project-runtime-codex-homes.js.map +1 -0
  56. package/dist/cli/session-search.d.ts.map +1 -1
  57. package/dist/cli/session-search.js +8 -1
  58. package/dist/cli/session-search.js.map +1 -1
  59. package/dist/cli/setup.d.ts +2 -2
  60. package/dist/cli/setup.d.ts.map +1 -1
  61. package/dist/cli/setup.js +482 -126
  62. package/dist/cli/setup.js.map +1 -1
  63. package/dist/cli/state.d.ts.map +1 -1
  64. package/dist/cli/state.js +79 -8
  65. package/dist/cli/state.js.map +1 -1
  66. package/dist/cli/update.d.ts +1 -0
  67. package/dist/cli/update.d.ts.map +1 -1
  68. package/dist/cli/update.js +42 -10
  69. package/dist/cli/update.js.map +1 -1
  70. package/dist/config/__tests__/codex-hooks.test.js +73 -29
  71. package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
  72. package/dist/config/codex-hooks.d.ts +14 -0
  73. package/dist/config/codex-hooks.d.ts.map +1 -1
  74. package/dist/config/codex-hooks.js +54 -51
  75. package/dist/config/codex-hooks.js.map +1 -1
  76. package/dist/config/generator.d.ts +1 -1
  77. package/dist/config/generator.d.ts.map +1 -1
  78. package/dist/config/generator.js +1 -1
  79. package/dist/config/generator.js.map +1 -1
  80. package/dist/hooks/__tests__/best-practice-research-skill.test.js +12 -0
  81. package/dist/hooks/__tests__/best-practice-research-skill.test.js.map +1 -1
  82. package/dist/hud/__tests__/authority.test.js +45 -12
  83. package/dist/hud/__tests__/authority.test.js.map +1 -1
  84. package/dist/hud/__tests__/reconcile.test.js +95 -0
  85. package/dist/hud/__tests__/reconcile.test.js.map +1 -1
  86. package/dist/hud/__tests__/render.test.js +6 -6
  87. package/dist/hud/__tests__/render.test.js.map +1 -1
  88. package/dist/hud/__tests__/tmux.test.js +2 -2
  89. package/dist/hud/__tests__/tmux.test.js.map +1 -1
  90. package/dist/hud/authority.d.ts.map +1 -1
  91. package/dist/hud/authority.js +17 -2
  92. package/dist/hud/authority.js.map +1 -1
  93. package/dist/hud/index.js +1 -4
  94. package/dist/hud/index.js.map +1 -1
  95. package/dist/hud/reconcile.d.ts.map +1 -1
  96. package/dist/hud/reconcile.js +42 -0
  97. package/dist/hud/reconcile.js.map +1 -1
  98. package/dist/hud/render.d.ts.map +1 -1
  99. package/dist/hud/render.js +6 -0
  100. package/dist/hud/render.js.map +1 -1
  101. package/dist/hud/tmux.d.ts.map +1 -1
  102. package/dist/hud/tmux.js +5 -4
  103. package/dist/hud/tmux.js.map +1 -1
  104. package/dist/mcp/__tests__/bootstrap.test.js +31 -1
  105. package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
  106. package/dist/mcp/bootstrap.d.ts +1 -0
  107. package/dist/mcp/bootstrap.d.ts.map +1 -1
  108. package/dist/mcp/bootstrap.js +32 -0
  109. package/dist/mcp/bootstrap.js.map +1 -1
  110. package/dist/modes/__tests__/base-autopilot-gates.test.d.ts +2 -0
  111. package/dist/modes/__tests__/base-autopilot-gates.test.d.ts.map +1 -0
  112. package/dist/modes/__tests__/base-autopilot-gates.test.js +154 -0
  113. package/dist/modes/__tests__/base-autopilot-gates.test.js.map +1 -0
  114. package/dist/modes/base.d.ts +4 -1
  115. package/dist/modes/base.d.ts.map +1 -1
  116. package/dist/modes/base.js +71 -1
  117. package/dist/modes/base.js.map +1 -1
  118. package/dist/pipeline/__tests__/orchestrator.test.js +144 -3
  119. package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
  120. package/dist/pipeline/__tests__/stages.test.js +109 -0
  121. package/dist/pipeline/__tests__/stages.test.js.map +1 -1
  122. package/dist/pipeline/orchestrator.d.ts.map +1 -1
  123. package/dist/pipeline/orchestrator.js +11 -4
  124. package/dist/pipeline/orchestrator.js.map +1 -1
  125. package/dist/pipeline/stages/code-review.d.ts +2 -0
  126. package/dist/pipeline/stages/code-review.d.ts.map +1 -1
  127. package/dist/pipeline/stages/code-review.js +2 -0
  128. package/dist/pipeline/stages/code-review.js.map +1 -1
  129. package/dist/pipeline/stages/ultraqa.d.ts +3 -0
  130. package/dist/pipeline/stages/ultraqa.d.ts.map +1 -1
  131. package/dist/pipeline/stages/ultraqa.js +3 -0
  132. package/dist/pipeline/stages/ultraqa.js.map +1 -1
  133. package/dist/ralplan/__tests__/consensus-gate.test.d.ts +2 -0
  134. package/dist/ralplan/__tests__/consensus-gate.test.d.ts.map +1 -0
  135. package/dist/ralplan/__tests__/consensus-gate.test.js +631 -0
  136. package/dist/ralplan/__tests__/consensus-gate.test.js.map +1 -0
  137. package/dist/ralplan/consensus-gate.d.ts +9 -1
  138. package/dist/ralplan/consensus-gate.d.ts.map +1 -1
  139. package/dist/ralplan/consensus-gate.js +287 -65
  140. package/dist/ralplan/consensus-gate.js.map +1 -1
  141. package/dist/scripts/__tests__/codex-native-hook.test.js +481 -0
  142. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  143. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  144. package/dist/scripts/codex-native-hook.js +145 -25
  145. package/dist/scripts/codex-native-hook.js.map +1 -1
  146. package/dist/scripts/codex-native-pre-post.d.ts +1 -0
  147. package/dist/scripts/codex-native-pre-post.d.ts.map +1 -1
  148. package/dist/scripts/codex-native-pre-post.js +130 -0
  149. package/dist/scripts/codex-native-pre-post.js.map +1 -1
  150. package/dist/session-history/__tests__/search.test.js +166 -0
  151. package/dist/session-history/__tests__/search.test.js.map +1 -1
  152. package/dist/session-history/search.d.ts +7 -0
  153. package/dist/session-history/search.d.ts.map +1 -1
  154. package/dist/session-history/search.js +83 -24
  155. package/dist/session-history/search.js.map +1 -1
  156. package/dist/sidecar/__tests__/collector.test.js +60 -0
  157. package/dist/sidecar/__tests__/collector.test.js.map +1 -1
  158. package/dist/sidecar/collector.d.ts.map +1 -1
  159. package/dist/sidecar/collector.js +3 -6
  160. package/dist/sidecar/collector.js.map +1 -1
  161. package/dist/state/__tests__/operations.test.js +622 -0
  162. package/dist/state/__tests__/operations.test.js.map +1 -1
  163. package/dist/state/__tests__/skill-active.test.js +82 -0
  164. package/dist/state/__tests__/skill-active.test.js.map +1 -1
  165. package/dist/state/operations.d.ts.map +1 -1
  166. package/dist/state/operations.js +31 -9
  167. package/dist/state/operations.js.map +1 -1
  168. package/dist/state/skill-active.d.ts.map +1 -1
  169. package/dist/state/skill-active.js +41 -1
  170. package/dist/state/skill-active.js.map +1 -1
  171. package/dist/team/__tests__/runtime.test.js +81 -57
  172. package/dist/team/__tests__/runtime.test.js.map +1 -1
  173. package/dist/team/runtime.js +4 -4
  174. package/dist/team/runtime.js.map +1 -1
  175. package/dist/utils/__tests__/paths.test.js +23 -0
  176. package/dist/utils/__tests__/paths.test.js.map +1 -1
  177. package/dist/utils/__tests__/version.test.js +27 -0
  178. package/dist/utils/__tests__/version.test.js.map +1 -1
  179. package/dist/utils/paths.d.ts.map +1 -1
  180. package/dist/utils/paths.js +4 -2
  181. package/dist/utils/paths.js.map +1 -1
  182. package/dist/utils/version.d.ts.map +1 -1
  183. package/dist/utils/version.js +7 -2
  184. package/dist/utils/version.js.map +1 -1
  185. package/dist/verification/__tests__/ci-rust-gates.test.js +4 -2
  186. package/dist/verification/__tests__/ci-rust-gates.test.js.map +1 -1
  187. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js +71 -3
  188. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js.map +1 -1
  189. package/package.json +1 -1
  190. package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
  191. package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +53 -2
  192. package/plugins/oh-my-codex/skills/best-practice-research/SKILL.md +6 -1
  193. package/skills/best-practice-research/SKILL.md +6 -1
  194. package/src/scripts/__tests__/codex-native-hook.test.ts +615 -0
  195. package/src/scripts/codex-native-hook.ts +162 -32
  196. package/src/scripts/codex-native-pre-post.ts +137 -0
@@ -25,6 +25,9 @@ export function createUltraqaStage(options = {}) {
25
25
  summary: options.summary ?? (hasQaEvidence
26
26
  ? (clean ? 'UltraQA gate clean.' : 'UltraQA found issues; return to ralplan.')
27
27
  : 'UltraQA evidence missing; fail closed and return to ralplan.'),
28
+ stage: 'ultraqa',
29
+ artifact_path: '.omx/state/autopilot-state.json#pipeline_stage_results.ultraqa.artifacts.qa_verdict',
30
+ ...(skipped ? { reason: options.summary ?? 'UltraQA explicitly skipped.' } : {}),
28
31
  };
29
32
  return {
30
33
  status: 'completed',
@@ -1 +1 @@
1
- {"version":3,"file":"ultraqa.js","sourceRoot":"","sources":["../../../src/pipeline/stages/ultraqa.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA8BH,MAAM,UAAU,kBAAkB,CAAC,UAA+B,EAAE;IAClE,OAAO;QACL,IAAI,EAAE,SAAS;QAEf,KAAK,CAAC,GAAG,CAAC,GAAiB;YACzB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC7B,MAAM,UAAU,GAAsB;gBACpC,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,GAAG,EAAE,GAAG,CAAC,GAAG;gBACZ,SAAS,EAAE,GAAG,CAAC,SAAS;gBACxB,kBAAkB,EAAG,GAAG,CAAC,SAAS,CAAC,SAAiD,IAAI,EAAE;gBAC1F,mBAAmB,EAAG,GAAG,CAAC,SAAS,CAAC,aAAa,CAAyC,IAAI,EAAE;gBAChG,WAAW,EAAE,uBAAuB,CAAC,GAAG,CAAC,IAAI,CAAC;aAC/C,CAAC;YACF,MAAM,aAAa,GAAG,OAAO,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS,CAAC;YACnF,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,KAAK,CAAC;YACzC,MAAM,KAAK,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;YACjE,MAAM,OAAO,GAAmB;gBAC9B,KAAK;gBACL,OAAO;gBACP,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,CAAC,aAAa;oBACxC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,0CAA0C,CAAC;oBAC9E,CAAC,CAAC,8DAA8D,CAAC;aACpE,CAAC;YAEF,OAAO;gBACL,MAAM,EAAE,WAAW;gBACnB,SAAS,EAAE;oBACT,KAAK,EAAE,SAAS;oBAChB,iBAAiB,EAAE,UAAU;oBAC7B,UAAU,EAAE,OAAO;oBACnB,wBAAwB,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO;oBACxD,WAAW,EAAE,UAAU,CAAC,WAAW;iBACpC;gBACD,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;aACpC,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,IAAY;IAClD,OAAO,YAAY,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;AAC5C,CAAC"}
1
+ {"version":3,"file":"ultraqa.js","sourceRoot":"","sources":["../../../src/pipeline/stages/ultraqa.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAkCH,MAAM,UAAU,kBAAkB,CAAC,UAA+B,EAAE;IAClE,OAAO;QACL,IAAI,EAAE,SAAS;QAEf,KAAK,CAAC,GAAG,CAAC,GAAiB;YACzB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC7B,MAAM,UAAU,GAAsB;gBACpC,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,GAAG,EAAE,GAAG,CAAC,GAAG;gBACZ,SAAS,EAAE,GAAG,CAAC,SAAS;gBACxB,kBAAkB,EAAG,GAAG,CAAC,SAAS,CAAC,SAAiD,IAAI,EAAE;gBAC1F,mBAAmB,EAAG,GAAG,CAAC,SAAS,CAAC,aAAa,CAAyC,IAAI,EAAE;gBAChG,WAAW,EAAE,uBAAuB,CAAC,GAAG,CAAC,IAAI,CAAC;aAC/C,CAAC;YACF,MAAM,aAAa,GAAG,OAAO,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS,CAAC;YACnF,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,KAAK,CAAC;YACzC,MAAM,KAAK,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;YACjE,MAAM,OAAO,GAAmB;gBAC9B,KAAK;gBACL,OAAO;gBACP,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,CAAC,aAAa;oBACxC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,0CAA0C,CAAC;oBAC9E,CAAC,CAAC,8DAA8D,CAAC;gBACnE,KAAK,EAAE,SAAS;gBAChB,aAAa,EAAE,qFAAqF;gBACpG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,OAAO,IAAI,6BAA6B,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACjF,CAAC;YAEF,OAAO;gBACL,MAAM,EAAE,WAAW;gBACnB,SAAS,EAAE;oBACT,KAAK,EAAE,SAAS;oBAChB,iBAAiB,EAAE,UAAU;oBAC7B,UAAU,EAAE,OAAO;oBACnB,wBAAwB,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO;oBACxD,WAAW,EAAE,UAAU,CAAC,WAAW;iBACpC;gBACD,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;aACpC,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,IAAY;IAClD,OAAO,YAAY,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=consensus-gate.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consensus-gate.test.d.ts","sourceRoot":"","sources":["../../../src/ralplan/__tests__/consensus-gate.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,631 @@
1
+ import assert from 'node:assert/strict';
2
+ import { describe, it } from 'node:test';
3
+ import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
4
+ import { join } from 'node:path';
5
+ import { tmpdir } from 'node:os';
6
+ import { getBaseStateDir } from '../../state/paths.js';
7
+ import { subagentTrackingPath } from '../../subagents/tracker.js';
8
+ import { buildRalplanConsensusGateForCwd, buildRalplanConsensusGateFromSources } from '../consensus-gate.js';
9
+ describe('ralplan consensus gate state roots', () => {
10
+ it('rejects invalid complete consensus even when it appears after a valid source', () => {
11
+ const validConsensus = {
12
+ ralplan_consensus_gate: {
13
+ complete: true,
14
+ sequence: ['architect-review', 'critic-review'],
15
+ ralplan_architect_review: {
16
+ agent_role: 'architect',
17
+ verdict: 'approve',
18
+ completed_at: '2026-06-12T10:00:00.000Z',
19
+ },
20
+ ralplan_critic_review: {
21
+ agent_role: 'critic',
22
+ verdict: 'approve',
23
+ completed_at: '2026-06-12T10:05:00.000Z',
24
+ },
25
+ },
26
+ };
27
+ const invalidConsensus = {
28
+ ralplan_consensus_gate: {
29
+ complete: true,
30
+ sequence: ['architect-review', 'critic-review'],
31
+ ralplan_architect_review: {
32
+ agent_role: 'architect',
33
+ verdict: 'iterate',
34
+ completed_at: '2026-06-12T10:10:00.000Z',
35
+ },
36
+ ralplan_critic_review: {
37
+ agent_role: 'critic',
38
+ verdict: 'approve',
39
+ completed_at: '2026-06-12T10:15:00.000Z',
40
+ },
41
+ },
42
+ };
43
+ const gate = buildRalplanConsensusGateFromSources([
44
+ { source: 'older-valid-source', value: validConsensus },
45
+ { source: 'later-invalid-source', value: invalidConsensus },
46
+ ]);
47
+ assert.equal(gate.complete, false);
48
+ assert.equal(gate.source, 'later-invalid-source');
49
+ assert.equal(gate.blockedReason, 'non_approving_ralplan_consensus_review');
50
+ assert.match(gate.blockedDetails?.join(' ') ?? '', /architect.*verdict=iterate/i);
51
+ });
52
+ it('rejects malformed complete consensus even when it appears after a valid source', () => {
53
+ const validConsensus = {
54
+ ralplan_consensus_gate: {
55
+ complete: true,
56
+ sequence: ['architect-review', 'critic-review'],
57
+ ralplan_architect_review: {
58
+ agent_role: 'architect',
59
+ verdict: 'approve',
60
+ completed_at: '2026-06-12T10:00:00.000Z',
61
+ },
62
+ ralplan_critic_review: {
63
+ agent_role: 'critic',
64
+ verdict: 'approve',
65
+ completed_at: '2026-06-12T10:05:00.000Z',
66
+ },
67
+ },
68
+ };
69
+ const malformedConsensus = {
70
+ ralplan_consensus_gate: {
71
+ complete: true,
72
+ sequence: ['critic-review', 'architect-review'],
73
+ ralplan_architect_review: {
74
+ agent_role: 'architect',
75
+ verdict: 'approve',
76
+ completed_at: '2026-06-12T10:10:00.000Z',
77
+ },
78
+ ralplan_critic_review: {
79
+ agent_role: 'critic',
80
+ verdict: 'approve',
81
+ completed_at: '2026-06-12T10:15:00.000Z',
82
+ },
83
+ },
84
+ };
85
+ const gate = buildRalplanConsensusGateFromSources([
86
+ { source: 'older-valid-source', value: validConsensus },
87
+ { source: 'later-malformed-source', value: malformedConsensus },
88
+ ]);
89
+ assert.equal(gate.complete, false);
90
+ assert.equal(gate.source, 'later-malformed-source');
91
+ assert.equal(gate.blockedReason, 'non_approving_ralplan_consensus_review');
92
+ assert.match(gate.blockedDetails?.join(' ') ?? '', /sequence is not architect-review then critic-review/i);
93
+ });
94
+ it('ignores ambient root consensus unless the ambient session is bound to this cwd', async () => {
95
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-ralplan-consensus-local-'));
96
+ const ambientRoot = await mkdtemp(join(tmpdir(), 'omx-ralplan-consensus-ambient-'));
97
+ const previousOmxRoot = process.env.OMX_ROOT;
98
+ const previousOmxStateRoot = process.env.OMX_STATE_ROOT;
99
+ const previousOmxTeamStateRoot = process.env.OMX_TEAM_STATE_ROOT;
100
+ try {
101
+ process.env.OMX_ROOT = ambientRoot;
102
+ delete process.env.OMX_STATE_ROOT;
103
+ delete process.env.OMX_TEAM_STATE_ROOT;
104
+ const ambientStateDir = getBaseStateDir(cwd);
105
+ await mkdir(ambientStateDir, { recursive: true });
106
+ await writeFile(join(ambientStateDir, 'ralplan-state.json'), JSON.stringify({
107
+ ralplan_consensus_gate: {
108
+ complete: true,
109
+ sequence: ['architect-review', 'critic-review'],
110
+ ralplan_architect_review: { agent_role: 'architect', verdict: 'approve' },
111
+ ralplan_critic_review: { agent_role: 'critic', verdict: 'approve' },
112
+ },
113
+ }, null, 2));
114
+ const gate = buildRalplanConsensusGateForCwd(cwd);
115
+ assert.equal(gate.complete, false);
116
+ assert.equal(gate.blockedReason, 'missing_sequential_architect_then_critic_approval');
117
+ }
118
+ finally {
119
+ if (typeof previousOmxRoot === 'string')
120
+ process.env.OMX_ROOT = previousOmxRoot;
121
+ else
122
+ delete process.env.OMX_ROOT;
123
+ if (typeof previousOmxStateRoot === 'string')
124
+ process.env.OMX_STATE_ROOT = previousOmxStateRoot;
125
+ else
126
+ delete process.env.OMX_STATE_ROOT;
127
+ if (typeof previousOmxTeamStateRoot === 'string')
128
+ process.env.OMX_TEAM_STATE_ROOT = previousOmxTeamStateRoot;
129
+ else
130
+ delete process.env.OMX_TEAM_STATE_ROOT;
131
+ await rm(cwd, { recursive: true, force: true });
132
+ await rm(ambientRoot, { recursive: true, force: true });
133
+ }
134
+ });
135
+ it('reads tracker-backed consensus evidence from OMX_STATE_ROOT instead of cwd/.omx/state', async () => {
136
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-ralplan-consensus-cwd-'));
137
+ const boxedRoot = await mkdtemp(join(tmpdir(), 'omx-ralplan-consensus-state-root-'));
138
+ const previousOmxRoot = process.env.OMX_ROOT;
139
+ const previousOmxStateRoot = process.env.OMX_STATE_ROOT;
140
+ const previousOmxTeamStateRoot = process.env.OMX_TEAM_STATE_ROOT;
141
+ const sessionId = 'sess-boxed-consensus';
142
+ try {
143
+ delete process.env.OMX_ROOT;
144
+ delete process.env.OMX_TEAM_STATE_ROOT;
145
+ process.env.OMX_STATE_ROOT = boxedRoot;
146
+ const baseStateDir = getBaseStateDir(cwd);
147
+ const sessionDir = join(baseStateDir, 'sessions', sessionId);
148
+ await mkdir(sessionDir, { recursive: true });
149
+ await writeFile(join(baseStateDir, 'session.json'), JSON.stringify({
150
+ session_id: sessionId,
151
+ native_session_id: 'thread-leader',
152
+ cwd,
153
+ }, null, 2));
154
+ await writeFile(subagentTrackingPath(cwd), JSON.stringify({
155
+ schemaVersion: 1,
156
+ sessions: {
157
+ [sessionId]: {
158
+ session_id: sessionId,
159
+ leader_thread_id: 'thread-leader',
160
+ updated_at: '2026-06-11T16:30:00.000Z',
161
+ threads: {
162
+ 'thread-leader': {
163
+ thread_id: 'thread-leader',
164
+ kind: 'leader',
165
+ first_seen_at: '2026-06-11T16:29:00.000Z',
166
+ last_seen_at: '2026-06-11T16:29:00.000Z',
167
+ turn_count: 1,
168
+ },
169
+ 'thread-architect': {
170
+ thread_id: 'thread-architect',
171
+ kind: 'subagent',
172
+ first_seen_at: '2026-06-11T16:29:30.000Z',
173
+ last_seen_at: '2026-06-11T16:29:30.000Z',
174
+ completed_at: '2026-06-11T16:29:30.000Z',
175
+ turn_count: 1,
176
+ },
177
+ 'thread-critic': {
178
+ thread_id: 'thread-critic',
179
+ kind: 'subagent',
180
+ first_seen_at: '2026-06-11T16:30:00.000Z',
181
+ last_seen_at: '2026-06-11T16:30:00.000Z',
182
+ completed_at: '2026-06-11T16:30:00.000Z',
183
+ turn_count: 1,
184
+ },
185
+ },
186
+ },
187
+ },
188
+ }, null, 2));
189
+ await writeFile(join(sessionDir, 'autopilot-state.json'), JSON.stringify({
190
+ current_phase: 'ralplan',
191
+ handoff_artifacts: {
192
+ ralplan_consensus_gate: {
193
+ complete: true,
194
+ sequence: ['architect-review', 'critic-review'],
195
+ ralplan_architect_review: {
196
+ agent_role: 'architect',
197
+ provenance_kind: 'native_subagent',
198
+ verdict: 'approve',
199
+ session_id: sessionId,
200
+ thread_id: 'thread-architect',
201
+ artifact_path: '.omx/plans/architect.md',
202
+ tracker_path: '.omx/state/subagent-tracking.json',
203
+ completed_at: '2026-06-11T16:29:30.000Z',
204
+ },
205
+ ralplan_critic_review: {
206
+ agent_role: 'critic',
207
+ provenance_kind: 'native_subagent',
208
+ verdict: 'approve',
209
+ session_id: sessionId,
210
+ thread_id: 'thread-critic',
211
+ artifact_path: '.omx/plans/critic.md',
212
+ tracker_path: '.omx/state/subagent-tracking.json',
213
+ completed_at: '2026-06-11T16:30:00.000Z',
214
+ },
215
+ },
216
+ },
217
+ }, null, 2));
218
+ const gate = buildRalplanConsensusGateForCwd(cwd, {
219
+ sessionId,
220
+ requireNativeSubagents: true,
221
+ });
222
+ assert.equal(gate.complete, true);
223
+ assert.equal(gate.blockedReason, null);
224
+ assert.match(String(gate.source), new RegExp(`${boxedRoot.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}`));
225
+ }
226
+ finally {
227
+ if (typeof previousOmxRoot === 'string')
228
+ process.env.OMX_ROOT = previousOmxRoot;
229
+ else
230
+ delete process.env.OMX_ROOT;
231
+ if (typeof previousOmxStateRoot === 'string')
232
+ process.env.OMX_STATE_ROOT = previousOmxStateRoot;
233
+ else
234
+ delete process.env.OMX_STATE_ROOT;
235
+ if (typeof previousOmxTeamStateRoot === 'string')
236
+ process.env.OMX_TEAM_STATE_ROOT = previousOmxTeamStateRoot;
237
+ else
238
+ delete process.env.OMX_TEAM_STATE_ROOT;
239
+ await rm(cwd, { recursive: true, force: true });
240
+ await rm(boxedRoot, { recursive: true, force: true });
241
+ }
242
+ });
243
+ it('accepts session-scoped tracker-backed reviews without an explicit sessionId option', async () => {
244
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-ralplan-consensus-discovered-session-'));
245
+ const boxedRoot = await mkdtemp(join(tmpdir(), 'omx-ralplan-consensus-discovered-root-'));
246
+ const previousOmxRoot = process.env.OMX_ROOT;
247
+ const previousOmxStateRoot = process.env.OMX_STATE_ROOT;
248
+ const previousOmxTeamStateRoot = process.env.OMX_TEAM_STATE_ROOT;
249
+ const sessionId = 'sess-discovered-consensus';
250
+ try {
251
+ delete process.env.OMX_ROOT;
252
+ delete process.env.OMX_TEAM_STATE_ROOT;
253
+ process.env.OMX_STATE_ROOT = boxedRoot;
254
+ const baseStateDir = getBaseStateDir(cwd);
255
+ const sessionDir = join(baseStateDir, 'sessions', sessionId);
256
+ await mkdir(sessionDir, { recursive: true });
257
+ await writeFile(join(baseStateDir, 'session.json'), JSON.stringify({
258
+ session_id: sessionId,
259
+ native_session_id: 'thread-leader',
260
+ cwd,
261
+ }, null, 2));
262
+ await writeFile(subagentTrackingPath(cwd), JSON.stringify({
263
+ schemaVersion: 1,
264
+ sessions: {
265
+ [sessionId]: {
266
+ session_id: sessionId,
267
+ leader_thread_id: 'thread-leader',
268
+ updated_at: '2026-06-12T10:03:00.000Z',
269
+ threads: {
270
+ 'thread-leader': {
271
+ thread_id: 'thread-leader',
272
+ kind: 'leader',
273
+ first_seen_at: '2026-06-12T09:59:00.000Z',
274
+ last_seen_at: '2026-06-12T09:59:00.000Z',
275
+ turn_count: 1,
276
+ },
277
+ 'thread-architect': {
278
+ thread_id: 'thread-architect',
279
+ kind: 'subagent',
280
+ first_seen_at: '2026-06-12T10:02:00.000Z',
281
+ last_seen_at: '2026-06-12T10:02:00.000Z',
282
+ completed_at: '2026-06-12T10:02:00.000Z',
283
+ turn_count: 1,
284
+ },
285
+ 'thread-critic': {
286
+ thread_id: 'thread-critic',
287
+ kind: 'subagent',
288
+ first_seen_at: '2026-06-12T10:03:00.000Z',
289
+ last_seen_at: '2026-06-12T10:03:00.000Z',
290
+ completed_at: '2026-06-12T10:03:00.000Z',
291
+ turn_count: 1,
292
+ },
293
+ },
294
+ },
295
+ },
296
+ }, null, 2));
297
+ await writeFile(join(sessionDir, 'ralplan-state.json'), JSON.stringify({
298
+ ralplan_consensus_gate: {
299
+ complete: true,
300
+ sequence: ['architect-review', 'critic-review'],
301
+ ralplan_architect_review: {
302
+ agent_role: 'architect',
303
+ provenance_kind: 'native_subagent',
304
+ verdict: 'approve',
305
+ thread_id: 'thread-architect',
306
+ completed_at: '2026-06-12T10:02:00.000Z',
307
+ },
308
+ ralplan_critic_review: {
309
+ agent_role: 'critic',
310
+ provenance_kind: 'native_subagent',
311
+ verdict: 'approve',
312
+ thread_id: 'thread-critic',
313
+ completed_at: '2026-06-12T10:03:00.000Z',
314
+ },
315
+ },
316
+ }, null, 2));
317
+ const gate = buildRalplanConsensusGateForCwd(cwd, {
318
+ requireNativeSubagents: true,
319
+ });
320
+ assert.equal(gate.complete, true);
321
+ assert.equal(gate.blockedReason, null);
322
+ assert.match(String(gate.source), new RegExp(`${sessionId}/ralplan-state\\.json$`));
323
+ }
324
+ finally {
325
+ if (typeof previousOmxRoot === 'string')
326
+ process.env.OMX_ROOT = previousOmxRoot;
327
+ else
328
+ delete process.env.OMX_ROOT;
329
+ if (typeof previousOmxStateRoot === 'string')
330
+ process.env.OMX_STATE_ROOT = previousOmxStateRoot;
331
+ else
332
+ delete process.env.OMX_STATE_ROOT;
333
+ if (typeof previousOmxTeamStateRoot === 'string')
334
+ process.env.OMX_TEAM_STATE_ROOT = previousOmxTeamStateRoot;
335
+ else
336
+ delete process.env.OMX_TEAM_STATE_ROOT;
337
+ await rm(cwd, { recursive: true, force: true });
338
+ await rm(boxedRoot, { recursive: true, force: true });
339
+ }
340
+ });
341
+ it('rejects stale top-level handoff consensus during a return-to-ralplan cycle', async () => {
342
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-ralplan-consensus-stale-'));
343
+ try {
344
+ const gate = buildRalplanConsensusGateForCwd(cwd, {
345
+ artifacts: {
346
+ current_phase: 'ralplan',
347
+ return_to_ralplan_reason: 'Code review requested changes.',
348
+ handoff_artifacts: {
349
+ ralplan_consensus_gate: {
350
+ complete: true,
351
+ sequence: ['architect-review', 'critic-review'],
352
+ ralplan_architect_review: {
353
+ agent_role: 'architect',
354
+ verdict: 'approve',
355
+ completed_at: '2026-06-11T16:00:00.000Z',
356
+ },
357
+ ralplan_critic_review: {
358
+ agent_role: 'critic',
359
+ verdict: 'approve',
360
+ completed_at: '2026-06-11T16:05:00.000Z',
361
+ },
362
+ },
363
+ },
364
+ },
365
+ });
366
+ assert.equal(gate.complete, false);
367
+ assert.equal(gate.blockedReason, 'missing_sequential_architect_then_critic_approval');
368
+ }
369
+ finally {
370
+ await rm(cwd, { recursive: true, force: true });
371
+ }
372
+ });
373
+ it('rejects stale local ralplan state consensus during a return-to-ralplan cycle', async () => {
374
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-ralplan-consensus-stale-local-state-'));
375
+ try {
376
+ const stateDir = join(cwd, '.omx', 'state');
377
+ await mkdir(stateDir, { recursive: true });
378
+ await writeFile(join(stateDir, 'ralplan-state.json'), JSON.stringify({
379
+ current_phase: 'complete',
380
+ ralplan_consensus_gate: {
381
+ complete: true,
382
+ sequence: ['architect-review', 'critic-review'],
383
+ ralplan_architect_review: {
384
+ agent_role: 'architect',
385
+ verdict: 'approve',
386
+ completed_at: '2026-06-11T16:00:00.000Z',
387
+ },
388
+ ralplan_critic_review: {
389
+ agent_role: 'critic',
390
+ verdict: 'approve',
391
+ completed_at: '2026-06-11T16:05:00.000Z',
392
+ },
393
+ },
394
+ }, null, 2));
395
+ const gate = buildRalplanConsensusGateForCwd(cwd, {
396
+ artifacts: {
397
+ current_phase: 'ralplan',
398
+ return_to_ralplan_reason: 'Code review requested changes.',
399
+ review_cycle: 1,
400
+ },
401
+ });
402
+ assert.equal(gate.complete, false);
403
+ assert.equal(gate.blockedReason, 'missing_sequential_architect_then_critic_approval');
404
+ }
405
+ finally {
406
+ await rm(cwd, { recursive: true, force: true });
407
+ }
408
+ });
409
+ it('rejects local nested handoff consensus when only the local container review_cycle advances', async () => {
410
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-ralplan-consensus-local-container-only-'));
411
+ try {
412
+ const stateDir = join(cwd, '.omx', 'state');
413
+ await mkdir(stateDir, { recursive: true });
414
+ await writeFile(join(stateDir, 'ralplan-state.json'), JSON.stringify({
415
+ current_phase: 'complete',
416
+ review_cycle: 2,
417
+ handoff_artifacts: {
418
+ ralplan_consensus_gate: {
419
+ complete: true,
420
+ sequence: ['architect-review', 'critic-review'],
421
+ ralplan_architect_review: {
422
+ agent_role: 'architect',
423
+ verdict: 'approve',
424
+ completed_at: '2026-06-12T10:00:00.000Z',
425
+ },
426
+ ralplan_critic_review: {
427
+ agent_role: 'critic',
428
+ verdict: 'approve',
429
+ completed_at: '2026-06-12T10:05:00.000Z',
430
+ },
431
+ },
432
+ },
433
+ }, null, 2));
434
+ const gate = buildRalplanConsensusGateForCwd(cwd, {
435
+ artifacts: {
436
+ current_phase: 'ralplan',
437
+ return_to_ralplan_reason: 'Code review requested changes.',
438
+ review_cycle: 1,
439
+ },
440
+ });
441
+ assert.equal(gate.complete, false);
442
+ assert.equal(gate.blockedReason, 'missing_sequential_architect_then_critic_approval');
443
+ }
444
+ finally {
445
+ await rm(cwd, { recursive: true, force: true });
446
+ }
447
+ });
448
+ it('accepts local nested handoff consensus when both reviews carry the advanced review_cycle', async () => {
449
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-ralplan-consensus-local-review-fresh-'));
450
+ try {
451
+ const stateDir = join(cwd, '.omx', 'state');
452
+ await mkdir(stateDir, { recursive: true });
453
+ await writeFile(join(stateDir, 'ralplan-state.json'), JSON.stringify({
454
+ current_phase: 'complete',
455
+ review_cycle: 2,
456
+ handoff_artifacts: {
457
+ ralplan_consensus_gate: {
458
+ complete: true,
459
+ sequence: ['architect-review', 'critic-review'],
460
+ ralplan_architect_review: {
461
+ agent_role: 'architect',
462
+ verdict: 'approve',
463
+ review_cycle: 2,
464
+ completed_at: '2026-06-12T10:00:00.000Z',
465
+ },
466
+ ralplan_critic_review: {
467
+ agent_role: 'critic',
468
+ verdict: 'approve',
469
+ review_cycle: 2,
470
+ completed_at: '2026-06-12T10:05:00.000Z',
471
+ },
472
+ },
473
+ },
474
+ }, null, 2));
475
+ const gate = buildRalplanConsensusGateForCwd(cwd, {
476
+ artifacts: {
477
+ current_phase: 'ralplan',
478
+ return_to_ralplan_reason: 'Code review requested changes.',
479
+ review_cycle: 1,
480
+ },
481
+ });
482
+ assert.equal(gate.complete, true);
483
+ assert.equal(gate.blockedReason, null);
484
+ }
485
+ finally {
486
+ await rm(cwd, { recursive: true, force: true });
487
+ }
488
+ });
489
+ it('rejects local state.handoff_artifacts consensus when only the local container review_cycle advances', async () => {
490
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-ralplan-consensus-local-state-container-only-'));
491
+ try {
492
+ const stateDir = join(cwd, '.omx', 'state');
493
+ await mkdir(stateDir, { recursive: true });
494
+ await writeFile(join(stateDir, 'ralplan-state.json'), JSON.stringify({
495
+ current_phase: 'complete',
496
+ review_cycle: 2,
497
+ state: {
498
+ handoff_artifacts: {
499
+ ralplan_consensus_gate: {
500
+ complete: true,
501
+ sequence: ['architect-review', 'critic-review'],
502
+ ralplan_architect_review: {
503
+ agent_role: 'architect',
504
+ verdict: 'approve',
505
+ completed_at: '2026-06-12T10:00:00.000Z',
506
+ },
507
+ ralplan_critic_review: {
508
+ agent_role: 'critic',
509
+ verdict: 'approve',
510
+ completed_at: '2026-06-12T10:05:00.000Z',
511
+ },
512
+ },
513
+ },
514
+ },
515
+ }, null, 2));
516
+ const gate = buildRalplanConsensusGateForCwd(cwd, {
517
+ artifacts: {
518
+ current_phase: 'ralplan',
519
+ return_to_ralplan_reason: 'Code review requested changes.',
520
+ review_cycle: 1,
521
+ },
522
+ });
523
+ assert.equal(gate.complete, false);
524
+ assert.equal(gate.blockedReason, 'missing_sequential_architect_then_critic_approval');
525
+ }
526
+ finally {
527
+ await rm(cwd, { recursive: true, force: true });
528
+ }
529
+ });
530
+ it('accepts local state.handoff_artifacts consensus when nested state and both reviews carry the advanced review_cycle', async () => {
531
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-ralplan-consensus-local-state-review-fresh-'));
532
+ try {
533
+ const stateDir = join(cwd, '.omx', 'state');
534
+ await mkdir(stateDir, { recursive: true });
535
+ await writeFile(join(stateDir, 'ralplan-state.json'), JSON.stringify({
536
+ current_phase: 'complete',
537
+ state: {
538
+ current_phase: 'ralplan',
539
+ return_to_ralplan_reason: 'Code review requested changes.',
540
+ review_cycle: 1,
541
+ handoff_artifacts: {
542
+ review_cycle: 2,
543
+ ralplan_consensus_gate: {
544
+ complete: true,
545
+ sequence: ['architect-review', 'critic-review'],
546
+ ralplan_architect_review: {
547
+ agent_role: 'architect',
548
+ verdict: 'approve',
549
+ review_cycle: 2,
550
+ completed_at: '2026-06-12T10:00:00.000Z',
551
+ },
552
+ ralplan_critic_review: {
553
+ agent_role: 'critic',
554
+ verdict: 'approve',
555
+ review_cycle: 2,
556
+ completed_at: '2026-06-12T10:05:00.000Z',
557
+ },
558
+ },
559
+ },
560
+ },
561
+ }, null, 2));
562
+ const gate = buildRalplanConsensusGateForCwd(cwd, {
563
+ artifacts: {
564
+ current_phase: 'ralplan',
565
+ return_to_ralplan_reason: 'Code review requested changes.',
566
+ review_cycle: 1,
567
+ },
568
+ });
569
+ assert.equal(gate.complete, true);
570
+ assert.equal(gate.blockedReason, null);
571
+ }
572
+ finally {
573
+ await rm(cwd, { recursive: true, force: true });
574
+ }
575
+ });
576
+ it('rejects stale review history consensus during a return-to-ralplan cycle', async () => {
577
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-ralplan-consensus-stale-history-'));
578
+ try {
579
+ const gate = buildRalplanConsensusGateForCwd(cwd, {
580
+ artifacts: {
581
+ current_phase: 'ralplan',
582
+ return_to_ralplan_reason: 'Code review requested changes.',
583
+ review_history: [{
584
+ ralplan_architect_review: {
585
+ agent_role: 'architect',
586
+ verdict: 'approve',
587
+ completed_at: '2026-06-11T16:00:00.000Z',
588
+ },
589
+ ralplan_critic_review: {
590
+ agent_role: 'critic',
591
+ verdict: 'approve',
592
+ completed_at: '2026-06-11T16:05:00.000Z',
593
+ },
594
+ }],
595
+ },
596
+ });
597
+ assert.equal(gate.complete, false);
598
+ assert.equal(gate.blockedReason, 'missing_sequential_architect_then_critic_approval');
599
+ }
600
+ finally {
601
+ await rm(cwd, { recursive: true, force: true });
602
+ }
603
+ });
604
+ it('rejects stale review array consensus during a return-to-ralplan cycle', async () => {
605
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-ralplan-consensus-stale-arrays-'));
606
+ try {
607
+ const gate = buildRalplanConsensusGateForCwd(cwd, {
608
+ artifacts: {
609
+ current_phase: 'ralplan',
610
+ return_to_ralplan_reason: 'Code review requested changes.',
611
+ architectReviews: [{
612
+ agent_role: 'architect',
613
+ verdict: 'approve',
614
+ completed_at: '2026-06-11T16:00:00.000Z',
615
+ }],
616
+ criticReviews: [{
617
+ agent_role: 'critic',
618
+ verdict: 'approve',
619
+ completed_at: '2026-06-11T16:05:00.000Z',
620
+ }],
621
+ },
622
+ });
623
+ assert.equal(gate.complete, false);
624
+ assert.equal(gate.blockedReason, 'missing_sequential_architect_then_critic_approval');
625
+ }
626
+ finally {
627
+ await rm(cwd, { recursive: true, force: true });
628
+ }
629
+ });
630
+ });
631
+ //# sourceMappingURL=consensus-gate.test.js.map