Skip to main content

ScenarioStep

Type Alias ScenarioStep 

Source
pub type ScenarioStep = ScenarioNode;
Expand description

Legacy alias.

Aliased Type§

pub enum ScenarioStep {
    Phase(String),
    Comprehension {
        comprehension: Comprehension,
        children: Vec<ScenarioNode>,
        continue_if: Option<ContinueIfSpec>,
        anchor: Option<String>,
    },
    DoWhile {
        condition: String,
        counter: Option<String>,
        children: Vec<ScenarioNode>,
    },
    DoUntil {
        condition: String,
        counter: Option<String>,
        children: Vec<ScenarioNode>,
    },
    IncludedScenario {
        name: String,
        children: Vec<ScenarioNode>,
    },
    Bindings {
        source: String,
        children: Vec<ScenarioNode>,
    },
}

Variants§

§

Phase(String)

A single phase to execute.

§

Comprehension

Iteration node — single-clause for_each, multi-clause for_combinations, or for_each_union all map here. The Comprehension AST captures the iteration shape; the runtime executes the cross-product of clauses for the Cartesian mode and the concatenation of sub-spaces’ products for Union mode.

YAML forms (all normalize to this variant):

# Single clause
- for_each: "k in 10,100"

# Multi-clause cross product
- for_each: "profile in profiles, k in {k_values}"

# Multi-clause cross product (map form)
- for_combinations:
    profile: "matching_profiles('{dataset}', '{prefix}')"
    k: "{k_values}"

# Union of sub-spaces
- for_each:
  - "k in 10, limit in 10,20,30"
  - "k in 100, limit in 100,200,300"

Fields

§comprehension: Comprehension
§children: Vec<ScenarioNode>
§continue_if: Option<ContinueIfSpec>

SRD-101 — optional continue_if pre-entry gate bounding this sweep: evaluated per iteration before the body; a false predicate halts the sweep at its each scope, gracefully.

§anchor: Option<String>

SRD-109 — table-row anchor: anchor: <view> declares one report-table row per iteration of this sweep, in the view of that name. Views sharing a name must share coordinate label sets. Key metrics designated on phases beneath this node attach to its rows.

§

DoWhile

Execute children while condition is true (test after).

Fields

§condition: String
§counter: Option<String>
§children: Vec<ScenarioNode>
§

DoUntil

Execute children until condition becomes true (test after).

Fields

§condition: String
§counter: Option<String>
§children: Vec<ScenarioNode>
§

IncludedScenario

Logical inclusion of another scenario by name.

Wherever this node appears (top-level of a scenario, inside a phases: list under a for_each / for_combinations / for_each_union, etc.), it expands to the children of the named scenario at execution time. The wrapper is preserved (not flattened) so the scope tree retains the include hierarchy and the renderer can show the operator which scenario each group of phases came from.

Resolution happens once after parsing (see crate::parse::resolve_scenario_includes); cycles (A includes B includes A) are rejected with a clear error naming the cycle path.

YAML form:

scenarios:
  smoke:
    - schema
    - rampup
  bench:
    - scenario: smoke
    - for_each: "k in 10,100"
      phases:
        - scenario: smoke
        - search

Fields

§name: String
§children: Vec<ScenarioNode>
§

Bindings

Scenario-tree-level Polydat bindings block — the canonical way to introduce a scope-local layer of bound names anywhere in the scenario tree.

source is Polydat matter text exactly as a phase-level bindings: block would contain. Anything the Polydat grammar accepts is valid: const NAME := <literal>, derived bindings (scaled := mul(workload_limit, 2)), shared cells, init bindings, etc. Workload-param {name} and string-interpolation references resolve through the scope chain at kernel build time — no separate preprocessing pass.

Bindings is also the canonical lowered form of set:. The parser recognizes set: { name: value, ... } as syntactic sugar and emits a Bindings node whose source is final <name> := <polydat-literal>\n (one line per pair, declaration order preserved). So

- set: { mode: verbose }
  phases:
    - announce

is semantically identical to

- bindings: |
    const mode := "verbose"
  phases:
    - announce

Both produce one Bindings node. Authors keep the short set: form for the common override case; the long form unlocks the full Polydat grammar (derived bindings, expressions referencing other in-scope names, etc.) without any new variant.

Lexical-shadow semantics are uniform with phase-level bindings:: a const NAME := <value> shadows any upstream binding for NAME over this node’s children subtree. The shadow is enforced via the local-final transit-suppression rule in materialize_wiring_from_outer — the same mechanism every other scope uses.

Composition example (two siblings, each defining its own value for the same name; the included subtree is physically cloned per include site so encapsulation is per-instance):

scenarios:
  fanout:
    - set: { mode: verbose }
      phases:
        - scenario: load_test
    - set: { mode: quiet }
      phases:
        - scenario: load_test

Fields

§source: String
§children: Vec<ScenarioNode>