14 KiB
#region ScenarioExecution.Spec [C:3] [TYPE ADR] [SEMANTICS spec,requirements,scenario,execution,run,step,engine]
@BRIEF First-class ScenarioRun/ScenarioStepRun execution engine that walks a validated DashboardTestScenario DAG and dispatches each step to a typed executor, with run lifecycle, cancellation, retry, timeout, and human-checkpoint pause/resume. The most critical missing piece — a scenario can be created but not executed.
@RELATION DEPENDS_ON -> [Doc.Adr.ADR0001]
@RELATION DEPENDS_ON -> [Doc.Adr.ADR0003]
@RELATION DEPENDS_ON -> [AgentTestStabilization.Spec]
@RELATION DEPENDS_ON -> [SupersetBaselineEngine.Spec]
@RELATION DEPENDS_ON -> [ScenarioRegistry.Spec]
@RELATION DEPENDS_ON -> [DashboardScenarioModel.Spec]
@RATIONALE 038 generates an immutable Verification Program IR. A ScenarioRun is a first-class entity independent of AgentRun and VerificationRun. Orchestration and deterministic program executors remain deterministic; a revision may additionally declare bounded AgentEvaluation steps whose typed outputs are resolved by DecisionPolicy, never by free-form orchestration.
@REJECTED Agent-orchestrated step execution — rejected because each step would be an LLM call and could rewrite program flow. Explicit versioned AgentEvaluationSpec inside a deterministic step boundary is allowed.
@REJECTED Reusing AgentRun as the execution run — rejected because AgentRun is the creation-process run; ScenarioRun is the created-test execution. Reusing VerificationRun — rejected because it is release-pipeline category verification, not arbitrary-DAG execution.
@REJECTED human as a dispatched executor — rejected; it is a runner-lifecycle suspend/resume control primitive, not a side-effect executor.
Navigation (DSA Indexer keywords)
@SEMANTICS: spec, requirements, feature, scenario, execution, run, step, runner, engine, resume, human
Feature Branch: 044-dashboard-scenario-execution
Created: 2026-08-07 | Status: Draft
Input: "Provide a Scenario Execution Engine: a deterministic runner that walks the validated DashboardTestScenario graph, dispatches each step by tool to a typed executor (browser, superset_api, xlsx, assertion, screenshot, report, artifact), and manages the run lifecycle (queued, running, waiting_human, blocked, cancel, retry, timeout, resume, passed, failed, inconclusive) with immutable execution snapshots pinned to a scenario revision."
User Scenarios
Story 1 — Start a Scenario Run (P1)
Why P1: Users must be able to run a saved scenario against an environment with pinned revision and parameters.
Independent Test: Start a run from a registry scenario + params and verify a ScenarioRun is created with the exact revision, environment, and parameter snapshot.
Acceptance:
- Given a saved scenario with params When "Run" is submitted Then a ScenarioRun is created pinned to
scenario_id+revision_id+content_hash, environment, and parameter snapshot. - Given the runner starts When execution begins Then the run derives RunnerPlan, preflights, and transitions through queued → running.
- Given a PROD environment When start is requested Then the service creates
ScenarioRun(pending_approval)plus an ActionApprovalGate before any step executes; approval queues it and denial/expiry blocks it.
Story 2 — Execute Steps Deterministically (P1)
Why P1: The core value — running the checks.
Independent Test: Execute a fixture scenario with browser/superset/xlsx/assertion/screenshot steps and verify each step dispatches to the correct executor and records a ScenarioStepRun.
Acceptance:
- Given the runner walks the DAG in topological order When each step is reached Then
ScenarioStep.Dispatchroutes by the version-pinned 038 ActionRegistry to a typed executor (browser→BrowserExecutor/Playwright, superset_api→037, sql_evidence→Superset SQL Lab adapter, transform/assertion→bounded 038 program engines, agent_evaluation→bounded evaluation adapter, xlsx→parser+norm, screenshot→ScreenshotService). - Given a step produces an output ref When a dependent step consumes it Then the ref is bound from the producer's outputs.
- Given a step fails When execution continues Then dependents are blocked per failure policy and the run records the failure.
Story 3 — Pause at Human Checkpoint and Resume (P1)
Why P1: Human checkpoints must suspend the run without losing state.
Independent Test: Reach a human step and verify the run pauses (waiting_human), persists step state, and resumes from the correct point after disposition.
Acceptance:
- Given a
humanstep is reached When the runner executes Then the run sets statuswaiting_human, persists the ScenarioStepRun as paused, creates a HumanCheckpoint (confirm/false_positive/inconclusive — NOT a 036 ApprovalGate) with evidence context, and stops advancing the DAG. - Given a human decision (confirm/false-positive/inconclusive) When submitted with its checkpoint version Then an atomic CAS consumes the checkpoint, records the outcome, and internally resumes dependents.
- Given a page reload mid-wait When reopened Then the run status, waiting step, and gate are recoverable by
scenario_run_id.
Story 4 — Cancel, Retry, Timeout (P2)
Why P2: Operational control over runs.
Independent Test: Cancel a running scenario, retry a failed step, and simulate a timeout; verify terminal states and step attempts.
Acceptance:
- Given a user requests cancel When submitted Then the run enters
cancel_requested, drains in-flight steps within a bounded window, and terminatescancelled. - Given a step fails When retry is requested Then a new attempt runs with bounded attempts and updated
attemptcount. - Given a step exceeds its timeout When triggered Then the step is marked failed/inconclusive with a timeout reason, and the run continues per policy.
Story 5 — Immutable Execution Snapshot (P2)
Why P2: Results must be reproducible regardless of later edits.
Independent Test: Run a scenario, then edit it, and verify the earlier run's results reference the original revision.
Acceptance:
- Given a run started When the scenario is later edited Then the run's
revision_id+content_hashsnapshot is unchanged. - Given results are stored When queried Then they include provenance (revision, runner_version, template_version, baseline_revision, environment, parameter snapshot).
Edge & Failure Cases
| # | Scenario | Category | Expected Behavior | Recovery |
|---|---|---|---|---|
| E1 | PROD run without approval | auth/gate | Durable pending_approval run + gate, no dispatch |
Approve via ActionApprovalGate |
| E2 | Step timeout | execution | Step failed/inconclusive with reason | Retry / continue |
| E3 | Retry exhausted | execution | Step failed; dependents blocked | Triage (047) |
| E4 | Superset 5xx/403/422 | integration | Typed error taxonomy preserved | Retry / continue |
| E5 | Runner crash mid-run | resilience | API/XLSX steps resume only if retry-safe; browser state replays from last browser-safe checkpoint | Recover / replay |
| E6 | Cancel mid-step | concurrency | In-flight completes or times out in drain window | — |
| E7 | Duplicate output ref | data-integrity | 038 validator rejects before run | Fix graph |
| E8 | Stale scenario run (registry) | data-quality | Warning-gated or blocked per policy | Revalidate |
Requirements
Functional
- SCEX-FR-001: A ScenarioRun MUST be a first-class entity pinned to
scenario_id(UUID) +revision_id(UUID) +content_hash, environment, parameter snapshot, and optionalagent_run_id/verification_run_idprovenance. - SCEX-FR-002: The runner MUST walk the DAG in topological order and dispatch each step only through the version-pinned 038 ActionRegistry. Browser, Superset API/SQL Lab, XLSX, bounded transform/assertion, screenshot, report and artifact executors are typed; unknown
{tool,action}is rejected. - SCEX-FR-003: Scenario orchestration MUST be deterministic and MUST NOT generate/rewrite SQL, DSL, assertions, graph or executor order at runtime. A declared AgentEvaluationSpec MAY run inside its bounded step contract; it is not agent-per-step orchestration.
- SCEX-FR-004: A
humanstep MUST suspend the run (statuswaiting_human), persist full HumanCheckpoint state (eligibility, evidence, expiry, CAS decision version), and internally resume dependents after its one-time disposition. HumanCheckpoint is distinct from ActionApprovalGate. - SCEX-FR-004a: A revision containing a
humanstep MUST bemanual_run_only. Scheduled, trigger, deploy, ETL and API execution are rejected before run creation; a HumanCheckpoint is never skipped to obtain an automatic PASS. - SCEX-FR-005: The lifecycle MUST include pending_approval, queued, running, waiting_human, blocked, cancel_requested, cancelled, passed, failed, inconclusive; cancel drains in-flight within a bounded window.
- SCEX-FR-006: Steps MUST support attempt counts, retry policy, per-step timeout, input/output ref binding, artifact_refs, and error_code.
- SCEX-FR-007: A ScenarioRun MUST be recoverable by
scenario_run_id; browser recovery MUST reconstruct state from a declared browser-safe checkpoint, not continue a dead Playwright context. Results MUST carry target and execution-principal provenance. - SCEX-FR-008: PROD-classified environments MUST require an ActionApprovalGate before execution.
- SCEX-FR-009: Executors MUST reuse 037 (metric_executor/comparison), 038 (capture), 036 (evidence/artifacts/HITL), and existing browser/xlsx infra; a second Playwright/LLM/SQL stack is forbidden.
- SCEX-FR-010:
humanis a runner-lifecycle control, not a dispatched executor; the executor registry covers the other seven tools. - SCEX-FR-011: Failed, inconclusive and blocked runs MUST emit idempotent 036 InvestigationSignals carrying immutable run/evidence provenance; 047 creates/updates the Queue/Episode. They MUST NOT automatically start a chat, an AgentRun, or a remediation action.
- SCEX-FR-012: An opened InvestigationCase MAY use the agent to construct diagnostic runs and controlled experiments under delegated policy. Agent work cannot bypass executor contracts, runner lifecycle, capacity, mutation policy or a required ActionApprovalGate; declared AgentEvaluationSpec is the only permitted runtime reasoning boundary.
- SCEX-FR-013: A HumanCheckpoint remains a manual-run-only analyst decision. The agent may summarize evidence but MUST NOT consume the checkpoint, choose its disposition, or turn it into scheduled automation.
- SCEX-FR-014:
SqlEvidenceExecutorMUST execute exactly the immutable 038 SqlEvidenceSpec through Superset backend/SQL Lab with pinned database identity, ExecutionPrincipal and RLS/security fingerprint. Runtime only supplies typed ParameterBindings and may not alter SQL, relation, projection, JOIN or WHERE. - SCEX-FR-015:
AgentEvaluationMUST be a separate immutable runtime record and DecisionPolicy MUST deterministically map it plus deterministic evidence to StepOutcome. A bare model verdict never directly sets ScenarioResult. - SCEX-FR-016: Browser actions and mutation safety MUST use the same versioned 038 ActionRegistry/mutation contract. Mutating browser steps in PROD are prohibited; test-data mutation needs fixture scope, record keys, side-effect/retry and cleanup policy independent of PROD approval.
Key Entities
- ScenarioRun: Recoverable execution instance of a pinned scenario revision; owns status, phase, params, provenance, steps.
- ScenarioStepRun: One step execution attempt/record: status, attempt, timing, inputs/outputs, artifact_refs, error_code, progress.
- RunnerPlan: Deterministically derived at run start from ScenarioRevision + ParameterBinding + TargetSnapshot + baseline/runtime policy.
runner.plan.jsonis diagnostic/reference materialization only. - ScenarioExecutorRegistry: Mapping of
step.tool→ typed executor;humanexcluded (lifecycle control). - ScenarioExecutionResult: Aggregated run result with pass/fail/inconclusive per step and provenance.
Success Criteria
- SC-001: A fixture scenario runs end-to-end, dispatching every step to the correct executor, in deterministic order.
- SC-002: Human checkpoint suspends the run and resumes from the exact next step without rerunning completed steps.
- SC-003: 100% of cancel requests terminate with
cancelledand bounded drain. - SC-004: Runs are recoverable by
scenario_run_idafter disconnect. - SC-005: Results reference an immutable revision snapshot + full provenance; editing the scenario after a run never changes that run's results.
- SC-006:
humanis not invoked as an executor; PROD runs are gated.
Clarifications
Session 2026-08-07
- Q: Is the agent the runner? → A: No. The backend runner orchestrates deterministically. The agent authors before/after runs and may reason only inside a declared bounded AgentEvaluationSpec.
- Q: Is human an executor? → A: No. It is a runner-lifecycle suspend/resume control; the executor registry covers browser/superset_api/xlsx/assertion/screenshot/report/artifact.
- Q: How does this differ from VerificationRun/AgentRun? → A: ScenarioRun executes the user-created DashboardTestScenario DAG; AgentRun is the creation run; VerificationRun is release-pipeline category verification. Three distinct run concepts.
Implementation Status & MVP Debt (audit 2026-08-07)
Facts (code check):
- 🔴 No ScenarioRun/ScenarioStepRun model or runner exists;
runner.plan.jsonis a stub{scenario_id, revision_id, step_count}(and is a reference artifact only — the RunnerPlan is derived at run start). - 🔴 No executor registry or dispatch;
execute_step/ScenarioStep.*executegrep = empty. - ✅ Executors to reuse already exist: 037
metric_executor_async/comparison.py, 038capture.py, 036 evidence/artifacts/HITL, 040 RunnerPool pattern.
#endregion ScenarioExecution.Spec