Skip to main content

WorkloadPhase

Struct WorkloadPhase 

Source
pub struct WorkloadPhase {
Show 28 fields pub cycles: Option<String>, pub concurrency: Option<String>, pub rate: Option<String>, pub daemon: bool, pub adapter: Option<String>, pub errors: Option<String>, pub tries: Option<u32>, pub tries_backoff: Option<BackoffSpec>, pub interval: Option<String>, pub repeat: Option<u64>, pub error_rate_max: Option<f64>, pub timeout: Option<String>, pub stop_when: Vec<StopConditionSpec>, pub throttle: Option<ThrottleField>, pub tags: Option<String>, pub ops: Vec<ParsedOp>, pub for_each: Option<String>, pub continue_if: Option<ContinueIfSpec>, pub loop_scope: Option<String>, pub iter_scope: Option<String>, pub checkpoint: Option<Checkpoint>, pub status_metrics: Vec<String>, pub bindings: BindingsDef, pub metrics: HashMap<String, MetricSpec>, pub dimensions: BTreeMap<String, DimensionSpec>, pub poll: Option<PhasePollSpec>, pub optimize: Option<OptimizeBlock>, pub key_metrics: Vec<KeyMetric>,
}
Expand description

A workload phase: runs as a separate Activity with its own cycle count, concurrency, rate limit, and op selection.

Fields§

§cycles: Option<String>

Number of stanzas for this phase. Each stanza executes all ops in sequence once. String type to support Polydat constant references like "{train_count, dimensions: Default::default(),}". Default 1 (one stanza).

§concurrency: Option<String>

Concurrency (async fibers). String type to support Polydat constant or workload param references like "{concurrency}". Default 1.

§rate: Option<String>

Rate limit (ops/sec). A number, or a {param} / iter-var reference resolved at the phase gather (the SRD-83 timeout: discipline: a rate that cannot be resolved fails the phase up front — it never silently becomes “unrated”). Default unlimited.

§daemon: bool

SRD-82 Part 6 — daemon phase. When true, this phase runs CONCURRENTLY with its foreground sibling phases (off the scenario’s foreground concurrency budget) and is stopped cooperatively when the scope’s foreground phases complete (a background “daemon unit” at the phase shell). Its own scope gives it an independent cursor base. Pair with an open-extent cursor (e.g. until_elapsed) so it runs for the foreground’s duration.

§adapter: Option<String>

Adapter override for this phase.

§errors: Option<String>

Error routing spec override.

§tries: Option<u32>

Total-attempts budget for this phase’s ops. tries: is the SIGIL for the conditional tries wrapper (SRD-82 Part 3b): when NO budget resolves anywhere in scope (op field, this phase field, the workload-root tries param, or an in-scope tries wire), the wrapper is not constructed and the op runs single-attempt. 1 = the same single-attempt behaviour, explicitly (shadows an inherited budget); 0 = ops FAIL WITHOUT EXECUTING; N ≥ 2 = up to N total attempts on adapter-retryable errors (CQL timeouts/overloads). None = inherit.

§tries_backoff: Option<BackoffSpec>

Retry-backoff overrides parsed from the map form of tries: (tries: {count: N, backoff: {ratio, min, max}}). None when the sugared numeric form was used (or tries absent) — the wrapper then falls back to the op’s standalone retry_backoff* params or the built-in defaults (ratio 2.0, min 100ms, max 10s). See BackoffSpec.

§interval: Option<String>

SRD-82/92 cross-level wrapper (scoping P0) — phase-execution pacing. interval: is the discriminator for a future WrapperLevel::Phase interval wrapper: re-run this phase, sleeping interval between runs. A raw duration string (e.g. "5m"), parsed at wrap time by the runtime. Declarative today — the phase-level cascade that consumes it is not built yet (see docs/cross-level-wrapper-cascade-scope.md).

§repeat: Option<u64>

Bound for interval — how many times to run the phase. None alongside interval = repeat until the session stops.

