Files
ss-tools/specs/042-dashboard-scenario-registry/spec.md

13 KiB

#region ScenarioRegistry.Spec [C:3] [TYPE ADR] [SEMANTICS spec,requirements,scenario,registry,lifecycle,management] @BRIEF First-class persistence, catalog, and lifecycle management for user-created dashboard test scenarios — the missing "find / open / manage" layer after generation. @RELATION DEPENDS_ON -> [Doc.Adr.ADR0001] @RELATION DEPENDS_ON -> [Doc.Adr.ADR0002] @RELATION DEPENDS_ON -> [Doc.Adr.ADR0005] @RELATION DEPENDS_ON -> [DashboardScenarioModel.Spec] @RELATION DEPENDS_ON -> [DashboardScenarioUi.Spec] @RELATION DEPENDS_ON -> [DatasetLineageBlastRadius.Spec] @RATIONALE 038/039 cover scenario generation but not post-creation management; a scenario is currently an ephemeral agent-session artifact materialized to git, with no registry, list, detail, versions, or lifecycle status. Without a persisted source of truth, the editor (043) and runner (044) have nothing stable to read from. @REJECTED Treating a scenario as a git-file-only artifact without a registry — rejected because search/filter/ownership/status/stale-detection/versions need a queryable projection, and a UI without a registry would be a facade over nonexistent runtime (the exact anti-pattern 042 exists to prevent). @REJECTED Hard-deleting a scenario that has run history — rejected because audit trail and reproducibility must survive; the canonical lifecycle terminal is archive.

Navigation (DSA Indexer keywords)

@SEMANTICS: spec, requirements, feature, scenario, registry, lifecycle, catalog, revision, stale

Feature Branch: 042-dashboard-scenario-registry Created: 2026-08-07 | Status: Draft Input: "Provide a first-class Scenario Registry: persistent storage, list/search/filter, scenario detail, ownership, lifecycle statuses, immutable revisions, clone/archive, and stale detection driven by dashboard/lineage change. This is the source of truth consumed by the Scenario Editor (043) and Scenario Execution Engine (044)."

User Scenarios

Story 1 — Find a Saved Scenario (P1)

Why P1: After "Save" the user falls into a void; finding scenarios across dashboards is the entry point for edit and run.

Independent Test: Create a persisted scenario fixture and verify the registry list returns it with dashboard, status, last run, and health, filterable by search/dashboard/status.

Acceptance:

  1. Given scenarios are persisted When the registry opens Then each row shows name, dashboard, lifecycle status, validation status, last run, last successful run, health, and last modified.
  2. Given the user searches or filters When the query changes Then results filter by name/tags, dashboard, status, and owner without a full reload.
  3. Given no scenarios exist When the registry renders Then an empty state with a "Create scenario" CTA is shown.

Story 2 — Open a Scenario Detail (P1)

Why P1: Viewing one scenario as a first-class page (not a chat session) is required for edit, run, and versioning.

Independent Test: Open a scenario by id and verify the detail shows overview metadata, steps, parameters, baselines, revisions, runs, and artifacts tabs from the registry, not from agent events.

Acceptance:

  1. Given a scenario id When the detail page opens Then it renders Overview (status, revision, dashboard, coverage, automation split, last run) plus Steps / Parameters / Baselines / Runs / Revisions / Artifacts tabs.
  2. Given the frontend requests a scenario by id When it loads Then GET /dashboard-testing/scenarios/{id} returns the persisted graph (this route currently missing — 039 calls it but backend 404s).
  3. Given a scenario detail is open When data is stale Then a refresh banner with the newer version is shown, never a silent overwrite.

Story 3 — Version a Scenario With Immutable Revisions (P1)

Why P1: Reproducibility requires runs pinned to an immutable revision snapshot, not to a moving "current" state.

Independent Test: Resolve a persisted scenario and verify a new revision is created with parent link and that a run references the exact revision hash.

