campaigns
Campaigns (C3) — the founder's training loop as hub objects: a task on a robot with a budget, whose rounds lock a spec (one declared change, a hypothesis, gates with predictions), train through createRun, are gated and band-scanned in simulation, get a verdict from their locked gates and a decision. Three rules are enforced in code; only a signed-in person may override one, with a reason.
GET /v1/campaigns
List campaigns
Campaigns visible to the caller (owner, org member or creator), newest first. No campaign is public: a campaign holds its owner's budget and runs.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
status | query | CampaignStatus | |
robot | query | string | Only campaigns on this robot repo ( |
slug | query | Slug | Only campaigns with this slug (one per owner). |
limit | query | integer | Page size. |
cursor | query | string | Opaque cursor from the previous page's |
Responses
| Status | Description | Body |
|---|---|---|
200 | A page of campaigns. | CampaignPage |
401 | Missing or invalid credentials. | Problem |
422 | Request failed validation. | Problem |
POST /v1/campaigns
Start a campaign — a task on a robot, with a budget and the three rules
C3. A campaign is the unit of the founder's training loop: a task on a robot repo the caller can see, a budget, an optional declared root checkpoint, and rounds. Its task picks the default gate battery for every round (stand → the posture battery stand, walk / omni → watch while training and c_matrix for the band scan, recovery → recovery, custom → smoke). The three rules — one variable per round, resume only from a PASS checkpoint, a FAIL ends the lineage — are enforced on every round and cannot be switched off; a signed-in person may override one on one round, with a reason (createRoundWithOverride). Creating spends nothing: key:write.
Request body
| Field | Type | Description |
|---|---|---|
name | string | |
slug | Slug | null | Unique per owner; derived from |
owner | Handle | null | The campaign's owner; defaults to the caller. |
robot | string | The robot repo, |
task | CampaignTask | |
description | string | null | |
budget_usd | number | Hard cap on what the campaign's rounds may spend (GPU as billed). |
per_run_limit_usd | number | null | C3b — the most one round may cost and be auto-approved for an agent working inside this campaign. Null: the workspace's per-run limit ( |
root | CheckpointRef | null |
Responses
| Status | Description | Body |
|---|---|---|
201 | Campaign created. | Campaign |
401 | Missing or invalid credentials. | Problem |
403 | Authenticated but not allowed (visibility, membership or scope). | Problem |
409 | State conflict (duplicate handle/slug, wrong repo kind, terminal job, ...). | Problem |
422 | Request failed validation. | Problem |
GET /v1/campaigns/{campaign_id}
Get a campaign (its rounds, spend, and what waits on a person)
Parameters
| Name | In | Type | Description |
|---|---|---|---|
campaign_id | path | string | Campaign id ( |
Responses
PATCH /v1/campaigns/{campaign_id}
Rename, re-describe, change the budget of, or stop a campaign
key:write, with two exceptions enforced in the handler: raising budget_usd or raising per_run_limit_usd (C3b) is a person's decision (a signed-in session; a key of any scope is 403). Together they are what lets an agent run rounds without asking — an agent that could raise either would have no limit at all. A key may lower them, rename the campaign, or stop it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
campaign_id | path | string | Campaign id ( |
Request body
| Field | Type | Description |
|---|---|---|
name | string | null | |
description | string | null | |
budget_usd | number | null | Lowering is |
per_run_limit_usd | number | null | C3b — lowering is |
status | string | null |
|
Responses
| Status | Description | Body |
|---|---|---|
200 | The updated campaign. | Campaign |
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/campaigns/{campaign_id}/rounds
Lock a round's spec and start its training run
C3. The spec — one declared change (a summary and the resolved-config keys it covers), a hypothesis, what is not being done, tripwires, gates with their predictions, an iteration cap — is locked here and never edited; a gate added later is shown and not counted. Then the three rules are checked, in code, before anything is spent:
-
One variable. The change the recipe makes, predicted against the parent checkpoint's run (its resolved config, and its recipe), must lie inside the declared keys (a declared key covers itself and every path under it).
run.*and a template's own bookkeeping never count. A round that stacks a sibling's change (same parent checkpoint) on its own is more than one variable. When the run's resolved config arrives, the same diff is recomputed on what it actually trained on; an undeclared key found then makes the roundconfounded. -
Resume only from PASS.
parentmust be the campaign's declared root, or a checkpoint of one of its rounds whose verdict at that step ispass. -
A FAIL ends the lineage. No checkpoint of a round whose verdict is
failorconfounded, or whose lineage was stopped, may be a parent.
A violation is 422 with one errors[] entry per rule (type is rule.one_variable, rule.resume_from_pass or rule.fail_ends_lineage, msg names the keys or the verdict) and nothing is recorded. Only a signed-in person may override a rule, with a reason, through createRoundWithOverride; no key of any scope can.
Budget: the round's run is priced with estimateRun; when its maximum would take the campaign past budget_usd (spent from the ledger, plus what in-flight rounds may still spend) the answer is 409 naming the numbers — the request is well-formed, the campaign has no money left for it. A priced run's own budget_usd is capped at what remains, so the hub stops it there. Then the run is created through createRun's own path (so executor: modal, C1's parent_checkpoint_step and C2's gate behave exactly as there), with the campaign's task-aware gate when the recipe names none. Spends compute: key:train.
Dry run (K3). ?dry_run=true runs every check above on the same body and records nothing: 200 with a RoundPreview — the three rules as verdicts (the 422's own entries, never a second implementation), the variables against the parent, the run's price with the campaign's remaining budget as its cap, every published checkpoint of the parent run with whether it may be a parent and the rule's sentence when not, whether the template reads each hyperparameter, and — when the parent run published no checkpoint at all (every imported run today) — why it cannot be fine-tuned. A malformed body, an unknown parent and a campaign that cannot afford the round answer as createRound would. A web fine-tune is a round, so this is its preview before the spend.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
campaign_id | path | string | Campaign id ( |
dry_run | query | boolean | K3 — check everything and record nothing; |
Request body
| Field | Type | Description |
|---|---|---|
name | string | The round's short name, e.g. "C2 arm A". |
parent | CheckpointRef | null | The checkpoint this round resumes from (null trains from scratch). Becomes the run's |
spec | RoundSpec | |
recipe | Recipe | |
scan | RoundScanRequest | null |
Responses
| Status | Description | Body |
|---|---|---|
200 |
| RoundPreview |
201 | Round created; its spec is locked and its run queued. | Round |
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 |
429 | The account's or the key's daily GPU-hour quota (as on | Problem |
503 | A service this endpoint needs is not configured in this deployment (M0's boot guarantee: the API boots with zero secrets, and an endpoint that needs one says so instead of returning a stack trace). | Problem |
POST /v1/campaigns/{campaign_id}/rounds/override
Start a round that breaks a rule — a person's decision, with a reason
C3. createRound, plus override: {rules, reason}. Session only: no API key of any scope may override a rule, so an agent can propose a round and never waive the rules it would break. rules must name exactly the rules this round violates (a rule named but not broken is 422: an override record says what was waived, never more), and reason is recorded with who and when on the round as an override chip. A round created with a one_variable override reads confounded whatever its gates say, and nothing resumes from it without another override. Budget, scope and every other check are createRound's.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
campaign_id | path | string | Campaign id ( |
Request body
| Field | Type | Description |
|---|---|---|
name | string | |
parent | CheckpointRef | null | |
spec | RoundSpec | |
recipe | Recipe | |
scan | RoundScanRequest | null | |
override | RoundOverride |
Responses
| Status | Description | Body |
|---|---|---|
201 | Round created with its override record. | Round |
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 |
503 | A service this endpoint needs is not configured in this deployment (M0's boot guarantee: the API boots with zero secrets, and an endpoint that needs one says so instead of returning a stack trace). | Problem |
GET /v1/campaigns/{campaign_id}/rounds/{round_n}
Get a round — its locked spec, the verdict at a step, the variables, the decisions
The verdict is the round's locked gates evaluated on the measured results at step (default: the chosen step — the one a decision named, else the measured checkpoint with the most counted gates passing, the earliest on a tie). Measurements come from the round's band scan at that step, else from the gate its run got while training. The hub's own 0.85–1.15 band verdict for the same rollout is returned beside it (evaluation.band) as a measurement, never as the verdict.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
campaign_id | path | string | Campaign id ( |
round_n | path | integer | The round's number within its campaign (1, 2, …). |
step | query | integer | Evaluate the locked gates at this checkpoint step instead of the chosen one. |
Responses
POST /v1/campaigns/{campaign_id}/rounds/{round_n}/decision
Decide a round — shortlist, iterate, stop the lineage, or done
C3. The operation's floor is key:write and each action has its own scope, enforced in the handler (x-action-scopes): stop is key:write (ending a lineage spends nothing); iterate is key:train (it says "train the next round from step", which an agent may propose inside the campaign's budget); shortlist and done are session only — the two human gates, which no key of any scope, and therefore no agent, can pass. shortlist records the chosen checkpoints (candidates, steps of this round's run) and the A/B controls (any visible checkpoint, usually the parent), each with its verdict at that step; it starts nothing. C4: it plans the real-robot session (createTrialSession) — one trial per run, the control first and last, a run sheet each — and, when the device is known (device_id, or the only one of the owner's that accepts every contract) and no agent's shortlist follow-up will, files one consent request per trial; a person approves each on the consent page. iterate refuses a step whose verdict is not pass (the resume rule, stated before the next round is written). done closes the campaign. C3b: shortlist is refused (422, rule.separates_from_control) when the round's control — the checkpoint it started from, measured in its own band scan — also passes every locked gate, unless the person sends override naming that rule with a reason. Every decision is recorded with who, when, how and the verdict it was taken on. AG1: when an agent session's shortlist decision waits on this round, a shortlist here answers it (the note is reason), and the hub then runs the 20-seed band scan on the picks (or waits for the round's own scan when it already covers them) and files one device consent request per pick that still passes the locked gates, the note as each request's reason — never approved here (M13).
Parameters
| Name | In | Type | Description |
|---|---|---|---|
campaign_id | path | string | Campaign id ( |
round_n | path | integer | The round's number within its campaign (1, 2, …). |
Request body
| Field | Type | Description |
|---|---|---|
action | RoundDecisionAction | |
reason | string | null | |
step | integer | null |
|
candidates | array of integer |
|
controls | array of CheckpointRef |
|
override | RoundOverride | null | C3b, |
device_id | Id | null | C4, |
minutes | integer | null | C4, |
Responses
| Status | Description | Body |
|---|---|---|
200 | The round, with the decision recorded. | Round |
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/campaigns/{campaign_id}/rounds/{round_n}/gates
Add a gate after the lock — shown, never counted
C3. A round's spec is locked when it starts; what someone learns afterwards may still be worth measuring (the founder added a stand tilt gate to a round that had started). The gate is evaluated and shown beside the locked ones with added_after_lock_at set and counted: false: it never changes the verdict.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
campaign_id | path | string | Campaign id ( |
round_n | path | integer | The round's number within its campaign (1, 2, …). |
Request body
| Field | Type | Description |
|---|---|---|
name | string | How the gate reads, e.g. "wz±0.20 tracking ≥ 50 %, opposite signs". |
metric | RoundGateMetric | |
op | string | |
threshold | number | |
cells | array of string | Battery cell names; empty means the whole checkpoint ( |
axis | string | null |
|
predicted | string | null | The value predicted at the lock, as written (e.g. "≥ 50 % both", "20 / 20"). |
counted | boolean | Whether it counts toward the verdict — true only for gates locked with the spec. |
added_after_lock_at | string (date-time) | null (date-time) | When a gate was added after the lock ( |
Responses
| Status | Description | Body |
|---|---|---|
201 | The round, with the gate added (not counted). | Round |
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 (53)
The schemas these operations reach before any other tag’s do. A type that links elsewhere is rendered on that tag’s page.
CampaignStatus
active — rounds may start; waiting — active, and a round's review waits on a decision (Campaign.waiting says which); done — a person closed it (decideRound {action: done}); stopped — stopped by updateCampaign. Neither done nor stopped takes new rounds.
CampaignPage
| Field | Type | Description |
|---|---|---|
items | array of Campaign | |
next_cursor | string | null |
CampaignCreate
| Field | Type | Description |
|---|---|---|
name | string | |
slug | Slug | null | Unique per owner; derived from |
owner | Handle | null | The campaign's owner; defaults to the caller. |
robot | string | The robot repo, |
task | CampaignTask | |
description | string | null | |
budget_usd | number | Hard cap on what the campaign's rounds may spend (GPU as billed). |
per_run_limit_usd | number | null | C3b — the most one round may cost and be auto-approved for an agent working inside this campaign. Null: the workspace's per-run limit ( |
root | CheckpointRef | null |
Campaign
| Field | Type | Description |
|---|---|---|
id | Id | |
slug | Slug | |
name | string | |
description | string | null | |
owner | RepoOwner | |
created_by | UserPublic | null | |
robot | RepoRef | |
task | CampaignTask | |
status | CampaignStatus | |
rules | CampaignRules | |
root | CheckpointRef | null | The declared root checkpoint rounds may resume from without a PASS verdict of their own. |
gate_defaults | CampaignGateDefaults | |
per_run_limit_usd | number | C3b — the most one round may cost (its estimate's maximum) and still be approved by the campaign's rules, without a person, when an agent session attached to this campaign proposes it. Beside |
spend | CampaignSpend | |
waiting | CampaignWaiting | null | |
rounds_total | integer | |
policy_on_robot | CampaignPolicyOnRobot | null | C4 — the checkpoint a person most recently promoted after a real-robot trial ( |
rounds | array of RoundSummary | Every round, newest first ( |
created_at | string (date-time) | |
updated_at | string (date-time) | |
finished_at | string (date-time) | null (date-time) |
CampaignUpdate
| Field | Type | Description |
|---|---|---|
name | string | null | |
description | string | null | |
budget_usd | number | null | Lowering is |
per_run_limit_usd | number | null | C3b — lowering is |
status | string | null |
|
RoundCreate
| Field | Type | Description |
|---|---|---|
name | string | The round's short name, e.g. "C2 arm A". |
parent | CheckpointRef | null | The checkpoint this round resumes from (null trains from scratch). Becomes the run's |
spec | RoundSpec | |
recipe | Recipe | |
scan | RoundScanRequest | null |
RoundPreview
K3 — createRound?dry_run=true: what createRound would decide on this body, recording nothing.
| Field | Type | Description |
|---|---|---|
fine_tunable | boolean | False when the parent run published no checkpoint the hub can resume from; |
not_fine_tunable | string | null | |
rules | array of RoundRuleVerdict |
|
variables | RoundVariables | null | |
estimate | RunEstimate | null | The round's run priced as |
checkpoints | array of RoundParentCheckpoint | Every published checkpoint of the parent run, newest first; empty for a round from scratch. |
hyperparams | TemplateHyperparams | null | |
warnings | array of string |
Round
| Field | Type | Description |
|---|---|---|
id | Id | |
campaign_id | Id | |
campaign_slug | string | |
n | integer | |
name | string | |
level | integer | |
attempt | integer | |
status | RoundStatus | |
verdict | RoundVerdictValue | |
lineage | string | |
parent | RoundParent | null | |
spec | RoundSpec | |
variables | RoundVariables | null | |
overrides | array of RoundOverrideRecord | |
decisions | array of RoundDecision | |
shortlist | array of RoundShortlistEntry | |
chosen_step | integer | null | |
steps | array of integer | Checkpoint steps with a finished measurement (scan, else gate). |
step_verdicts | array of RoundStepVerdict | AG1 — the locked gates at every measured step, oldest first (not only the chosen one), so a round card, a run's checkpoint rows and a shortlist column all read the round's own verdict at each checkpoint. Named |
evaluation | RoundEvaluation | |
parent_evaluation | RoundEvaluation | null | The same locked gates on the parent checkpoint's own measurement (the A/B control), when it has one. |
control | RoundControl | null | C3b — the checkpoint the round started from, measured in this round's own band scan and judged by its locked gates. |
scan_id | string | null | |
scan | RoundScanRequest | null | The band scan this round asked for. |
run | Run | null | |
estimate_usd_max | number | null | What the run could cost at most when it was created (the reservation). |
evidence | string | null | |
warnings | array of string | What the hub noticed and did not refuse (a declared key the recipe does not move, …). |
tripwire | TripwireState | null | |
trial_sessions | array of RoundTrialSession | C4 — the real-robot sessions of this round's checkpoints, newest first: the order, each trial's status and verdict, whether the bracket held. |
created_at | string (date-time) |
RoundOverrideCreate
RoundCreate plus the person's override.
| Field | Type | Description |
|---|---|---|
name | string | |
parent | CheckpointRef | null | |
spec | RoundSpec | |
recipe | Recipe | |
scan | RoundScanRequest | null | |
override | RoundOverride |
RoundDecisionCreate
| Field | Type | Description |
|---|---|---|
action | RoundDecisionAction | |
reason | string | null | |
step | integer | null |
|
candidates | array of integer |
|
controls | array of CheckpointRef |
|
override | RoundOverride | null | C3b, |
device_id | Id | null | C4, |
minutes | integer | null | C4, |
RoundGate
One gate of a round's spec: metric op threshold over cells, with the value predicted for it written down when the spec was locked. counted and added_after_lock_at are set by the hub.
| Field | Type | Description |
|---|---|---|
name | string | How the gate reads, e.g. "wz±0.20 tracking ≥ 50 %, opposite signs". |
metric | RoundGateMetric | |
op | string | |
threshold | number | |
cells | array of string | Battery cell names; empty means the whole checkpoint ( |
axis | string | null |
|
predicted | string | null | The value predicted at the lock, as written (e.g. "≥ 50 % both", "20 / 20"). |
counted | boolean | Whether it counts toward the verdict — true only for gates locked with the spec. |
added_after_lock_at | string (date-time) | null (date-time) | When a gate was added after the lock ( |
CampaignTask
What the campaign trains, which picks its rounds' default gate battery (C3 — the C1 × C2 run judged a stand policy on a walking battery): stand → stand (upright, drift, tilt, joint asymmetry) while training and for the band scan; walk and omni → watch while training, c_matrix for the scan; recovery → recovery for both; custom → smoke for both. C3b: the stand battery is the zero-command cell plus three pushes calibrated to separate a trained stand from a network that outputs ~0 (lateral ±6 N·s and backward 4 N·s at 8 s, all scored on posture).
CheckpointRef
A checkpoint of a run — checkpoints/step_<step>/ of its output model repo.
| Field | Type | Description |
|---|---|---|
run_id | Id | |
step | integer | null | The checkpoint step. Null on a campaign's |
CampaignRules
Which rules the hub enforces on this campaign's rounds. All three are always true: they cannot be switched off for a campaign, only overridden on one round by a signed-in person with a reason.
| Field | Type | Description |
|---|---|---|
one_variable | boolean | |
resume_from_pass | boolean | |
fail_ends_lineage | boolean | |
separates_from_control | boolean | C3b — always |
CampaignGateDefaults
The gate a round's run gets when its recipe names none, and the band scan it gets when it finishes — picked by the campaign's task.
CampaignSpend
Money, from the ledger: spent_usd sums the terminal rows of the campaign's round runs; reserved_usd is what rounds still training may yet spend (their estimateRun maximum); remaining_usd = budget_usd − spent − reserved, never below 0. Gate and scan rollouts are counted, not priced (the hub does not bill sim time).
| Field | Type | Description |
|---|---|---|
budget_usd | number | |
spent_usd | number | |
reserved_usd | number | |
remaining_usd | number | |
by_round | array of CampaignRoundSpend | |
unpriced_rollouts | integer | Gate and scan rollouts of the campaign's runs — sim time, never billed. |
CampaignWaiting
What waits on a person, and since when.
| Field | Type | Description |
|---|---|---|
kind | string |
|
round | integer | |
since | string (date-time) | |
reason | string | One sentence, e.g. "Round 3 is reviewed: 2 checkpoints PASS their locked gates." |
CampaignPolicyOnRobot
C4 — the checkpoint a person promoted after a real-robot trial.
| Field | Type | Description |
|---|---|---|
trial_id | Id | |
label | string | null | |
model_repo | string | |
run_id | string | null | |
step | integer | null | |
device | string | null | |
decided_at | string (date-time) | |
decided_by | UserPublic | null |
RoundSummary
One row of a campaign's round timeline.
| Field | Type | Description |
|---|---|---|
n | integer | |
name | string | |
level | integer | Depth in the lineage — 1 for a round from scratch or from the root. |
attempt | integer | Which attempt at this parent checkpoint (siblings count from 1). |
status | RoundStatus | |
verdict | RoundVerdictValue | |
gates_passed | integer | |
gates_total | integer | |
chosen_step | integer | null | |
parent | RoundParent | null | |
lineage | string | |
change | RoundChange | |
override_rules | array of CampaignRuleName | |
variables | RoundVariables | null | |
evidence | string | null | One line generated from the verdict, the scan and any tripwire. |
run_id | string | null | |
run_status | JobStatus | null | |
cost_usd | number | |
priced | boolean | |
decision | RoundDecisionAction | null | The latest decision's action. |
separates | boolean | null | C3b — |
trial_sessions | array of RoundTrialSession | C4 — the real-robot sessions of this round's checkpoints, newest first: the order, each trial's status and verdict, whether the bracket held. |
created_at | string (date-time) |
RoundSpec
The founder's per-round spec, locked when the round starts (C3). locked_at / locked_by are set by the hub; nothing in it is ever edited afterwards.
| Field | Type | Description |
|---|---|---|
change | RoundChange | |
hypothesis | RoundHypothesis | |
not_doing | array of string | |
tripwires | array of GateTripwire | Passed to the run's gate ( |
gates | array of RoundGate | |
iteration_cap | integer | Iterations this round may train. Written into the template's own cap ( |
locked_at | string (date-time) | null (date-time) | |
locked_by | UserPublic | null | |
locked_via | string | null |
RoundScanRequest
The band scan the hub queues when the round's run finishes (default: the campaign's gate_defaults.scan_battery × scan_seeds, on the run's own executor).
| Field | Type | Description |
|---|---|---|
battery | string | null | |
seeds | integer | null | |
executor | RolloutExecutor | null |
RoundRuleVerdict
| Field | Type | Description |
|---|---|---|
rule | CampaignRuleName | |
status | string | |
msg | string | The |
RoundVariables
The one-variable rule's arithmetic. basis: planned — computed at the start from the recipe against the parent checkpoint's run; resolved — recomputed on the run's own resolved config once it arrived; none — the round trains from scratch, so there is nothing to diff. changed lists every counted key that moved (bookkeeping excluded), undeclared those outside the declared change.
| Field | Type | Description |
|---|---|---|
basis | string | |
declared | integer | Keys the round declared. |
found | integer | Counted keys that changed. |
changed | array of string | |
undeclared | array of string | |
bookkeeping | integer | Keys that changed by construction ( |
one_variable | boolean | |
stacked_on | integer | null | The sibling round whose change this round stacks on its own, if it does. |
comparison | string | null | L1 — |
cannot_compare | array of string | L1 — declared keys under which the parent recorded nothing, so the rule can neither pass nor fail them ("cannot be compared"). They are not in |
parent_has_no_record | integer | L1 — |
child_has_no_record | integer | L1 — |
groups | array of RoundVariablesGroup | L1 — the counted changes by RL structure ( |
RoundParentCheckpoint
One published checkpoint of the parent run, judged as a parent of this round would be (resume_from_pass, fail_ends_lineage).
| Field | Type | Description |
|---|---|---|
step | integer | |
can_be_parent | boolean | |
reason | string | null | The rule's own sentence when it cannot be a parent. |
verdict | string | null | The round's verdict at this step on its locked gates, when the parent run is a round of this campaign. |
cells_passed | integer | null | Cells that passed in the step's latest sim gate or band scan ( |
cells_total | integer | null |
TemplateHyperparams
Whether the template reads what the recipe sets. accepted: null — the hub does not know which hyperparameters this template reads (a trainer run by path). Only ppo_isaac takes overrides (Hydra config paths); a name the template does not read would be ignored by the trainer, so it is listed in ignored.
| Field | Type | Description |
|---|---|---|
accepted | boolean | null | |
ignored | array of string | |
reads | array of string | null |
RoundStatus
training — the run is queued or running; scanning — the run ended and its band scan is being measured; review — measured, waiting on a decision; decided — a decision was recorded; failed — the run ended without a single checkpoint to judge.
RoundVerdictValue
The round's locked gates at the step: pass — every counted gate PASSes; partial — some do; fail — none does; confounded — the one-variable rule was broken (overridden at the start, or an undeclared key found in the resolved config), whatever the gates say; pending — nothing measured yet. An unmeasured gate never passes.
RoundParent
Where the round resumed from — a checkpoint and, when it has one, the round that produced it.
| Field | Type | Description |
|---|---|---|
run_id | string | |
step | integer | null | |
round | integer | null | |
is_root | boolean |
RoundOverrideRecord
| Field | Type | Description |
|---|---|---|
rule | CampaignRuleName | |
reason | string | |
by | UserPublic | null | |
at | string (date-time) | |
detail | string | What the rule said when it was overridden, e.g. "parent R2 · step 700 is a partial (6 of 7)". |
RoundDecision
| Field | Type | Description |
|---|---|---|
action | RoundDecisionAction | |
reason | string | null | |
step | integer | null | |
verdict | RoundVerdictValue | |
by | UserPublic | null | |
via | string | |
at | string (date-time) |
RoundShortlistEntry
| Field | Type | Description |
|---|---|---|
role | string | |
run_id | string | |
step | integer | |
verdict | RoundVerdictValue | |
model_repo | string | null | The run's output model repo; the checkpoint is |
RoundStepVerdict
AG1 — the round's locked gates at one checkpoint (C3's evaluation, at every measured step, not only the chosen one).
| Field | Type | Description |
|---|---|---|
step | integer | |
verdict | RoundVerdictValue | |
source | string | null | |
rollout_id | string | null | |
seeds | integer | null | |
gates_passed | integer | |
gates_total | integer | |
results | array of RoundGateResult | |
band | RoundBand | null |
RoundEvaluation
| Field | Type | Description |
|---|---|---|
step | integer | null | |
source | string | null | Where the measurement came from — the round's band scan, or a gate while training. |
run_id | string | null | The run whose checkpoint was measured (the parent's, for |
rollout_id | string | null | |
battery | string | null | |
seeds | integer | null | |
verdict | RoundVerdictValue | |
gates_passed | integer | |
gates_total | integer | Counted gates. |
results | array of RoundGateResult | |
hypothesis | RoundGateResult | null | |
band | RoundBand | null |
RoundControl
C3b — the control: the checkpoint the round started from, measured in the round's own band scan (same battery, seeds and conditions) and judged by the round's locked gates, beside the candidate. A parent control is its own rollout on the parent's model repo (it carries no run_id of this round, so it never enters the band); an untrained control is the scan's step-0 row. When it passes every locked gate the candidate passes — all of them, when the candidate passes all — separates is false, the round carries the warning "the gates do not separate candidate from control", and shortlisting it needs a person's override with a reason.
| Field | Type | Description |
|---|---|---|
role | RoundControlRole | |
run_id | string | null | The run whose checkpoint is the control (the parent's, or this round's own). |
step | integer | null | |
model_repo | string | null | The model repo holding it, |
rollout_id | string | null | The rollout that measured it (a |
status | RoundControlStatus | |
reason | string | null | Why it is |
evaluation | RoundEvaluation | null | The round's locked gates on the control's measurement ( |
separates | boolean | null | Against |
compared_step | integer | null | The candidate step |
warning | string | null | The sentence that also appears in |
RoundTrialSession
C4 — a real-robot session of this round's checkpoints, as the campaign row prints it.
| Field | Type | Description |
|---|---|---|
id | Id | |
status | TrialSessionStatus | |
device | string | null | |
order | array of TrialRef | |
bracket_holds | boolean | null | |
note | string | null | The first line of a candidate's notes, as filed. |
created_at | string (date-time) |
RoundOverride
| Field | Type | Description |
|---|---|---|
rules | array of CampaignRuleName | Exactly the rules this round breaks. |
reason | string | Why, in the person's words — recorded on the round and shown with the chip. |
RoundDecisionAction
shortlist (session) — the checkpoints for a real-robot trial; iterate (key:train) — train the next round from step; stop (key:write) — end this lineage; done (session) — close the campaign.
RoundGateMetric
What a gate reads from the measured cells at a step. Per listed cell: alive (seeds upright, a count), alive_rate (upright / seeds), tracking (measured / commanded on axis, or every commanded axis), pass (1 when the hub's band rule PASSes the cell, else 0), and the posture metrics (the median over the cell's seeds): tilt_max_deg, asym_max_deg, drift_m, and — on a push cell (C3b) — recover_s, the seconds from the push until the base stayed within 3° of upright and under 5 cm/s to the end (a seed that never settled counts the whole window left after the push). Every listed cell must satisfy the comparison. Over the checkpoint: pass_rate (PASS cells / cells, of the listed cells or all), and tracking_gap — |ratio₁ − ratio₂| of exactly two listed cells (the founder's left–right turn gap).
CampaignRoundSpend
| Field | Type | Description |
|---|---|---|
n | integer | |
cost_usd | number | The round's run as billed (the ledger); 0 while it runs, and for an unpriced run. |
priced | boolean | False for a |
reserved_usd | number | What a round still training may spend at most (its estimate), 0 once it has ended. |
RoundChange
The ONE change this round makes: a summary a person reads, and the resolved-config keys it covers (a key covers itself and every path under it, so env.events.push_robot covers env.events.push_robot.params.velocity_range.x[0]). One conceptual change may span several keys.
| Field | Type | Description |
|---|---|---|
summary | string | |
keys | array of string |
CampaignRuleName
The three rules the hub enforces on every round (the founder's own): one_variable — one declared change per round, diffed against what the parent checkpoint was trained on; resume_from_pass — a round resumes only from a checkpoint whose verdict is PASS, or from the campaign's declared root; fail_ends_lineage — no checkpoint of a FAIL, confounded or stopped round is ever a parent, nor (C4) a checkpoint whose real-robot trial a person stopped (setTrialVerdict {stop}). C3b adds a fourth, checked when a round is shortlisted rather than when it starts: separates_from_control — a candidate whose round's control (the checkpoint the round started from, measured in its own band scan) passes every locked gate the candidate passes cannot be shortlisted, because its gates cannot tell what it learned from what it began with; a person may override it with a reason (RoundDecisionCreate.override).
RoundHypothesis
What the round expects and how to read it if it is wrong. test, when given, is evaluated and shown like a gate but never counted: a checkpoint can pass while its round's hypothesis fails, and the page keeps the two apart.
| Field | Type | Description |
|---|---|---|
claim | string | |
reading | string | null | The locked reading, e.g. "if it still collapses, the DR is not the cause". |
test | RoundGate | null |
RoundVariablesGroup
| Field | Type | Description |
|---|---|---|
id | RunConfigGroupId | |
name | string | |
changed | integer | |
undeclared | integer | |
changes_contract | boolean | K3 — the group is part of the policy's IO contract (actions, observations, the contract block): a change here makes a policy a robot registered for the parent's contract will refuse. |
RoundGateResult
| Field | Type | Description |
|---|---|---|
gate | RoundGate | |
verdict | GateVerdictOrNotCounted | |
passed | boolean | null | For a gate that is not counted, whether its comparison held. |
value | number | null | The value compared (the worst listed cell for a per-cell metric). |
measured | string | null | The measurement as a person reads it, e.g. "+80 % / +87 %", "19 / 20 · 105 %". |
RoundBand
The hub's 0.85–1.15 band rule on the same rollout — a measurement shown beside the verdict.
| Field | Type | Description |
|---|---|---|
gates_passed | integer | |
gates_total | integer | |
alive_rate | number | null |
RoundControlRole
parent — the parent checkpoint a resumed round started from (the parent run's own checkpoints/step_<step>/); untrained — for a round from scratch, the step-0 checkpoint its own run published (the weights before training, or after the trainer's first update where that is what it saves, as rsl_rl's model_0.pt is).
RoundControlStatus
planned — the run has not ended, so nothing is queued yet; measuring — its rollout is queued or running; measured — the locked gates were evaluated on it; unavailable — it cannot be measured (reason says why: the template published no step-0 checkpoint, the scan was skipped, its rollout failed, …).
TrialSessionStatus
open — trials still to run; needs_verdict — a candidate waits on a person; decided — every candidate has a verdict (or never ran).
TrialRef
One trial as a session strip or a campaign row prints it.
| Field | Type | Description |
|---|---|---|
id | Id | |
index | integer | |
role | TrialRole | |
label | string | The checkpoint as a person names it — |
step | integer | null | |
model_repo | string | null | |
status | TrialStatus | |
tilt_mean_deg | number | null | |
tilt_max_deg | number | null | |
verdict | TrialVerdictAction | null |
GateVerdictOrNotCounted
A gate's result at a step: PASS / FAIL, unmeasured (the cells or the metric are not in the measurement — never a pass), or not_counted (a gate added after the lock; its measured value is still shown).
TrialRole
candidate — a checkpoint on trial, which takes a person's verdict; control — the checkpoint the robot already runs (usually the round's parent), run first and last to bracket the candidates. A control is measured, never judged.
TrialStatus
Derived on every read from the consent request, the approval, the driver's events, the log and the verdict — never stored. unfiled (no consent request yet), awaiting_approval, denied, approved (issued, the device has not started), running, refused (the device refused it before starting), expired (the window passed unused), needs_verdict (a candidate that ran and has no verdict), measured (a control that ran), decided, withdrawn (not filed: its checkpoint failed the scan it was waiting on).
TrialVerdictAction
promote — this checkpoint becomes the campaign's policy on the robot; iterate — back to sim, the next round drafted from the notes; stop — this checkpoint's lineage ends, like a FAIL.