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
@@ -6,6 +6,672 @@ import { tmpdir } from 'node:os';
6
6
  import { subagentTrackingPath } from '../../subagents/tracker.js';
7
7
  import { buildAutopilotRalplanUltragoalGateError, canAdvanceAutopilotRalplanToUltragoal, } from '../ralplan-gate.js';
8
8
  describe('autopilot ralplan gate', () => {
9
+ it('rejects invalid next-state complete consensus before falling back to older valid current state', async () => {
10
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-autopilot-ralplan-next-invalid-terminal-'));
11
+ const sessionId = 'sess-autopilot-next-invalid-terminal';
12
+ const trackingPath = subagentTrackingPath(cwd);
13
+ try {
14
+ await mkdir(join(trackingPath, '..'), { recursive: true });
15
+ await writeFile(trackingPath, JSON.stringify({
16
+ schemaVersion: 1,
17
+ sessions: {
18
+ [sessionId]: {
19
+ session_id: sessionId,
20
+ leader_thread_id: 'thread-leader',
21
+ updated_at: '2026-06-12T10:00:00.000Z',
22
+ threads: {
23
+ '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 },
24
+ '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 },
25
+ '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 },
26
+ },
27
+ },
28
+ },
29
+ }, null, 2));
30
+ const nextState = {
31
+ current_phase: 'ralplan',
32
+ return_to_ralplan_reason: 'Code review requested a plan update.',
33
+ handoff_artifacts: {
34
+ ralplan_consensus_gate: {
35
+ complete: true,
36
+ sequence: ['architect-review', 'critic-review'],
37
+ ralplan_architect_review: {
38
+ agent_role: 'architect',
39
+ provenance_kind: 'native_subagent',
40
+ verdict: 'iterate',
41
+ session_id: sessionId,
42
+ thread_id: 'thread-architect-new',
43
+ artifact_path: '.omx/artifacts/architect-new.md',
44
+ tracker_path: '.omx/state/subagent-tracking.json',
45
+ completed_at: '2026-06-12T10:01:00.000Z',
46
+ },
47
+ ralplan_critic_review: {
48
+ agent_role: 'critic',
49
+ provenance_kind: 'native_subagent',
50
+ verdict: 'approve',
51
+ session_id: sessionId,
52
+ thread_id: 'thread-critic-new',
53
+ artifact_path: '.omx/artifacts/critic-new.md',
54
+ tracker_path: '.omx/state/subagent-tracking.json',
55
+ completed_at: '2026-06-12T10:02:00.000Z',
56
+ },
57
+ },
58
+ },
59
+ };
60
+ const currentState = {
61
+ current_phase: 'ralplan',
62
+ handoff_artifacts: {
63
+ ralplan_consensus_gate: {
64
+ complete: true,
65
+ sequence: ['architect-review', 'critic-review'],
66
+ ralplan_architect_review: {
67
+ agent_role: 'architect',
68
+ provenance_kind: 'native_subagent',
69
+ verdict: 'approve',
70
+ session_id: sessionId,
71
+ thread_id: 'thread-architect-old',
72
+ artifact_path: '.omx/artifacts/architect-old.md',
73
+ tracker_path: '.omx/state/subagent-tracking.json',
74
+ completed_at: '2026-06-12T09:59:30.000Z',
75
+ },
76
+ ralplan_critic_review: {
77
+ agent_role: 'critic',
78
+ provenance_kind: 'native_subagent',
79
+ verdict: 'approve',
80
+ session_id: sessionId,
81
+ thread_id: 'thread-critic-old',
82
+ artifact_path: '.omx/artifacts/critic-old.md',
83
+ tracker_path: '.omx/state/subagent-tracking.json',
84
+ completed_at: '2026-06-12T10:00:00.000Z',
85
+ },
86
+ },
87
+ },
88
+ };
89
+ const decision = canAdvanceAutopilotRalplanToUltragoal({ cwd, sessionId, nextState, currentState });
90
+ assert.equal(decision.allowed, false);
91
+ assert.equal(decision.evidence?.source, 'next-autopilot-state:handoff_artifacts');
92
+ assert.equal(decision.evidence?.blockedReason, 'non_approving_ralplan_consensus_review');
93
+ assert.match(buildAutopilotRalplanUltragoalGateError(decision), /architect.*verdict=iterate/i);
94
+ }
95
+ finally {
96
+ await rm(cwd, { recursive: true, force: true });
97
+ }
98
+ });
99
+ it('rejects stale nested ralplan handoff consensus when parent state returned to ralplan', async () => {
100
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-autopilot-ralplan-stale-nested-'));
101
+ const sessionId = 'sess-autopilot-stale-nested';
102
+ const trackingPath = subagentTrackingPath(cwd);
103
+ try {
104
+ await mkdir(join(trackingPath, '..'), { recursive: true });
105
+ await writeFile(trackingPath, JSON.stringify({
106
+ schemaVersion: 1,
107
+ sessions: {
108
+ [sessionId]: {
109
+ session_id: sessionId,
110
+ leader_thread_id: 'thread-leader',
111
+ updated_at: '2026-06-12T10:00:00.000Z',
112
+ threads: {
113
+ '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 },
114
+ '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 },
115
+ '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 },
116
+ },
117
+ },
118
+ },
119
+ }, null, 2));
120
+ const nextState = {
121
+ current_phase: 'ralplan',
122
+ return_to_ralplan_reason: 'Code review requested a plan update.',
123
+ review_cycle: 2,
124
+ handoff_artifacts: {
125
+ ralplan: {
126
+ review_cycle: 2,
127
+ ralplanConsensusGate: {
128
+ complete: true,
129
+ sequence: ['architect-review', 'critic-review'],
130
+ ralplan_architect_review: {
131
+ agent_role: 'architect',
132
+ provenance_kind: 'native_subagent',
133
+ verdict: 'approve',
134
+ session_id: sessionId,
135
+ thread_id: 'thread-architect-stale',
136
+ artifact_path: '.omx/artifacts/architect-stale.md',
137
+ tracker_path: '.omx/state/subagent-tracking.json',
138
+ completed_at: '2026-06-12T09:59:30.000Z',
139
+ },
140
+ ralplan_critic_review: {
141
+ agent_role: 'critic',
142
+ provenance_kind: 'native_subagent',
143
+ verdict: 'approve',
144
+ session_id: sessionId,
145
+ thread_id: 'thread-critic-stale',
146
+ artifact_path: '.omx/artifacts/critic-stale.md',
147
+ tracker_path: '.omx/state/subagent-tracking.json',
148
+ completed_at: '2026-06-12T10:00:00.000Z',
149
+ },
150
+ },
151
+ },
152
+ },
153
+ };
154
+ const decision = canAdvanceAutopilotRalplanToUltragoal({ cwd, sessionId, nextState });
155
+ assert.equal(decision.allowed, false);
156
+ assert.equal(decision.evidence?.blockedReason, 'missing_sequential_architect_then_critic_approval');
157
+ }
158
+ finally {
159
+ await rm(cwd, { recursive: true, force: true });
160
+ }
161
+ });
162
+ it('rejects stale raw handoff consensus when parent state returned to ralplan', async () => {
163
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-autopilot-ralplan-stale-raw-handoff-'));
164
+ const sessionId = 'sess-autopilot-stale-raw-handoff';
165
+ const trackingPath = subagentTrackingPath(cwd);
166
+ try {
167
+ await mkdir(join(trackingPath, '..'), { recursive: true });
168
+ await writeFile(trackingPath, JSON.stringify({
169
+ schemaVersion: 1,
170
+ sessions: {
171
+ [sessionId]: {
172
+ session_id: sessionId,
173
+ leader_thread_id: 'thread-leader',
174
+ updated_at: '2026-06-12T10:00:00.000Z',
175
+ threads: {
176
+ '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 },
177
+ '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 },
178
+ '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 },
179
+ },
180
+ },
181
+ },
182
+ }, null, 2));
183
+ const currentState = {
184
+ current_phase: 'ralplan',
185
+ return_to_ralplan_reason: 'Code review requested a plan update.',
186
+ review_cycle: 1,
187
+ handoff_artifacts: {
188
+ ralplan_consensus_gate: {
189
+ complete: true,
190
+ sequence: ['architect-review', 'critic-review'],
191
+ ralplan_architect_review: {
192
+ agent_role: 'architect',
193
+ provenance_kind: 'native_subagent',
194
+ verdict: 'approve',
195
+ session_id: sessionId,
196
+ thread_id: 'thread-architect-stale',
197
+ artifact_path: '.omx/artifacts/architect-stale.md',
198
+ tracker_path: '.omx/state/subagent-tracking.json',
199
+ completed_at: '2026-06-12T09:59:30.000Z',
200
+ },
201
+ ralplan_critic_review: {
202
+ agent_role: 'critic',
203
+ provenance_kind: 'native_subagent',
204
+ verdict: 'approve',
205
+ session_id: sessionId,
206
+ thread_id: 'thread-critic-stale',
207
+ artifact_path: '.omx/artifacts/critic-stale.md',
208
+ tracker_path: '.omx/state/subagent-tracking.json',
209
+ completed_at: '2026-06-12T10:00:00.000Z',
210
+ },
211
+ },
212
+ },
213
+ };
214
+ const decision = canAdvanceAutopilotRalplanToUltragoal({ cwd, sessionId, currentState });
215
+ assert.equal(decision.allowed, false);
216
+ assert.equal(decision.evidence?.blockedReason, 'missing_sequential_architect_then_critic_approval');
217
+ }
218
+ finally {
219
+ await rm(cwd, { recursive: true, force: true });
220
+ }
221
+ });
222
+ for (const { lane, architectVerdict, criticVerdict } of [
223
+ { lane: 'architect', architectVerdict: 'iterate', criticVerdict: 'approve' },
224
+ { lane: 'critic', architectVerdict: 'approve', criticVerdict: 'iterate' },
225
+ ]) {
226
+ it(`rejects complete ralplan consensus when ${lane} review verdict is iterate`, () => {
227
+ const state = {
228
+ current_phase: 'ralplan',
229
+ handoff_artifacts: {
230
+ ralplan_consensus_gate: {
231
+ complete: true,
232
+ sequence: ['architect-review', 'critic-review'],
233
+ ralplan_architect_review: {
234
+ agent_role: 'architect',
235
+ provenance_kind: 'native_subagent',
236
+ verdict: architectVerdict,
237
+ session_id: 'sess-autopilot-iterate',
238
+ thread_id: 'thread-architect',
239
+ artifact_path: '.omx/artifacts/architect.md',
240
+ tracker_path: '.omx/state/subagent-tracking.json',
241
+ completed_at: '2026-05-28T18:34:51.000Z',
242
+ },
243
+ ralplan_critic_review: {
244
+ agent_role: 'critic',
245
+ provenance_kind: 'native_subagent',
246
+ verdict: criticVerdict,
247
+ session_id: 'sess-autopilot-iterate',
248
+ thread_id: 'thread-critic',
249
+ artifact_path: '.omx/artifacts/critic.md',
250
+ tracker_path: '.omx/state/subagent-tracking.json',
251
+ completed_at: '2026-05-28T18:35:10.000Z',
252
+ },
253
+ },
254
+ },
255
+ };
256
+ const decision = canAdvanceAutopilotRalplanToUltragoal({
257
+ cwd: process.cwd(),
258
+ sessionId: 'sess-autopilot-iterate',
259
+ currentState: state,
260
+ });
261
+ assert.equal(decision.allowed, false);
262
+ assert.equal(decision.evidence?.blockedReason, 'non_approving_ralplan_consensus_review');
263
+ const error = buildAutopilotRalplanUltragoalGateError(decision);
264
+ assert.match(error, /non-approving architect or critic review evidence/i);
265
+ assert.doesNotMatch(error, /missing ralplan consensus gate/i);
266
+ assert.match(error, new RegExp(`${lane}.*verdict=iterate`, 'i'));
267
+ });
268
+ }
269
+ it('accepts fresh next-state consensus over stale invalid current-state consensus', async () => {
270
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-autopilot-ralplan-fresh-next-valid-'));
271
+ const sessionId = 'sess-autopilot-fresh-next-valid';
272
+ const trackingPath = subagentTrackingPath(cwd);
273
+ try {
274
+ await mkdir(join(trackingPath, '..'), { recursive: true });
275
+ await writeFile(trackingPath, JSON.stringify({
276
+ schemaVersion: 1,
277
+ sessions: {
278
+ [sessionId]: {
279
+ session_id: sessionId,
280
+ leader_thread_id: 'thread-leader',
281
+ updated_at: '2026-06-12T10:03:00.000Z',
282
+ threads: {
283
+ '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 },
284
+ '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 },
285
+ '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 },
286
+ },
287
+ },
288
+ },
289
+ }, null, 2));
290
+ const nextState = {
291
+ current_phase: 'ralplan',
292
+ review_cycle: 2,
293
+ handoff_artifacts: {
294
+ ralplan_consensus_gate: {
295
+ complete: true,
296
+ sequence: ['architect-review', 'critic-review'],
297
+ ralplan_architect_review: {
298
+ agent_role: 'architect',
299
+ provenance_kind: 'native_subagent',
300
+ verdict: 'approve',
301
+ review_cycle: 2,
302
+ session_id: sessionId,
303
+ thread_id: 'thread-architect-fresh',
304
+ artifact_path: '.omx/artifacts/architect-fresh.md',
305
+ tracker_path: '.omx/state/subagent-tracking.json',
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
+ review_cycle: 2,
313
+ session_id: sessionId,
314
+ thread_id: 'thread-critic-fresh',
315
+ artifact_path: '.omx/artifacts/critic-fresh.md',
316
+ tracker_path: '.omx/state/subagent-tracking.json',
317
+ completed_at: '2026-06-12T10:03:00.000Z',
318
+ },
319
+ },
320
+ },
321
+ };
322
+ const currentState = {
323
+ current_phase: 'ralplan',
324
+ return_to_ralplan_reason: 'Code review requested a plan update.',
325
+ review_cycle: 1,
326
+ handoff_artifacts: {
327
+ ralplan_consensus_gate: {
328
+ complete: true,
329
+ sequence: ['architect-review', 'critic-review'],
330
+ ralplan_architect_review: {
331
+ agent_role: 'architect',
332
+ provenance_kind: 'native_subagent',
333
+ verdict: 'block',
334
+ review_cycle: 1,
335
+ session_id: sessionId,
336
+ thread_id: 'thread-architect-stale',
337
+ artifact_path: '.omx/artifacts/architect-stale.md',
338
+ tracker_path: '.omx/state/subagent-tracking.json',
339
+ completed_at: '2026-06-12T10:00:00.000Z',
340
+ },
341
+ ralplan_critic_review: {
342
+ agent_role: 'critic',
343
+ provenance_kind: 'native_subagent',
344
+ verdict: 'approve',
345
+ review_cycle: 1,
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:01:00.000Z',
351
+ },
352
+ },
353
+ },
354
+ };
355
+ const decision = canAdvanceAutopilotRalplanToUltragoal({ cwd, sessionId, nextState, currentState });
356
+ assert.equal(decision.allowed, true);
357
+ assert.equal(decision.evidence?.source, 'next-autopilot-state');
358
+ assert.equal(decision.evidence?.blockedReason, null);
359
+ }
360
+ finally {
361
+ await rm(cwd, { recursive: true, force: true });
362
+ }
363
+ });
364
+ it('accepts tracker-backed native reviews without duplicated session, tracker, or artifact fields', async () => {
365
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-autopilot-ralplan-tracker-resolved-'));
366
+ const sessionId = 'sess-autopilot-tracker-resolved';
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:03: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': { 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 },
380
+ '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 },
381
+ },
382
+ },
383
+ },
384
+ }, null, 2));
385
+ const state = {
386
+ current_phase: 'ralplan',
387
+ handoff_artifacts: {
388
+ ralplan_consensus_gate: {
389
+ complete: true,
390
+ sequence: ['architect-review', 'critic-review'],
391
+ ralplan_architect_review: {
392
+ agent_role: 'architect',
393
+ provenance_kind: 'native_subagent',
394
+ verdict: 'approve',
395
+ thread_id: 'thread-architect',
396
+ completed_at: '2026-06-12T10:02:00.000Z',
397
+ },
398
+ ralplan_critic_review: {
399
+ agent_role: 'critic',
400
+ provenance_kind: 'native_subagent',
401
+ verdict: 'approve',
402
+ thread_id: 'thread-critic',
403
+ completed_at: '2026-06-12T10:03:00.000Z',
404
+ },
405
+ },
406
+ },
407
+ };
408
+ const decision = canAdvanceAutopilotRalplanToUltragoal({ cwd, sessionId, currentState: state });
409
+ assert.equal(decision.allowed, true);
410
+ assert.equal(decision.evidence?.blockedReason, null);
411
+ }
412
+ finally {
413
+ await rm(cwd, { recursive: true, force: true });
414
+ }
415
+ });
416
+ it('rejects omitted review session ids when no transition session context exists', async () => {
417
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-autopilot-ralplan-no-session-context-'));
418
+ const trackingPath = subagentTrackingPath(cwd);
419
+ try {
420
+ await mkdir(join(trackingPath, '..'), { recursive: true });
421
+ await writeFile(trackingPath, JSON.stringify({
422
+ schemaVersion: 1,
423
+ sessions: {},
424
+ }, null, 2));
425
+ const state = {
426
+ current_phase: 'ralplan',
427
+ handoff_artifacts: {
428
+ ralplan_consensus_gate: {
429
+ complete: true,
430
+ sequence: ['architect-review', 'critic-review'],
431
+ ralplan_architect_review: {
432
+ agent_role: 'architect',
433
+ provenance_kind: 'native_subagent',
434
+ verdict: 'approve',
435
+ thread_id: 'thread-architect',
436
+ },
437
+ ralplan_critic_review: {
438
+ agent_role: 'critic',
439
+ provenance_kind: 'native_subagent',
440
+ verdict: 'approve',
441
+ thread_id: 'thread-critic',
442
+ },
443
+ },
444
+ },
445
+ };
446
+ const decision = canAdvanceAutopilotRalplanToUltragoal({ cwd, currentState: state });
447
+ assert.equal(decision.allowed, false);
448
+ assert.match(buildAutopilotRalplanUltragoalGateError(decision), /cannot resolve session_id/);
449
+ }
450
+ finally {
451
+ await rm(cwd, { recursive: true, force: true });
452
+ }
453
+ });
454
+ it('rejects architect and critic reviews that reuse the same native tracker thread', async () => {
455
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-autopilot-ralplan-duplicate-thread-'));
456
+ const sessionId = 'sess-autopilot-duplicate-thread';
457
+ const trackingPath = subagentTrackingPath(cwd);
458
+ try {
459
+ await mkdir(join(trackingPath, '..'), { recursive: true });
460
+ await writeFile(trackingPath, JSON.stringify({
461
+ schemaVersion: 1,
462
+ sessions: {
463
+ [sessionId]: {
464
+ session_id: sessionId,
465
+ leader_thread_id: 'thread-leader',
466
+ updated_at: '2026-06-12T10:03:00.000Z',
467
+ threads: {
468
+ '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 },
469
+ '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 },
470
+ },
471
+ },
472
+ },
473
+ }, null, 2));
474
+ const state = {
475
+ current_phase: 'ralplan',
476
+ handoff_artifacts: {
477
+ ralplan_consensus_gate: {
478
+ complete: true,
479
+ sequence: ['architect-review', 'critic-review'],
480
+ ralplan_architect_review: {
481
+ agent_role: 'architect',
482
+ provenance_kind: 'native_subagent',
483
+ verdict: 'approve',
484
+ session_id: sessionId,
485
+ thread_id: 'thread-reviewer',
486
+ completed_at: '2026-06-12T10:02:00.000Z',
487
+ },
488
+ ralplan_critic_review: {
489
+ agent_role: 'critic',
490
+ provenance_kind: 'native_subagent',
491
+ verdict: 'approve',
492
+ session_id: sessionId,
493
+ thread_id: 'thread-reviewer',
494
+ completed_at: '2026-06-12T10:03:00.000Z',
495
+ },
496
+ },
497
+ },
498
+ };
499
+ const decision = canAdvanceAutopilotRalplanToUltragoal({ cwd, sessionId, currentState: state });
500
+ assert.equal(decision.allowed, false);
501
+ assert.match(buildAutopilotRalplanUltragoalGateError(decision), /distinct native subagent tracker threads/);
502
+ }
503
+ finally {
504
+ await rm(cwd, { recursive: true, force: true });
505
+ }
506
+ });
507
+ it('rejects tracker-backed native reviews composed from different sessions', async () => {
508
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-autopilot-ralplan-cross-session-'));
509
+ const trackingPath = subagentTrackingPath(cwd);
510
+ try {
511
+ await mkdir(join(trackingPath, '..'), { recursive: true });
512
+ await writeFile(trackingPath, JSON.stringify({
513
+ schemaVersion: 1,
514
+ sessions: {
515
+ 'sess-architect': {
516
+ session_id: 'sess-architect',
517
+ leader_thread_id: 'thread-leader-a',
518
+ updated_at: '2026-06-12T10:02:00.000Z',
519
+ threads: {
520
+ '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 },
521
+ '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 },
522
+ },
523
+ },
524
+ 'sess-critic': {
525
+ session_id: 'sess-critic',
526
+ leader_thread_id: 'thread-leader-c',
527
+ updated_at: '2026-06-12T10:03:00.000Z',
528
+ threads: {
529
+ '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 },
530
+ '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 },
531
+ },
532
+ },
533
+ },
534
+ }, null, 2));
535
+ const state = {
536
+ current_phase: 'ralplan',
537
+ handoff_artifacts: {
538
+ ralplan_consensus_gate: {
539
+ complete: true,
540
+ sequence: ['architect-review', 'critic-review'],
541
+ ralplan_architect_review: {
542
+ agent_role: 'architect',
543
+ provenance_kind: 'native_subagent',
544
+ verdict: 'approve',
545
+ session_id: 'sess-architect',
546
+ thread_id: 'thread-architect',
547
+ completed_at: '2026-06-12T10:02:00.000Z',
548
+ },
549
+ ralplan_critic_review: {
550
+ agent_role: 'critic',
551
+ provenance_kind: 'native_subagent',
552
+ verdict: 'approve',
553
+ session_id: 'sess-critic',
554
+ thread_id: 'thread-critic',
555
+ completed_at: '2026-06-12T10:03:00.000Z',
556
+ },
557
+ },
558
+ },
559
+ };
560
+ const decision = canAdvanceAutopilotRalplanToUltragoal({ cwd, currentState: state });
561
+ assert.equal(decision.allowed, false);
562
+ assert.match(buildAutopilotRalplanUltragoalGateError(decision), /same native subagent tracker session/);
563
+ }
564
+ finally {
565
+ await rm(cwd, { recursive: true, force: true });
566
+ }
567
+ });
568
+ it('rejects stale review session ids even when transition session context exists', async () => {
569
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-autopilot-ralplan-live-session-mismatch-'));
570
+ const sessionId = 'sess-autopilot-live-session';
571
+ const trackingPath = subagentTrackingPath(cwd);
572
+ try {
573
+ await mkdir(join(trackingPath, '..'), { recursive: true });
574
+ await writeFile(trackingPath, JSON.stringify({
575
+ schemaVersion: 1,
576
+ sessions: {
577
+ [sessionId]: {
578
+ session_id: sessionId,
579
+ leader_thread_id: 'thread-leader',
580
+ updated_at: '2026-06-12T10:03:00.000Z',
581
+ threads: {
582
+ '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 },
583
+ '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 },
584
+ '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 },
585
+ },
586
+ },
587
+ },
588
+ }, null, 2));
589
+ const state = {
590
+ current_phase: 'ralplan',
591
+ handoff_artifacts: {
592
+ ralplan_consensus_gate: {
593
+ complete: true,
594
+ sequence: ['architect-review', 'critic-review'],
595
+ ralplan_architect_review: {
596
+ agent_role: 'architect',
597
+ provenance_kind: 'native_subagent',
598
+ verdict: 'approve',
599
+ thread_id: 'thread-architect',
600
+ completed_at: '2026-06-12T10:02:00.000Z',
601
+ },
602
+ ralplan_critic_review: {
603
+ agent_role: 'critic',
604
+ provenance_kind: 'native_subagent',
605
+ verdict: 'approve',
606
+ session_id: 'sess-stale-critic',
607
+ thread_id: 'thread-critic',
608
+ completed_at: '2026-06-12T10:03:00.000Z',
609
+ },
610
+ },
611
+ },
612
+ };
613
+ const decision = canAdvanceAutopilotRalplanToUltragoal({ cwd, sessionId, currentState: state });
614
+ assert.equal(decision.allowed, false);
615
+ assert.match(buildAutopilotRalplanUltragoalGateError(decision), /critic review session_id=sess-stale-critic does not match/);
616
+ }
617
+ finally {
618
+ await rm(cwd, { recursive: true, force: true });
619
+ }
620
+ });
621
+ it('rejects tracker-backed native reviews whose subagent threads are not completed', async () => {
622
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-autopilot-ralplan-incomplete-thread-'));
623
+ const sessionId = 'sess-autopilot-incomplete-thread';
624
+ const trackingPath = subagentTrackingPath(cwd);
625
+ try {
626
+ await mkdir(join(trackingPath, '..'), { recursive: true });
627
+ await writeFile(trackingPath, JSON.stringify({
628
+ schemaVersion: 1,
629
+ sessions: {
630
+ [sessionId]: {
631
+ session_id: sessionId,
632
+ leader_thread_id: 'thread-leader',
633
+ updated_at: '2026-06-12T10:03:00.000Z',
634
+ threads: {
635
+ '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 },
636
+ '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 },
637
+ '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 },
638
+ },
639
+ },
640
+ },
641
+ }, null, 2));
642
+ const state = {
643
+ current_phase: 'ralplan',
644
+ handoff_artifacts: {
645
+ ralplan_consensus_gate: {
646
+ complete: true,
647
+ sequence: ['architect-review', 'critic-review'],
648
+ ralplan_architect_review: {
649
+ agent_role: 'architect',
650
+ provenance_kind: 'native_subagent',
651
+ verdict: 'approve',
652
+ session_id: sessionId,
653
+ thread_id: 'thread-architect',
654
+ completed_at: '2026-06-12T10:02:00.000Z',
655
+ },
656
+ ralplan_critic_review: {
657
+ agent_role: 'critic',
658
+ provenance_kind: 'native_subagent',
659
+ verdict: 'approve',
660
+ session_id: sessionId,
661
+ thread_id: 'thread-critic',
662
+ completed_at: '2026-06-12T10:03:00.000Z',
663
+ },
664
+ },
665
+ },
666
+ };
667
+ const decision = canAdvanceAutopilotRalplanToUltragoal({ cwd, sessionId, currentState: state });
668
+ assert.equal(decision.allowed, false);
669
+ assert.match(buildAutopilotRalplanUltragoalGateError(decision), /architect tracker thread thread-architect is not completed/);
670
+ }
671
+ finally {
672
+ await rm(cwd, { recursive: true, force: true });
673
+ }
674
+ });
9
675
  it('rejects native review evidence from the session leader even when malformed tracking marks it as subagent', async () => {
10
676
  const cwd = await mkdtemp(join(tmpdir(), 'omx-autopilot-ralplan-leader-spoof-'));
11
677
  const sessionId = 'sess-autopilot-leader-spoof';
@@ -98,6 +764,7 @@ describe('autopilot ralplan gate', () => {
98
764
  kind: 'subagent',
99
765
  first_seen_at: '2026-05-28T18:34:51.000Z',
100
766
  last_seen_at: '2026-05-28T18:34:51.000Z',
767
+ completed_at: '2026-05-28T18:34:51.000Z',
101
768
  turn_count: 1,
102
769
  mode: 'architect',
103
770
  },
@@ -106,6 +773,7 @@ describe('autopilot ralplan gate', () => {
106
773
  kind: 'subagent',
107
774
  first_seen_at: '2026-05-28T18:35:10.000Z',
108
775
  last_seen_at: '2026-05-28T18:35:10.000Z',
776
+ completed_at: '2026-05-28T18:35:10.000Z',
109
777
  turn_count: 1,
110
778
  mode: 'critic',
111
779
  },