Files
Robert Helewka a420af230b 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>
2026-07-09 14:29:46 -04:00

124 lines
4.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Engine pins — every number hand-checked before pinning.
RA_benefit = v×(1rf), RA_cost = v×(1+rf), PV = Σ RA_n/(1.1)^n, initial
undiscounted. The composite reproduction lands within Forrester's own table
rounding of the published Financial Summary (benefits PV $223 low, costs PV
$0.22 low) — pinned both engine-exact (±$1) and against PUBLISHED (±$1,000,
the convention the retired workflow notebooks used).
"""
import pytest
from teicalc import (
BENEFITS_VERBATIM,
COSTS_VERBATIM,
PUBLISHED,
X_LABELS,
YEAR_INDEX,
YEARS,
by_calendar,
compute_summary,
discount_factor,
money,
npv,
payback_label,
payback_months,
payback_years,
roi_pct,
)
# Hand-checked risk-adjusted PVs per row (see module docstring).
ROW_PVS = {
"ai_contact_resolution": 51_699_826.78,
"ai_content_sentiment": 11_326_357.54,
"ai_forecasting_supervision": 19_469_777.37,
"data_driven_profit_lift": 3_123_065.36,
"legacy_solution_savings": 16_077_540.50,
"amazon_connect_usage": 20_819_775.10,
"implementation_migration": 1_555_794.82,
"ongoing_management": 607_505.86,
}
@pytest.fixture(scope="module")
def composite():
return compute_summary(BENEFITS_VERBATIM, COSTS_VERBATIM, 0.10)
def test_calendar_mapping():
assert YEARS == [2026, 2027, 2028]
assert YEAR_INDEX == {2026: 1, 2027: 2, 2028: 3}
assert X_LABELS == ["Initial", "2026", "2027", "2028"]
assert by_calendar({"1": 10, "2": 20, "3": 30}) == {2026: 10, 2027: 20, 2028: 30}
def test_primitives():
assert discount_factor(0, 0.10) == 1.0
assert discount_factor(1, 0.10) == pytest.approx(1 / 1.1)
assert npv([110], 0.10) == pytest.approx(100)
assert npv([110], 0.10, initial=-50) == pytest.approx(50)
assert roi_pct(101_696_791, 22_983_076) == pytest.approx(342.48, abs=0.1)
assert roi_pct(100, 0) == 0.0
assert money(78_713_492) == "$78.7M"
assert money(-250_000) == "-$250K"
def test_payback_edges():
assert payback_years(0, [100]) == 0.0
assert payback_years(500, []) is None
assert payback_years(500, [-100, 200]) is None # gap widens, never covered
assert payback_years(300, [-100, 400]) == pytest.approx(2.0)
assert payback_months(100, [1_200]) == pytest.approx(1.0)
assert payback_label(None) == "beyond 2028"
assert payback_label(0.0) == "immediate"
assert payback_label(0.7178) == "0.7 months (~Jan 2026)"
assert payback_label(14.2) == "14.2 months (~Mar 2027)"
def test_per_row_pvs(composite):
rows = composite["rows"]["benefits"] + composite["rows"]["costs"]
assert len(rows) == 8
for row in rows:
assert row["pv"] == pytest.approx(ROW_PVS[row["field_key"]], abs=1)
def test_composite_totals_engine_exact(composite):
assert composite["benefits_pv"] == pytest.approx(101_696_567.55, abs=1)
assert composite["costs_pv"] == pytest.approx(22_983_075.78, abs=1)
assert composite["npv"] == pytest.approx(78_713_491.78, abs=1)
assert composite["roi_pct"] == pytest.approx(342.4846, abs=0.01)
assert composite["payback_months"] == pytest.approx(0.7178, abs=0.001)
assert composite["initial_costs"] == pytest.approx(1_196_250, abs=0.01)
def test_composite_reproduces_published(composite):
assert composite["benefits_pv"] == pytest.approx(PUBLISHED["benefits_pv"], abs=1_000)
assert composite["costs_pv"] == pytest.approx(PUBLISHED["costs_pv"], abs=1_000)
assert composite["npv"] == pytest.approx(PUBLISHED["npv"], abs=1_000)
assert round(composite["roi_pct"]) == PUBLISHED["roi_pct"]
assert composite["payback_months"] < PUBLISHED["payback_months_max"]
assert composite["payback_label"] == "0.7 months (~Jan 2026)"
def test_yearly_schedules(composite):
assert composite["benefits_by_year"][2026] == pytest.approx(27_279_019.00, abs=0.01)
assert composite["benefits_by_year"][2027] == pytest.approx(40_333_658.20, abs=0.01)
assert composite["benefits_by_year"][2028] == pytest.approx(57_983_494.40, abs=0.01)
assert composite["costs_by_year"][2026] == pytest.approx(7_281_066.70, abs=0.01)
assert composite["costs_by_year"][2027] == pytest.approx(8_771_168.50, abs=0.01)
assert composite["costs_by_year"][2028] == pytest.approx(10_539_889.05, abs=0.01)
assert composite["cumulative_net_by_year"][2028] == pytest.approx(97_807_797.35, abs=0.01)
def test_cross_foots(composite):
assert composite["npv"] == pytest.approx(
composite["benefits_pv"] - composite["costs_pv"], abs=0.01)
for y in YEARS:
assert composite["net_by_year"][y] == pytest.approx(
composite["benefits_by_year"][y] - composite["costs_by_year"][y], abs=0.01)
assert composite["cumulative_net_by_year"][2028] == pytest.approx(
sum(composite["net_by_year"].values()) - composite["initial_costs"], abs=0.01)
for table, total in (("benefits", "benefits_pv"), ("costs", "costs_pv")):
assert sum(r["pv"] for r in composite["rows"][table]) == pytest.approx(
composite[total], abs=0.01)