Skip to content

The assembled diagnostic bundle (metadata + clock + series + events + verdict).

GET
/v1/admin/sessions/{id}/diagnostic-bundle
curl --request GET \
--url http://localhost:8080/v1/admin/sessions/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/diagnostic-bundle \
--header 'Authorization: Bearer <token>'
id
required
string format: uuid

OK.

Media typeapplication/json

GET /v1/admin/sessions/{id}/diagnostic-bundle response shape (ST-06/ST-07).

object
trace
object
session_id
string format: uuid
host_id
string format: uuid
profile_id
string
started_at
string format: date-time
ended_at
string | null format: date-time
window
object
from_ms
integer
to_ms
integer
clock
One of:
object
client_offset_ms
number
uncertainty_ms
number
measured_at
string format: date-time
series

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
key
additional properties
Array<object>
object
ts_unix_ms
integer
v
number
events
Array<object>
object
source
string
Allowed values: agent browser
ts_unix_ms
integer
type
string
payload
object
key
additional properties
any
derived_windows
object
hitches
Array<object>
object
from_ms
integer
to_ms
integer
present_interval_sd_ms
number
abr_downshifts
Array<object>
object
ts_unix_ms
integer
from_kbps
integer
to_kbps
integer
encoder_saturation
Array<object>
object
from_ms
integer
to_ms
integer
encode_ms_p95
number
likely_network_congestion
Array<object>
object
from_ms
integer
to_ms
integer
packets_lost_delta
integer
rtt_ms_p95
number
classifier

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
verdict
required

The control plane owns this vocabulary and grows it; the enum below is today’s set, not a closed world.

string
Allowed values: likely_encoder_saturation likely_network_congestion likely_client_presentation_limit nominal indeterminate_client_hidden unknown
evidence
required
Array<string>
reason
required

One sentence.

string
window
required
object
from_ms
required
integer
to_ms
required
integer
n_host
required

Agent samples in the window.

integer
n_client
required

Browser samples in the window.

integer
warmup_excluded_ms

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.

integer
clock
required
object
quality
required
string
Allowed values: measured unmeasured
offset_ms
number
uncertainty_ms
number
applied

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.

boolean
age_ms

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.

integer
evidence_tier
required
string
Allowed values: full host_only client_only insufficient
falsifiers
required
Array<object>

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
name
required

Taxonomy series name, e.g. encoder.fps.

string
estimator
required
string
Allowed values: p10 p95 max delta mean any count_ge_threshold
value
required

Null when the series had no samples in the window.

number | null
op
required
string
Allowed values: >= <= > < ==
threshold
required
number
unit
required
string
Allowed values: fps ms count bool fraction
n
required

Samples the estimator consumed.

integer
holds
required
boolean
note
string
thresholds_version
required
string
ingest

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
rejected_ts
required

Client samples + trace events dropped for an implausible ts_unix_ms since this control plane last started.

integer
last_rejected_ts_unix_ms

The offending value, verbatim.

integer
last_rejected_reason

The likely domain of the offending value, e.g. “looks like seconds”.

string
captures

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.

Array<object>

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
capture_id
required
string format: uuid
kind
required
string
ts_unix_ms
required

Agent wall-clock at completion.

integer
encoding
required

Gzip+base64 puts the payload in data; json puts it in json.

string
Allowed values: gzip+base64 json
content_type
required

What the decoded bytes are, e.g. text/vnd.graphviz or application/json.

string
data

Base64 of the gzip stream. Present when encoding = gzip+base64.

string
json

The result object. Present when encoding = json.

object
key
additional properties
any
bytes
required

Uncompressed size AFTER any truncation.

integer
compressed_bytes
required
integer
original_bytes

Uncompressed size BEFORE truncation.

integer
truncated
required

True when the budget forced a line-boundary cut; original_bytes then says how much was there.

boolean
duration_ms
required

Arm to done.

integer
error

Set only when the capture was accepted and then failed. The event is still emitted, so a poller always terminates on a body.

string
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.

Media typeapplication/json
object
error
required
object
code
required

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.

string
message
required
string
live_sessions

Present on restart_required.

integer
session_id

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.

string format: uuid
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.

Array<object>
object
id
required
string format: uuid
name
required
string
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).

Media typeapplication/json
object
error
required
object
code
required

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.

string
message
required
string
live_sessions

Present on restart_required.

integer
session_id

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.

string format: uuid
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.

Array<object>
object
id
required
string format: uuid
name
required
string
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.

Media typeapplication/json
object
error
required
object
code
required

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.

string
message
required
string
live_sessions

Present on restart_required.

integer
session_id

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.

string format: uuid
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.

Array<object>
object
id
required
string format: uuid
name
required
string
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"
}
]
}
}