feat(scheduler-core): define decision payload types and snapshot schema (task 7.3)

Adds DispatchDecision (wraps JobAlloc), PendDecision (wraps
JobPendReason), PreemptVictim, PreemptDecision to controller.capnp.
Replaces task 7.1's empty SnapshotData placeholder wholesale with the
real 11-field struct (config/jobs/queues/workers/resources/resvals/
users/projects/prngSeed/internalState/internalVersion), in both the
capnp schema and its typemap.h C mirror. Extends ReplayDecision's
ts-only placeholder with a purely additive body union (dispatch@1/
pend@2/preempt@3).

Deviates from design.md's literal SchedUser/SchedProject mapnames
(xce_sched_user_t/xce_sched_project_t): those names are already real
C structs in sched/types.h, which shares a translation unit with
typemap.h in core_events.c/schedobj.c -- reusing them would be a
genuine duplicate-typedef compile error, not a style choice. Used
fresh mapnames (sched_snapshot_user_t/sched_snapshot_project_t)
instead, field lists unchanged, documented in both files.

Found and fixed a real bug mid-implementation: a doc comment's
literal */ substring prematurely closed a C block comment, corrupting
sched_snapshot_data_t and cascading into ~20 unrelated-looking compile
errors (bug-1493).

Five deep round-trip tests added to test_e2e_capnp.c. Full project
build and controller_unit_test (1082/1082) verified clean, confirmed
independently three times.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019dw5WnN3DXStaEaPYfACU1
This commit is contained in:
Rongsong Shen 2026-08-04 13:11:26 +00:00
parent 755230705c
commit bbb3972ae6
Signed by: rshen
SSH key fingerprint: SHA256:8Vf2pZ3h6rJa7EhGK+WaAQ9Mta/apZvteW6g9U/WKKk
4 changed files with 755 additions and 33 deletions

View file

@ -573,15 +573,52 @@ typedef struct {
char *sched_policy;
} replay_header_t;
/* Placeholder -- task 7.3 replaces this wholesale (not merely appends to)
* with the real 11-field snapshot struct (config/jobs/queues/workers/
* resources/resvals/users/projects/prngSeed/internalState/internalVersion,
* design.md's Wire Protocol > ReplayFormat section). The single reserved
* byte below has no capnp counterpart -- SnapshotData has zero capnp fields
* in this task, so the generated encode_SnapshotData/decode_SnapshotData
* bodies are no-ops regardless of what this C struct contains. */
/* task 7.3 (Req 5 AC 21): SchedUser/SchedProject mirror controller.capnp's
* SchedUser/SchedProject structs. Field lists match xce_sched_user_t/
* xce_sched_project_t (src/scheduler/include/sched/types.h) exactly -- name
* only, name+priority respectively -- but these are FRESH, wire-only C
* types under different names, NOT aliases of the scheduler-internal ones.
* See controller.capnp's comment at `struct SchedUser` for the full
* rationale: sched/types.h is scheduler-private and already `#include`s
* this file, so a duplicate `xce_sched_user_t`/`xce_sched_project_t`
* typedef here would break every scheduler .c file that includes both
* headers (confirmed: core_events.c, schedobj.c already do). */
typedef struct {
uint8_t _reserved;
char *name;
} sched_snapshot_user_t;
typedef struct {
char *name;
int32_t priority;
} sched_snapshot_project_t;
/* task 7.3 (Req 5 AC 21): the full snapshot struct, replacing the task 7.1
* placeholder wholesale. Every domain-object pointer reuses a pre-existing
* native type (already used natively throughout the scheduler/controller)
* except users/projects (sched_snapshot_user_t/sched_snapshot_project_t
* above) and the two scheduler-internal-only opaque fields. internal_state
* follows the same raw uint8_t-pointer + size_t pattern as every other Data
* field in this file (e.g. replay_header_t.config_hash above) -- the generated
* encode_SnapshotData/decode_SnapshotData codec is a documented no-op for
* it; real extraction is task 9+ hand-written code. internal_version is a
* format tag for internal_state so an incompatible future internal layout
* is rejected rather than misinterpreted (this task's Observable). */
typedef struct {
xce_conf4sched_t *config;
xce_jobs_data_t *jobs;
xce_queue_t **queues;
int n_queues;
xce_workers_data_t *workers;
xce_resource_data_t *resources;
xce_resval_list_t *resvals;
sched_snapshot_user_t **users;
int n_users;
sched_snapshot_project_t **projects;
int n_projects;
uint64_t prng_seed;
uint8_t *internal_state;
size_t internal_state_len;
uint32_t internal_version;
} sched_snapshot_data_t;
typedef struct {
@ -636,10 +673,41 @@ typedef struct {
uint32_t n_pended;
} session_summary_t;
/* Placeholder -- task 7.3 adds the `body` union (dispatch/pend/preempt)
* here once DispatchDecision/PendDecision/PreemptDecision exist. */
/* task 7.3 (Req 5 AC 5, AC 20): the three decision payload types --
* dispatch/pend reuse existing native types (xce_job_alloc_t,
* xce_job_preason_t); preempt_victim_t/sched_preempt_decision_t are fresh,
* wire-only types, deliberately distinct from decision.h's core-internal
* xce_preempt_victim_t/xce_preempt_t (task 4.4's in-process live-decision
* representation) -- see controller.capnp's matching comment. */
typedef struct {
xce_job_alloc_t *alloc;
} sched_dispatch_decision_t;
typedef struct {
uint64_t jobid;
xce_job_preason_t *reason;
} sched_pend_decision_t;
typedef struct {
uint64_t jobid;
char *workerid;
} preempt_victim_t;
typedef struct {
uint64_t jobid;
preempt_victim_t **victims;
int n_victims;
xce_job_preason_t *reason;
} sched_preempt_decision_t;
typedef struct {
uint64_t ts;
int body_which;
union {
sched_dispatch_decision_t *dispatch;
sched_pend_decision_t *pend;
sched_preempt_decision_t *preempt;
} body;
} replay_decision_t;
typedef struct {