--- id: "bug-1888" status: "fixed" status_updated: "2026-09-29" status_note: "" component: "scheduler" severity: "wrong-result" timestamp: "2026-09-29T10:32:13Z" last_seen: "2026-09-29T10:32:13Z" occurrences: 1 files: ["src/scheduler/src/snapshot_wire.c", "src/scheduler/src/snapshot_load.c"] tags: ["scheduler", "snapshot", "persistence", "resreq"] related: ["bug-1887"] fix_commits: ["077b1213"] --- # bug-1888: snapshots save a job's resreq as a debug dump; restored jobs lose select and rusage ## Description **Observed:** saving a snapshot of a pending job whose resreq is `rusage[mem=2]` stores `submit->resreq` as ``` Primary: Tasks: min = 1, max = 1 Rusages: res mem value 2.000000 per 3 duration -1.000000 decay 0 ``` and the loaded job has no rusage (and no select). With bug-1887 fixed the loader rejects that text outright (snapshot tests failed: "parse_resreq failed for jobid 201: Primary: ..."). **Expected:** the snapshot stores the resreq text the job was submitted with, and the restored job parses to the same request. **Impact:** wrong result: every job restored from a snapshot -- a `.replay` start snapshot (simulator replays), REPL snapshots -- lost its select and rusage, so replays of sessions with pending jobs at snapshot time could decide differently from the live scheduler. A save/restore field-completeness violation (persistence.md). **Found by:** test (while fixing bug-1887, 2026-09-29) ## Environment - OS: no /etc/os-release; Docker container; NixOS kernel; kernel Linux 6.18.33 x86_64 - libc: glibc 2.42-47 (interpreter /nix/store/wb6rhpznjfczwlwx23zmdrrw74bayxw4-glibc-2.42-47/lib/ld-linux-x86-64.so.2) - Toolchain: gcc (GCC) 15.2.0, meson 1.9.1 - Build: asan (src/xce.build.discrete) - Code: scheduler-framework @ 9c51de88-dirty - Deployment: n/a (unit test) ## Reproduction 1. Build the scheduler tests; run `src/xce.build.discrete/scheduler/testsuite/sched_snapshot_save_load_test` at a commit before 077b1213 with test_snapshot_round_trip_keeps_job_resreq_text added. 2. Observe the saved text is the dump, not `rusage[mem=2]`. - Frequency: deterministic - Evidence: test output quoted above ## Root cause `build_wire_job()` (snapshot_wire.c) filled `submit->resreq` with `format_resreq()`, a human-readable debug dump, because the scheduler job kept only the parsed resreq, not its text. The loader's parser accepted the dump as a primary with neither select nor rusage (the bug-1887 leniency). ## Fix `xce_sched_job_t` keeps the resreq text (`resreq_str`, set at ingest, JOB_UPDATE and snapshot load, freed at teardown) and the snapshot saves it; a job without it restores as the loader's "type == any" default (077b1213). ## Verification - Test: test_snapshot_round_trip_keeps_job_resreq_text in src/scheduler/testsuite/test_snapshot_save_load.c (push a job with rusage[mem=2], save, load into a second core): RED before (saved text was the dump), GREEN after (text kept, restored rusage count 1) - Suites: ASAN debug build (src/xce.build.discrete), `meson test --no-suite xceadmin`: 117/117 OK, 0 sanitizer reports; xcelib_test 695 tests 0 failures (2026-09-29) - Live: 3-round sequential HA soak on rebuilt ASAN binaries (/home/claude/tmp/xce-bug1885-soak, 2026-09-29): PASS, 15 jobs, zero job loss, all 3 nodes led; SIMVERIFY 4 files 0 mismatches; each recording replays with detect_leaks=1 at exit 0, 0 mismatches; no sanitizer report in the scheduler or controller stderr ## References - Related: none