myxce/.wolf/bugs/bug-1594.md
Rongsong Shen d26ff8870d
feat(buglog): one Markdown record per bug, checked against a record standard
The buglog was one 27K-line JSON file whose fields covered only symptom,
root cause and fix, as free text: 2% of entries named the code version a
bug was found on, 12% the build profile, 36% a way to reproduce, and 58% of
the file was OpenWolf hook auto-detections ("Missing guard clause",
"Function not marked async" on .md files).

- .claude/skills/buglog/bug-record.md: the record standard. Eight
  sections (Summary as the title, Description, Environment, Reproduction;
  Root cause, Fix, Verification, References once fixed), each with the
  content it must contain -- e.g. Environment needs the OS, the libc the
  failing binary loads (from its ELF interpreter: glibc 2.42 in the nix
  shell vs 2.40 on the host), toolchain, build profile and commit.
- .wolf/bugs/<id>.md: 500 records migrated from buglog.json; every field
  verified to round-trip. They carry legacy: true and an explicit "not
  recorded" where the old log had no such field; component derived from
  file paths, severity from keywords (else unknown), fix_commits from
  hashes in status_note/fix that git resolves (91 of 463 fixed).
- .wolf/buglog-archive.json: the 710 hook auto-detections, verbatim.
- .wolf/buglog.json is now an index generated from the records, keeping
  the fields OpenWolf's hooks and `openwolf bug search` read.
- scripts/buglog.py rewritten: new (template + Environment collected from
  the machine and --binary), check, status (refuses a status the record
  doesn't support; fixed needs Root cause, Fix, Verification and
  --commit hashes git resolves), note, recur, set, show, list, triage,
  env, index. 29 unittest cases in scripts/tests/test_buglog.py.
- scripts/git-hooks/pre-commit runs `check --staged`: incomplete staged
  records, a legacy record hand-changed to fixed without the fix-time
  sections, a new record claiming legacy: true, or a stale index refuse
  the commit.
- scripts/gitea-sync.py reads the records: issue body = the record's
  sections plus linked fix commits (origin remote, GITEA_COMMIT_REPO to
  override), and a body hash so an issue's text is refreshed when the
  record changes.
- bug-1866 rewritten to the full standard as the worked example.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 03:40:11 +00:00

38 lines
3.5 KiB
Markdown

---
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