sandboxes

Read Placement Refusals

Placement refusals over a window, newest first.

The kind is placement_refused. Every row carries a null sandboxId by nature: the refusal is the record that no box was ever created, so there is none to name.

Empty is a legitimate answer, and no longer means the producer is missing. _emit_placement_refused in context_gateway.py has three call sites, so an empty window means no placement walk met a refusal -- not that nothing can record one. Stated because an endpoint that returns nothing is otherwise indistinguishable from a broken one, and because the note this replaces said the opposite for as long as the producer was outstanding.

A row is also not a failed acquisition. One of those three call sites emits immediately before returning a box that started, recording only that the walk passed over a candidate first; the other two precede the allocation error a client is waiting on. Nothing in the payload distinguishes them.

get/api/sandboxes/admin/placement-refusals

Query parameters

hoursinteger
limitinteger

Response

Successful Response

eventIdinteger required
occurredAtstring required
recordedAtstring required
eventKind'placement_refused' | 'acquired' | 'ready' | 'readiness_timeout' | 'stopped' | 'resumed' | 'deleted' | 'superseded' | 'reconciled' required

Kind of transition recorded in the append-only sandbox event log.

source'gateway' | 'reaper' | 'reconciler' | 'drain' required

Which component wrote a ledger event.

RECONCILER matters on its own: it is what keeps a cause we inferred after the fact distinguishable from a cause we actually caused.

DRAIN is separate from it for the same reason, one step removed. The drain synthesizes a superseded event when a colliding acquisition proves an earlier box is gone: inferred, so not GATEWAY, but inferred from something a gateway witnessed rather than from sweeping a provider after the fact. Folding it into RECONCILER would inflate exactly the gateway-to-reconciler ratio that models/sandbox_ledger.py calls the ledger's own trustworthiness metric, and no later migration could separate the two again -- an enum value cannot be removed, and by then the rows are indistinguishable.

causeOfDeath'idle_reap' | 'preemption' | 'health_check_kill' | 'readiness_failed' | 'lease_released' | 'lease_expired' | 'age_limit' | 'explicit_teardown' | 'superseded' | 'unknown_reconciled' required

Why a sandbox left its last open phase.

UNKNOWN_RECONCILED is first-class and load-bearing. A hard preemption leaves nobody running to write a truthful cause, so the reconciler has to be able to say it does not know. Without this value the reconciler is forced to pick a plausible cause instead, and every other cause in the ledger stops being trustworthy.

sandboxIdstring nullable required
sandboxAliasstring required
payloadobject required

Changes