Acceptance:

  1. Given a scenario is edited When a new revision is saved Then scenario_id (UUID), revision_id (UUID), and parent_revision_id form a linked chain, and a candidate revision is created without advancing current_revision.
  2. Given a run starts When it references a scenario Then it pins scenario_id + revision_id + content_hash so later edits never change what was executed.
  3. Given revisions exist When the user requests a diff Then the change set between two revisions is returned (added/changed/removed).

Story 4 — Detect Scenario Staleness (P2)

Why P2: A scenario pins chart/filter/metric references; when the dashboard or lineage changes the scenario becomes stale and must be revalidated.

Independent Test: Feed a dashboard release diff / lineage change and verify affected scenarios transition to NEEDS_REVALIDATION with a listed reason.

Acceptance:

  1. Given a dashboard release removes a referenced chart When the registry recomputes staleness Then scenarios referencing it become NEEDS_REVALIDATION or BLOCKED with a reason.
  2. Given a lineage blast-radius change touches a scenario's dataset When evaluated Then the affected scenarios are flagged via 041 blast radius, not by blind rescan.
  3. Given a scenario is stale When the user runs it Then run is warning-gated (or blocked per policy), never silently executed against changed truth.

Story 5 — Manage Scenario Lifecycle (P2)

Why P2: Scenarios need explicit lifecycle states and operations (archive/restore/clone) with RBAC, and never destructive deletion of run history.

Independent Test: Perform clone, archive, and restore on a scenario and verify state transitions and RBAC enforcement.

Acceptance:

  1. Given the lifecycle states DRAFT/READY/STALE/DISABLED/DEPRECATED/ARCHIVED When transitions are requested Then only valid transitions apply and each is audit-logged.
  2. Given a scenario has run history When a user requests deletion Then the operation is archive (audit trail preserved), not hard delete; hard delete requires explicit admin scope and an empty-run guard.
  3. Given clone is requested When executed Then a new scenario with its own id, derived revisions, and cleared owner lineage is created from a snapshot.

Edge & Failure Cases

# Scenario Category Expected Behavior Recovery
E1 Scenario not found data 404 NOT_FOUND Navigate to list
E2 Concurrent edit on same revision concurrency 409 with current revision hash Reload / compare / discard
E3 Revision not found in chain data 404 for the revision Show revision history
E4 Stale scenario run attempted data-quality Warning-gate or block Revalidate / mark pending
E5 Blast-radius engine unavailable integration Staleness skipped with warning, never false-stale Retry / manual revalidate
E6 RBAC denied on archive/clone auth 403 permission_denied, no confirm control Contact admin
E7 Dashboard deleted while scenario references it data-integrity Scenario flagged orphan/blocked with reason Re-target / deprecate
E8 429 rate limit on list/query throttling Retry-After honored Wait and retry

Requirements

Functional

  • SCREG-FR-001: The system MUST persist scenarios as a first-class entity in a scenario_registry projection (scenario_id, revision, dashboard, environment compatibility, owner, tags, lifecycle status, validation status, last run, health).
  • SCREG-FR-002: The system MUST expose GET /dashboard-testing/scenarios (list/search/filter by name, tag, dashboard, status, owner) and GET /dashboard-testing/scenarios/{id} (detail).
  • SCREG-FR-003: Every executable-graph edit MUST create a new immutable candidate revision (revision_id UUID + content_hash + parent_revision_id); the content hash includes the 038 Verification Program (SQL/DSL/assertion/AgentEvaluationSpec) but excludes ParameterBindings and other runtime state. Runs pin an explicit revision snapshot. Entity-metadata edits (name/description/tags) MUST NOT create an executable revision (content_hash unchanged).
  • SCREG-FR-003a: ActivateCurrentRevision MUST be a separate atomic operation. It may advance current_revision only after deterministic eligibility checks and the recorded 036 delegated-authority decision or ActionApprovalGate; saving a revision never silently changes an automation target.
  • SCREG-FR-004: Scenario detail MUST be loadable by id independent of any agent session (not event-driven).
  • SCREG-FR-005: Lifecycle states MUST include DRAFT, READY, STALE, NEEDS_REVALIDATION, BLOCKED, DISABLED, DEPRECATED, ARCHIVED; only valid transitions apply and are audit-logged.
  • SCREG-FR-006: The system MUST support lifecycle operations clone, rename, archive, restore, and RBAC-scoped delete (archive-only when run history exists).
  • SCREG-FR-007: Staleness MUST be computed from dashboard release diffs and 041 lineage blast radius; affected scenarios transition to NEEDS_REVALIDATION/BLOCKED with a reason.
  • SCREG-FR-008: RBAC MUST distinguish scenario:view, scenario:create, scenario:edit, scenario:archive; editing a scenario does NOT grant running it.
  • SCREG-FR-009: Hard delete MUST be forbidden for scenarios with run history; terminal lifecycle is archive to preserve audit reproducibility.
  • SCREG-FR-010: Registry health and staleness findings MUST emit an idempotent 036 InvestigationSignal, from which 047 may link an Investigation Queue item. An analyst opens a persistent agent case explicitly; signal production MUST NOT auto-start an agent conversation or tool action.
  • SCREG-FR-011: A delegated agent MAY create/save validated immutable revisions and portfolio operations through the same server-owned handle, ACL, lifecycle and outbox contracts as an analyst. Risky lifecycle/publish actions remain subject to their ActionApprovalGate policy.
  • SCREG-FR-012: Registry workflow, stale recovery and lifecycle actions MUST use persistent pages, inline panels or agent cases; modal/dialog interaction MUST NOT be required.

