11package ensigncycle
22
3- import "testing"
3+ import (
4+ "strings"
5+ "testing"
6+ )
47
58// Offline table tests for the host-specific reviewer-reuse assertions. They prove
69// each assertion requires a REAL reuse tool call targeting the validation reviewer
@@ -236,6 +239,16 @@ func TestAssertCodexReviewerReuse(t *testing.T) {
236239 decl := `{"type":"item.completed","item":{"type":"agent_message","text":` + mustJSONString (w ) + `}}`
237240 liveAbsentTwoFresh [i ] = decl + "\n " + spawnValidation + "\n " + spawnImpl + "\n " + freshCycle2Spawn
238241 }
242+ falseAbsentNarrations := []string {
243+ "The validation reviewer stays alive for the rejection-flow re-review; this does not close or redispatch the worker." ,
244+ "The host has no dedicated shutdown tool, so I will keep the two reusable workers and route validation back to the kept-alive reviewer." ,
245+ "The validation reviewer is being reused for re-review only; the implementation worker that applied the fix is not doing validation." ,
246+ }
247+ falseAbsentReuse := make ([]string , len (falseAbsentNarrations ))
248+ for i , w := range falseAbsentNarrations {
249+ decl := `{"type":"item.completed","item":{"type":"agent_message","text":` + mustJSONString (w ) + `}}`
250+ falseAbsentReuse [i ] = decl + "\n " + realReuseV2
251+ }
239252
240253 cases := []struct {
241254 name string
@@ -259,6 +272,9 @@ func TestAssertCodexReviewerReuse(t *testing.T) {
259272 {"live FO absence wording 7 + two fresh validation spawns" , liveAbsentTwoFresh [7 ], false },
260273 {"live FO absence wording 8 + two fresh validation spawns" , liveAbsentTwoFresh [8 ], false },
261274 {"live FO absence wording 9 + two fresh validation spawns" , liveAbsentTwoFresh [9 ], false },
275+ {"PR #464 affirmative reuse with redispatch negation must not classify absent" , falseAbsentReuse [0 ], false },
276+ {"PR #464 reusable-workers narration with shutdown negation must not classify absent" , falseAbsentReuse [1 ], false },
277+ {"PR #465 validation reviewer reused while implementation worker is not validating" , falseAbsentReuse [2 ], false },
262278 {
263279 "loose narration only" ,
264280 `{"type":"item.completed","item":{"type":"agent_message","text":"I will send_input to the validation worker."}}` ,
@@ -298,3 +314,84 @@ func TestAssertCodexReviewerReuse(t *testing.T) {
298314 })
299315 }
300316}
317+
318+ func TestAssertCodexReviewerReuseAcceptsAdvanceModeValidationReroute (t * testing.T ) {
319+ jsonl := strings .Join ([]string {
320+ codexAgentMessageLine ("The Codex runtime has a reusable worker route (`followup_task`), so I will keep the cycle-1 validation reviewer addressable." ),
321+ codexCommandLine (`${SPACEDOCK_BIN:-spacedock} dispatch build --workflow-dir . --entity-path rejection-task.md --stage implementation --checklist-file impl.checklist` ),
322+ codexCommandLine (`${SPACEDOCK_BIN:-spacedock} dispatch build --workflow-dir . --entity-path rejection-task.md --stage validation --checklist-file validation-cycle1.checklist` ),
323+ codexWaitLine (),
324+ codexCommandLine (`${SPACEDOCK_BIN:-spacedock} dispatch build --workflow-dir . --entity-path rejection-task.md --stage implementation --checklist-file rework.checklist --feedback-context-file rework.feedback --feedback-reflow --advance` ),
325+ codexWaitLine (),
326+ codexCommandLine (`${SPACEDOCK_BIN:-spacedock} dispatch build --workflow-dir . --entity-path rejection-task.md --stage validation --checklist-file validation-cycle2.checklist --advance` ),
327+ codexAgentMessageLine ("The validation re-review assignment is ready. I am routing it to the kept-alive cycle-1 validation reviewer now." ),
328+ codexWaitLine (),
329+ }, "\n " )
330+
331+ if err := assertCodexReviewerReuse (jsonl ); err != nil {
332+ t .Fatalf ("Codex 0.142 live transcript with --advance validation re-review should pass: %v" , err )
333+ }
334+
335+ noValidationAdvance := strings .Replace (jsonl , " --stage validation --checklist-file validation-cycle2.checklist --advance" , " --stage validation --checklist-file validation-cycle2.checklist" , 1 )
336+ if err := assertCodexReviewerReuse (noValidationAdvance ); err == nil {
337+ t .Fatal ("expected transcript without validation --advance re-review to fail" )
338+ }
339+ }
340+
341+ func TestAssertCodexReviewerReuseAcceptsCIAdvanceModeWithoutImplementationFeedbackReflow (t * testing.T ) {
342+ jsonl := strings .Join ([]string {
343+ codexAgentMessageLine ("Because Codex has an addressable worker route, I am routing the rework back to the existing implementation worker rather than spawning the reviewer to do fix work." ),
344+ codexCommandLine (`${SPACEDOCK_BIN:-spacedock} dispatch build --workflow-dir . --entity-path rejection-task.md --stage implementation --checklist-file impl.checklist` ),
345+ codexCommandLine (`${SPACEDOCK_BIN:-spacedock} dispatch build --workflow-dir . --entity-path rejection-task.md --stage validation --checklist-file validation-cycle1.checklist` ),
346+ codexWaitLine (),
347+ codexCommandLine (`${SPACEDOCK_BIN:-spacedock} dispatch build --workflow-dir . --entity-path rejection-task.md --stage implementation --checklist-file rework.checklist --advance` ),
348+ codexWaitLine (),
349+ codexAgentMessageLine ("I am advancing back to validation and reusing the kept-alive cycle-1 validation reviewer for the re-review, keeping it separate from the worker that applied the fix." ),
350+ codexCommandLine (`${SPACEDOCK_BIN:-spacedock} dispatch build --workflow-dir . --entity-path rejection-task.md --stage validation --checklist-file validation-cycle2.checklist --advance` ),
351+ codexAgentMessageLine ("The cycle-2 validation assignment is built. I am routing it to the original validation reviewer through the addressable worker handle, not to the implementation rework worker." ),
352+ codexWaitLine (),
353+ }, "\n " )
354+
355+ if err := assertCodexReviewerReuse (jsonl ); err != nil {
356+ t .Fatalf ("CI advance-mode transcript without implementation --feedback-reflow should still prove validation reviewer reuse: %v" , err )
357+ }
358+ }
359+
360+ func TestAssertCodexReviewerReuseAcceptsLiveAdvanceModeReuseNarration (t * testing.T ) {
361+ jsonl := strings .Join ([]string {
362+ codexAgentMessageLine ("The Codex runtime has `followup_task`, so the cycle-1 validation reviewer is reusable if it remains addressable." ),
363+ codexCommandStartedLine (`${SPACEDOCK_BIN:-spacedock} dispatch build --workflow-dir . --entity-path rejection-task.md --stage implementation --checklist-file impl-cycle1.checklist` ),
364+ codexCommandLine (`${SPACEDOCK_BIN:-spacedock} dispatch build --workflow-dir . --entity-path rejection-task.md --stage implementation --checklist-file impl-cycle1.checklist` ),
365+ codexCommandStartedLine (`${SPACEDOCK_BIN:-spacedock} dispatch build --workflow-dir . --entity-path rejection-task.md --stage validation --checklist-file validation-cycle1.checklist` ),
366+ codexCommandLine (`${SPACEDOCK_BIN:-spacedock} dispatch build --workflow-dir . --entity-path rejection-task.md --stage validation --checklist-file validation-cycle1.checklist` ),
367+ codexWaitLine (),
368+ codexCommandStartedLine (`${SPACEDOCK_BIN:-spacedock} dispatch build --workflow-dir . --entity-path rejection-task.md --stage implementation --checklist-file impl-cycle2.checklist --feedback-context-file cycle1-feedback.txt --feedback-reflow --advance` ),
369+ codexCommandLine (`${SPACEDOCK_BIN:-spacedock} dispatch build --workflow-dir . --entity-path rejection-task.md --stage implementation --checklist-file impl-cycle2.checklist --feedback-context-file cycle1-feedback.txt --feedback-reflow --advance` ),
370+ codexWaitLine (),
371+ codexAgentMessageLine ("The rework satisfies its checklist: 1 done, 0 skipped, 0 failed, and the standalone fix marker is present. I'm advancing back to validation and reusing the kept-alive cycle-1 validation reviewer for the second-cycle re-review." ),
372+ codexCommandStartedLine (`${SPACEDOCK_BIN:-spacedock} dispatch build --workflow-dir . --entity-path rejection-task.md --stage validation --checklist-file validation-cycle2.checklist --feedback-context-file cycle2-review.txt --advance` ),
373+ codexCommandLine (`${SPACEDOCK_BIN:-spacedock} dispatch build --workflow-dir . --entity-path rejection-task.md --stage validation --checklist-file validation-cycle2.checklist --feedback-context-file cycle2-review.txt --advance` ),
374+ codexAgentMessageLine ("The second-cycle validation transition is committed. I'm sending the re-review to the kept-alive validation reviewer, which keeps the fix worker separate from the reviewer." ),
375+ codexWaitLine (),
376+ }, "\n " )
377+
378+ if err := assertCodexReviewerReuse (jsonl ); err != nil {
379+ t .Fatalf ("Codex live advance-mode reuse narration should pass: %v" , err )
380+ }
381+ }
382+
383+ func codexAgentMessageLine (text string ) string {
384+ return `{"type":"item.completed","item":{"type":"agent_message","text":` + mustJSONString (text ) + `}}`
385+ }
386+
387+ func codexCommandLine (command string ) string {
388+ return `{"type":"item.completed","item":{"type":"command_execution","command":` + mustJSONString (command ) + `,"status":"completed","exit_code":0}}`
389+ }
390+
391+ func codexCommandStartedLine (command string ) string {
392+ return `{"type":"item.started","item":{"type":"command_execution","command":` + mustJSONString (command ) + `,"status":"in_progress"}}`
393+ }
394+
395+ func codexWaitLine () string {
396+ return `{"type":"item.completed","item":{"type":"collab_tool_call","tool":"wait","receiver_thread_ids":[],"status":"completed"}}`
397+ }
0 commit comments