Run Lifecycle Reference
Every execution on QubitHub is a Run row: a database record that tracks one circuit-execution attempt from submission to terminal state. This page documents the lifecycle so you can answer “what’s happening to my run right now?” and (if you’re a privacy-aware user) “what does QubitHub record about my executions?”.
State machine
Section titled “State machine”A run moves through these states:
pending → running → completed ↓ → failed ↓ → cancelled| State | What it means |
|---|---|
pending | Run was created (POST /runs returned 201) but the executor hasn’t picked it up yet |
running | The Dagster executor has the run; the circuit is being prepared or executed in the sandbox |
completed | Terminal — execution succeeded and results were written. Stays in this state forever |
failed | Terminal — execution failed at some stage. error_class + error_message carry the cause. Stays in this state forever |
cancelled | Terminal — the user cancelled the run before it reached a terminal state |
Each transition is recorded in the audit log and emits a server-side analytics event. Both happen in the same database transaction as the state change, so analytics and audit are guaranteed consistent with the actual run state.
Audit log
Section titled “Audit log”State transitions write to the audit_logs table via the platform’s log_run_transition helper. The audited actions are:
| Action | Fires on |
|---|---|
run.started | pending → running |
run.completed | running → completed |
run.failed | running → failed (covers both execute-stage and storage-stage failures) |
Each audit row carries:
actor_user_id— who owns the run (server-side, not client-claimed)action— one of the three aboveresource_type = "run",resource_id = <run UUID>metadata— JSON blob with the transition-specific context (framework, backend, error class on failures, etc.)created_at— server-side timestamp
The audit log is the source of truth for reconstructing what happened to a stalled or surprising run — gh query the run ID, get the full transition timeline.
Server-side analytics
Section titled “Server-side analytics”A parallel set of events fires via the platform’s services/posthog_server.py capture helper. These are canonical for operational reliability dashboards (completion rate, framework-level error rate, queue-depth proxies) — distinct from the user-action funnel which still uses the client-side circuit_executed event.
| Event | Fires on | Stage |
|---|---|---|
run_requested | POST /runs returns 201 | Submission |
run_started | execute_circuit_op flips status to running | Execute begins |
run_completed | store_results_op writes results and flips status to completed | Terminal — success |
run_failed | Any op flips status to failed | Terminal — failure |
Each event carries run_id, circuit_id, framework, backend_class / backend_name, and stage-specific fields like execution_time, shots, unique_states (completed), or error_class, stage (failed).
run_viewed_shared_link is a separate client-side event that fires when a run-detail route mounts — dedup’d per runId so refreshes don’t inflate.
For the full canonical event schema, see docs/architecture/POSTHOG_EVENTS.md in the repository.
Consent gating
Section titled “Consent gating”Analytics capture is gated on your consent at submission time:
- The frontend sends
X-Analytics-Consent: granted|deniedon POST/runs, defaulting to denied unless the cookie-consent banner has been accepted. - The router stamps the decision onto the run row as
Run.analytics_consent(Boolean, nullable for legacy runs). - The background Dagster ops read
Run.analytics_consentand short-circuit the PostHog capture if it’s notTrue.
This means: revoking consent on the cookie banner stops new runs from being captured — old runs that were captured under prior consent remain in PostHog (you can request deletion via support@qubithub.co under GDPR Article 17). Per-run consent stamping is on the GDPR-compliant default-deny side per EDPB Guidelines 5/2020.
The audit log is not consent-gated — it’s the platform’s record of what happened to its own resources, kept for security and debugging. It records actor_user_id (your account) but not client telemetry like browser fingerprint or IP.
What gets stored on the run row
Section titled “What gets stored on the run row”A run row contains:
| Field | What it is |
|---|---|
id | Run UUID — the public URL slug at /<owner>/<circuit>/runs/<id> |
user_id | The user who submitted (always your account, even on someone else’s public circuit) |
circuit_id + circuit_version | What was executed |
status | Current state (see above) |
backend_type / backend_name | What you asked for |
framework | Resolved from the circuit’s manifest |
shots | Number of repetitions requested |
results | Outcome counts, execution_time, unique_states, etc. (only populated on completed) |
error_class + error_message | Populated on failed. Class is one of six taxonomy values; see Troubleshooting → Run failure error classes |
analytics_consent | True / False / NULL (legacy) — controls server-side capture only |
created_at, started_at, completed_at | Server-side timestamps |
Public-circuit runs can be viewed by anyone with the URL (the run page does not expose the submitter’s identity to anonymous visitors beyond what’s on the run-page badges). Private-circuit runs are 404 to anyone except the circuit owner.
Debugging a stalled run
Section titled “Debugging a stalled run”If a run sits in running longer than expected:
- Check the run page — the badge shows the current state and the framework / backend being used
- The dagster-stranded-runs health monitor at
/api/health/dagster/runsreports counts of runs that have beenrunningpast their expected window. Public endpoint, returns JSON. - If a run is stuck and never reaches a terminal state, Submit Feedback with the run URL — the audit log + Sentry trace are keyed by run ID and let us reconstruct the failure path
The platform also runs a recovery sweep that catches runs stranded past their TTL and flips them to failed with a synthetic internal_error class. So a truly orphaned run is a bug, not a forever-stuck state.
Related
Section titled “Related”- Troubleshooting → Run failure error classes — what each
error_classvalue means - Privacy Policy — full data-flow including analytics + audit retention
docs/architecture/POSTHOG_EVENTS.md— canonical event schema for both client- and server-side captures