--- id: "bug-1567" status: "fixed" status_updated: "2026-09-24" status_note: "" component: "scheduler" severity: "unknown" timestamp: "2026-08-17T09:00:00Z" last_seen: "2026-09-19T09:00:00Z" occurrences: 2 files: ["src/scheduler/src/sim.c", "src/scheduler/src/sim_loop.c"] tags: ["scheduler", "simulation-mode", "sim-mode", "replay", "job-picker", "scheduler-core", "known-scope-boundary", "tdd"] related: [] legacy: true --- # bug-1567: xce_scheduler -i -s : WARN 'failed to resolve job picker plugin (rc=-2)' on load; all… ## Description xce_scheduler -i -s : WARN 'failed to resolve job picker plugin (rc=-2)' on load; all pre-existing jobs stay PEND forever, nothing ever dispatches in simulation/interactive mode ## Environment _Not recorded (migrated from buglog.json)._ ## Reproduction _Not recorded (migrated from buglog.json)._ ## Root cause Two compounding, both explicitly documented 'Known scope boundary' gaps in the scheduler-core sim driver (task 11.1/11.2, .kiro/specs/scheduler-core): (1) sched_sim_driver_start() (sim.c) loads the initial snapshot via xce_sched_core_load_snapshot() BEFORE any picker plugin is registered into core->plugins -- only job_pick_plugin's NAME is threaded through from the ReplayHeader (sim.h:206-216's own doc comment). sched_resolve_job_picker() therefore returns -ENOENT (=-2), producing the WARN, and the picker-rebuild walk (on_queue_update/on_job_push) inside xce_sched_core_load_snapshot() is silently skipped for every job/queue in the initial snapshot. The real picker only gets registered moments later, in sim_register_default_picker() (sim_loop.c:381, called from sched_sim_driver_run() right after start() returns) -- but nothing re-pushes the already-loaded jobs/queues into it, so any job present in the replay file's INITIAL snapshot is permanently invisible to the fcfs picker's next_job(). (2) Independently, sim_picker_thread_fn() (sim_loop.c:448) has its own documented scope boundary: real resource-matching allocation (sched_make_allocation()) needs a live xce_scheduler_t* that the sim driver deliberately doesn't have, and no core-only equivalent exists yet (deferred to the separate, not-yet-designed .kiro/specs/scheduler-allocation spec) -- so EVERY candidate the picker selects is unconditionally turned into a PEND decision; dispatch is not implemented in simulation mode at all today, regardless of resource availability. ## Fix FIXED (TDD, RED->GREEN). New file src/scheduler/src/sim_picker.c: sim_bootstrap_picker() (replaces sim_loop.c's sim_register_default_picker(), moved out because sim_loop.c was already at its documented 800-line 'zero line-budget headroom' cap) registers the real builtin_fcfs picker AND then replays the picker-rebuild walk (on_queue_update per queue, on_job_push per pending job) that xce_sched_core_load_snapshot() had to skip at initial-snapshot-load time. Wired into scheduler_srcs, sched_sim_isolation_lib, and all 9 white-box test TUs that #include sim_loop.c directly (test_sim_isolation.c mechanically re-verified). New regression test: test_sim_event_loop.c's test_job_present_only_in_initial_snapshot_still_reaches_the_picker -- builds a fixture with a job baked into the INITIAL snapshot (not a ReplayEvent), asserts it gets a live PEND decision. RED confirmed by temporarily no-op'ing the rebuild walk (test failed as expected), GREEN with the real fix restored. Full scheduler suite green (41/41, only pre-existing unrelated bug-1560 skipped/excluded from that count). Note: finding (2) from the original diagnosis (sim mode never dispatches, only PENDs -- scheduler-allocation spec gap) is NOT fixed here, by design -- out of scope, a whole separate not-yet-designed spec. ## Verification _Not recorded (migrated from buglog.json)._ ## References _Not recorded (migrated from buglog.json)._