Skip to content

Parameter Resolution

The workflow engine resolves task inputs, experiment configuration, snapshots, user overrides, and output persistence at different lifecycle stages.

The Frequency Parameter Policy specifies the agreed design for exploration and calibrated frequencies, derived drive frequencies, YAML export, and update UX. Its implementation gaps are tracked separately from the current lifecycle described here.

Parameter model contracts

BaseTask defines three symmetric declaration/runtime pairs:

CollectionModelMeaning
input_specInputParameterSpecResolution and override policy declared by the task class
input_parametersInputParameterModelValues resolved for one task instance
run_specRunParameterSpecExperiment configuration specified by the task class
run_parametersRunParameterModelEffective experiment configuration for one run
output_specOutputParameterSpecCalibration outputs declared by the task class
output_parametersOutputParameterModelCalibration values produced by one task instance

Every calibration input spec explicitly states its resolution and override policies through a named constructor:

python
input_spec = {
    "qubit_frequency": InputParameterSpec.required_database(
        unit="GHz",
    ),
    "readout_amplitude": InputParameterSpec.database_or_default(
        default=DEFAULT_READOUT_AMPLITUDE,
        unit="a.u.",
    ),
}

resolution has three explicit values:

  • database_required: use the database value and fail when it is absent.
  • database_or_default: prefer the database value and otherwise use default.
  • default_only: do not read this parameter from the database.

The constructors default to allowing user overrides; pass user_override="forbidden" when a task must prohibit them. A permitted user override has higher precedence than the selected baseline. The constructor's default is spec-time fallback data; the effective runtime value is stored separately in input_parameters as an InputParameterModel.

For coupling tasks, InputParameterSpec.parameter_name selects the database key and InputParameterSpec.qid_role selects control, target, or coupling data. Qubit tasks read from the selected qubit record.

Normal workflow execution

Task construction resolves Run parameters in this order, from highest to lowest precedence:

  1. Explicit task_details[task_name].run_parameters
  2. Task-specific entries in CalibConfig.task_run_parameters
  3. Legacy per-task entries in CalibConfig.default_run_parameters
  4. Shared entries in CalibConfig.default_run_parameters
  5. run_spec specified on the task class

Use default_run_parameters only for values intentionally shared by every declaring task. A shared value overrides task-specific defaults, including Qubex optimized defaults: qubit spectroscopy normally uses a 1024 ns interval and resonator spectroscopy uses 0 ns. Use task_run_parameters when a template should preserve or configure one named task. Nested entries in default_run_parameters remain readable only for existing flow documents.

readout_duration is session-scoped in Qubex. QDash passes the shared value when constructing the Experiment, records the effective value on each task that uses the session readout pulse, and rejects a per-task value that differs from the session. Qubex spectroscopy is an intentional exception: qubit/control spectroscopy uses its dedicated 1024 ns pulse and resonator spectroscopy uses its dedicated 8192 ns pulse, so those tasks do not expose the shared readout_duration parameter.

QubexTask.preprocess() then resolves each declared Input parameter:

  1. Follow the input spec's resolution policy.
  2. Produce an effective InputParameterModel for the task instance.
  3. Reapply an explicit user override when user_override="allowed".
  4. Reject an override when user_override="forbidden".

The effective Input and Run parameter models are recorded in task result history for provenance and later snapshot re-execution.

Execution-level parameter policy

The operation itself determines the baseline; no additional source selector is needed:

OperationCalibration input baselineRun parameter baselineOutput persistence default
Normal workflowCurrent DB, following task input specsTask/workflow specsEnabled
Tasks quick runCurrent DB, following task input specsTask specs and submitted overridesDisabled
Task re-executionSource task snapshotSource task snapshotExisting re-execution setting

This gives re-execution one stable meaning: reproduce the recorded execution conditions, optionally with explicit parameter overrides. Running the same task against current calibration state is a new Tasks quick run, not a re-execution mode.

user_override and persist_output_parameters remain independent policies. A permitted override has the highest precedence; choosing to persist new outputs does not change how inputs were selected.

A re-execution must not silently fall back to current database values. Such fallback would make it non-reproducible. Missing required snapshot data should fail with an actionable error; the operator can then start a new Tasks quick run against current state.

Model boundaries

Task classes declare immutable intent with InputParameterSpec, RunParameterSpec, and OutputParameterSpec. Each task instance receives the matching mutable runtime model: InputParameterModel, RunParameterModel, and OutputParameterModel. All three specs use default for their initial value and expose create_model() for the conversion.

