--- id: "bug-1758" status: "fixed" status_updated: "2026-09-24" status_note: "" component: "scheduler" severity: "unknown" timestamp: "2026-09-02T03:23:00Z" last_seen: "2026-09-19T09:00:00Z" occurrences: 1 files: ["src/scheduler/testsuite/test_core_events.c"] tags: ["scheduler-dispatch-commit", "core_events-c", "test_core_events-c", "sched_reconcile_job_resource_usage", "mem-reservation", "resInUse", "unrelated-branch-breakage", "discovered-by-worker-rejoin-resync-validation"] related: [] legacy: true --- # bug-1758: scheduler suite (meson test --suite scheduler): sched_core_events_test FAILs deterministically… ## Description scheduler suite (meson test --suite scheduler): sched_core_events_test FAILs deterministically -- test_core_events.c:1364:test_job_rusage_reconciles_mem_reservation_against_usage:FAIL: Expected 4 Was 0. Discovered as one of 2 failures (the other is a pre-existing, unrelated libxce/meson.build ASAN-flag gap) during worker-rejoin-resync feature-level /kiro-validate-impl full-suite run; confirmed NOT caused by worker-rejoin-resync. ## Environment _Not recorded (migrated from buglog.json)._ ## Reproduction _Not recorded (migrated from buglog.json)._ ## Root cause NOT YET ROOT-CAUSED (logged, not investigated -- out of scope for the session that found it). Confirmed via git blame that the ENTIRE failing test function, including the failing sanity assertion at line 1364 itself, was newly added by commit eb06f16d ("fix(scheduler): wire mem reservation reconciliation into live rusage event path", .kiro/specs/scheduler-dispatch-commit/), not by worker-rejoin-resync or any earlier commit -- this is that commit's own new test failing against its own new code, not a regression it caused in pre-existing coverage. The failure is at the test's OWN pre-condition sanity check (line 1364, before the rusage/reconciliation event the test is actually about is even pushed): a JOBS_PUSH-dispatched job with a real 4.0 "mem" xce_alloc_t is asserted to have already charged 4.0 into w->resInUse ("matching sched_charge_account()'s existing behavior", per the test's own comment) -- but val[0] reads back 0. Two live hypotheses, neither yet confirmed: (a) core_events.c's XCE_CORE_EVENT_JOBS_PUSH handler (used here to simulate a dispatch by directly attaching job1->allocs) never actually calls sched_charge_account()/an equivalent resInUse-charging step for a pushed RUN job carrying allocs -- JOBS_PUSH may be resync-shaped (report already-existing state) rather than dispatch-shaped (perform a fresh charge) by design, making the test's own sanity-check premise wrong; or (b) charging happens but keyed off a different resource-index/worker-pointer path than this test's fixture reads back from. Needs an actual debugging pass (e.g. kiro-debug) to distinguish; not attempted here. RESOLVED (2026-09-08, follow-up session): hypothesis (a) confirmed, but with the opposite implication than it first suggested -- this is NOT a production gap. core_session.c's own core_begin_session_internal() doc comment (lines 156-176) already documents the real architecture: resInUse/sharedInUse is never charged incrementally at JOBS_PUSH/dispatch time. It is fully RE-DERIVED once per round by sched_account_jobs() (scheduler.c:1434) -- iterates every currently-RUN job in core->jobs and calls sched_charge_account() on each one's accounts -- called by BOTH the real normal-mode driver (driver.c:761) and the sim driver (sim_loop.c:1118), always BEFORE anything else in that round reads resInUse. JOBS_PUSH intentionally does none of this itself (confirmed by reading its full handler in core_events.c and builtin_fcfs_on_job_push() -- neither calls sched_charge_account/sched_uncharge_account anywhere), and neither does the terminal-state cleanup path (JOB_STATE_CHANGE/JOB_UPDATE just free the accounts structure) -- both are consistent with a 'recompute from source of truth each round' design that needs no incremental charge/uncharge pairing at all. The test's own precondition assertion (checking resInUse immediately after JOBS_PUSH, with no round boundary simulated) was checking an invariant that was never the real contract -- a test bug, not a production one. ## Fix FIXED (2026-09-08, follow-up session). test_job_rusage_reconciles_mem_reservation_against_usage (test_core_events.c) now calls sched_charge_account(&core, tracked->accounts) right after JOBS_PUSH and before the resInUse sanity assertion -- simulating the exact reconciliation step sched_account_jobs() would perform for this test's one RUN job, the same primitive sched_account_jobs() itself calls internally (test_core_events.c already white-box #includes resource.c, where sched_charge_account() lives; sched_account_jobs() itself is scheduler.c, not included here, so its single-job effect is reproduced directly rather than pulling in that whole file). No production code changed -- the bug was entirely in the test's precondition assumption, not the scheduler. Verified: full scheduler suite xce-build.sh scheduler asan --incremental: 77/77 Ok (was 76/77, this test's own prior deterministic failure now gone); full xce-build.sh all asan --incremental: 94/94 Ok, zero regressions. ## Verification _Not recorded (migrated from buglog.json)._ ## References _Not recorded (migrated from buglog.json)._