myxce/.kiro/specs/scheduler-sim-decision-trace/tasks.md
Rongsong Shen 4f951f2b52
feat(scheduler-sim-decision-trace): trace entry sequence and line budget
Task 1.4: requirement path push/pop with balanced begin/end entries
carrying the full nesting path, one entry per traced event kind, and a
line budget that stops storing at the bound and counts omitted lines.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 08:05:44 +00:00

28 KiB

Implementation Plan

Notes for every task below:

  • Every new test file is registered in the scheduler test build with the source set it needs, and runs in the scheduler suite. Registration only appends entries, so parallel tasks that each register a test do not conflict.
  • Every new trace source file is added to the scheduler's main source list by the task that creates it.
  • "Under ASAN" means the standard debug + ASAN scheduler build.
  • 1. Foundation: baselines, shared formatting, trace model and transport

  • 1.1 Capture the trace-off REPL transcript baseline before any feature change

    • Build a scripted REPL session over a resource-contention replay fixture. The fixture has several jobs competing for a shared license, a cluster-wide limit and a host-scoped limit, plus a parallel job and an alternative-requirement job.
    • The session exercises step, continue with collapsed ranges, a decision breakpoint, a round-begin breakpoint, info subcommands, set units and set output.
    • Store the captured console transcript, the --sim-output recording and the --sim-verify result as committed test fixtures. Add a test that replays the script and compares byte for byte, ignoring only wall-clock metadata fields.
    • Produce the baseline on the tree before any trace code exists. Later tasks use it to prove that output is unchanged with tracing off.
    • Done when the new baseline test passes on the unmodified tree under ASAN and the fixtures are committed.
    • Requirements: 10.4, 10.5
  • 1.2 Move the units and value formatting helpers into the shared REPL formatting module

    • Move these helpers out of the info module so a new renderer can reuse them, with no change in behaviour:
      • units-mode translation;
      • numeric-resource and consumable value formatting;
      • the current-units lookup.
    • Done when every existing REPL test and the 1.1 baseline test pass unchanged under ASAN, and the helpers can be called from other REPL files.
    • Requirements: 7.7
  • 1.3 Build the trace record model foundation, test first

    • Define these types: record, settings snapshot, verdict kinds, record kinds, path, no-plan and position-end. Define these constants: line bound (default 1000, range 50 to 100000) and outcome hosts (50).
    • The per-record arena copies every string and number, so a record never points into scheduler memory. The record reports its own byte size, and freeing a NULL record is a no-op.
    • Job selection matching covers all jobs, a plain job, an array element, and every element of an array (including elements created later).
    • Finishing a record as a no-decision kind records the kind and the error.
    • Create the capture source next to the model source, as an empty module for now, and register both in the scheduler build.
    • Add both to the core isolation test's source scan, with a new check that rejects stdio and file I/O in those two files. They are not added to the isolated core state-machine library.
    • Done when model unit tests pass under ASAN for selection matching, arena copying and size, and record finishing, and the isolation test passes with the new files scanned.
    • Requirements: 1.2, 1.3, 1.8, 2.4, 9.1, 11.2
  • 1.4 Build the trace entry sequence and the line budget, test first

    • Path push and pop, with balanced requirement begin and end entries. Each entry stores its full nesting path: single, compound container, alternative i/n, or member j/m.
    • Entry kinds, each rendering as exactly one line:
      • requirement begin and end;
      • a skipped alternative, the alternative result, and a member merge failure;
      • attempt reasons;
      • cluster-wide check end;
      • no plan;
      • plan begin, discarded, not tried, and end;
      • position begin, end, and scan error;
      • host verdict;
      • commit;
      • finalize failure.
    • The line budget stops storing entries once the bound is reached and counts the omitted lines exactly.
    • Done when model tests pass under ASAN for nesting and balance, every entry kind, and budget edges (bound-1, bound and bound+1) with exact omitted counts.
    • Requirements: 3.3, 3.4, 3.6, 4.3, 4.4, 4.5, 4.7, 4.8, 5.10, 9.1, 9.2
  • 1.5 Add plan and verdict counters, search-end statements, summary tallies and rollback merging, test first

    • The model counts generated, tried, discarded and not-tried plans for each requirement scope.
    • The search-end entry's statement follows the design's conditions: none generated, all discarded, or none placed. The decision-wide counters use the same conditions.
    • Per-verdict host evaluations and requirement outcomes stay exact after truncation.
    • At summary level, host entries are not stored. Instead, a position-summary entry holds the accepted host, a count for each verdict kind (a host with several kinds counts once under each), and a tally of hits per limit.
    • Consecutive released-host calls merge into one rollback entry.
    • Done when model tests pass under ASAN for:
      • every search-end condition, including a plan that is not tried after a discarded one;
      • counters after truncation;
      • summary tallies for a host with both a shortfall and a limit hit;
      • rollback merging.
    • Requirements: 4.6, 4.9, 5.8, 5.9, 5.10, 9.3
  • 1.6 Make every white-box test that includes a hooked scheduler source also compile the trace model and capture sources

    • Use the design's include-pattern search to find the 28 tests that include the election, scheduler, allocator-runner, host-iterator, resource or live-driver sources. Give each one the trace model and capture sources, so the live-driver change in 1.7 and the hook tasks after it still link.
    • Done when the full scheduler test suite builds and passes under ASAN with the new includes and no hooks in place yet.
    • Requirements: 11.4
  • 1.7 Add the trace attachment and trace-only op to scheduling decisions

    • Decisions gain a trace attachment, which every existing constructor leaves empty.
    • A new trace-only op, with its own constructor, is appended after the existing ops without renumbering them.
    • The live driver's drain loop skips the trace-only op and frees any attached trace defensively. Live never produces either.
    • Done when a decision test shows every existing constructor leaves the attachment empty, existing op values are unchanged and the trace-only constructor works, and the existing live-driver and decision tests pass unchanged under ASAN.
    • Requirements: 2.4, 10.1, 11.4
  • 1.8 Add the core trace gate and the hook macro, test first

    • The scheduling core gains a session-settings pointer and a record-under-construction pointer. Both stay empty unless the simulator REPL sets them.
    • The hook macro evaluates its call only when a record is being built.
    • Done when a gate test passes under ASAN showing that:
      • a hook argument with a side effect is not evaluated when no record is being built;
      • a full allocation with tracing never enabled creates no record.
    • Requirements: 11.1, 11.2, 11.3
  • 2. Allocator-side capture of scheduler state

  • 2.1 Capture job selection facts, cluster-wide limits and attempt failure reasons, test first

    • Selection capture: policy name, the job's queue and queue priority, the job's priority and its queue time.
    • Cluster-wide limit capture: each matched limit's name and scope instance, read from the job's matched cluster-wide limits.
    • Attempt failure reasons: summarized per pend-reason code, with the hosts and resources they name, captured before the scheduler replaces the job's stored reason.
    • Done when capture tests over a fixture core and job pass under ASAN, showing exact copied values that do not change when the source structures change later.
    • Requirements: 2.2, 2.3, 3.5
  • 2.2 Capture shortfall and limit rows from the satisfaction check, test first

    • Each checked row carries the resource name, flags, value type, total, in-use, provisionally reserved, requested and met.
    • A row whose resource is flagged as a limit is a limit row. It is resolved to its limit through the scope's matched limits and carries the limit name, the scope instance (plus the host for host scope) and the limited resource's name.
    • The cluster-wide scope keeps every row. A host scope keeps only unmet rows, and these set the host's shortfall and/or limit verdict.
    • Done when capture tests pass under ASAN showing that limit rows are never reported as shortfalls, scope strings are correct, and each scope keeps the right rows.
    • Requirements: 4.1, 4.2, 5.4, 5.5
  • 2.3 Capture decision outcomes and reconstructed dispatches, test first

    • Dispatch: per-host allocation rows and shared rows, with limit charges listed separately.
      • A limit charge is identified by the limit flag, or by its name prefix when the resource is unknown.
      • It is resolved to its limit by name through the job's matched limits. An unresolved charge falls back to a raw number.
      • The first 50 hosts are kept in detail. The rest are aggregated into per-resource totals (excluding limits), per-limit totals and an omitted-host count.
    • Pend: a copy of the decision's pend-reason set.
      • The main reason and host-less entries are always kept.
      • The first 50 hosts are kept with all their entries; the rest are counted per pend-reason code.
    • Reconstructed dispatch: a record holding the reconstruction notice and the dispatch outcome.
    • Done when capture tests pass under ASAN for:
      • a dispatch with shared and host limit charges;
      • 51-host dispatch and pend aggregates;
      • a pend copy equal to its source under the existing pend-reason equality, for 50 or fewer hosts;
      • the raw-number fallback.
    • The full scheduler test suite, including the 28 tests updated in 1.6, must still build and pass under ASAN with the completed capture source. Missing scheduler sources are added to those tests, or stubbed.
    • Requirements: 2.5, 6.1, 6.2, 6.3, 6.4, 9.4
  • 3. Allocator-thread hooks at the decision seams

  • 3.1 Hook the allocator loop: position, record lifecycle, selection and no-decision paths (P)

    • Position: when session settings are present, every real job pop increments it.
    • Record start: a wanted job starts a record with its selection facts; its cluster-wide limits are added after election.
    • No-decision paths:
      • not found: no selection;
      • no scheduling object: selection without limits;
      • allocation error, pend without a reason, or decision-build failure: the record is finished as that kind and pushed as a trace-only decision.
    • Normal decisions: a built decision gets its outcome captured and the record attached.
    • Pointer clearing: every path that hands a record away clears the record-under-construction pointer; the session-end marker also clears it.
    • Done when allocator-loop tests using the real allocator thread pass under ASAN for each no-decision kind, the position count, outcome attachment, and the pointer being clear after each job.
    • Requirements: 2.1, 2.2, 2.3, 2.4, 6.1, 6.4, 11.2
    • Boundary: TraceHooks (allocator loop)
    • Depends: 2.1, 2.3
  • 3.2 Hook resource-requirement branching (P)

    • Single, top-level compound, each alternative and each member push their path level and record exactly one begin and one end.
    • The begin carries task counts and requested resources for single requirements and members, and the member count for containers.
    • A member that fails or errors records the number of members not tried. A merge failure after a member is a separate entry.
    • A skipped alternative is recorded in its position. Either the chosen alternative is recorded, with the alternatives after it as not tried, or "all failed" is recorded.
    • Attempt failure reasons are captured before the job's stored reason is replaced.
    • Done when branching tests pass under ASAN for:
      • a single requirement;
      • a compound with a failing member and a merge failure;
      • an alternative job with a skipped, a failed and a chosen alternative;
      • per-alternative reasons; with every scheduler result unchanged.
    • Requirements: 3.1, 3.2, 3.3, 3.4, 3.5, 3.6
    • Boundary: TraceHooks (resource-requirement branch)
    • Depends: 2.1
  • 3.3 Hook the host pre-filter, the host scan and the satisfaction check (P)

    • The pre-filter records a selection mismatch and a pre-filter internal error as host verdicts.
    • A host scan that stops on an error marks the current position as a scan error.
    • The satisfaction check hands every row to the current record.
    • Done when host-iterator and resource tests pass under ASAN for the selection-mismatch verdict, the pre-filter internal error, scan-error marking, and row capture in both scopes, with iterator and check results identical to an untraced run.
    • Requirements: 4.1, 4.2, 4.4, 5.2, 5.3, 5.4, 5.5, 5.7
    • Boundary: TraceHooks (host iterator, satisfaction check)
    • Depends: 2.2
  • 3.4 Hook the allocator runner: cluster-wide check, plans, positions, candidates and finalize

    • The runner records:
      • an allocator decline and a generator start failure, as no-plan reasons;
      • the cluster-wide check scope and its end, with "no plans tried" on failure;
      • each generated plan as tried, discarded or not tried;
      • each plan's end, with the failed position or the internal error;
      • each position's begin and end (filled, unfilled, scan error, or internal error after acceptance; the unfilled end is shown as a scan error when 3.3 marked the position);
      • each claimed-host skip;
      • each candidate's per-host result: accepted; rejected, with the verdict taken from the rows 3.3 records, or a selection mismatch when no rows were recorded; or internal error;
      • the released hosts, when a failed plan had claims;
      • commit or finalize failure;
      • search end.
    • Done when runner tests pass under ASAN covering every recorded outcome above, with runner return values and pend reasons identical to an untraced run.
    • Requirements: 4.1, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.1, 5.2, 5.6, 5.7, 5.8
    • Depends: 2.2, 3.3
  • 4. Simulator REPL trace surface

  • 4.1 Render trace records to text, test first (P)

    • Hierarchy: header, selection, requirements, cluster-wide checks and plans, positions and hosts, then the outcome. Every budgeted entry renders as exactly one line, in the order shown in the design's example.
    • Summary level: renders position summaries with per-limit names.
    • Truncated records: render a marker with the omitted line count, followed by the fixed-size totals block.
    • Outcome: at most 50 hosts, then aggregates and an omitted-host marker. Limit charges are listed separately, with limit amounts formatted by the limited resource.
    • No-decision records: render the "unavailable" lines. Internal-error and pend-without-reason records also render the captured hierarchy.
    • Reconstructed records: render the reconstruction notice and the outcome.
    • Formatting: amounts use the units mode passed in, and job identifiers use the existing job-identifier formatting. Output goes to one or two sinks, with identical bytes in each.
    • Add the renderer source to the scheduler's main source list.
    • The renderer test includes only the model, capture-free fixtures and the shared formatting module.
    • Done when golden renderer tests pass under ASAN for full and summary levels, every units mode, truncation, the outcome cap, each no-decision kind and reconstructed records.
    • Requirements: 2.1, 2.4, 2.5, 3.1, 3.2, 4.3, 5.1, 5.9, 6.1, 6.2, 6.3, 6.4, 7.6, 7.7, 9.2, 9.3, 9.4
    • Boundary: TraceRenderer
  • 4.2 Store the latest trace per job and serve info trace, test first

    • Storing: a new trace for a job replaces its earlier one.
    • Memory bound: accounted from each record's size.
      • At 64 MiB, the oldest traces are evicted, never the newest.
      • Evicted jobs are marked as discarded; a newer capture clears the mark.
    • info trace for a job or element: renders the stored trace at the level it was captured, using the current units mode. With no stored trace, it reports one of: "discarded", "no trace" with the job's state, or "unknown job".
    • info trace for an array: renders each element's trace in index order and marks discarded elements. When no element has a stored trace, it lists the elements' states.
    • Add the store source to the scheduler's main source list.
    • The store test includes the model, the renderer and the shared formatting module, with a fixture job table.
    • Done when store tests pass under ASAN for replacement, eviction that never drops the newest trace, the three no-trace replies, and an array mixing stored and discarded elements.
    • Requirements: 1.7, 7.8, 7.9, 7.10, 7.11, 9.5, 9.6
    • Depends: 4.1
  • 4.3 Parse the trace command and manage trace settings, test first

    • trace re-parses the raw input line, so it is not limited by the normal tokenizer. It accepts:
      • on all, or on job followed by any number of job selectors;
      • an optional level (default summary) and an optional line bound (50 to 100000, default 1000);
      • an optional trailing file path of up to 4095 bytes, taken from the rest of the line, with optional quotes;
      • off and status.
    • An invalid argument is named in an error, and the settings stay unchanged.
    • This task only parses and stores the file path. Opening the file, the same-file checks and leaving settings unchanged when the open fails are added in 4.5.
    • Add the trace control source to the scheduler's main source list.
    • Settings objects are reference-counted and held as "next session" and "current session". Commands change only "next".
    • trace status shows:
      • the settings in effect, or the next settings when no session is running;
      • any replacement waiting for the next session;
      • stored-trace memory use against its bound.
    • Done when command tests pass under ASAN for every grammar form, every invalid-argument class, a path longer than 63 characters, 20 job selectors, and status output before, during and after a session.
    • Requirements: 1.1, 1.2, 1.3, 1.4, 1.5, 1.7, 1.8, 1.9, 1.10, 1.12
    • Depends: 4.2
  • 4.4 Pass the scheduler log path to the simulation driver (P)

    • The scheduler's log path goes from the command line through the simulation arguments into the simulation driver, where the trace file checks can read it. Only the simulation driver and the command-line entry point change.
    • Done when a simulation start test under ASAN shows the driver holds the configured log path, or the default path when none is given.
    • Requirements: 8.3
    • Boundary: SimIntegration (driver arguments)
  • 4.5 Manage the trace file copy and output-file conflicts, test first

    • When a command names a file, it is opened for appending at once. An open failure names the file and the cause, and the settings stay unchanged.
    • A path that is the same file (device and inode) as the current simulation output file or the scheduler log is rejected.
    • Expose a conflict check, so set output can reject any trace file that is still open.
    • A replaced or disabled file stays open until the session in progress ends; with no session in progress it is closed immediately.
    • Shutdown flushes and closes every open trace file. Trace code never writes to the scheduler log.
    • Done when file tests pass under ASAN for:
      • an open failure;
      • each same-file rejection, including through a hard link;
      • a replaced file kept open until the session ends;
      • an immediate close;
      • flushing at shutdown.
    • Requirements: 8.2, 8.3, 8.4, 8.5, 8.6, 8.7
    • Depends: 4.3, 4.4
  • 4.6 Emit traces inline and apply settings at session boundaries, test first

    • At session begin:
      • reset the per-round traced and flushed flags;
      • make the next settings current, stamping the session number and resetting the position;
      • publish the settings to the scheduling core, or publish nothing when tracing is off.
    • At session end:
      • withdraw the published settings;
      • release the current settings, closing their file if it was replaced;
      • clear the in-progress state.
    • This task owns making the simulator's decision echo printer non-static and declaring it in the simulator header, with its format unchanged, so continue-mode emission prints exactly the echo line that was suppressed. No other simulation-loop change belongs here.
    • Emitting a traced decision or trace-only record:
      • marks the round as traced, in any mode;
      • in continue mode, flushes any active collapsed range on the round's first traced item, then prints the suppressed echo line for traced decisions;
      • renders the trace to the console and to the current file with identical bytes, flushes both, and hands the record to the store.
    • The emission test includes the REPL and simulation sources it calls: the collapsed-range flush and the echo printer.
    • Done when emission tests pass under ASAN showing:
      • trace placement in step mode;
      • flush, then echo, then trace in continue mode;
      • the flags reset after a round that ended in step mode;
      • the file copy byte-equal to the console output.
    • Requirements: 1.6, 7.1, 7.2, 7.3, 8.1, 8.5
  • 5. Wire the trace into the REPL and the simulation driver

  • 5.1 Make every white-box test that includes REPL or simulation sources compile the trace sources, and register the trace REPL sources with the simulation isolation checks

    • Add the trace control, store and renderer sources to the simulation isolation library and to the simulation isolation test's scan list.
    • Find the tests with the design's full include-pattern search. To the 26 tests that include the REPL or simulation-loop sources, add the trace REPL sources.
    • Of those 26, 19 include no hooked source, so they also get the trace model and capture sources. Where the capture source needs a scheduler source those tests do not already include, add it or provide a stub, and list it in the task notes.
    • Done when all of the following pass under ASAN: a full scheduler build including the scheduler binary, the full scheduler test suite, and the simulation isolation test.
    • Requirements: 10.5, 11.3
  • 5.2 Wire the trace commands into the REPL

    • Route trace with the raw line, and route info trace.
    • Help gains a trailing Trace section, and the info subcommand list and info usage line include info trace.
    • set output rejects an open trace file. Quit and end of input shut tracing down.
    • The continue-mode rollup emits a traced round on its own, after its pend list is built, using the same idle rule as range flushes, and never starts a collapsed range from it.
    • Add the trace entry points and their interactive-only gates to the REPL header.
    • Update the 1.1 baseline fixture for exactly the changed help and info-usage lines and nothing else. The test's diff against the old fixture shows only those lines.
    • Done when REPL tests pass under ASAN for help sections and alignment, command routing, the set output rejection and the traced-round rollup, and the updated baseline test passes.
    • Requirements: 1.11, 7.3, 7.4, 8.4, 8.6, 10.4, 10.5
  • 5.3 Wire tracing into the simulation driver's session and decision flow

    • Session hooks: session begin runs after a successful begin-session and before reconciliation. Session end runs after the decision stream ends.
    • Drain loop:
      • trace-only decisions are handled first, with no verification, recording, echo or breakpoint check;
      • traced decisions go to the trace emitter after the echo gate and before the breakpoint check;
      • unclaimed traces are freed before each decision is freed.
    • Reconstructed dispatches: wanted jobs get a reconstructed record, handled in the same order.
    • The echo-printer export belongs to 4.6.
    • Done when driver tests pass under ASAN showing:
      • trace-only decisions never reach verification or recording;
      • a decision breakpoint stops after that decision's trace is printed and stored, with no later trace stored;
      • reconstructed traces print before the round's live decisions;
      • a non-interactive simulation never publishes settings.
    • Requirements: 1.6, 2.5, 7.1, 7.2, 7.3, 7.5, 10.1, 11.3
  • 6. Validation

  • 6.1 End-to-end trace scenarios over the contention fixture

    • Drive the real simulator REPL with tracing on for selected jobs and for all jobs, at both levels.
    • Assert that every section of Requirements 2 to 6 appears with the expected content:
      • alternative and compound labels;
      • cluster-wide rows and limit rejections;
      • plans, positions and host verdicts;
      • rollback;
      • dispatch and pend outcomes.
    • Assert ordering in step mode, continue mode and at breakpoints.
    • Assert info trace at a breakpoint, after the job finishes, for an array, and after changing units mode.
    • The trace file must equal the inline traces byte for byte.
    • Done when the end-to-end test passes under ASAN.
    • Requirements: 1.1, 1.2, 1.6, 2.1, 2.2, 2.3, 3.1, 3.4, 4.1, 4.2, 4.3, 4.5, 5.1, 5.3, 5.4, 5.5, 5.6, 5.8, 5.9, 6.1, 6.2, 6.4, 7.1, 7.3, 7.4, 7.5, 7.8, 7.9, 8.1
  • 6.2 Error-path trace scenarios with the real allocator

    • Include the scheduler sources directly, so source-level and link-level fault injection apply.
    • Inject each fault and assert its traced outcome:
      • a plan-claims growth failure, through the heap-allocator macro;
      • a snapshot failure, through the vector-copy wrap;
      • finalize failures, through the allocation-constructor wraps;
      • a failing host scan;
      • a failing per-host uncommitted lookup;
      • an allocation function that returns an error;
      • an unknown job identifier placed directly on the job hand-off buffer.
    • Done when the error-path test passes under ASAN and each injected fault produces its specified trace lines.
    • Requirements: 2.4, 3.2, 4.4, 4.5, 5.7
  • 6.3 Prove tracing never changes scheduling

    • Run the contention replay four ways: tracing off, all jobs at summary level, all jobs at full level, and a job subset.
    • Every run must produce identical decision sequences, pend-reason sets, final accounting state, --sim-verify results and --sim-output recordings (apart from wall-clock fields).
    • With tracing off, the baseline transcript (as updated in 5.2) must stay unchanged.
    • The existing equivalence, verification and live-driver suites must pass unchanged.
    • Done when the equivalence test and the full scheduler suite pass under ASAN.
    • Requirements: 10.1, 10.2, 10.3, 10.4, 10.5, 11.4
  • 6.4 Bounds under large traces and the final full build

    • Trace a 1000-host parallel job with up to 64 tasks, at full level with the default bound. The stored entries must stay within the bound, with exact counters.
    • Run 10,000 traced decisions. Stored-trace memory must never exceed 64 MiB.
    • Correct the stale file sizes in the scheduler component guide and list the new files.
    • Done when the bounds test passes and a full ASAN build of all components passes with no test failures.
    • Requirements: 9.1, 9.3, 9.5, 11.2