The three runtime models may share persisted calibration metadata internally, but their distinct types keep input, run, and output roles visible at API boundaries and in type checking.

Snapshot re-execution

Re-execution behavior

For a single-task re-execution, CalibService passes source_task_id to SnapshotParameterLoader, which loads that exact task result. task_name and qid then validate that the selected history record matches the requested task. This avoids resolving an already identified task indirectly through its execution.

TaskExecutor applies parameters in this sequence:

  1. Construct the task from class and workflow defaults.
  2. Require a matching source snapshot and validate its declared Input coverage.
  3. Replace Input and Run collections with the snapshot and merged user overrides.
  4. Mark calibration Inputs as resolved, so preprocess() cannot refresh them from the database.
  5. Reapply only explicit user overrides.
  6. Run the experiment and record the resulting effective parameters.

The second override application preserves values computed during preprocessing while guaranteeing that explicit user input remains authoritative. The snapshot marker prevents preprocessing from replacing calibration inputs with current database values.

Calibration inputs are resolved before task preprocessing and passed as InputParameterModel values:

text
Execution request
  -> CalibrationInputResolver(operation context)
  -> Apply permitted user overrides
  -> Task.preprocess(resolved inputs)
  -> Task.run()

Task preprocessing may compute derived runtime values, but it must not independently change the selected point-in-time source. Database access for declared calibration inputs belongs to CalibrationInputResolver.

Effective-input validation

Numeric constraints such as greater_than and less_than belong to InputParameterSpec. The executor validates them after database or snapshot resolution and after user overrides, but before run().

Concrete task preprocess() and run() methods must treat Input and Run parameters as read-only. They must not repair an invalid value, replace it with a default, or otherwise change the effective parameter collections. A missing database value may select the specified default only when the input spec uses database_or_default(); a present but invalid database, snapshot, or override value fails execution.

For a single-task re-execution, a missing source_task_id, a mismatch between the selected result and the requested task, or incomplete declared snapshot inputs causes execution to fail instead of silently changing its baseline.

Single-task result re-execution

POST /task-results/{task_id}/re-execute invokes the system single-task-executor with the source execution and source task IDs. It accepts task-level overrides in this shape:

json
{
  "parameter_overrides": {
    "input": {"qubit_frequency": 5.1},
    "run": {"shots": 2000}
  }
}

The source task ID both selects the recorded parameter snapshot and links the child result to its parent. The source execution ID remains execution context; it is not used to re-identify the single source task.

This endpoint is available for API clients that require exact snapshot re-execution. The Tasks UI instead offers Run again, which uses the current task definition and prefills compatible values from the selected historical result.

Tasks page quick run

POST /tasks/{task_name}/execute also uses single-task-executor, but sets source_execution_id to None.

  • input_parameter_overrides becomes parameter_overrides.input.
  • run_parameter_overrides becomes an entry in task_run_parameters for the selected task.
  • A SnapshotParameterLoader is still created when Input overrides exist so they can be reapplied after preprocessing.
  • When source_task_id is supplied by Run again, it records provenance without restoring the source snapshot; the submitted form values and current task definition remain authoritative.
  • With no Input override, Qubex preprocessing loads current database values normally.

The Tasks page Reload action is client-side preparation only. It reads the selected qubit or coupling record and fills the form. The server treats every non-empty submitted field as an explicit override; it does not distinguish a typed value from a value inserted by Reload.

Output persistence

persist_output_parameters controls authoritative write-back. When false, task history, execution state, figures, raw data, and in-memory output processing still occur, but BackendSaver skips calibration database and backend parameter writes.

When persistence is enabled:

  • Qubit outputs update the qubit calibration repository.
  • Coupling outputs update the coupling calibration repository.
  • Successful qubit outputs are synchronized through the backend parameter updater.
  • Failed validation skips backend parameter updates unless force_update_params is true.

The API field update_params is passed to single-task-executor as force_update_params and also controls GitHub integration for that run. It does not replace persist_output_parameters; persistence must be enabled before output values can be written.

Implementation files

  • src/qdash/workflow/calibtasks/base.py
  • src/qdash/workflow/calibtasks/qubex/base.py
  • src/qdash/workflow/engine/orchestrator.py
  • src/qdash/workflow/engine/task/snapshot_loader.py
  • src/qdash/workflow/engine/task/executor.py
  • src/qdash/workflow/engine/task/backend_saver.py
  • src/qdash/workflow/service/calib_service.py
  • src/qdash/workflow/service/single_task_flow.py

Released under the Apache 2.0 License.