Reference
Execution Receipt
The machine-readable record of what ota actually executed.
referenceautomation buildersintermediatestable2026-05-30
Recommended next
What a receipt is for
Read the receipt after a command runs if you need to audit what happened.
Use it when you want to compare runs, debug failures, or prove which backend and env values were used.
- the receipt is the machine-readable record of execution, not diagnosis
- the receipt tells you what ota chose, what ran, what succeeded, and what was blocked
- the receipt is what automation should read after execution, not before it
- the receipt makes the execution trail reviewable while failure output keeps
WhyandNextbefore the trailingRUN SUMMARYblock, and the compact summary now leads withStatusfor faster scanning - repo receipts can include a
Policy:section when policy-backed provisioning selected a source or backend-specific config - receipts can also include
host_service_cleanupwhen ota attempted host-managed service shutdown during interrupt cleanup - receipts can also include
execution_conflict.reasons[]when active execution ownership blocked the run path
Receipt fields
oktells you whether the command completed successfullypathtells you which repo or workspace file ota resolved for the runscopetells you whether the receipt came from a repo command or a workspace commandcontracttells you which contract governed the executionevaluated_inputscarries captured replay inputs while ota authored the receipt; a matching input can only support the named trust class, never broader ambient state- a consumed replay authority appears as
evaluated_inputs[].kind: promoted_replay_baseline; itsartifact_lineage.replay_authoritybinds the receipt to the portable authority manifest, SCM-review trust root, selected attestation, declared consumption posture, and promotion identity rather than claiming its producer ran during replay - a baseline producer receipt carries its attested recording reference in
witnessed_observations.replay_baseline_recordings[]; this is historical regeneration evidence, while a later replay receipt carries only the separately selected authority evaluated_inputs[*].hydration_provenancerecords the declared and runner-resolved source posture for a selected structured hydration lane, so a later config-file read cannot rewrite what that execution usedwitnessed_observationscarries attested execution evidence separately from evaluated inputs, so observed query variation cannot be mistaken for a current-run decision inputbackendtells you where the work ran, such as native, container, or remotelifecycletells you whether container execution was persistent or ephemeralstepsshows the ordered execution steps and their statussummarygives the roll-up counts for errors, warnings, info, and stepsnextgives the safest follow-up action when ota can suggest onenext_stepsgives that same follow-up lane as an ordered machine-readable array when ota can break it into explicit stepsenv_sourcesshows which env values won and where they came fromnative_prerequisitesshows the selected native prerequisite evidence for the executed native path, including additive check, activation, provisioning, and note detail when presentnative_prerequisites[*].activation.appliedtells you whether ota actually ran inside that activation for this command or only reported the declared activation shapepolicyshows which effective approved provisioning source ota resolved for the run and any backend-specific source confighost_service_cleanupshows first-class host-managed service cleanup evidence when ota owned the stop pathexecution_conflict.reasons[]shows typed active-execution conflict ownership such ashost_service,compose_project,write_path,runtime_listener, or conservative unresolvedservice_taskownership- a single fixed
runtime_listenercollision keeps the machine reason stable while receipt follow-up points to--host-port <free port>only when the selected lane admits that override; explicit ports are refused rather than silently remapped - a live legacy
service_taskrecord withoutruntime_owners[]stays fail-closed because Ota cannot prove its endpoint from old evidence; restart that service once with the current Ota binary to record precise listener ownership
How to read it
- Check
okfirst to see whether execution succeeded - Then check
scopeandcontractto confirm what ota ran against - Then check
backendandlifecycleto understand the execution model - Then read
stepsto see what actually ran and where the run stopped - Then read
summary,next, and optionalnext_stepsfor the roll-up and safest follow-up - Then inspect
env_sourcesif you need provenance for the values that won - Then inspect
native_prerequisiteswhen the selected path depended on host-native build tooling or task-scoped shell activation - Then inspect
policyif you need the approved provisioning source or source config - Then inspect
host_service_cleanupwhen the run was interrupted and ota owned host-managed service shutdown - Then inspect
execution_conflict.reasons[]and optional ownerruntime_owners[]when another active execution claimed an overlapping listener, write namespace, or unresolved service boundary - If the owner reports
legacy_or_unresolvedruntime ownership, restart that active service once with the current Ota binary before retrying cross-mode execution - If a step failed, the receipt should let you tell whether the failure was from setup, the task body, or the backend itself
Repo example
A repo receipt should be enough to tell you what happened in that repo run without opening the terminal output again.
Repo task runjson
{ ok: true, path: "/workspace/acme/app/ota.yaml", scope: "repo", contract: "/workspace/acme/app/ota.yaml", backend: "container", lifecycle: "ephemeral", steps: [ { "order": 1, "label": "setup", "status": "ok" }, { "order": 2, "label": "test", "status": "ok" } ], summary: { "error_count": 0, "warn_count": 0, "info_count": 0, "step_count": 2 }, next: "run `ota run test` again after your code changes", env_sources: [ { "name": "NODE_ENV", "source": "task.env", "value": "test" } ], policy: [ "tool node (package: nodejs) 22 via choco (source_config: feed=internal-choco)" ]}Workspace example
A workspace receipt should tell you which member blocked the rollout and which members finished cleanly.
Workspace runjson
{ ok: false, path: "/workspace/acme/ota.workspace.yaml", scope: "workspace", contract: "/workspace/acme/ota.workspace.yaml", backend: "native", lifecycle: "persistent", steps: [ { "order": 1, "label": "api", "status": "ok" }, { "order": 2, "label": "web", "status": "blocked" } ], summary: { "error_count": 1, "warn_count": 0, "info_count": 0, "step_count": 2 }, next: "run `ota workspace doctor` to inspect the blocked member"}How to use it
- use
ota execution plan --jsonwhen you need to inspect backend, lifecycle, image, or target selection without running setup or tasks - workflow-aware planning follows the selected workflow run path first and only falls back to setup when the workflow has no run phase
prepare.taskstays additive workflow context rather than the concrete execution task- use
ota execution plan --json --mode containeror--mode remotewhen you want the same backend-configuration gate thatota runandota upwould enforce before execution starts - use
ota workspace execution plan --jsonwhen you need the same read-only execution decision across selected workspace repos instead of one repo at a time, including workspace-pinned or repo-default workflow paths - use
ota workspace execution plan --json --repo <name>when the decision boundary is the selected repo set, not the full required/optional workspace roll-up - use
ota receipt --jsonwhen you want the same repo readiness scan as an archive-ready receipt artifact without provisioning, setup, or writes - repo receipts can now include additive
receipt.toolchains[]evidence for the selected provider-backed ecosystem path, alongside the existing readiness findings and execution identity - when ota actually runs provider fulfillment commands on the recorded execution path, the same toolchain entry can also include additive
fulfilledandcommands[]evidence - every successful repo receipt now includes a normalized
receipt.contract_snapshot_hash, and--archivealso materializes that normalized contract JSON under.ota/contractsso the receipt can point at the exact semantic contract truth it used - every successful repo receipt now also includes additive
receipt.assumption_set_hash, derived from the canonical extracted semantic path/value map instead of the raw snapshot blob - when a selected task or workflow closure declares
tasks.<name>.replay_inputs,receipt.evaluated_inputs[]captures each static file SHA-256 identity before execution begins; those identities narrow only the named file input, never ambient runtime or external state. Usekind: static_filefor generic immutable repo files,kind: presentation_profilefor declared output-shaping or normalization policy files, andkind: comparator_profilefor declared equivalence or tolerance policy files. The same field also captures lockfile-strict Node hydration and selected static Compose image evidence; compare all of them only through archived baseline versus current receipt, never through a later filesystem read - use
policies.replay_inputs.identity.tasks|workflowswhen selected replay-sensitive closures must refuse unless every declared replay input has a matching immutable pin. Agent safety, claim assurance, replay admission, Doctor/provisioning findings, proof, CI projection, and receipt evidence reuse one command-scoped loaded policy snapshot and replay-input observation set; each task-qualified input is observed once for command admission, and aggregate monorepo Doctor JSON retains each member policy record. Runtime proof pins that admitted authority for its detached child and includes post-readiness seam observers plus its selected negative-control task before proof artifacts or child runtime spawn. Lifecycle proof admits the exact prerequisite-plus-assertion closure before tasks or service transitions. Recursive outcome hooks are part of admission and the projected CI execution closure, so a governed or mismatched hook blocks before its parent starts and cannot disappear from provider evidence. Hard-pin refusals retain the active policy record, while generic readiness receipts do not reconstruct policy after execution. Bothdenyandreviewrefuse before native provisioning, dependency hydration, proof side effects, or task startup. Missing, unreadable, or mismatched declared hard pins always refuse and cannot be weakened toreview; unavailable observations and active policy load failures also fail closed. Mutatingota doctor --fixapplies the same admission before repo-hygiene or native tool-activation mutation, whileota doctor --fix --dry-runremains a non-mutating preview. CI projection carries requirements, not render-host observations, so provider checkouts recompute observed identities - use
artifacts.<name>.replayfor generated fixtures or model baselines. Keepkind: generated_sourcewhen the same outputs already have generated-source lineage; replay authority is additive and must not duplicate output ownership. Agenerated_sourceconsumer with the producer in top-leveldepends_onis ordinary generated-source execution; without that unconditional dependency, it uses promoted replay authority. A dedicatedreplay_baselinealways consumes promoted authority.ota baseline record --artifact <name>requires a clean Git source identity before it creates a receipt-bound recording, thenota baseline promote --artifact <name> --attestation <path>explicitly selects it through a committed manifest. That manifest embeds the selected attestation and declares SCM review as its external trust root; Ota does not verify reviewer inclusion or signer provenance. Doctor reportsOTA_REPLAY_BASELINE_UNAVAILABLEbefore a selected replay consumer starts when that authority is unavailable or drifted.consumption: read_onlymounts a runner-owned snapshot outside the writable workspace across the selected ephemeral-container closure and projects command-capable typed preparation through that same boundary;consumption: verify_unchangedkeeps native replay available but reportsreplay_artifact_mutation_detectedif the baseline changes after the task. It does not upgrade that detection posture to read-only enforcement. Replay-baseline symlinks must remain inside declared artifact outputs. Neither path regenerates the baseline or auto-promotes the newest recording - when a selected closure declares
tasks.<name>.witnessed_observations.query_traces,receipt.witnessed_observations.query_traces[]carries attested per-subject/per-run query identity records, source path and SHA-256 identity, and a divergent-subject summary separately fromevaluated_inputs[]; it reports observed query variation without claiming model causality or treating historical output as a current-run input - add
--archiveto persist the JSON receipt under.ota/receipts(keeps the newest 50), including its normalized snapshot reference and matching identity; authority-bearing execution archives also carry a canonical selected-invocation scope, so history re-derives the exact governed closure instead of trusting a lane label or the current worktree contract - use
ota receipt --json --historywhen you need the archived repo receipt index without rerunning diagnosis - on a protected Linux systemd Launcher deployment, use
ota receipt --json --history --source systemd_protected_launcher; the fixed history service selects the administrator-bound repository catalog, returns the exact archive, immutable contract snapshot, and finalization sidecar, and Core applies the same semantic archive verifier without local fallback - add
--archive-identity <sha256:...>to select one exact protected archive; protected history rejects repository paths,--file,OTA_FILE, malformed or incomplete manifests, and any object or semantic verification mismatch - history reads valid archives newest first and surfaces malformed files as skipped entries. Snapshot-less older archives remain inspectable as
legacy_unverified, but cannot be selected as baselines, proof inputs, or crossing-authority evidence - use
ota receipt --json --baseline latestwhen you need introduced, resolved, unchanged, and semantic contract-drift evidence against the newest valid archived receipt for the same contract - use
ota receipt --json --baseline <file>when the baseline should come from an explicit repo receipt JSON artifact instead of.ota/receipts - when that baseline carries
receipt.contract_snapshot_ref, readsummary.comparison.contract_snapshot_changed,contract_changes[], andlikely_related_changes[]to connect new blockers to contract drift - read
summary.comparison.correlationfirst for the top-level advisory posture;possibly_relatedis reserved for coarse same-family overlap, while unrelated drift staysno_clear_correlation - use
ota receipt --json --snapshot latestor--snapshot promotedwhen you need the archived normalized semantic contract JSON itself rather than just drift evidence --snapshot <file>accepts either an archived receipt JSON artifact or an archived.ota/contracts/...snapshot JSON file and reports the resolvedselection_kind,snapshot_hash,assumption_set_hash,summary.assumption_count, andsnapshot_path- receipt diff stays read-only and exits
0when the comparison succeeds, even if the current or baseline receipt is blocked - use
ota run <task> --dry-run --jsonfor task-level execution previews without starting the run path; the published schema isrun-preview.json, and blocked previews still stay on the same stdout preview envelope so automation can readsummary.primary_blockerdirectly - use
ota up --jsonfor readiness roll-ups and receipts - use
ota workspace run --json,ota workspace up --json,ota workspace refresh --json, andota workspace status --jsonfor workspace records; refresh stays read-only in preview mode and can also reflect stricter sync choices when those flags are used - use
ota workspace receipt --jsonwhen you want the same workspace scan as an archive-ready receipt artifact - read receipts after execution, not before it
- compare receipts across runs when you need to prove what changed
- use receipts when you need the execution trail, not the readiness diagnosis
What it is not
- not live logs
- not a diagnosis report
- not a contract inference result
- not a replacement for
doctor - not a replacement for
detect - not the place to discover new contract fields
Use cases
- confirm what ota actually executed after a successful
ota run - debug a failed
ota upwithout guessing which backend or lifecycle was used - inspect which steps were blocked before a task could finish
- compare a native run and a container-backed run
- feed a machine-readable execution trail into CI or agent workflows
- review workspace roll-ups after multi-repo bootstrap or execution