Key Entities

  • ScenarioRegistryEntry: Queryable projection of a scenario: name, description, dashboard, environment compatibility, owner, tags, current revision, lifecycle status, validation status, last run, last successful run, health, last modified, baseline compatibility.
  • ScenarioRevision: Immutable snapshot of a DashboardTestScenario graph (revision_id UUID + content_hash + parent_revision_id); later saves are candidate, and only explicit activation makes one revision current. scenario_id is a UUID assigned at Save; scenario_key is the semantic slug.
  • ScenarioLifecycleState: DRAFT / READY / STALE / NEEDS_REVALIDATION / BLOCKED / DISABLED / DEPRECATED / ARCHIVED with a valid-transition map.
  • ScenarioStalenessSignal: Cause of staleness (dashboard release diff, lineage blast-radius change, removed reference) with severity and affected scenario ids.

Success Criteria

  • SC-001: A persisted scenario is listable, searchable, and filterable and renders a full detail page from the registry within 200ms of data load.
  • SC-002: GET /scenarios/{id} returns the persisted graph for 100% of fixture scenarios (fixes the current missing-route 404).
  • SC-003: Every run references an immutable revision snapshot; editing a scenario after a run never changes what was executed.
  • SC-004: 100% of fixture lineage/dashboard changes that invalidate a referenced chart/filter/dataset mark the scenario NEEDS_REVALIDATION/BLOCKED with a reason.
  • SC-005: No scenario with run history can be hard-deleted; archive is the terminal state preserving the audit trail.

Clarifications

Session 2026-08-07

  • Q: Is 042 a UI feature or backend? → A: Backend-first (persistence, CRUD, versions, staleness) + a thin registry/detail list surface consumed by 043/045; heavy view/edit UI is 043, run monitor is 045.
  • Q: Where does the scenario graph live? → A: In a scenario_registry projection (canonical) plus the materialized scenario.yaml/runner.plan.json in the dashboard git repo (artifacts). The registry is the queryable source of truth.
  • Q: How does staleness work? → A: From dashboard release StructureDiff (037) and 041 lineage blast radius; never a blind rescan.
  • Q: Is delete ever allowed? → A: Only archive for scenarios with runs; hard delete requires admin scope and empty run history.

Implementation Status & MVP Debt (audit 2026-08-07)

Facts (code check):

  • 🔴 No Scenario/scenario_registry DB table exists; scenario lives as in-memory Pydantic + materialized git artifact.
  • 🔴 GET /dashboard-testing/scenarios/{id} is called by frontend getScenarioDraft but does not exist on the backend (only POST routes) → 404.
  • 🟡 scenario_key + content_hash are emitted by 038; revision_id/content_hash are the registry revision base — the technical basis for revisions is present, but there is no revision storage/UX.

#endregion ScenarioRegistry.Spec