§error_rate_max: Option<f64>

OPT-IN error-rate circuit breaker (e.g. 0.1 = fail this phase once >10% of its ops error, after a 50-op floor). Overrides a session-wide error_rate_max= param when one was set. There is NO built-in default (SRD-82 §“AggregateGuard retired as a default”) — aggregate health belongs to visible stop_when: conditions; this field exists as an explicit shorthand only.

§timeout: Option<String>

SRD-83 governance timeout (GAP-12). A duration ("2.5h", "150ms", bare fractional seconds) or a {param} reference; on expiry the phase ends Interrupted+Failed with reason class timeout — the protocol OUT-OF-RANGE disposition: the system is disqualified at this tier, the partial result is not usable. Desugars at the phase gather into a synthesized, logged elapsed_ms > stop condition (the error_rate_max precedent). Distinct from a BUDGET: a clean time-boxed measurement is a bounded cursor or a stop_when … effect: stop (Interrupted+Succeeded), not this.

§stop_when: Vec<StopConditionSpec>

SRD-83 — stop conditions for this phase shell. Each is a polydat predicate over runtime-state wires, plus a firing trigger and an effect. Evaluated at triggers; a true predicate stops the phase with its effect.

§throttle: Option<ThrottleField>

SRD-83 §throttle — adaptive backpressure governor: keep the windowed attempt-failure fraction under a bound by walking a dynamic control (concurrency/rate) down under overload and back up on recovery. throttle: true = defaults.

§tags: Option<String>

Tag filter to select ops from blocks (e.g., "block:schema").

§ops: Vec<ParsedOp>

Inline ops for this phase (parsed into ParsedOp list).

§for_each: Option<String>

Phase template iteration: "var in expr". The phase is instantiated once per element of the Polydat expression result (which must be a comma-separated string). Each instance has {var} available as a workload param in its ops and config.

Example: for_each: "profile in matching_profiles('{dataset}', '{prefix}')"

§continue_if: Option<ContinueIfSpec>

SRD-101 — optional continue_if pre-entry gate bounding this phase’s for_each sweep (see ContinueIfSpec). Ignored when for_each is absent (no sweep to bound).

§loop_scope: Option<String>

Loop scope mode for for_each phases.

Controls how the loop context is seeded from the outer scope:

  • clean (default): snapshot of outer scope at loop entry
  • inherit: outer scope’s live state (includes prior phase mutations)
§iter_scope: Option<String>

Iteration scope mode for for_each phases.

Controls how each iteration is seeded from the loop scope:

  • inherit (default for for_each): each iteration starts from the loop scope’s current state. All loop-level variables are implicitly shared with iterations, so iteration N+1 sees what N wrote.
  • clean: each iteration starts from the loop scope snapshot (isolated)
§checkpoint: Option<Checkpoint>

Summary report configuration for this phase. Checkpoint declaration: skip-on-resume eligibility plus optional sub-properties (hashing, verify op). None = no declaration = phase always re-runs on resume. See SRD-44 §“Eligibility — checkpoint: per-phase declaration”.

Parsed via Checkpoint’s custom deserialize from the three YAML forms (short string, disabled string/bool, full mapping).

§status_metrics: Vec<String>

Names of metrics to surface on the inline progress line and the per-phase ✓ DONE summary. Empty (default) → no extra metrics shown; the status line carries only the universal counters (pct, throughput, ok-rate, errors, retries, concurrency, duration).

Each name is matched against the live relevancy aggregates (recall_at_10, precision_at_10, …) by exact equality. Workloads that compute custom relevancy metrics list the names they want emphasized; nothing is presumed to be present.

Example:

phases:
  ann_query:
    status_metrics: [recall_at_10]
§bindings: BindingsDef

Phase-level Polydat bindings: block (SRD-13c, SRD-13d). Captured on the phase AST so the scope-tree pre-walk (SRD-13d §3) can classify phase-level Polydat content via crate::polydat_matter::HasPolydatMatter and so the runtime can compose a phase kernel layered between the workload kernel and any op-template kernels.

