feat(scheduler-core): define replay stream envelope schema (task 7.1)

Adds ReplayCluster/ReplayHeader/SnapshotEntry/ReplayEvent/
SessionSummary/ReplaySession to controller.capnp, additively, first
task of Phase 3 (Foundation: Replay Wire Format).

Requirements.md's AC 20 capnp sketch isn't self-contained -- ReplayEvent's
union references JobStateChangeEvent/JobUpdateEvent (task 7.2's job),
SnapshotEntry.data/ReplayDecision's union reference SnapshotData/
DispatchDecision/PendDecision/PreemptDecision (task 7.3's job), none
of which exist yet. Resolved by verifying capnp's real constraints
against the toolchain directly: SnapshotData is an empty {} placeholder
(task 7.3 replaces its mapname'd C struct wholesale when adding the
real ~11 fields), ReplayDecision holds only {ts} (task 7.3 appends a
body union at new ordinals), and ReplayEvent's union holds only the 9
members with pre-existing backing types (Conf4Sched/SchedJobData/
WorkerData/ResourceData/ResValList/QueueConf/SchedJobRusages/Void),
deferring jobStateChange/jobUpdate to task 7.2 as new ordinals --
capnp requires strictly sequential ordinals with no holes, so this
split is compiler-mandated, not stylistic.

Round-trip test added to test_e2e_capnp.c. Full project build (all
binaries sharing this schema) and 1075/1075 controller_unit_test
verified clean.

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 09:38:13 +00:00
parent d39ffc1b4e
commit 68a6196517
Signed by: rshen
SSH key fingerprint: SHA256:8Vf2pZ3h6rJa7EhGK+WaAQ9Mta/apZvteW6g9U/WKKk
4 changed files with 407 additions and 1 deletions

View file

@ -541,4 +541,88 @@ struct ctrl_hello_reply_s {
uint64_t config_tag; /* primary's current config tag */
};
/* ── Replay stream envelope frames (scheduler-core Group 7 task 7.1,
* Req 5 AC 20) ──────────────────────────────────────────────────────────
* Frame-only wire types for the `.replay` stream envelope -- same "no live
* C struct" convention as capnp_snap_hdr_t/capnp_persist_cfg_t/
* capnp_host_admin_state_t above (see controller.capnp's comment at
* `struct ReplayCluster` for the full Group 7 task split). The C-side
* reader/writer that actually populates/consumes these (recording,
* `.replay` file I/O) is task 9+, out of this schema-only task's scope. */
typedef struct {
char *name;
char **controllers;
int n_controllers;
char *recording_host;
} replay_cluster_t;
typedef struct {
char *recorder_version;
/* configHash is a Data field -- the generated encode_/decode_ codec is
* a documented no-op for Data fields in this codebase's capnpc-c setup
* (same limitation as e.g. upgrade_config_req_s.sha256/bytes above);
* real byte extraction is task 9+ hand-written code, same raw_sha256-
* style pattern used throughout this file. This pointer/len pair exists
* only so the mapname target type is well-formed; nothing here reads it
* yet. */
uint8_t *config_hash;
size_t config_hash_len;
replay_cluster_t *cluster;
uint64_t recording_start_ts;
char *recording_start_wall;
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. */
typedef struct {
uint8_t _reserved;
} sched_snapshot_data_t;
typedef struct {
uint64_t ts;
sched_snapshot_data_t *data;
} replay_snapshot_entry_t;
typedef struct {
uint64_t ts;
int body_which;
union {
xce_conf4sched_t *config_push;
xce_jobs_data_t *jobs_push;
xce_workers_data_t *workers_push;
xce_resource_data_t *resources_push;
xce_resval_list_t *resvals_full;
xce_resval_list_t *resvals_delta;
xce_queue_t *queue_update;
xce_job_rusages_t *job_rusage;
/* endSession: Void, no storage */
} body;
} replay_event_t;
typedef struct {
uint64_t duration_ns;
uint32_t n_decisions;
uint32_t n_dispatched;
uint32_t n_pended;
} session_summary_t;
/* Placeholder -- task 7.3 adds the `body` union (dispatch/pend/preempt)
* here once DispatchDecision/PendDecision/PreemptDecision exist. */
typedef struct {
uint64_t ts;
} replay_decision_t;
typedef struct {
uint64_t begin_round;
replay_decision_t **decisions;
int n_decisions;
session_summary_t *summary;
} replay_session_t;
#endif