Deployment stage receipts
Inspect durable deployment-stage attempt observations and the evidence required before scoped QA.
Table: deployment_stage_receipts
Durable executor observations for non-QA deployment-stage attempts. Events do not substitute for this authority.
id INTEGER PRIMARY KEY
run_id TEXT NOT NULL REFERENCES deployment_runs(id)
stage_name TEXT NOT NULL
attempt_number INTEGER NOT NULL -- allocated before dispatch; increasing per run/stage
correlation_id TEXT NOT NULL -- idempotency key for one dispatch
target_kind TEXT NOT NULL -- persistent_environment | run_preview
target_name TEXT -- required when ready
status TEXT NOT NULL -- pending | ready | failed | cancelled
observed_url TEXT
observed_release_lineage TEXT -- required when ready; exact run candidate
observed_artifact_identity TEXT -- must match when the run pins an artifact
executor TEXT NOT NULL
executor_receipt TEXT
failure_reason TEXT -- required when failed or cancelled
created_at TEXT NOT NULL
completed_at TEXT -- required when ready
UNIQUE(run_id, stage_name, attempt_number)
UNIQUE(run_id, stage_name, correlation_id)
The attempt number, rather than row insertion order, determines the current
observation. A repeated correlation is accepted only with identical immutable
dispatch inputs, and a terminal callback cannot change its evidence. Scoped QA
consumes only the latest ready attempt from the QA target's earlier
source_stage, with the exact target and release lineage and, when the run pins
one, the exact artifact identity. A delayed older success cannot override a
newer failure, and a superseded receipt cannot revalidate an accepted execution
or later-stage prerequisite. Run-preview readiness requires an observed URL;
command-only persistent environments do not.
Who fills those observed columns is a per-target-kind decision,
registered in deploy_pipeline_stage_receipt_producers.RECEIPT_PRODUCERS.
Each producer takes one ProducerContext (the stage, its QA target, the
run and stage names, the project, the dispatch correlation id and the
dispatch callable) and returns a StageObservation: target name,
observed release lineage, optionally an observed URL and artifact identity. The
step runner's diagnostic travels to executor_receipt instead, so a producer
that reads a served URL and commit back reports them structurally rather than
encoding them in one string. An empty observed-identity column is not a gap to
fill with whatever string is at hand — the store compares observed against
pinned, so an invented value refuses the receipt, and a run pinning an artifact
identity no producer reads back is refused before the stage dispatches. The
registry's key set is the supported-target-kind list.
Release verification — how release-to-done reads both QA authorities and who observes a stage receipt — lives in release authorities. Human verdict notices reach the waiting agent; settled QA results and owner delivery notices live in release notices.
Table: deployment_run_timings
Release phase timings: the start/end Deployment start timing: records each
run-scoped driver timing scope stores through deployment_runs.timings.record
at each pipeline stage and when it closes. Read them with yoke deployment-runs timings RUN-ID. They are
diagnostics; nothing operational reads them, and a refused write never fails
the run (see deployment start).
id INTEGER PRIMARY KEY
run_id TEXT NOT NULL REFERENCES deployment_runs(id)
batch_id TEXT NOT NULL -- one driver timing scope
sequence INTEGER NOT NULL -- record order within the scope; a retried flush inserts nothing twice
step TEXT NOT NULL
phase TEXT NOT NULL -- start | end
recorded_at TIMESTAMPTZ NOT NULL -- the driver clock's record timestamp
elapsed_ms DOUBLE PRECISION -- end records only
outcome TEXT -- end records only: ok | failed
record TEXT NOT NULL -- the full JSON record as the driver wrote it
UNIQUE(batch_id, sequence)