Implementation Notes

  • 1.1: build dir is src/xce.build. Baseline test sched_repl_trace_baseline_test runs the built xce_scheduler (depends: scheduler); regenerate fixtures with XCE_REPL_BASELINE_REGEN=1 (script.txt is hand-written). Fixture sends the license value as a RESVALS_FULL event because shared resvals in the snapshot are dropped on load (bug-1923). sim_output.replay has no session decisions (set output switches files before session 1 is finalized); decisions are covered by set_output.replay and sim_verify.txt.
  • 1.3: sched_trace_ctl_wants whole-array selectors match elements only, not the bare key. A bare id in trace on job <id> can't be told apart from an array base for a job that doesn't exist yet, so 4.3's parser must emit both {key,false} and {key,true}, or the matcher must also accept jobid == key.
  • 1.3: design's record header lists a "file tag", but xce_sched_trace_ctl_t has no such field; the 4.2/4.6 store/emit tasks must set it or drop it explicitly.
  • 1.3: trace sources (sched_trace.c, sched_trace_capture.c) may not include <stdio.h> (core isolation test); capture copies raw strings/numbers and leaves formatting to the renderer.
  • 1.4: sched_trace_host_verdict(rec, 0, err) means "derive from rows" (rec->host_row_verdicts shortfall/limit, else SELECT, phase per-host); an explicit SELECT is the pre-filter phase. 2.2's row capture must set host_row_verdicts and 3.3/3.4 hooks must follow this. sched_trace_pos_scan_error stores no entry; it turns the next UNFILLED position end into SCAN_ERROR. Plan numbers restart per requirement. trace.h forward-declares struct xce_alloc_plan_s (tag added in alloc_iter.h) to avoid the core.h include loop. resreq_begin may store a NULL req name for a NULL rusage; 4.1's renderer must tolerate it.