Migrate Amazon Connect TEI study to the Mercury Notebook Pattern

studies/202602_AmazonConnect -> studies/202602_TEI_Amazon_Connect,
rebuilt as pattern Variant 4 (TEI composite reproduction):

- teicalc/ self-contained engine (stdlib-only): Forrester's tables as
  the never-edited verbatim anchor, NPV/ROI/payback + risk adjustment
  transplanted from core/calculations, ClientDrivers overlay (contacts/
  agents/fixed driver map, growth re-base, identity at composite scale),
  scenario stress with core-identical semantics
- one deliverable notebook (business_case.ipynb): widget-pair sidebar
  drivers, published-vs-overlay KPI columns, cash-flow/waterfall/scenario
  charts, verification gate, backstage JSON data appendix
- gate + tests reproduce the published totals within PDF rounding:
  NPV $78.7M / ROI 342% / payback <6 months (engine $78,713,492 /
  342.48% / 0.7 months); 27 study tests, headless nbconvert green,
  stage simulation leak-free, exports carry the appendix
- old Athena workflow (00_provision..04_export, config.py, seed_data.py)
  deleted; git history preserves it; root test fixture repointed to
  teicalc.anchor
- docs: study README rewritten; root README points new studies at
  template/MercuryNotebook; pattern doc stale ctm-token-calculator paths
  now cite studies/202607_CTM_GenesysCX; Variant 4 cites this study as
  its realized reference

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-09 14:29:46 -04:00
parent c3260ae7b8
commit a420af230b
33 changed files with 8235 additions and 6923 deletions

View File

@@ -0,0 +1,67 @@
"""
Scenario stress — transplanted from the retired shared ``core/calculations/scenarios.py``
with identical semantics.
Forrester TEI risk-adjusts benefits *down* and costs *up*; scenarios stress
both levers:
* ``adoption`` scales nominal values (``year_values`` and ``initial``).
* ``risk_delta`` is *added* to a benefit's risk factor and *subtracted*
from a cost's (conservative = more uncertainty on benefits, less padding
on costs), then clamped to [0, 1].
``"moderate"`` is the identity — the headless default reproduces the
published study. Note the counterintuitive corollary: the conservative
scenario *lowers* costs PV, because 80% adoption shrinks consumption-priced
usage and the clamp caps cost padding.
"""
from __future__ import annotations
from copy import deepcopy
SCENARIOS: dict[str, dict[str, float]] = {
"conservative": {"adoption": 0.80, "risk_delta": 0.10},
"moderate": {"adoption": 1.00, "risk_delta": 0.00},
"aggressive": {"adoption": 1.15, "risk_delta": -0.05},
}
def apply_scenario(
items: list[dict],
scenario: str = "moderate",
*,
multipliers: dict[str, dict[str, float]] | None = None,
table: str | None = None,
) -> list[dict]:
"""
Deep-copied value rows with the scenario applied; inputs are not mutated.
Each row needs ``year_values`` (year-string → float), optionally
``initial`` and ``risk_adjustment``, and a ``table`` of ``"benefits"``
or ``"costs"`` (or pass ``table=`` to force one) — the table decides the
sign of ``risk_delta``.
"""
cfg = (multipliers or SCENARIOS).get(scenario)
if cfg is None:
raise KeyError(f"Unknown scenario: {scenario!r}")
adoption = float(cfg.get("adoption", 1.0))
risk_delta = float(cfg.get("risk_delta", 0.0))
out: list[dict] = []
for raw in items:
item = deepcopy(raw)
item_table = item.get("table") or table or "benefits"
item["table"] = item_table
item["year_values"] = {
k: float(v) * adoption for k, v in item["year_values"].items()
}
if item.get("initial") is not None:
item["initial"] = float(item["initial"]) * adoption
ra = float(item.get("risk_adjustment") or 0.0)
new_ra = ra + risk_delta if item_table == "benefits" else ra - risk_delta
item["risk_adjustment"] = max(0.0, min(1.0, new_ra))
out.append(item)
return out