run_summary.hpp¶
RunSummary — the end-of-run one-screen summary, as DATA.
This header declares 1 type (22 members).
Extracted from include/shulib/diag/run_summary.hpp — this page is that header's documentation, reformatted, so it cannot disagree with the code. Prose about how to think about the API lives in the user guide; worked recipes live in the cookbook; this page is the complete, mechanical list of what exists.
Contents¶
struct RunSummarymotionsStartedmotionsSettledmotionsTimedOutmotionsCancelledmotionsAbortedhasHeadingDataheadingMaxheadingFinalgatingRejectsbrownoutworstLoopDtfirstFaultfirstFaultTimedroppedRecordsdroppedLinesblackboxDroppedbatteryStartbatteryEndsetBuildHashsetRoutineIdbuildHashroutineId
struct RunSummary¶
The end-of-run summary as DATA, never as an assembled essay: structured fields that one producer fills and any number of renderers format — the boxed terminal block, an appended blackbox frame, a wire message. A VALUE TYPE that owns its provenance strings in bounded in-struct arrays and allocates nothing, so a sink may RETAIN a copy without holding a dangling view into some caller's stack. Assembled once per run and delivered through hal::ITelemetrySink::summarize().
struct, declared at include/shulib/diag/run_summary.hpp:45.
RunSummary::motionsStarted¶
Motions the scheduler handed a start(). It EXCEEDS the four outcome counts below whenever a motion was still running when the summary was taken — they partition the FINISHED motions only, so started minus their sum is what was still in flight.
field, declared at include/shulib/diag/run_summary.hpp:50.
RunSummary::motionsSettled¶
Exited inside its tolerances — the only outcome that means success
field, declared at include/shulib/diag/run_summary.hpp:51.
RunSummary::motionsTimedOut¶
Exited on the watchdog; each one also raised MOTION_TIMEOUT
field, declared at include/shulib/diag/run_summary.hpp:52.
RunSummary::motionsCancelled¶
user/pre-empt cancels (no causal fault)
field, declared at include/shulib/diag/run_summary.hpp:53.
RunSummary::motionsAborted¶
fault-policy / task-boundary aborts
field, declared at include/shulib/diag/run_summary.hpp:54.
RunSummary::hasHeadingData¶
False when no motion produced heading data (record stream off, or nothing ran) — renderers show "n/a", never a fabricated 0.0 (a 0.0° claim with no data behind it is exactly the lying-number failure C5's brief bans).
field, declared at include/shulib/diag/run_summary.hpp:60.
RunSummary::headingMax¶
worst per-motion final |heading error| (radians)
field, declared at include/shulib/diag/run_summary.hpp:61.
RunSummary::headingFinal¶
the LAST motion's final |heading error| (radians)
field, declared at include/shulib/diag/run_summary.hpp:62.
RunSummary::gatingRejects¶
GPS_GATE_REJECT episodes (FaultLatch tally)
field, declared at include/shulib/diag/run_summary.hpp:65.
RunSummary::brownout¶
HealthMonitor::brownedOut() — latched, E1 semantics
field, declared at include/shulib/diag/run_summary.hpp:66.
RunSummary::worstLoopDt¶
LoopMonitor::worstDt()
field, declared at include/shulib/diag/run_summary.hpp:67.
RunSummary::firstFault¶
the ROOT CAUSE (FaultLatch first-fault)
field, declared at include/shulib/diag/run_summary.hpp:68.
RunSummary::firstFaultTime¶
when it latched (0 if none)
field, declared at include/shulib/diag/run_summary.hpp:69.
RunSummary::droppedRecords¶
RateLimitedSink::droppedRecords()
field, declared at include/shulib/diag/run_summary.hpp:72.
RunSummary::droppedLines¶
RateLimitedSink::droppedLines()
field, declared at include/shulib/diag/run_summary.hpp:73.
RunSummary::blackboxDropped¶
Frames the E1 blackbox (diag::SdSink) dropped because its RAM byte budget was exhausted, or because a device write failed. A SEPARATE counter from the two above on purpose: those are rate-limiter drops on the terminal channel, and merging two different failures into one number is how a diagnostic starts lying. 0 also means "no blackbox was attached", which is why renderers show this one only when it is non-zero (TermSink's summarize note). — E1
field, declared at include/shulib/diag/run_summary.hpp:80.
RunSummary::batteryStart¶
Pack volts READ at session start, never caller-typed: a typed 12.6 that was really 11.9 is exactly the lying number this record exists to avoid.
field, declared at include/shulib/diag/run_summary.hpp:85.
RunSummary::batteryEnd¶
Pack volts read when the summary was assembled; with batteryStart, the run's sag. Both are 0 V on a summary nobody filled in — there is no "unset" sentinel here.
field, declared at include/shulib/diag/run_summary.hpp:88.
RunSummary::setBuildHash¶
Empty ⇒ MISSING (rendered loudly; header note). 47 bytes admits a full 40-char git SHA plus a "-dirty" suffix.
function, declared at include/shulib/diag/run_summary.hpp:92.
RunSummary::setRoutineId¶
Copy the auton routine's name (e.g. "redLeftTall") in, TRUNCATED at 31 characters. Empty is ordinary here — only buildHash treats empty as the loud MISSING case.
function, declared at include/shulib/diag/run_summary.hpp:95.
RunSummary::buildHash¶
The stored hash; EMPTY means the build system provided none, which renderers must print as MISSING rather than anything plausible-looking. LIFETIME: the view points into THIS object — it dies with the summary, the next setBuildHash() invalidates it, and a copied summary hands back views into the COPY. That is the whole reason this is a value type rather than a struct of string_views.
function, declared at include/shulib/diag/run_summary.hpp:102.
RunSummary::routineId¶
The stored routine name; empty if never set. Same lifetime rule as buildHash(): the view is into this object, never into what the caller passed setRoutineId().
function, declared at include/shulib/diag/run_summary.hpp:106.
Design commentary, from the header¶
The header opens with the reasoning behind these shapes. It is reproduced here in full because a reference that only lists signatures teaches nobody why.
The header’s own reasoning — 27 lines
RunSummary — the end-of-run one-screen summary, as DATA (master plan §18.3; WS13,
chunk C5). The §18.3 block is one of the two ideas worth salvaging from the legacy
"logging extreme" code, re-expressed the §18 way: STRUCTURED FIELDS the sinks
format, never an essay assembled in a motion loop.
Why a struct on the sink seam (hal::ITelemetrySink::summarize) rather than text
pushed through log(): the summary is a RECORD with one producer and many possible
renderings — TermSink draws the boxed block, E1's SdSink will append it to the
blackbox, H1's wire can carry it to VexBuilder. Formatting it before the seam
would freeze the terminal rendering as the only consumer (§18.1 "one record, many
sinks" applies to every record type, not just the per-tick one).
VALUE TYPE, deliberately: the provenance strings live in bounded in-struct arrays
(set via setBuildHash/setRoutineId), not string_views — a sink that RETAINS a
summary (FakeTelemetrySink, the E1 blackbox) must not be handed dangling views
into some caller's stack. Nothing here allocates.
Content mapping, stated honestly (§18.3's sketch shows "scored 6 pin · 1 cup"):
game-object scoring belongs to the strategy layer (the G-phase command registry —
the library cannot know what a motion scored). The M2-honest equivalent is the
MOTION LEDGER (started/settled/timeout/cancelled/aborted); when G2's registry
exists, scoring lands as an ADDITIVE field, not a reshape.
The "MISSING" contract (§18.5): an EMPTY buildHash means the build system did not
provide one. Renderers must say MISSING, loudly — never invent a plausible value.
A wrong hash is worse than an absent one.
Last updated 2026-08-15 — published from the main release branch, commit fa545ff. This site tracks releases, so between them it can lag the repository — that lag is deliberate, and it is what keeps the development log off the public site. For the current state of the code, see the repository.