Today the parser ALSO merges this block into per-op bindings (legacy parse.rs::parse_phases behaviour) so the existing runtime keeps working unchanged. Once SRD-13d phases 3–9 land (per-template kernels with proper bind_outer_scope chaining through the phase kernel), the per-op merge is removed and ops resolve phase bindings via the Polydat scope chain.

§metrics: HashMap<String, MetricSpec>

Phase-level synthetic-metric declarations. Mirror of ParsedOp::metrics (same MetricSpec schema and YAML shapes), but evaluated once at phase completion against the phase scope kernel rather than per-cycle. Each entry’s value: is a Polydat expression over phase-scope wires (bindings, captures, params, iter-vars) plus the executor-injected phase_start wire (epoch millis at phase start). The canonical phase-duration metric reads a clock via a volatile phase binding and subtracts the injected origin:

bindings: |
  volatile now_ms := current_epoch_millis()
metrics:
  time_to_index: { value: now_ms - phase_start }

yielding the phase’s wall-clock duration in millis. Empty when absent. No dedicated clock node is needed: current_epoch_millis() is a single read, and phase_start arrives as plain data, so the expression re-evaluates correctly at the completion-time pull. Declaring the clock read as its own volatile binding (rather than nesting it in the metric value) explicitly acknowledges the non-deterministic node, so the phase kernel stays clean under --strict.

The synthesiser emits volatile __metric_<name> := <value> onto the phase kernel (see nmbrs_runtime::scope::synthesize_metric_binding_name); the executor pulls each at completion and records it on the phase component as the declared instrument (gauge by default).

§dimensions: BTreeMap<String, DimensionSpec>

Dimensions this phase introduces: label NAME → declaration.

Declared at the tier that owns the name, per the component tree’s label-ownership rule (a name is set on exactly one tier and inherited downward). Values are not enumerated — they arrive from data via a metric’s cell:.

BTreeMap for deterministic synthesis order: a coordinate’s rendering is what keys a cell, so an order that varied between runs would key one coordinate two ways.

§poll: Option<PhasePollSpec>

Phase-level poll spec — when present, the phase’s cycle execution runs in a wall-clock loop until a GK predicate over captures returns true. SRD-75.

The presence of this field carries semantics beyond the data: it forbids concurrency > 1 (serial-cycle loop is the unit of work), and it triggers scope-synthesis to allocate shared cells on the phase scope for capture names referenced by the predicate / if: conditions / metric values so cross-op visibility happens through the canonical Polydat chain (no sidecar HashMap; see SRD-75 §“Architectural shape”).

§optimize: Option<OptimizeBlock>

SRD-86 — when present, the executor dispatches the named optimizer over the phase: it writes each axis as an input wire on the phase’s binding kernel and reads the objective wire back (the objective is just a wire read). Workload-local config; nmbrs-runtime maps it to its optimizer contract and discovers the optimizer via the link-time registry (nmbrs describe optimizers).

Sugar: a bare string value is shorthand for { objective: <str> } with every other field defaulted (method: sweep, no servo:) — so optimize: "0 - err_rate" ≡ optimize: { objective: "0 - err_rate" }. See [de_optimize].

§key_metrics: Vec<KeyMetric>

SRD-109 — key-metric designations: key_metrics: {column: "agg(family)", ...}. Aggregate qualification is mandatory (no implied aggregates); the report synthesizer attaches these columns to the row of the phase’s nearest enclosing anchor, or the spine. Empty = spine-only via the SRD-91 instrument contract defaults.

Trait Implementations§

Source§

impl Clone for WorkloadPhase

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for WorkloadPhase

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for WorkloadPhase

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<'de> Deserialize<'de> for WorkloadPhase

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl HasPolydatMatter for WorkloadPhase

Source§

fn polydat_matter(&self) -> PolydatMatter

Classify this node’s contribution to Polydat content.
Source§

impl Serialize for WorkloadPhase

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.