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>
38 lines
3.5 KiB
Markdown
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
|