trials
Real-robot trials (C4) — a session of trials on one device, each a checkpoint run under its own M13 approval with a run sheet locked at approval, the log and summary the driver uploads signed with the device key, the operator's notes from a phone, and a person's verdict (promote / iterate / stop) that the campaign's rules read.
GET /v1/trial-sessions
List real-robot sessions
Newest first. No session is public: a session is visible to its owner (the campaign's, else the device's) and the owner org's members; filters narrow within that.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
campaign | query | string | A campaign id or slug. |
device_id | query | Id | |
status | query | TrialSessionStatus | |
limit | query | integer | Page size. |
cursor | query | string | Opaque cursor from the previous page's |
Responses
| Status | Description | Body |
|---|---|---|
200 | A page of sessions. | TrialSessionPage |
401 | Missing or invalid credentials. | Problem |
403 | Authenticated but not allowed (visibility, membership or scope). | Problem |
422 | Request failed validation. | Problem |
POST /v1/trial-sessions
Plan a real-robot session — one trial per checkpoint, in bracket order
C4. A session is a sequence of trials on one device, each a checkpoint run under its own M13 approval, in an order the hub writes down before anything runs: the control first, the candidates by ascending sim risk (fewer locked gates passed, then fewer seeds upright, runs later), the control again last — the founder's A/B/A bracket (700 → A800 → 700), whose rule is checked once both control runs have a log (TrialSession.bracket). Each trial gets a run sheet drafted from the review — the stages (hang → floor → teleop), gain profile, kd and power scale, the environment, the abort rules, the predictions copied from the round's locked gates with the sim conditions they were measured under, and the criteria the log will be judged against — editable until its approval is issued, and locked then (RunSheet.locked_at; the token carries its digest). With a device_id (or when exactly one of the owner's devices embodies the robot and accepts every trial's contract) the hub files one consent request per trial at once — never an approval (M13). decideRound {shortlist} calls this for the round it shortlists; AG1's agent shortlist files its requests through the same trials. key:write: a plan and requests a person must still approve, one by one.
Request body
| Field | Type | Description |
|---|---|---|
campaign | string | null | A campaign id or slug. |
round | integer | null | The round whose shortlist to trial (with |
candidates | array of TrialCheckpoint | |
controls | array of TrialCheckpoint | |
device_id | Id | null | The device to trial on. Default: the only one of the owner's devices that embodies the robot and accepts every trial's contract; none or several leave the trials |
minutes | integer | Each trial's approval window — the whole run sheet, hang to teleop. |
reason | string | null | Why these checkpoints go to the robot; each consent request carries it. |
bracket_tolerance_deg | number | How far the two control runs' tilt max may differ for the bracket to hold (default 1.0°, DECISIONS "C4"). |
Responses
| Status | Description | Body |
|---|---|---|
201 | The session, its trials and their run sheets. | TrialSession |
401 | Missing or invalid credentials. | Problem |
403 | Authenticated but not allowed (visibility, membership or scope). | Problem |
404 | Resource not found (or hidden from the caller). | Problem |
409 | State conflict (duplicate handle/slug, wrong repo kind, terminal job, ...). | Problem |
422 | Request failed validation. | Problem |
GET /v1/trial-sessions/{session_id}
Get a real-robot session — its order, bracket check and trials
Parameters
| Name | In | Type | Description |
|---|---|---|---|
session_id | path | Id | A real-robot session id ( |
Responses
| Status | Description | Body |
|---|---|---|
200 | The session. | TrialSession |
401 | Missing or invalid credentials. | Problem |
404 | Resource not found (or hidden from the caller). | Problem |
POST /v1/trial-sessions/{session_id}/requests
File the consent requests of a session's unfiled trials
For a session created without a device (none of the owner's devices accepted every contract, or several did): names the device and files one M13 consent request per trial that has none, each pinned to the checkpoint's ONNX and its digest and carrying the session's reason. A contract the device does not accept is 409 naming the trial, and nothing is filed. Idempotent: a trial that already has a request is left alone. Never approves anything (M13).
Parameters
| Name | In | Type | Description |
|---|---|---|---|
session_id | path | Id | A real-robot session id ( |
Request body
| Field | Type | Description |
|---|---|---|
device_id | Id |
Responses
| Status | Description | Body |
|---|---|---|
200 | The session, with the trials' requests. | TrialSession |
401 | Missing or invalid credentials. | Problem |
403 | Authenticated but not allowed (visibility, membership or scope). | Problem |
404 | Resource not found (or hidden from the caller). | Problem |
409 | State conflict (duplicate handle/slug, wrong repo kind, terminal job, ...). | Problem |
422 | Request failed validation. | Problem |
GET /v1/trials
List trials
Newest first, under the session's visibility rule. status=needs_verdict is what the Inbox's "needs your verdict" card reads; approval_id is how a driver finds the trial an approval belongs to.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
session_id | query | Id | |
campaign | query | string | A campaign id or slug. |
device_id | query | Id | |
approval_id | query | Id | |
status | query | TrialStatus | |
limit | query | integer | Page size. |
cursor | query | string | Opaque cursor from the previous page's |
Responses
GET /v1/trials/{trial_id}
Get a trial — run sheet, approval, log, summary, criteria, notes, verdict
One real-robot trial as a record. criteria are judged on every read from the uploaded summary against what was written down before the run: the run sheet's criteria (locked with its approval) and the round's locked gates the log can measure, each with the sim measurement beside it; a comparison with the session's control trials is pending until one of them has a log. log.files[].url are presigned GETs (1 h). Invisible is 404.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
trial_id | path | Id | A trial id ( |
Responses
PATCH /v1/trials/{trial_id}/run-sheet
Edit a trial's run sheet before its approval locks it
Partial: a key that is absent is unchanged, and null clears an optional one. Stages, gain profile, kd and power scale, environment, abort rules and criteria may change until the trial's approval is issued; from then on the sheet is what a person approved and this is 409 — "no tuning on site". The approval token carries the locked sheet's digest (run_sheet_sha256), and the driver refuses a sheet that does not hash to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
trial_id | path | Id | A trial id ( |
Request body
| Field | Type | Description |
|---|---|---|
stages | array of RunSheetStage | |
gain_profile | string | |
kd_scale | number | |
power_scale | number | |
environment | RunSheetEnvironment | |
abort_rules | array of string | |
criteria | array of RunSheetCriterion |
Responses
| Status | Description | Body |
|---|---|---|
200 | The trial, with the edited run sheet. | Trial |
401 | Missing or invalid credentials. | Problem |
403 | Authenticated but not allowed (visibility, membership or scope). | Problem |
404 | Resource not found (or hidden from the caller). | Problem |
409 | State conflict (duplicate handle/slug, wrong repo kind, terminal job, ...). | Problem |
422 | Request failed validation. | Problem |
POST /v1/trials/{trial_id}/log/presign
Presigned PUTs for the log files a driver will upload
The driver's first step after a trial's run stops: one presigned PUT (1 h) per log file, under trials/{trial_id}/log/. Bytes never pass through the API. Allowed only while the trial's approval is running or stopped and no log has been recorded; the upload is not a record until uploadTrialLog names each file's sha256 under the device's signature.
Storage (L0). The declared sizes count toward the trial session owner's storage quota (STORAGE_QUOTA_BYTES, the same 50 GiB as repo files): over it is 413 and no URL is issued.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
trial_id | path | Id | A trial id ( |
Request body
| Field | Type | Description |
|---|---|---|
approval_id | Id | |
files | array of object | |
name | string | |
bytes | integer |
Responses
| Status | Description | Body |
|---|---|---|
200 | One PUT per file. | TrialLogPresign |
401 | Missing or invalid credentials. | Problem |
403 | Authenticated but not allowed (visibility, membership or scope). | Problem |
404 | Resource not found (or hidden from the caller). | Problem |
409 | State conflict (duplicate handle/slug, wrong repo kind, terminal job, ...). | Problem |
413 | A file is over | Problem |
422 | Request failed validation. | Problem |
POST /v1/trials/{trial_id}/log
Record the log and summary the driver computed on the robot, signed
The driver's word on what the robot-side command wrote: state: uploaded with each file's sha256, bytes and rows and the summary it computed on the box (tilt mean and max over the log's steady second half, the worst left–right joint asymmetry, per-joint tracking error, the motor temperatures the command printed at stop, battery, falls, what stopped it, the stages it ran), or missing / malformed with the reason — a stated failure, never silence. Signed with the device's own Ed25519 key over the canonical payload (trial_log_payload: approval, device, trial, state, files, summary, stages, detail, ts) and verified against the key registered for the trial's device, exactly like postDeviceEvent. The hub then hashes every uploaded object and refuses (422) a file whose bytes do not match the signed digest, re-derives the log's own numbers (tilt, asymmetry, tracking) from the CSV and stores whether they agree (summary.hub_check). Once only (409 after), while the approval is running or stopped. Audited trial.log.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
trial_id | path | Id | A trial id ( |
Request body
| Field | Type | Description |
|---|---|---|
approval_id | Id | |
state | string | |
files | array of TrialLogFile | |
summary | object | The |
detail | string | null | |
ts | string | The driver's clock, ISO 8601, exactly as signed. |
signature | string |
Responses
| Status | Description | Body |
|---|---|---|
201 | The trial, with its log and summary. | Trial |
401 | Missing or invalid credentials. | Problem |
403 | Authenticated but not allowed (visibility, membership or scope). | Problem |
404 | Resource not found (or hidden from the caller). | Problem |
409 | State conflict (duplicate handle/slug, wrong repo kind, terminal job, ...). | Problem |
413 | The summary exceeds the device event cap (64 KiB) or a file its cap. | Problem |
422 | Request failed validation. | Problem |
GET /v1/trials/{trial_id}/series
The log as plottable series — tilt at 50 Hz, joints on request
Read out of the uploaded log files (every stage, on the trial's own clock, with the stage boundaries) and decimated like getEpisodeSeries: min/max per bucket, so a one-frame tilt spike survives. channels picks what to return: tilt (degrees, from the logged gravity vector — the founder's acos(−g_z)), q:<joint>, tgt:<joint>, act:<joint>; default tilt. 409 while no log is recorded.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
trial_id | path | Id | A trial id ( |
channels | query | string | Comma-separated channel names (default |
max_points | query | integer |
Responses
| Status | Description | Body |
|---|---|---|
200 | The series. | TrialSeries |
401 | Missing or invalid credentials. | Problem |
404 | Resource not found (or hidden from the caller). | Problem |
409 | State conflict (duplicate handle/slug, wrong repo kind, terminal job, ...). | Problem |
PATCH /v1/trials/{trial_id}/notes
Save the operator's notes — a partial autosave
The phone form's autosave: a key that is absent is unchanged, null clears it, and the response carries filed_at (the time of this save) so the form can say "notes saved 14:33". Fields are taps — stability 1–5, drift, four toggles, which motors were hot — plus free text kept in the language it was written in (lang, detected when absent). A machine translation (translation), when the hub has one, is labelled as one and never replaces the text; this hub fills it from recorded fixtures only (no live model call). The first save is audited trial.notes; later saves update the same record. Notes may be filed from the moment the trial is approved, and until its verdict.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
trial_id | path | Id | A trial id ( |
Request body
| Field | Type | Description |
|---|---|---|
stability | integer | null | |
drift | TrialNotesDrift | null | |
drift_when | string | null | |
feet_lift_clean | boolean | null | |
landing_noise | boolean | null | |
motors_hot | TrialMotorsHot | null | |
fell | boolean | null | |
text | string | null | |
lang | string | null |
Responses
| Status | Description | Body |
|---|---|---|
200 | The notes as saved. | TrialNotes |
401 | Missing or invalid credentials. | Problem |
403 | Authenticated but not allowed (visibility, membership or scope). | Problem |
404 | Resource not found (or hidden from the caller). | Problem |
409 | State conflict (duplicate handle/slug, wrong repo kind, terminal job, ...). | Problem |
422 | Request failed validation. | Problem |
POST /v1/trials/{trial_id}/notes/videos
Start a phone video's presigned multipart upload
One multipart upload under trials/{trial_id}/videos/, straight from the phone to object storage (M3's presigned multipart, 8 MiB parts, 1 h URLs); completeTrialVideo takes the part list from storage and attaches the video to the notes. Up to 2 GiB and eight videos a trial.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
trial_id | path | Id | A trial id ( |
Request body
| Field | Type | Description |
|---|---|---|
filename | string | |
bytes | integer | |
content_type | string | null | |
duration_s | number | null |
Responses
| Status | Description | Body |
|---|---|---|
201 | The upload, with a presigned PUT per part. | TrialVideoUpload |
401 | Missing or invalid credentials. | Problem |
403 | Authenticated but not allowed (visibility, membership or scope). | Problem |
404 | Resource not found (or hidden from the caller). | Problem |
409 | State conflict (duplicate handle/slug, wrong repo kind, terminal job, ...). | Problem |
413 | Larger than 2 GiB, or the session owner's storage quota would be exceeded (L0: trial videos count toward it). | Problem |
422 | Request failed validation. | Problem |
POST /v1/trials/{trial_id}/notes/videos/{video_id}/complete
Finish a phone video's upload and attach it to the notes
Completes the multipart upload from the parts object storage holds (the phone need not keep ETags), checks the stored size against the declared one, and adds the video to TrialNotes.videos. Audited trial.video.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
trial_id | path | Id | A trial id ( |
video_id | path | Id |
Request body
| Field | Type | Description |
|---|---|---|
duration_s | number | null |
Responses
| Status | Description | Body |
|---|---|---|
200 | The notes, with the video. | TrialNotes |
401 | Missing or invalid credentials. | Problem |
403 | Authenticated but not allowed (visibility, membership or scope). | Problem |
404 | Resource not found (or hidden from the caller). | Problem |
409 | State conflict (duplicate handle/slug, wrong repo kind, terminal job, ...). | Problem |
POST /v1/trials/{trial_id}/verdict
Record a person's verdict on a candidate trial (web session only)
Session only — a person decides what a real robot showed; no API key of any scope, and so no agent, can (403). Three options, none the default, each with a reason: promote — this checkpoint becomes the campaign's policy on the robot (Campaign.policy_on_robot, and the baseline the next session's criteria are drafted from); iterate — back to simulation: the checkpoint stays a valid parent, and an agent session attached to the campaign is woken with the verdict, the notes and the summary to draft the next round from (a person still approves it); stop — this checkpoint's lineage ends the way a FAIL does: no round may resume from it (rule.fail_ends_lineage), and iterating from it is refused. Only a candidate trial takes a verdict (a control is measured, not judged), only once, and only after its run started. Audited trial.verdict, with a sentence in listActivity.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
trial_id | path | Id | A trial id ( |
Request body
| Field | Type | Description |
|---|---|---|
action | TrialVerdictAction | |
reason | string |
Responses
| Status | Description | Body |
|---|---|---|
200 | The trial, with its verdict. | Trial |
401 | Missing or invalid credentials. | Problem |
403 | Authenticated but not allowed (visibility, membership or scope). | Problem |
404 | Resource not found (or hidden from the caller). | Problem |
409 | State conflict (duplicate handle/slug, wrong repo kind, terminal job, ...). | Problem |
422 | Request failed validation. | Problem |
Schemas (52)
The schemas these operations reach before any other tag’s do. A type that links elsewhere is rendered on that tag’s page.
TrialSessionPage
| Field | Type | Description |
|---|---|---|
items | array of TrialSession | |
next_cursor | string | null |
TrialSessionCreate
Either a campaign round (campaign + round), whose shortlist supplies the candidates and controls, or explicit candidates and controls (checkpoints the caller can read). One control is run first and again last; two controls are run first and last.
| Field | Type | Description |
|---|---|---|
campaign | string | null | A campaign id or slug. |
round | integer | null | The round whose shortlist to trial (with |
candidates | array of TrialCheckpoint | |
controls | array of TrialCheckpoint | |
device_id | Id | null | The device to trial on. Default: the only one of the owner's devices that embodies the robot and accepts every trial's contract; none or several leave the trials |
minutes | integer | Each trial's approval window — the whole run sheet, hang to teleop. |
reason | string | null | Why these checkpoints go to the robot; each consent request carries it. |
bracket_tolerance_deg | number | How far the two control runs' tilt max may differ for the bracket to hold (default 1.0°, DECISIONS "C4"). |
TrialSession
| Field | Type | Description |
|---|---|---|
id | Id | |
owner | RepoOwner | |
campaign | TrialCampaignRef | null | |
round | TrialRoundRef | null | |
robot | RepoRef | null | |
device | TrialDeviceRef | null | |
status | TrialSessionStatus | |
order | array of TrialRef | The trials in the order they run. |
order_rule | string | How the order was written — "control first and last; candidates by sim risk, lowest first". |
bracket | TrialBracket | |
minutes | integer | |
reason | string | null | |
unfiled_reason | string | null | Why trials are unfiled — no device named and none or several could be chosen. |
created_by | UserPublic | null | |
created_at | string (date-time) | |
trials | array of Trial | Every trial in full ( |
TrialRequestsCreate
| Field | Type | Description |
|---|---|---|
device_id | Id |
TrialPage
| Field | Type | Description |
|---|---|---|
items | array of Trial | |
next_cursor | string | null |
Trial
| Field | Type | Description |
|---|---|---|
id | Id | |
session_id | Id | |
index | integer | This trial's place in the session's order (1-based). |
of | integer | How many trials the session has. |
role | TrialRole | |
label | string | |
status | TrialStatus | |
campaign | TrialCampaignRef | null | |
round | TrialRoundRef | null | |
model_repo | RepoRef | |
run_id | string | null | |
checkpoint_step | integer | null | |
onnx_path | string | null | |
device | TrialDeviceRef | null | |
request_id | string | null | |
approval | Approval | null | The approval the trial rides on — the consent record, linked, never replaced. |
withdrawn_reason | string | null | |
refused_reason | string | null | The device's machine reason when it refused the run. |
sim | TrialSim | null | |
run_sheet | RunSheet | |
log | TrialLog | |
summary | TrialSummary | null | |
criteria | array of TrialCriterion | |
notes | TrialNotes | null | |
verdict | TrialVerdict | null | |
session | TrialSession | null | The session without its full trials ( |
created_at | string (date-time) |
RunSheetUpdate
| Field | Type | Description |
|---|---|---|
stages | array of RunSheetStage | |
gain_profile | string | |
kd_scale | number | |
power_scale | number | |
environment | RunSheetEnvironment | |
abort_rules | array of string | |
criteria | array of RunSheetCriterion |
TrialLogPresignRequest
| Field | Type | Description |
|---|---|---|
approval_id | Id | |
files | array of object | |
name | string | |
bytes | integer |
TrialLogPresign
| Field | Type | Description |
|---|---|---|
files | array of object | |
name | string | |
url | string (uri) | |
expires_at | string (date-time) |
TrialLogUpload
Signed like a device event: signature is the device key's Ed25519 signature (base64url) over the canonical JSON of {approval_id, device_id, trial_id, kind: "trial_log", state, files: [{name, stage, sha256, bytes, rows}], summary, detail, ts} — ts exactly as sent.
| Field | Type | Description |
|---|---|---|
approval_id | Id | |
state | string | |
files | array of TrialLogFile | |
summary | object | The |
detail | string | null | |
ts | string | The driver's clock, ISO 8601, exactly as signed. |
signature | string |
TrialSeries
| Field | Type | Description |
|---|---|---|
trial_id | Id | |
rows | integer | null | |
rate_hz | number | null | |
duration_s | number | null | |
sampled_points | integer | |
downsample | string | |
channels | array of TrialChannel | |
points | array of EpisodeSeriesPoint | |
stages | array of TrialSeriesStage | |
baseline | object | null | The tilt-max criterion's threshold, drawn as a line. |
name | string | |
value | number | |
warnings | array of string |
TrialNotesUpdate
A partial save — absent keys are unchanged, null clears.
| Field | Type | Description |
|---|---|---|
stability | integer | null | |
drift | TrialNotesDrift | null | |
drift_when | string | null | |
feet_lift_clean | boolean | null | |
landing_noise | boolean | null | |
motors_hot | TrialMotorsHot | null | |
fell | boolean | null | |
text | string | null | |
lang | string | null |
TrialNotes
| Field | Type | Description |
|---|---|---|
trial_id | Id | |
stability | integer | null | 1 fell or nearly, 5 like the best run so far. |
drift | TrialNotesDrift | null | |
drift_when | string | null | When it drifted, e.g. "while standing". |
feet_lift_clean | boolean | null | |
landing_noise | boolean | null | |
motors_hot | TrialMotorsHot | null | |
fell | boolean | null | |
text | string | null | |
lang | string | null | The text's language as written ( |
translation | TrialTranslation | null | |
videos | array of TrialVideo | |
filed_at | string (date-time) | null (date-time) | The last save. |
first_filed_at | string (date-time) | null (date-time) | |
filed_by | UserPublic | null | |
filed_via | string | null |
TrialVideoCreate
| Field | Type | Description |
|---|---|---|
filename | string | |
bytes | integer | |
content_type | string | null | |
duration_s | number | null |
TrialVideoUpload
| Field | Type | Description |
|---|---|---|
video_id | Id | |
part_size | integer | |
parts | array of object | |
part_number | integer | |
url | string (uri) | |
expires_at | string (date-time) |
TrialVideoComplete
| Field | Type | Description |
|---|---|---|
duration_s | number | null |
TrialVerdictCreate
| Field | Type | Description |
|---|---|---|
action | TrialVerdictAction | |
reason | string |
TrialCheckpoint
A checkpoint to trial — checkpoints/step_<step>/ of a run's output model repo.
| Field | Type | Description |
|---|---|---|
run_id | Id | |
step | integer |
TrialCampaignRef
| Field | Type | Description |
|---|---|---|
id | Id | |
slug | string | |
name | string |
TrialRoundRef
| Field | Type | Description |
|---|---|---|
id | Id | |
n | integer | |
name | string |
TrialDeviceRef
| Field | Type | Description |
|---|---|---|
id | Id | |
name | string | |
adapter | string | |
adapter_info | DeviceAdapterInfo | null |
TrialBracket
The A/B/A bracket check, the founder's rule: run the control first and last, and when the two control runs differ by more than the tolerance the session was polluted (battery, floor, temperature) and its A/B decides nothing. holds is null until both control runs have a log, or when the session has no second control run.
| Field | Type | Description |
|---|---|---|
metric | string | |
tolerance | number | |
controls | array of object | |
trial_id | Id | |
index | integer | |
value | number | null | |
delta | number | null | |
holds | boolean | null | |
sentence | string | One line the page prints, e.g. "The two 700 runs agree within 0.35°…". |
TrialSim
The checkpoint's verdict in simulation, from its round's locked gates.
| Field | Type | Description |
|---|---|---|
verdict | string | null | |
gates_passed | integer | null | |
gates_total | integer | null | |
alive | string | null |
RunSheet
What will be done on the robot, written before anything runs: drafted from the review when the trial is planned, editable until its approval is issued, locked then (locked_at = the approval's issued_at; digest is what the token's run_sheet_sha256 binds). "No tuning on site" is the rule, not a field.
| Field | Type | Description |
|---|---|---|
stages | array of RunSheetStage | |
gain_profile | string | The robot's PD gain profile, by the name its own config uses ( |
kd_scale | number | |
power_scale | number | |
environment | RunSheetEnvironment | |
abort_rules | array of string | |
criteria | array of RunSheetCriterion | |
baseline | RunSheetBaseline | null | |
predicted | RunSheetPredicted | null | |
locked_at | string (date-time) | null (date-time) | |
locked_by | UserPublic | null | |
digest | string | sha256 of the canonical sheet (stages without their status, settings, environment, abort rules, criteria). |
TrialLog
| Field | Type | Description |
|---|---|---|
state | TrialLogState | |
files | array of TrialLogFile | |
rows | integer | null | |
rate_hz | number | null | |
columns | array of string | |
format | string | null |
|
detail | string | null | The driver's stated reason for |
uploaded_at | string (date-time) | null (date-time) | |
uploaded_by | string | null | The device that signed it. |
signature | string | null | The device's Ed25519 signature (base64url) over |
signed | boolean | True when the signature verified against the device's registered key (always, for a stored log). |
TrialSummary
Computed on the robot box by the driver from the log the robot-side command wrote, with the founder's own formulas (tools/policy_io.summarize, docs/DECISIONS.md "C4"): tilt = acos(−g_z) over the judged stage's steady second half; a pair's asymmetry = |mean(l) + mean(r)| there (his mirror convention, l ≈ −r); tracking error = mean(target − measured) per joint; the motor temperatures his deploy script prints at stop; falls when its tilt protection fired. Numbers the log cannot give are null, never invented.
| Field | Type | Description |
|---|---|---|
judged_stage | string | null | |
window | string |
|
rows | integer | null | |
duration_s | number | null | |
rate_hz | number | null | Rows over logged time. |
loop_hz | number | null | The control rate the command itself reported, else |
stopped_by | string | null |
|
stopped_detail | string | null | |
falls | integer | null | |
tilt_mean_deg | number | null | |
tilt_max_deg | number | null | |
asym_max | TrialAsymmetry | null | |
asymmetry | array of TrialAsymmetry | |
tracking_error_rad | array of TrialPair | |
temps_c | array of TrialPair | |
temps_source | string | null | Where the temperatures came from — |
battery_v | TrialBattery | null | |
stages | array of TrialStageResult | |
transcript_tail | array of string | The last lines the command printed. |
hub_check | TrialHubCheck | null |
TrialCriterion
| Field | Type | Description |
|---|---|---|
name | string | |
metric | RunSheetCriterionMetric | |
op | RunSheetCriterionOp | |
threshold | number | null | The threshold used — for |
reference | string | null | |
joint | string | null | |
measured | number | null | |
measured_text | string | null | As printed — "2.4° ankle_pitch", "+0.199 / −0.203 rad". |
sim_value | number | null | |
verdict | TrialCriterionVerdict | |
source | string |
TrialVerdict
| Field | Type | Description |
|---|---|---|
action | TrialVerdictAction | |
reason | string | |
decided_by | UserPublic | null | |
decided_at | string (date-time) | |
effect | string | What the verdict did — one sentence (the campaign's policy, a lineage ended, an agent woken). |
RunSheetStage
One stage of the run sheet, as a person reads it and as the driver maps it onto a command configured on the robot box (the hub sends values, never a command line). duration_s null runs until the operator stops it (teleop). status comes from the driver's signed log upload.
| Field | Type | Description |
|---|---|---|
name | string |
|
label | string | null | |
command | RunSheetCommand | null | |
imu | boolean | False runs without the IMU (hanging, feet off the floor). |
teleop | RunSheetTeleop | null | |
duration_s | number | null | |
note | string | null | What must be true, e.g. "feet off the floor", "someone within reach". |
judged | boolean | The stage whose log the headline summary is computed on (default the last). |
status | string | null | |
elapsed_s | number | null |
RunSheetEnvironment
| Field | Type | Description |
|---|---|---|
floor | string | null | The floor's material, as the operator names it. |
mu_estimate | number | null | |
calibration_commit | string | null | |
battery_v | number | null | The battery at the start, as the operator read it. |
notes | string | null |
RunSheetCriterion
| Field | Type | Description |
|---|---|---|
name | string | |
metric | RunSheetCriterionMetric | |
op | RunSheetCriterionOp | |
threshold | number | null | |
joint | string | null |
|
sim_value | number | null | The value measured in simulation ( |
tolerance | number | null |
|
reference | string | null | Where the threshold was written down, e.g. "s1e baseline 08-08", "round gate". |
TrialLogFile
| Field | Type | Description |
|---|---|---|
name | string | The file's name on the box, e.g. |
stage | string | null | |
sha256 | Sha256 | |
bytes | integer | |
rows | integer | null | |
url | string (uri) | null (uri) | A presigned GET (1 h), on read. |
TrialChannel
| Field | Type | Description |
|---|---|---|
name | string | |
unit | string |
TrialSeriesStage
| Field | Type | Description |
|---|---|---|
name | string | |
start_s | number | |
end_s | number | null |
TrialNotesDrift
TrialMotorsHot
| Field | Type | Description |
|---|---|---|
hot | boolean | |
joints | array of string | Which, as the operator felt them, e.g. |
TrialTranslation
A machine translation of the notes' text, labelled as one and never replacing it. This hub fills it only from recorded fixtures (TRIAL_TRANSLATION=recorded); no live model call is made.
| Field | Type | Description |
|---|---|---|
text | string | |
lang | string | |
source | string | |
model | string | null |
TrialVideo
| Field | Type | Description |
|---|---|---|
id | Id | |
filename | string | |
bytes | integer | |
content_type | string | null | |
duration_s | number | null | |
state | string | |
url | string (uri) | null (uri) | A presigned GET (1 h) once uploaded. |
uploaded_at | string (date-time) | null (date-time) |
RunSheetBaseline
The real-robot numbers a <=control criterion compares against when the campaign has a promoted policy: that trial's own summary.
| Field | Type | Description |
|---|---|---|
trial_id | Id | |
label | string | |
tilt_mean_deg | number | null | |
tilt_max_deg | number | null | |
asym_max_deg | number | null |
RunSheetPredicted
| Field | Type | Description |
|---|---|---|
lines | array of RunSheetPrediction | |
battery | string | null | The sim battery the lines were measured on. |
sim_power_scale | number | null | |
sim_kd_scale | number | null | |
caveat | string | null | Computed: e.g. "sim numbers are at power 1.0; this trial runs 0.8". |
TrialLogState
awaiting — the run has not ended or the driver has not reported; uploaded — files and a summary, signed; missing — the driver found no log where the box's config said the command would write one; malformed — it found one it could not read.
TrialAsymmetry
| Field | Type | Description |
|---|---|---|
joint | string | The pair without its side, e.g. |
deg | number |
TrialPair
A left / right pair of one joint.
| Field | Type | Description |
|---|---|---|
joint | string | |
left | number | null | |
right | number | null |
TrialBattery
| Field | Type | Description |
|---|---|---|
start | number | null | |
end | number | null |
TrialStageResult
| Field | Type | Description |
|---|---|---|
name | string | |
status | string | |
start_s | number | null | Seconds from the trial's start (the first stage's launch). |
end_s | number | null | |
rows | integer | null | |
returncode | integer | null | |
stopped_by | string | null | |
detail | string | null |
TrialHubCheck
The hub re-derived the log's own numbers from the uploaded CSV.
| Field | Type | Description |
|---|---|---|
agrees | boolean | |
differences | array of string |
RunSheetCriterionMetric
What the log measures: tilt_mean_deg, tilt_max_deg (over the judged stage's steady second half), asym_max_deg (the worst left–right pair), falls, tracking_error_rad (|mean target − measured| of joint, both sides), loop_hz, temp_max_c.
RunSheetCriterionOp
<= < >= > == against threshold; <=control against the mean of the session's control trials (or the campaign's promoted baseline, baseline); as_in_sim — within tolerance of sim_value, reported as as_in_sim / differs_from_sim, never pass/fail.
TrialCriterionVerdict
PASS / FAIL against a threshold; as_in_sim / differs_from_sim for a comparison with simulation (never a pass); pending — the control it compares with has no log yet; unmeasured — the log does not carry the metric.
RunSheetCommand
| Field | Type | Description |
|---|---|---|
vx | number | |
vy | number | |
wz | number |
RunSheetTeleop
| Field | Type | Description |
|---|---|---|
speed | number | W/S, m/s. |
turn | number | Q/E, rad/s. |
side | number | A/D, m/s. |
hold_s | number | How long one key press holds its command. |
RunSheetPrediction
| Field | Type | Description |
|---|---|---|
gate | string | |
predicted | string | null | As written when the round's spec was locked. |
measured_in_sim | string | null | The value the round measured at this checkpoint. |
verdict | string | null |