--- id: "bug-1594" status: "fixed" status_updated: "2026-09-24" status_note: "" component: "scheduler" severity: "unknown" timestamp: "2026-08-19T08:00:00Z" last_seen: "2026-09-19T09:00:00Z" occurrences: 1 files: ["src/scheduler/src/sim_loop.c (sched_sim_driver_run)", "src/scheduler/src/repl.c (repl_dispatch", "new xce_repl_on_replay_complete)", "src/scheduler/include/repl.h", "src/scheduler/src/repl_internal.h"] tags: ["scheduler", "repl", "continue", "quit", "exit-behavior", "ux"] related: ["bug-1596"] legacy: true --- # bug-1594: User-reported: in the scheduler's --interactive REPL, `continue` with no breakpoints set runs the… ## Description User-reported: in the scheduler's --interactive REPL, `continue` with no breakpoints set runs the simulation to completion and the process then exits -- the operator never gets a chance to inspect the final simulated state (info job/queue/worker/resource/summary). Related: the simulator should never terminate except via an explicit `quit`. ## Environment _Not recorded (migrated from buglog.json)._ ## Reproduction _Not recorded (migrated from buglog.json)._ ## Root cause requirements.md's own AC 22 pseudocode for the REPL integration never re-enters the REPL after the replay loop's `for each event in replay_file` reaches EOF -- it prints two informational lines ("replay complete"/"output written to") and falls straight through to sched_sim_driver_run()'s return, which unwinds back to main() and the process exits normally. This matches the literal pseudocode but is a genuine UX gap the requirement text never called out: `continue` (mode=XCE_REPL_MODE_CONTINUE, no breakpoint match) is the ONLY path that can reach EOF without another repl_command_loop() re-entry already pausing execution first (step's budget-exhaustion pause and every breakpoint hit both already re-enter the REPL mid-stream; only a completed `continue` run had no re-entry point at all). ## Fix Fixed as part of task 12.5. Added xce_repl_on_replay_complete() (repl.c) + its sim->interactive-gated inline wrapper xce_repl_check_replay_complete() (repl.h), called from sim_loop.c immediately after the replay for(;;) loop breaks (EOF or AC20 end-of-stream marker), before the --sim-output file is closed. It prints the existing completion banner, sets a new sim->repl_state->replay_complete flag, and calls repl_command_loop(sim) so the process blocks at the `(sim) ` prompt instead of returning. repl_dispatch()'s `step`/`continue` branches now check replay_complete first: if set, they print "[sim] replay already complete -- no more events to process. Use 'quit' to exit." and return false (re-prompt) instead of returning true (which would have handed control back to a driver loop that no longer exists). The only remaining exit paths are repl_cmd_quit() (explicit `quit`) and readline() returning NULL on stdin EOF (already treated as an implicit quit, pre-existing documented behavior, unchanged). Batch (non-interactive) `--sim` mode is unaffected -- xce_repl_check_replay_complete() is a no-op when sim->interactive is false, mirroring every other REPL hook's existing gating. New tests in test_repl_execution_control.c: scripted stdin `continue\ninfo summary\nquit\n` against a fixture with zero breakpoints asserts the process does NOT exit after 'replay complete' and that `info summary` after it reports the final job/session state correctly; a second test asserts `step`/`continue` issued after replay_complete print the re-prompt message and the REPL stays alive. ## Verification _Not recorded (migrated from buglog.json)._ ## References - Related: bug-1596