The assembled diagnostic bundle (metadata + clock + series + events + verdict).
const url = 'http://localhost:8080/v1/admin/sessions/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/diagnostic-bundle';const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}use reqwest;
#[tokio::main]pub async fn main() { let url = "http://localhost:8080/v1/admin/sessions/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/diagnostic-bundle";
let mut headers = reqwest::header::HeaderMap::new(); headers.insert("Authorization", "Bearer <token>".parse().unwrap());
let client = reqwest::Client::new(); let response = client.get(url) .headers(headers) .send() .await;
let results = response.unwrap() .json::<serde_json::Value>() .await .unwrap();
dbg!(results);}curl --request GET \ --url http://localhost:8080/v1/admin/sessions/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/diagnostic-bundle \ --header 'Authorization: Bearer <token>'Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”Responses
Section titled “Responses”OK.
GET /v1/admin/sessions/{id}/diagnostic-bundle response shape (ST-06/ST-07).
object
object
object
Named metric series; keys include encoder.encode_ms, encoder.fps, abr.setpoint_kbps, transport.rtt_ms, transport.packets_lost, client.present_interval_sd_ms, the present-cadence series client.present_fps_median / client.present_interval_median_ms / client.present_interval_max_ms / client.present_beat_fraction / client.present_long_frames / client.present_n (absent for sessions from clients predating them), client.rvfc_capture_time_available, and the qualified pair client.rvfc_capture_to_display_ms / client.glass_to_glass_ms. client.present_fps remains a MEAN and is kept for continuity; client.present_fps_median is the one to read. client.glass_to_glass_ms is deprecated in favour of client.rvfc_capture_to_display_ms, which names what is measured (RTP capture-time to browser present) rather than overclaiming glass-to-glass; both carry the same value this release. Unmarked historical glass_to_glass values are omitted. THE FIELD DICTIONARY OF RECORD for every series name and raw key — its unit, clock, window, estimator and sample-count key — is docs/session-trace/metrics.json in the quasar repo (the metric manifest); the taxonomy, the browser ingest allow-list and the trace-format table are all derived from it.
object
object
object
object
object
object
object
object
object
The single stream-health judgement as a value (ST-09): state + prose evidence + the falsifiers that would overturn it + window/clock/tier. Observational only, no session authority. An unknown verdict string is DATA to a consumer.
object
The control plane owns this vocabulary and grows it; the enum below is today’s set, not a closed world.
One sentence.
object
Agent samples in the window.
Browser samples in the window.
Milliseconds at the head of the window excluded from warm-up-sensitive rules (hitch detection and the encoder.fps floor). 0 when nothing was excluded.
object
Whether the offset was actually applied to the client-clock series before the rules ran. False for an unmeasured clock, in which case every cross-source coincidence claim is downgraded and says so.
Now minus the clock’s measured_at (ms). Staleness is visible: the client re-posts the offset while it drifts, so a large age means the estimate stopped being refreshed.
One named, estimator-qualified number the verdict relies on (ST-09). holds is whether the data satisfies the condition; a series with no samples reports value null, n 0, holds false and a note. Some falsifiers are INFORMATIVE — client.present_beat_fraction is compared against the upper bound of its own unit, so it cannot fail; it is in the set to carry the number and the note that explains it.
object
Taxonomy series name, e.g. encoder.fps.
Null when the series had no samples in the window.
Samples the estimator consumed.
Per-session ingest rejection counters (in-memory, admin-read-only). A client sample or trace event whose ts_unix_ms is not plausibly a Unix-epoch-ms stamp is dropped at ingest rather than stored where it would silently vanish outside every read window. Absent or zeroed when nothing was rejected; the batch itself still returns 202.
object
Client samples + trace events dropped for an implausible ts_unix_ms since this control plane last started.
The offending value, verbatim.
The likely domain of the offending value, e.g. “looks like seconds”.
Session-capture: every capture belonging to this session, REGARDLESS of the bundle’s window (captures are sparse, explicitly requested, and exempt from the rolling trace prune). Always present; empty when there are none.
One capture result — the stored diag.* trace event’s payload plus its timestamp. Bounded by construction: compressed_bytes never exceeds the capture’s byte budget.
object
Agent wall-clock at completion.
Gzip+base64 puts the payload in data; json puts it in json.
What the decoded bytes are, e.g. text/vnd.graphviz or application/json.
Base64 of the gzip stream. Present when encoding = gzip+base64.
The result object. Present when encoding = json.
object
Uncompressed size AFTER any truncation.
Uncompressed size BEFORE truncation.
True when the budget forced a line-boundary cut; original_bytes then says how much was there.
Arm to done.
Set only when the capture was accepted and then failed. The event is still emitted, so a poller always terminates on a body.
Example
{ "clock": { "unmeasured": true }, "events": [ { "source": "agent" } ], "classifier": { "verdict": "likely_encoder_saturation", "clock": { "quality": "measured" }, "evidence_tier": "full", "falsifiers": [ { "estimator": "p10", "op": ">=", "unit": "fps" } ] }, "captures": [ { "encoding": "gzip+base64" } ]}Missing/invalid/expired/revoked token.
object
object
E.g. validation_failed, unauthorized, forbidden, not_found, conflict, session_quota_exceeded, home_in_use, home_not_provisioned, parent_app_disabled, profile_ineligible, profile_not_launchable_for_app, no_host_available, capacity_exhausted, restart_required, rate_limited, internal. Open string, not an enum: new codes are additive and an unknown one falls through to a client’s generic per-status branch.
Present on restart_required.
Steam library discovery Phase 3, ADDITIVE: present on home_in_use when the guard could name the CONFLICTING live session - the one already holding the home. It is here so the client can offer “go to your running session” with a link instead of a dead-end toast. OMITTED rather than empty when the conflict is known but the session is not, so a client branches on presence and never renders a link to nowhere. Load-bearing once derived tiles exist: the lock is held by the PARENT’s home, so a user who clicks a game tile can be refused because a DIFFERENT app (the Steam launcher, or another game from the same install) is running, and without the session id the refusal reads as a bug. See control-api.md §Derived tiles.
Steam library discovery Phase 3, ADDITIVE: present on the 409 conflict from DELETE /v1/apps/{id} when the app has derived tiles and ?delete_derived=true was not sent. A LIST, not a count - the point of the confirmation is that the admin sees what they are about to destroy. Capped; an empty array means the tiles could not be listed, never that there are none.
object
Examplegenerated
{ "error": { "code": "example", "message": "example", "live_sessions": 1, "session_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "derived_tiles": [ { "id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "name": "example" } ] }}Authenticated but insufficient role / not the owner (precedes resource lookup).
object
object
E.g. validation_failed, unauthorized, forbidden, not_found, conflict, session_quota_exceeded, home_in_use, home_not_provisioned, parent_app_disabled, profile_ineligible, profile_not_launchable_for_app, no_host_available, capacity_exhausted, restart_required, rate_limited, internal. Open string, not an enum: new codes are additive and an unknown one falls through to a client’s generic per-status branch.
Present on restart_required.
Steam library discovery Phase 3, ADDITIVE: present on home_in_use when the guard could name the CONFLICTING live session - the one already holding the home. It is here so the client can offer “go to your running session” with a link instead of a dead-end toast. OMITTED rather than empty when the conflict is known but the session is not, so a client branches on presence and never renders a link to nowhere. Load-bearing once derived tiles exist: the lock is held by the PARENT’s home, so a user who clicks a game tile can be refused because a DIFFERENT app (the Steam launcher, or another game from the same install) is running, and without the session id the refusal reads as a bug. See control-api.md §Derived tiles.
Steam library discovery Phase 3, ADDITIVE: present on the 409 conflict from DELETE /v1/apps/{id} when the app has derived tiles and ?delete_derived=true was not sent. A LIST, not a count - the point of the confirmation is that the admin sees what they are about to destroy. Capped; an empty array means the tiles could not be listed, never that there are none.
object
Examplegenerated
{ "error": { "code": "example", "message": "example", "live_sessions": 1, "session_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "derived_tiles": [ { "id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "name": "example" } ] }}No such resource.
object
object
E.g. validation_failed, unauthorized, forbidden, not_found, conflict, session_quota_exceeded, home_in_use, home_not_provisioned, parent_app_disabled, profile_ineligible, profile_not_launchable_for_app, no_host_available, capacity_exhausted, restart_required, rate_limited, internal. Open string, not an enum: new codes are additive and an unknown one falls through to a client’s generic per-status branch.
Present on restart_required.
Steam library discovery Phase 3, ADDITIVE: present on home_in_use when the guard could name the CONFLICTING live session - the one already holding the home. It is here so the client can offer “go to your running session” with a link instead of a dead-end toast. OMITTED rather than empty when the conflict is known but the session is not, so a client branches on presence and never renders a link to nowhere. Load-bearing once derived tiles exist: the lock is held by the PARENT’s home, so a user who clicks a game tile can be refused because a DIFFERENT app (the Steam launcher, or another game from the same install) is running, and without the session id the refusal reads as a bug. See control-api.md §Derived tiles.
Steam library discovery Phase 3, ADDITIVE: present on the 409 conflict from DELETE /v1/apps/{id} when the app has derived tiles and ?delete_derived=true was not sent. A LIST, not a count - the point of the confirmation is that the admin sees what they are about to destroy. Capped; an empty array means the tiles could not be listed, never that there are none.
object
Examplegenerated
{ "error": { "code": "example", "message": "example", "live_sessions": 1, "session_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "derived_tiles": [ { "id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "name": "example" } ] }}