-
Notifications
You must be signed in to change notification settings - Fork 1
Architecture
Hoda Rezvanjoo edited this page May 28, 2026
·
1 revision
┌──────────────────────────┐
Streamlit UI ─────── │ app.py (wizard + UI) │
└────────────┬─────────────┘
│ reads/writes
┌────────────▼─────────────┐
State machine ────── │ core/wizard_state.py │
└────────────┬─────────────┘
│ consumed by
┌────────────────────┼────────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ Module 1–4 │ │ Module 5 │ │ Module 6–7 │
│ (inputs) │──▶ │ (LP solver) │──▶ │ (forecast + │
│ │ │ │ │ interpretation)│
└───────────────┘ └───────────────┘ └───────────────┘
│ │ │
▼ ▼ ▼
┌───────────────────────────────────────────────────────┐
│ core/csv_import.py · core/kpi_config.py │
│ (KPI schema + last-mile parser) │
└───────────────────────────────────────────────────────┘
- Module 1 validates objectives + budget. Captures goal-value weights, test-and-learn carve-out, seasonality multipliers.
- Module 2 assigns priority 1 / 2 to each platform per objective. "Active platforms" are those with at least one priority slot.
- Module 3 collects per-platform historical budget + raw KPI values, either manually or via CSV.
-
Module 4 derives
cpu_per_goal[platform][goal][var]— cost per one unit of each count KPI. Flags outliers (CPU > 100× the per-goal median) and drops them. - Module 5 builds the LP, runs three scenario solves, returns binding constraints + shadow prices + an objective decomposition, and on request runs Monte Carlo robustness analysis.
- Module 6 turns each scenario's allocation into per-KPI forecasts with data-driven confidence bands.
- Module 7 classifies the plan, scores confidence on a 40–100 scale, builds a diversification-capped Plan B, summarises risks.
- One direction of data flow. Modules depend only on numbered predecessors. No circular imports between M1–M7.
-
Single state object.
WizardStateis the source of truth. Modules read snapshots but never mutate state — each module is testable in isolation. -
LP is one module, not many. Solver, diagnostics, Monte Carlo,
and shrinkage live together in
module5.pyso the logic that explains the LP sits next to the LP itself. -
Configuration is data, not branches.
Module7Policyis a frozen dataclass of every interpretation threshold. Tighten one field to make the report more conservative; no code change required. -
Every constraint is named. Each
LpConstraintcarries a meaningful label so binding-constraint diagnostics work automatically — you can ask "why is platform X capped?" and get a literal answer.