myxce/src/scheduler/CLAUDE.md
Rongsong Shen 25e35bacaf
docs(scheduler): document driver-equivalence invariant, scope decision-parity fix spec
Elevates the normal-mode/simulation-mode driver equivalence guarantee
from a one-line architectural description in CLAUDE.md to an enforced
steering constraint (scheduler-driver-equivalence.md), backed by
bug-1611/bug-1613 as concrete evidence of violation. Scopes the fix as
its own spec (scheduler-sim-decision-parity, requirements + design)
rather than reopening the closed scheduler-core spec or folding it
into scheduler-sim-repl-verbosity's explicitly narrower boundary.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-22 02:52:00 +00:00

5 KiB

XCE Scheduler

Overview

C-based job scheduling engine with a plugin architecture. Determines job-to-node assignments based on resource requirements and scheduling policies. Since scheduler-core (2026-08), the engine is split into a mode-agnostic core state machine driven by two interchangeable drivers — a controller-connected normal-mode driver and a standalone .replay-file simulation driver — so scheduling decisions can be recorded live and deterministically replayed offline for debugging/tuning.

Build

/xce-build scheduler    # debug + ASAN + tests; add `all` instead of `scheduler` when a downstream
                         # task also needs xceadmin/controller binaries coexisting in the same build dir

Architecture

  • Core (core.c/core_events.c/core_session.c/core_clock.c) — passive, event-driven xce_sched_core_t state machine. Zero controller I/O (no netio/xceapi/client/delay/idgen); core_clock.c is the one sanctioned exception (clock_gettime, virtualized two-base+speed clock formula, xce_core_now()). test_core_isolation.c mechanically enforces this for core.c/core.h/core_events.c/core_session.c (source-text scan) plus core_clock.c too on the nm(1) undefined-symbol layer (all four compiled together into the isolated sched_core_isolation_lib archive, meson.build) — core_clock.c is deliberately excluded only from the wall-clock text scan, since it owns the one sanctioned clock_gettime() call. Picker→allocator handoff is a strict jbuf cbuf capacity-1 rendezvous — this is the project's determinism invariant, not a tuning knob; never raise it without re-deriving Req 5 AC 7 in .kiro/specs/scheduler-core/requirements.md.
  • Picker plugin interface (plugin.h's xce_job_picker_iface_t, plugins/builtin_fcfs.c) — job-selection strategies are pluggable; scheduler.c's sched_job_picker() branches on whether a plugin still uses the legacy job_elect_fn-only shape (plugins/fcfs.c, kept as-is for a compat-wrapper exercise, not the live default) vs the native hook interface (builtin_fcfs, the registered default). New scheduling policies → add as a picker plugin under src/plugins/, do not modify the core loop.
  • Drivers — driver.c (normal mode: capnp↔core event translation, decision publishing, deferred admin-request handling) and sim.c/sim_loop.c/sim_record.c/sim_verify.c (simulation mode: .replay file loading, discrete virtual clock, --sim-verify/--sim-alt-events/--sim-output). Both drive the identical core session/decision-callback protocol — one core, two consumers. This equivalence is a DESIGN INVARIANT, not just an architectural description — see .kiro/steering/scheduler-driver-equivalence.md for the precise (state-level, not just decision-level) contract, known violations (bug-1611, bug-1613), and the testing discipline required of any change in this area.
  • Replay/recording — recording.c/recording_events.c/recording_session.c (live capture) and sim.c/sim_loop.c (simulation-side decode) do the actual capnp encode/decode of the .replay binary stream (src/schema/controller.capnp); snapshot.c/snapshot_wire.c/snapshot_load.c only populate/consume the plain in-memory sched_snapshot_data_t struct that recording.c's write_snapshot_entry() then serializes — no capnp or file I/O lives in the snapshot files themselves. Controlled via OPCode_schedAdmin (src/controller/cluster.c) and xceadmin scheduler record start|stop|status / scheduler dump <FILE>.
  • Interactive REPL (repl.c/repl_break.c/repl_info.c/repl_params.c, --interactive) — single-step/breakpoint/state-inspection/snapshot-capture control over the simulation driver; drives the exact same sched_sim_driver_run() as batch --sim, gated only by sim->interactive, so REPL and batch runs are decision-equivalent by construction (test_repl_equivalence.c).

Links against libxce from src/lib/. Full design/requirements: .kiro/specs/scheduler-core/.

Conventions

  • C standard: gnu17
  • Format with clang-format
  • New scheduling policies → add as a plugin under src/plugins/, do not modify the core engine
  • Shared types defined in src/include/xce/ (libxce)
  • Files stay under the repo's 800-line cap — several core/sim/repl/snapshot/recording modules are deliberately split across multiple *_events.c/*_session.c/*_wire.c-style files for this reason; keep new logic in the file matching its concern rather than growing one file past the cap. Not yet true project-wide: scheduler.c (1382 lines) and plugins/builtin_fcfs.c (1026 lines) are pre-existing exceptions over the cap with no split or exemption note — do not use them as precedent for new files, and prefer splitting them opportunistically rather than growing them further.

See Also

  • Shared library: src/lib/CLAUDE.md
  • Root guidelines: CLAUDE.md (repo root)
  • Architecture/requirements: .kiro/specs/scheduler-core/design.md, .kiro/specs/scheduler-core/requirements.md