Core Concepts
devqubit treats each execution as a run — a complete, tracked experiment with enough context to:
reproduce what happened,
compare results across time / devices / SDKs,
debug failures (even partial ones),
gate changes in CI via verification policies.
Terminology
Run Record: lightweight metadata + user logs + pointers to artifacts (
devqubit.run/1.0schema).Artifacts: content-addressed blobs (SHA-256) stored in an object store.
UEC / ExecutionEnvelope: canonical, structured execution context produced by adapters (
devqubit.envelope/1.0schema).
How It Works
When you wrap a backend with run.wrap(), devqubit intercepts executions and automatically captures circuits, device state, and results. Manual logging (log_param, log_metric) is stored alongside. Everything flows into a content-addressed store for deduplication and integrity, with queryable metadata in a registry.
%%{init:{
"theme":"base",
"flowchart":{"curve":"basis","nodeSpacing":34,"rankSpacing":44,"htmlLabels":true},
"themeVariables":{
"fontFamily":"ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, Helvetica, Arial, sans-serif",
"fontSize":"14px",
"background":"#ffffff",
"textColor":"#0f172a",
"lineColor":"#94a3b8",
"clusterBkg":"#f8fafc",
"clusterBorder":"#cbd5e1",
"edgeLabelBackground":"#ffffff"
}
}}%%
flowchart TB
subgraph USER["User Code"]
direction TB
TRACK["with track(project) as run"]
LOG["log_param()<br/>log_metric()<br/>set_tag()"]
WRAP["backend = run.wrap(device)"]
EXEC["backend.run(circuit, shots=1000)"]
TRACK --> LOG
TRACK --> WRAP
WRAP --> EXEC
end
subgraph CAPTURE["Adapter automatic capture"]
direction LR
CAP_PRG["📄 Circuit"]
CAP_DEV["🔧 Device"]
CAP_RES["📊 Results"]
end
subgraph PERSIST["Storage"]
direction TB
ENV["ExecutionEnvelope"]
RR["Run Record"]
STORE[("Object Store<br/>content-addressed")]
REG[("Registry<br/>queryable index")]
ENV -->|artifact| STORE
RR --> REG
STORE -.->|refs| RR
end
subgraph TOOLS["Analysis"]
direction LR
DIFF["diff()"]
VERIFY["verify()"]
DIFF ~~~ VERIFY
end
EXEC --> CAPTURE
CAP_PRG --> ENV
CAP_DEV --> ENV
CAP_RES --> ENV
LOG --> RR
REG --> TOOLS
STORE --> TOOLS
linkStyle default stroke:#94a3b8,stroke-width:1.4
%% Subgraphy jako “sekcje” + białe karty w środku
style USER fill:#eff6ff,stroke:#2563eb,stroke-width:1.6,color:#0f172a
style CAPTURE fill:#fffbeb,stroke:#d97706,stroke-width:1.6,color:#0f172a
style PERSIST fill:#ecfdf5,stroke:#059669,stroke-width:1.6,color:#064e3b
style TOOLS fill:#f5f3ff,stroke:#7c3aed,stroke-width:1.6,color:#3b0764
classDef card fill:#ffffff,stroke:#cbd5e1,stroke-width:1.2,color:#0f172a;
class TRACK,LOG,WRAP,EXEC,CAP_PRG,CAP_DEV,CAP_RES,ENV,RR,DIFF,VERIFY card
classDef pill fill:#ffffff,stroke:#cbd5e1,stroke-width:1.2,color:#0f172a;
class STORE,REG pill
What Is Persisted Where?
Store |
Content |
Purpose |
|---|---|---|
Object store |
Immutable blobs by SHA-256 digest |
Deduplication, integrity, offline bundles |
Registry |
Run records (run_id, project, timestamps, fingerprints, artifact pointers) |
Queries, listing, baseline management |
Run
A run captures everything about a single experiment execution. Run records follow the devqubit.run/1.0 schema:
Category |
Description |
|---|---|
Metadata |
Project, timestamps, status, run name, adapter |
Parameters |
Configuration values via |
Metrics |
Numeric results via |
Tags |
String key-value pairs via |
Artifacts |
Programs (QASM/QPY), results, device snapshots, envelopes, notes |
Fingerprints |
Stable hashes for reproducibility and comparison |
Environment |
Python + packages (optional capture) |
Provenance |
Git commit/branch/dirty state (optional capture) |
Run Lifecycle
%%{init:{
"theme":"base",
"flowchart":{"curve":"basis","nodeSpacing":34,"rankSpacing":40,"htmlLabels":true},
"themeVariables":{
"fontFamily":"ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, Helvetica, Arial, sans-serif",
"fontSize":"14px",
"background":"#ffffff",
"textColor":"#0f172a",
"lineColor":"#94a3b8",
"clusterBkg":"#f8fafc",
"clusterBorder":"#cbd5e1",
"edgeLabelBackground":"#ffffff"
}
}}%%
flowchart LR
S((" ")) --> R[RUNNING]
R -->|success| F[FINISHED]
R -->|exception| X[FAILED]
R -->|interrupted| K[KILLED]
F --> E((" "))
X --> E
K --> E
linkStyle default stroke:#94a3b8,stroke-width:1.4
classDef ghost fill:#334155,stroke:#334155,color:#334155;
classDef running fill:#eff6ff,stroke:#2563eb,stroke-width:1.6,color:#0f172a;
classDef finished fill:#ecfdf5,stroke:#059669,stroke-width:1.6,color:#064e3b;
classDef failed fill:#fee2e2,stroke:#dc2626,stroke-width:1.6,color:#7f1d1d;
classDef killed fill:#fffbeb,stroke:#d97706,stroke-width:1.6,color:#7c2d12;
class S,E ghost
class R running
class F finished
class X failed
class K killed
Robustness guarantees:
Best-effort finalization — failures during finalization are recorded; the system still attempts to persist.
Content integrity — artifacts are addressed by digest; corruption is detectable.
Schema evolution — explicit
schemafield enables backwards-compatible readers.
Artifacts
Artifacts are immutable blobs stored by digest, enabling deduplication, caching, and integrity verification.
Role |
Description |
|---|---|
|
Circuit/program artifacts (QPY, QASM) — used for fingerprinting |
|
Raw SDK result payloads |
|
Raw backend properties (lossless capture) |
|
ExecutionEnvelope (UEC JSON) |
|
Compile/execute options, environment snapshots |
|
Notes, attachments |
Artifact ingestion enforces a maximum size (~20 MB default). For larger blobs, store a URI pointer or truncate with meta.original_digest marker.
Fingerprints
Fingerprints are stable hashes computed from run contents, excluding volatile fields (timestamps, job IDs).
Fingerprint |
Based on |
|---|---|
|
Program hashes (from UEC program snapshot) |
|
Device identity + stable snapshots |
|
Adapter + SDK + compile/execute config |
|
Combined fingerprint of program + device + intent |
Use fingerprints to detect what changed between runs — same program fingerprint means same circuit structure, even if run at different times.
Comparison and Verification
diff compares two runs across multiple dimensions: parameter/metric changes, program match (digest/structural/parametric), device drift (calibration deltas), and result distribution distance (TVD with optional bootstrap noise context).
verify checks a candidate run against a baseline with a policy: required equality constraints (params/program), and TVD thresholds (hard limit or noise-calibrated)
from devqubit.compare import diff, verify_baseline
# Compare two runs
result = diff("run_a", "run_b")
print(result.tvd, result.program.structural_match)
# CI verification
result = verify_baseline("candidate", project="bell")
assert result.ok