Docs · reference
Deployments and phases
Every deployment kind, its phases in order, what each phase records as evidence, and how failure is handled.
A deployment is one change to an environment, run as an ordered list of phases. Each phase ends ok, failed, or skipped and records a JSON evidence object. The last phase is always verdict. GET /v1/deployments/{id} returns the deployment and its phases; denv deployment watch prints them as they change.
Statuses
| Deployment | Meaning |
|---|---|
pending |
Created, not started. |
running |
Phases executing. |
succeeded |
Every non-skipped phase ok. |
failed |
A phase failed and nothing was reverted. |
rolled_back |
A deploy failed and the environment was restored to its previous version. |
| Phase | Meaning |
|---|---|
pending, running, ok, failed, skipped |
skipped is used both for phases a kind does not need this time (e.g. provision when a host exists) and for every phase after a failure. |
Failure rule
When a phase fails, the remaining phases up to verdict are marked skipped, the deployment's Error is set to <phase>: <message>, and verdict runs anyway so the outcome is recorded. For a deploy with a previous healthy version and a host, verdict sends env.rollback to that version and the status becomes rolled_back; otherwise the environment's status becomes failed. For every other kind the verdict records the failure and changes nothing else.
Each phase is bounded by the orchestrator's command timeout (15 minutes).
deploy
POST /v1/projects/{project}/deploy, deploy-from-source, POST /v1/sandboxes (image form), push webhooks.
| # | Phase | Evidence | Notes |
|---|---|---|---|
| 1 | resolve |
{version, number, services, volumes} |
Creates the version row from the parsed spec; remembers the previous current version for rollback. |
| 2 | place |
{host, reason} |
environment already on host, target <cloud>, first connected host in team, or no connected host; provisioning. Sidecars are preferred over provider hosts. |
| 3 | provision |
{cloud, provider, ref, ip, name} |
Skipped (host already placed) when a host was found. Otherwise creates a machine through the first non-manual cloud; fails with no connected host and no cloud that can provision: … when there is none. |
| 4 | join |
{host, joined_in_ms} |
Skipped when placed. Waits up to 6 minutes for any host of the team to connect. |
| 5 | prepare |
{version, endpoints} |
Sends env.create; the sidecar prepares datasets, starts, waits for health, probes egress. |
| 6 | start |
{started_in_ms} |
Derived from the env.create result. |
| 7 | health |
{endpoints} |
Derived from the env.create result. |
| 8 | warm |
{exit} or {exit, stderr} |
Skipped (no warm command) unless warm was given. Runs it in the first service with a 600 s timeout; non-zero exit fails. |
| 9 | snapshot |
{snapshot, datasets, frozen_for, consistent} |
env.snapshot named after the version id. |
| 10 | ingress |
{endpoints, names: "pending ingress proxy"} |
Always skipped today. |
| 11 | verdict |
{version, snapshot, took_ms} on success; {reverted_to}, {reverted: "no previous version"}, or {reverted: "rollback failed: …"} on failure |
Marks the version healthy and makes it the environment's current version. |
fork
POST /v1/envs/{env}/fork, POST /v1/sandboxes (from_version). Creates a new environment (stage fork, parent version set) on the source's host.
| # | Phase | Evidence |
|---|---|---|
| 1 | place |
{host, reason: "same host as source snapshot"}; fails if the source's host is not connected. |
| 2 | clone |
{forked_in_ms, from} from env.fork. |
| 3 | health |
{endpoints}, derived. |
| 4 | verdict |
{env, took_ms}; the fork's current version is the source version. |
snapshot
POST /v1/envs/{env}/snapshot. Creates a new version with the same spec as the current one.
| # | Phase | Evidence |
|---|---|---|
| 1 | snapshot |
{snapshot, datasets, frozen_for, consistent}. |
| 2 | health |
{answered: true}: true executed in the first service after unpause. |
| 3 | verdict |
{version, snapshot, took_ms}; on failure {kept: <previous version>} and nothing changes. |
rollback
POST /v1/envs/{env}/rollback. The version must be a healthy snapshot of this environment.
| # | Phase | Evidence |
|---|---|---|
| 1 | restore |
{snapshot} from env.rollback; fails if the host is not connected. |
| 2 | health |
{restored: <snapshot>}, derived. |
| 3 | verdict |
{version}; the environment's current version is set. |
verify
POST /v1/envs/{env}/verify. Requires x-denv.agent.service and x-denv.verifier in the current version's spec. Creates a new version row for the capture.
| # | Phase | Evidence | Notes |
|---|---|---|---|
| 1 | stop |
{agent_service, mode: "pause"} |
Recorded only; the freeze happens inside collect so there is no gap. |
| 2 | collect |
{files, bytes, missing, refused} |
verify.collect: agent paused, paths copied to a root-owned directory, special files refused. |
| 3 | snapshot |
{snapshot, datasets, frozen_for, consistent} |
Agent kept paused unless resume; the version is marked healthy. |
| 4 | clone |
{grader_env, forked_in_ms} |
A new environment <env>-verify-<suffix> (stage verify) forked from the capture. |
| 5 | grade |
{reward, exit_code, stdout, stderr, source, ran_for} |
verify.run on the grader's fork; refused: true when collect refused anything. |
| 6 | verdict |
{reward, source, exit_code, refused, missing, agent_frozen, took_ms} |
The grader's fork is destroyed. On failure reward is null. |
The agent's environment keeps its previous current version; the capture version exists in versions and is healthy, so it can be forked. The agent service remains paused unless resume: true.
destroy
DELETE /v1/envs/{env}.
| # | Phase | Evidence |
|---|---|---|
| 1 | teardown |
null; skipped with {reason: "host not connected; datasets left in place"} when the host is unreachable. |
| 2 | verdict |
null; the environment's status becomes destroyed. |
promote
Declared with phases gate.fork, gate.consistency, gate.replay, gate.invariants, gate.soak, apply, verdict. Not yet available: no API route starts a promotion.
Events
Every deployment appends deployment.started ({kind}) and deployment.finished ({status, took_ms, error}) to subjects env:<id> and dep:<id>; provision appends host.provisioned; GitHub-triggered deploys append deployment.source ({sha, branch, repo}) to dep:<id>. Read them with GET /v1/events?subject=….