# Scenario Lab The scenario lab (`means.lab`) is the shared application layer over `means.planning`. It owns scenario validation, named hypotheses, variant generation, sensitivity ranking, and stable presentation models. The CLI (`means-plan`), TUI (`means-tui`), and web UI (`means-web`) all consume one typed API -- no surface-specific financial calculation forks exist. ## Core concepts ### Hypotheses A **hypothesis** is a named question over the scenario with at least two named alternatives. Each alternative carries typed overrides targeting fields from the finite registry: - `starting_cash` -- the opening cash balance - `reserve_floor` -- the minimum cash floor - `extra_debt_payment` -- the monthly extra debt payment - `allocation_day` -- the monthly extra-allocation date All alternative names within a hypothesis must be unique. ### Variants The lab evaluates the Cartesian product of hypothesis alternatives. Variant expansion fails closed above a documented bound (`MAX_VARIANTS = 64`). ```python from decimal import Decimal from means.lab import ( Alternative, Hypothesis, HypothesisTarget, LabRequest, OverrideTarget, ScenarioLab, ) request = LabRequest( scenario=scenario, hypotheses=[ Hypothesis( name='Starting cash', alternatives=[ Alternative( name='low', targets=[ HypothesisTarget( field=OverrideTarget.STARTING_CASH, value=Decimal('3000.00'), ), ], ), Alternative( name='high', targets=[ HypothesisTarget( field=OverrideTarget.STARTING_CASH, value=Decimal('8000.00'), ), ], ), ], ), ], ) result = ScenarioLab().evaluate(request) ``` ### Sensitivity ranking Sensitivity is **descriptive**, not causal. For each hypothesis and metric, the lab measures the spread observed across the evaluated variants and reports the range with its low and high variant labels. This does not prove that a hypothesis causes the observed difference. ### Shared result model The typed `EvaluationResult` returned by `ScenarioLab().evaluate(...)` is the single presentation model consumed by every surface (CLI, TUI, WUI). Results serialize only application-layer types -- never private data. ## Fictional example This example uses entirely fictional data: A scenario-lab document wraps the planning scenario under a `scenario:` key and adds optional `hypotheses`: ```yaml scenario: name: Fictional demo scenario as_of: 2026-01-01 through: 2026-06-30 starting_cash: '5000.00' reserve_floor: '500.00' flows: - uid: income name: Income category: salary kind: inflow amount: '3000.00' start: 2026-01-01 frequency: monthly debts: - uid: card name: Card balance: '2000.00' annual_rate: '0.18' minimum_payment: '150.00' due_day: 5 extra_debt_payment: '200.00' allocation_day: 10 hypotheses: - name: Reserve policy alternatives: - name: Conservative reserve targets: - field: reserve_floor value: '1000.00' - name: Lean reserve targets: - field: reserve_floor value: '250.00' ``` ## Privacy and safety - All computation is local; no financial data is sent remotely. - Neither the TUI nor the WUI mutates a Ledger. - The WUI binds to loopback (`127.0.0.1`) by default. - The WUI parses no arbitrary paths from browser input. - Both interfaces label scenario math as **hypotheses**, not predictions or financial advice. - Optional UI dependencies do not enlarge the base installation.