From a420af230ba05475694a470112fc364abe50a415 Mon Sep 17 00:00:00 2001 From: Robert Helewka Date: Thu, 9 Jul 2026 14:29:46 -0400 Subject: [PATCH] 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 --- README.md | 78 +- docs/Mercury_Notebook_Pattern_V1-00.md | 21 +- studies/202602_AmazonConnect/.DS_Store | Bin 6148 -> 0 bytes studies/202602_AmazonConnect/README.md | 71 - studies/202602_AmazonConnect/__init__.py | 0 studies/202602_AmazonConnect/config.py | 44 - .../notebooks/00_provision.ipynb | 1004 --- .../notebooks/01_benefits.ipynb | 1333 ---- .../notebooks/02_costs.ipynb | 1197 --- .../notebooks/03_business_case.ipynb | 2996 ------- .../notebooks/04_export.ipynb | 195 - studies/202602_TEI_Amazon_Connect/README.md | 97 + studies/202602_TEI_Amazon_Connect/config.toml | 81 + .../docs/202602_TEI Report Amazon Connect.pdf | Bin .../exports/.gitkeep | 0 .../notebooks/business_case.ipynb | 6946 +++++++++++++++++ .../202602_TEI_Amazon_Connect/pyproject.toml | 36 + .../scripts/export_report.py | 47 + .../teicalc/__init__.py | 56 + .../teicalc/anchor.py} | 56 +- .../teicalc/model.py | 267 + .../teicalc/overlay.py | 107 + .../teicalc/scenarios.py | 67 + .../teicalc/staging.py | 29 + .../tests/conftest.py | 7 + .../tests/test_anchor.py | 95 + .../tests/test_model.py | 123 + .../tests/test_overlay.py | 96 + .../tests/test_scenarios.py | 75 + .../tests/test_staging.py | 15 + template/MercuryNotebook/README.md | 2 +- tests/conftest.py | 13 +- tests/test_export.py | 4 +- 33 files changed, 8235 insertions(+), 6923 deletions(-) delete mode 100644 studies/202602_AmazonConnect/.DS_Store delete mode 100644 studies/202602_AmazonConnect/README.md delete mode 100644 studies/202602_AmazonConnect/__init__.py delete mode 100644 studies/202602_AmazonConnect/config.py delete mode 100644 studies/202602_AmazonConnect/notebooks/00_provision.ipynb delete mode 100644 studies/202602_AmazonConnect/notebooks/01_benefits.ipynb delete mode 100644 studies/202602_AmazonConnect/notebooks/02_costs.ipynb delete mode 100644 studies/202602_AmazonConnect/notebooks/03_business_case.ipynb delete mode 100644 studies/202602_AmazonConnect/notebooks/04_export.ipynb create mode 100644 studies/202602_TEI_Amazon_Connect/README.md create mode 100644 studies/202602_TEI_Amazon_Connect/config.toml rename studies/{202602_AmazonConnect => 202602_TEI_Amazon_Connect}/docs/202602_TEI Report Amazon Connect.pdf (100%) rename studies/{202602_AmazonConnect => 202602_TEI_Amazon_Connect}/exports/.gitkeep (100%) create mode 100644 studies/202602_TEI_Amazon_Connect/notebooks/business_case.ipynb create mode 100644 studies/202602_TEI_Amazon_Connect/pyproject.toml create mode 100644 studies/202602_TEI_Amazon_Connect/scripts/export_report.py create mode 100644 studies/202602_TEI_Amazon_Connect/teicalc/__init__.py rename studies/{202602_AmazonConnect/seed_data.py => 202602_TEI_Amazon_Connect/teicalc/anchor.py} (75%) create mode 100644 studies/202602_TEI_Amazon_Connect/teicalc/model.py create mode 100644 studies/202602_TEI_Amazon_Connect/teicalc/overlay.py create mode 100644 studies/202602_TEI_Amazon_Connect/teicalc/scenarios.py create mode 100644 studies/202602_TEI_Amazon_Connect/teicalc/staging.py create mode 100644 studies/202602_TEI_Amazon_Connect/tests/conftest.py create mode 100644 studies/202602_TEI_Amazon_Connect/tests/test_anchor.py create mode 100644 studies/202602_TEI_Amazon_Connect/tests/test_model.py create mode 100644 studies/202602_TEI_Amazon_Connect/tests/test_overlay.py create mode 100644 studies/202602_TEI_Amazon_Connect/tests/test_scenarios.py create mode 100644 studies/202602_TEI_Amazon_Connect/tests/test_staging.py diff --git a/README.md b/README.md index 3824447..cc2fbc4 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Palladium is a Jupyter notebook + Streamlit toolkit for building Total Economic ┌──────────────────────────────────────────────────────────────────┐ │ Palladium │ │ │ -│ studies/202602_AmazonConnect/ ← one folder per TEI study │ +│ studies/202512_GenesysCX/ ← legacy study (this path) │ │ studies/YYYYMM_/ │ │ ├─ notebooks/ ─┐ │ │ ├─ seed_data.py │ │ @@ -78,7 +78,7 @@ From any notebook, setup is one import: ```python from core.bootstrap import init -pal = init(study="202602_AmazonConnect") # loads .env, connects, imports study +pal = init(study="202512_GenesysCX") # loads .env, connects, imports study pal.client.list_reports() pal.seed_data.BENEFITS ``` @@ -113,23 +113,26 @@ python -m palladium test ### Run a study end-to-end -Each study lives in `studies//`. The reference study is the -February 2026 Forrester *Total Economic Impact™ Of Amazon Connect*: +Each new study is self-contained under the +[Mercury Notebook Deliverable Pattern](docs/Mercury_Notebook_Pattern_V1-00.md). +The reference TEI study is the February 2026 Forrester *Total Economic +Impact™ Of Amazon Connect* (pattern Variant 4 — composite reproduction): ```bash -make lab # then browse to studies/202602_AmazonConnect/notebooks/ +cd studies/202602_TEI_Amazon_Connect +python -m venv .venv && source .venv/bin/activate && pip install -e ".[dev]" +mercury --working-dir notebooks/ # serve the deliverable (the stage) +python scripts/export_report.py # export .html/.md report sources ``` -| Notebook | Purpose | -|----------|---------| -| `00_provision.ipynb` | **Run first** — creates the report template + fields, lets you select the CRM client and the Proposal/Engagement to attach to (pulling the client's profile to avoid re-entry), creates the tool, seeds the published values, calculates, and verifies the totals | -| `01_benefits.ipynb` | Quantify and risk-adjust benefit categories | -| `02_costs.ipynb` | Document implementation and ongoing costs | -| `03_business_case.ipynb` | Financial summary, scenario analysis, visualizations | -| `04_export.ipynb` | Generate report-ready JSON for the html2docx pipeline | +Its notebook reproduces the published totals within the PDF's rounding — +**NPV $78.7M • ROI 342% • Payback <6 months** — and the verification gate +asserts it on every headless run. See the study's README for details. -The Amazon Connect notebooks reproduce the published study totals within -rounding: **NPV $78.7M • ROI 342% • Payback <6 months**. +The remaining legacy study, `studies/202512_GenesysCX/`, still uses the +shared `core/` workflow (`make lab`, provision → push → calculate); it +migrates to the pattern next, after which `core/`'s notebook helpers and +`app/` retire. ### Streamlit application (study-agnostic) @@ -176,20 +179,17 @@ the published Forrester totals. ## Adding a new study +Copy the template, not an existing study: + ```bash -cp -r studies/202602_AmazonConnect studies/202612_GenesysCloud -cd studies/202612_GenesysCloud +cp -r template/MercuryNotebook studies/YYYYMM_TEI_Vendor_Product ``` -1. **`README.md`** — update the title, source citation, key numbers. -2. **`seed_data.py`** — replace `BENEFITS` and `COSTS` with the new study's rows. -3. **`config.py`** — set `STUDY_SLUG`, leave `TOOL_PUBLIC_ID` blank until provisioned. -4. **`docs/`** — drop the source PDF here. -5. Open the notebooks; the imports (`core.calculations`, `core.notebook_helpers`, - `core.tei_client`) are study-agnostic. Update the markdown narrative. - -The shared `core/` package and the `app/` Streamlit UI need no changes — -they introspect the TEI Report template via the API. +Then follow `template/MercuryNotebook/README.md`: rename `studylib/` to +your study package (underscores only — dashes break Python imports), +replace the toy model, re-pin the tests, rework the notebook. +`studies/202602_TEI_Amazon_Connect/` is the worked TEI example; +`studies/202607_CTM_GenesysCX/` is the full multi-notebook reference. --- @@ -269,24 +269,22 @@ palladium/ │ ├── main.py # entry point │ ├── views/ # benefits, costs, summary, versions (NOT `pages/` — avoids Streamlit auto-multipage) │ └── components/ # tables, charts -├── studies/ # One folder per TEI engagement -│ ├── 202512_GenesysCX/ # CX Cloud (Genesys + Salesforce) TEI +├── template/ +│ └── MercuryNotebook/ # copy-me pattern scaffold (runnable) +├── studies/ # One folder per engagement +│ ├── 202512_GenesysCX/ # CX Cloud TEI — legacy shared-core layout │ │ ├── README.md # NPV $10.8M · ROI 266% + AI-token line │ │ ├── config.py / seed_data.py # study-scoped PALLADIUM_GENESYSCX_* keys │ │ └── notebooks/ # 00_provision, 01_business_case -│ └── 202602_AmazonConnect/ -│ ├── README.md -│ ├── config.py # TOOL_PUBLIC_ID, REPORT_PUBLIC_ID -│ ├── seed_data.py # 5 benefits + 3 costs from the PDF -│ ├── notebooks/ -│ │ ├── 00_provision.ipynb # creates template+tool in Athena, seeds & verifies -│ │ ├── 01_benefits.ipynb -│ │ ├── 02_costs.ipynb -│ │ ├── 03_business_case.ipynb -│ │ └── 04_export.ipynb -│ ├── exports/ # generated; .gitignored -│ └── docs/ -│ └── 202602_TEI Report Amazon Connect.pdf +│ ├── 202602_TEI_Amazon_Connect/ # Amazon Connect TEI — pattern Variant 4 +│ │ ├── README.md # NPV $78.7M · ROI 342%, reproduced + gated +│ │ ├── teicalc/ # self-contained engine (anchor/model/overlay) +│ │ ├── notebooks/business_case.ipynb +│ │ ├── tests/ · scripts/ · config.toml · pyproject.toml +│ │ ├── exports/ # generated; .gitignored +│ │ └── docs/ +│ │ └── 202602_TEI Report Amazon Connect.pdf +│ └── 202607_CTM_GenesysCX/ # CTM × Genesys study — pattern reference impl ├── tests/ # 50 tests for core/ │ ├── test_client.py │ ├── test_calculations.py diff --git a/docs/Mercury_Notebook_Pattern_V1-00.md b/docs/Mercury_Notebook_Pattern_V1-00.md index 3fa6bdf..20b1461 100644 --- a/docs/Mercury_Notebook_Pattern_V1-00.md +++ b/docs/Mercury_Notebook_Pattern_V1-00.md @@ -15,7 +15,7 @@ agent building or modifying a study. Rules are imperative (MUST/SHOULD/NEVER), e with a one-line *why*. Long code lives in the runnable template [`template/MercuryNotebook/`](../template/MercuryNotebook/) — copy it to start a study; snippets here are excerpts from it. The full-scale reference implementation is the CTM -Genesys study, [`studies/202512_GenesysCX/ctm-token-calculator/`](../studies/202512_GenesysCX/ctm-token-calculator/). +Genesys study, [`studies/202607_CTM_GenesysCX/`](../studies/202607_CTM_GenesysCX/). --- @@ -58,13 +58,11 @@ palladium/ │ └── MercuryNotebook/ # copy-me starting point (runnable) └── studies/ ├── YYYYMM_TEI_Vendor_Product/ # vendor TEI study, e.g. 202602_TEI_Amazon_Connect - └── YYYYMM_Client_EngagementName/ # client study, e.g. 202512_CTM_GenesysCX + └── YYYYMM_Client_EngagementName/ # client study, e.g. 202607_CTM_GenesysCX ``` - Names MUST use **underscores, never dashes** — dashed directories can't be Python packages, and everything in a study is importable code. - *(The CTM study's inner `ctm-token-calculator/` predates this rule; it gets renamed - when the studies migrate.)* - Every study is self-contained with this layout (from the template): ``` @@ -238,7 +236,7 @@ Each section heading carries ``; a sidebar table of conten **onclick-JS** navigation (fragment `href`s don't scroll in Mercury's SPA, and python-markdown escapes any raw `<` inside handler attributes — keep handlers comparison-free). Recipe: the ToC cell in -[`studies/202512_GenesysCX/ctm-token-calculator/notebooks/ctm_business_case_corrected.ipynb`](../studies/202512_GenesysCX/ctm-token-calculator/notebooks/ctm_business_case_corrected.ipynb). +[`studies/202607_CTM_GenesysCX/notebooks/ctm_business_case_corrected.ipynb`](../studies/202607_CTM_GenesysCX/notebooks/ctm_business_case_corrected.ipynb). --- @@ -263,7 +261,7 @@ def anchor(key): overlays are auditable; corrections made by editing the source are arguments. Show a **vendor/deck-frame KPI column beside the contracted column** so the walk from the pitch to reality stays explicit. Reference: `TCO_VERBATIM`/`TCO_CONTRACTED`/`tco()` in -[`studies/202512_GenesysCX/ctm-token-calculator/tokencalc/appendix4.py`](../studies/202512_GenesysCX/ctm-token-calculator/tokencalc/appendix4.py). +[`studies/202607_CTM_GenesysCX/tokencalc/appendix4.py`](../studies/202607_CTM_GenesysCX/tokencalc/appendix4.py). ### Baseline-relative case frame @@ -316,28 +314,31 @@ Keep the vendor's claimed benefits **verbatim**, add the costs the pitch omitted (consumption meters, implementation labour, double-billing), and bill contract mechanics as signed (ramp, milestones, managed services). The headline is the walk: *as-pitched → corrected*. Reference: -[`notebooks/ctm_business_case_corrected.ipynb`](../studies/202512_GenesysCX/ctm-token-calculator/notebooks/ctm_business_case_corrected.ipynb). +[`notebooks/ctm_business_case_corrected.ipynb`](../studies/202607_CTM_GenesysCX/notebooks/ctm_business_case_corrected.ipynb). ### Variant 2 — Scenario notebook on a thin module A second question over the same engine (e.g. "migration + WFM only, no AI") gets a **thin scenario module** that scopes and extrapolates but duplicates nothing, plus its own notebook and test pins. Reference: `tokencalc/migration_wfm.py` + -[`notebooks/ctm_migration_wfm.ipynb`](../studies/202512_GenesysCX/ctm-token-calculator/notebooks/ctm_migration_wfm.ipynb). +[`notebooks/ctm_migration_wfm.ipynb`](../studies/202607_CTM_GenesysCX/notebooks/ctm_migration_wfm.ipynb). ### Variant 3 — Exploratory calculator Early-phase what-if surface: scenario selectors, tornado/break-even sweeps, no contract anchoring yet. Still engine-backed and gate-checked; it graduates into Variant 1 as facts arrive. Reference: -[`notebooks/ctm_token_calculator.ipynb`](../studies/202512_GenesysCX/ctm-token-calculator/notebooks/ctm_token_calculator.ipynb). +[`notebooks/ctm_token_calculator.ipynb`](../studies/202607_CTM_GenesysCX/notebooks/ctm_token_calculator.ipynb). ### Variant 4 — TEI composite reproduction Reproduce a published TEI study's composite organization as the verbatim anchor (`ANCHOR_VERBATIM` = Forrester's tables), verify the reproduction against the published ROI/NPV/payback in the gate, then personalize with client inputs as the overlay. This -is the target shape for `studies/202602_AmazonConnect/` when it migrates off Streamlit. +is realized by [`studies/202602_TEI_Amazon_Connect/`](../studies/202602_TEI_Amazon_Connect/) +(package `teicalc`): Forrester's Amazon Connect composite as the anchor, the gate pinning +the published $78.7M NPV / 342% ROI / <6-month payback, and a client-driver overlay +(agents / contacts / growth) that is the identity at composite scale. --- diff --git a/studies/202602_AmazonConnect/.DS_Store b/studies/202602_AmazonConnect/.DS_Store deleted file mode 100644 index b1bc858e925d93fb375ed4bdb59c7154b9b72c92..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~F>b>!3`IX%4*|M(?5HIN=naG*JwYxI#2y292)gU&`J}kS%^VoPCqO=tGGY4< zmI=TPfAbG80@%@=*n3!+F&{8v!Gzm5@b5#RJ8QCa#;1cJMgVePIgIO=CCK6hvL;(6D>TdL!Lrq2 z4DoujlO?aK$=2E1VL5zQ-r0PLp;>Q-6(%&R0R<@_1y%}t_I&j7|Cj!3{$I5yl>$=W z%@nZVcsd^VQhB!idp)n8v+C`, and: - -1. Replace `seed_data.py` with your benefits/costs. -2. Update `config.py` with the new tool/report public IDs. -3. Tweak the notebooks' narrative; the helper imports are the same. - -The only thing that changes between studies is the **data** and the -**narrative prose** in the notebooks. All math, charts, and API calls -come from `core/`. diff --git a/studies/202602_AmazonConnect/__init__.py b/studies/202602_AmazonConnect/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/studies/202602_AmazonConnect/config.py b/studies/202602_AmazonConnect/config.py deleted file mode 100644 index 98466ad..0000000 --- a/studies/202602_AmazonConnect/config.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Study configuration for the Amazon Connect TEI (February 2026). - -Set ``TOOL_PUBLIC_ID`` to the public_id of the live TEI tool instance in -Athena once it has been created. ``REPORT_PUBLIC_ID`` is the template -this tool was created from (Athena admin sets up Report templates). - -Until both are filled in, the notebooks fall back to local-only mode: -they compute summaries from ``seed_data.py`` using ``core.calculations`` -and skip the network round-trip. -""" - -from __future__ import annotations - -import os - -#: Human-friendly study identifier — used in export metadata + filenames. -STUDY_SLUG = "202602_AmazonConnect" - -#: TEI Report template public_id (12-char short UUID). Provisioned in -#: Athena admin → TEI → Reports. -REPORT_PUBLIC_ID: str = os.getenv("PALLADIUM_REPORT_PUBLIC_ID", "") - -#: TEI Tool instance public_id. Created via the API -#: (``client.create_tool``) or the Streamlit app sidebar. -TOOL_PUBLIC_ID: str = os.getenv("PALLADIUM_TOOL_PUBLIC_ID", "") - -#: Default discount rate used for local validation of the study numbers. -DISCOUNT_RATE = 0.10 - -#: Analysis horizon (years). -ANALYSIS_YEARS = 3 - -def _int_env(name: str) -> int | None: - raw = os.getenv(name, "").strip() - return int(raw) if raw else None - - -#: Athena Proposal PK this tool is linked to (a TEI tool must attach to a -#: Proposal OR an Engagement — set exactly one). -PROPOSAL_ID: int | None = _int_env("PALLADIUM_PROPOSAL_ID") - -#: Athena Engagement PK (alternative attachment point). -ENGAGEMENT_ID: int | None = _int_env("PALLADIUM_ENGAGEMENT_ID") diff --git a/studies/202602_AmazonConnect/notebooks/00_provision.ipynb b/studies/202602_AmazonConnect/notebooks/00_provision.ipynb deleted file mode 100644 index bd18684..0000000 --- a/studies/202602_AmazonConnect/notebooks/00_provision.ipynb +++ /dev/null @@ -1,1004 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "2b0c5d04", - "metadata": {}, - "source": [ - "# 00 · Provision — Amazon Connect TEI in Athena\n", - "\n", - "Creates everything this study needs in the Athena sandbox, end to end:\n", - "\n", - "1. **Report template** *Amazon Connect 2026* (3 years, 10% discount rate) + **field definitions**\n", - "2. **Client selection** — browse the CRM, pick the client, and pull their profile (industry, agent counts, revenue) so nothing is re-entered\n", - "3. **Attachment** — pick (or create) the **Proposal or Engagement** the tool binds to\n", - "4. **Tool instance** + **seed values** from `seed_data.py` (the published Forrester figures)\n", - "5. **Server-side calculation** and **verification** against the published totals: **NPV \\$78.7M · ROI 342% · payback <6 months**\n", - "6. Persists all IDs to `.env` so the other notebooks, the CLI, and the Streamlit app pick them up automatically.\n", - "\n", - "Safe to re-run — every step finds existing objects before creating new ones." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "5bcc7740", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Athena connected — https://athena.ouranos.helu.ca (1 report templates visible)\n", - "📁 Study: 202602_AmazonConnect\n" - ] - } - ], - "source": [ - "import sys, pathlib # path shim: works on a fresh kernel\n", - "for _p in [pathlib.Path.cwd(), *pathlib.Path.cwd().parents]:\n", - " if (_p / \"pyproject.toml\").exists():\n", - " sys.path.insert(0, str(_p)); break\n", - "\n", - "import pandas as pd\n", - "from core.bootstrap import init, update_env\n", - "\n", - "pal = init(study=\"202602_AmazonConnect\")\n", - "client, seed, config = pal.client, pal.seed_data, pal.config\n", - "assert pal.connection.get(\"status\") == \"ok\", \"Fix the connection first → 00_setup.ipynb\"" - ] - }, - { - "cell_type": "markdown", - "id": "cc8a4e03", - "metadata": {}, - "source": [ - "## 1 · Report template (find or create)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "386ae38b", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Found existing report template xsUTbjh4iDnJ (status: active)\n" - ] - } - ], - "source": [ - "REPORT_NAME, VENDOR = \"Amazon Connect 2026\", \"AWS\"\n", - "\n", - "report = next(\n", - " (r for r in client.list_reports()\n", - " if r.get(\"name\") == REPORT_NAME and r.get(\"vendor\") == VENDOR),\n", - " None,\n", - ")\n", - "if report is None:\n", - " report = client.create_report(\n", - " name=REPORT_NAME,\n", - " vendor=VENDOR,\n", - " version=\"1.0\",\n", - " description=\"Forrester Total Economic Impact of Amazon Connect, Feb 2026\",\n", - " analysis_period_years=seed.ASSUMPTIONS[\"analysis_years\"],\n", - " discount_rate=seed.ASSUMPTIONS[\"discount_rate\"],\n", - " status=\"draft\",\n", - " )\n", - " print(f\"Created report template {report['id']}\")\n", - "else:\n", - " print(f\"Found existing report template {report['id']} (status: {report.get('status')})\")\n", - "\n", - "REPORT_ID = report[\"id\"]" - ] - }, - { - "cell_type": "markdown", - "id": "dab83777", - "metadata": {}, - "source": [ - "## 2 · Field definitions\n", - "\n", - "Derived straight from `seed_data.py`. Three methodology notes:\n", - "\n", - "- **Benefit risk adjustment** lives on the field definition — Athena applies `value × (1 − risk_adj)` at calculate time.\n", - "- **Costs**: Athena never risk-adjusts costs, but Forrester adjusts them *upward*. We therefore push cost values pre-multiplied by `(1 + risk_adj)` in step 5, and keep the field-level adjustment at 0 so nothing is applied twice.\n", - "- **Year-0 \"Initial\" amounts** have no native slot in the TEI API, so each cost gets a companion non-annual `_initial` field. The client folds these back automatically on read." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "dc46ab46", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0 fields created, 11 already existed.\n" - ] - } - ], - "source": [ - "def field_defs():\n", - " defs, sort = [], 0\n", - " for b in seed.BENEFITS:\n", - " sort += 1\n", - " defs.append({\n", - " \"table\": \"benefits\",\n", - " \"field_key\": b[\"field_key\"],\n", - " \"label\": b[\"label\"],\n", - " \"description\": b[\"notes\"][:200],\n", - " \"field_type\": \"currency\",\n", - " \"category\": b[\"category\"],\n", - " \"is_annual\": True,\n", - " \"risk_adjustment\": str(b[\"risk_adjustment\"]),\n", - " \"sort_order\": sort,\n", - " \"is_required\": True,\n", - " \"source_notes\": b[\"notes\"],\n", - " })\n", - " for c in seed.COSTS:\n", - " sort += 1\n", - " defs.append({\n", - " \"table\": \"costs\",\n", - " \"field_key\": c[\"field_key\"],\n", - " \"label\": c[\"label\"],\n", - " \"description\": c[\"notes\"][:200],\n", - " \"field_type\": \"currency\",\n", - " \"category\": c[\"category\"],\n", - " \"is_annual\": True,\n", - " \"risk_adjustment\": \"0\", # applied client-side, see note above\n", - " \"sort_order\": sort,\n", - " \"is_required\": True,\n", - " \"source_notes\": c[\"notes\"],\n", - " })\n", - " sort += 1\n", - " defs.append({\n", - " \"table\": \"costs\",\n", - " \"field_key\": f\"{c['field_key']}_initial\",\n", - " \"label\": f\"{c['label']} — initial (Year 0)\",\n", - " \"description\": \"One-time Year-0 amount (companion field).\",\n", - " \"field_type\": \"currency\",\n", - " \"category\": c[\"category\"],\n", - " \"is_annual\": False,\n", - " \"risk_adjustment\": \"0\",\n", - " \"sort_order\": sort,\n", - " \"is_required\": False,\n", - " \"source_notes\": \"Year-0 lump sum; Athena treats non-annual values as Year 1.\",\n", - " })\n", - " return defs\n", - "\n", - "existing = {f[\"field_key\"] for f in client.list_fields(REPORT_ID)}\n", - "created = 0\n", - "for d in field_defs():\n", - " if d[\"field_key\"] not in existing:\n", - " client.create_field(REPORT_ID, d)\n", - " created += 1\n", - "print(f\"{created} fields created, {len(existing)} already existed.\")\n", - "\n", - "if report.get(\"status\") == \"draft\":\n", - " client.update_report(REPORT_ID, status=\"active\")\n", - " print(\"Report template activated.\")" - ] - }, - { - "cell_type": "markdown", - "id": "d5841b4e", - "metadata": {}, - "source": [ - "## 3 · Select the client\n", - "\n", - "Browse the CRM. Adjust `CLIENT_SEARCH` to narrow the list, then set `CLIENT_ID`\n", - "below (it auto-selects when exactly one client matches)." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "4070b9c2", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
idnameverticalclient_typeemployee_countcontact_center_agent_countsupervisor_count
02Global Guardian InsuranceNoneFor-Profit120002500None
13EudaimonixNoneFor-Profit1500300None
24Aetherium ForgeNoneFor-Profit50042None
\n", - "
" - ], - "text/plain": [ - " id name vertical client_type employee_count \\\n", - "0 2 Global Guardian Insurance None For-Profit 12000 \n", - "1 3 Eudaimonix None For-Profit 1500 \n", - "2 4 Aetherium Forge None For-Profit 500 \n", - "\n", - " contact_center_agent_count supervisor_count \n", - "0 2500 None \n", - "1 300 None \n", - "2 42 None " - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "CLIENT_SEARCH = \"\" # e.g. \"Acme\" — empty lists everyone\n", - "\n", - "clients = client.list_clients(search=CLIENT_SEARCH or None)\n", - "if clients:\n", - " display(pd.DataFrame(clients)[\n", - " [c for c in (\"id\", \"name\", \"vertical\", \"client_type\", \"employee_count\",\n", - " \"contact_center_agent_count\", \"supervisor_count\")\n", - " if c in clients[0]]\n", - " ])\n", - "else:\n", - " print(\"No clients found — create one in the Athena UI (Orbit → Clients) and re-run.\")" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "4e97978c", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Client profile — no re-entry needed downstream:\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
Global Guardian Insurance
id2
nameGlobal Guardian Insurance
abbreviated_nameGGI
verticalNone
client_typeFor-Profit
employee_count12000
revenue4500000000.0
contact_center_agent_count2500
service_desk_agent_count300
supervisor_countNone
location_count120
\n", - "
" - ], - "text/plain": [ - " Global Guardian Insurance\n", - "id 2\n", - "name Global Guardian Insurance\n", - "abbreviated_name GGI\n", - "vertical None\n", - "client_type For-Profit\n", - "employee_count 12000\n", - "revenue 4500000000.0\n", - "contact_center_agent_count 2500\n", - "service_desk_agent_count 300\n", - "supervisor_count None\n", - "location_count 120" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "CLIENT_ID = 2 # ← set from the `id` column above, or leave for auto-pick\n", - "\n", - "if CLIENT_ID is None and len(clients) == 1:\n", - " CLIENT_ID = clients[0][\"id\"]\n", - " print(f\"Auto-selected the only client: {clients[0]['name']} (id={CLIENT_ID})\")\n", - "assert CLIENT_ID is not None, \"Set CLIENT_ID from the table above and re-run this cell.\"\n", - "\n", - "profile = client.client_profile(CLIENT_ID)\n", - "CLIENT_NAME = profile[\"name\"]\n", - "print(f\"\\nClient profile — no re-entry needed downstream:\")\n", - "display(pd.DataFrame([profile]).T.rename(columns={0: CLIENT_NAME}))" - ] - }, - { - "cell_type": "markdown", - "id": "0ae76599", - "metadata": {}, - "source": [ - "### Client data → study assumptions\n", - "\n", - "Where the CRM has real numbers, they override the Forrester composite\n", - "(2,000 agents / 200 supervisors). `CLIENT_ASSUMPTIONS` is what `01_benefits.ipynb`\n", - "uses for scaling discussions." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "fcccc591", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
assumptionForrester compositeGlobal Guardian Insurance (CRM)
0agents_fte20002500
\n", - "
" - ], - "text/plain": [ - " assumption Forrester composite Global Guardian Insurance (CRM)\n", - "0 agents_fte 2000 2500" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Indicative scale factor vs composite: 1.25× (apply judgement — benefits don't all scale linearly)\n" - ] - } - ], - "source": [ - "CLIENT_ASSUMPTIONS = dict(seed.ASSUMPTIONS)\n", - "overrides = {\n", - " \"agents_fte\": profile.get(\"contact_center_agent_count\"),\n", - " \"supervisors_fte\": profile.get(\"supervisor_count\"),\n", - "}\n", - "rows = []\n", - "for key, val in overrides.items():\n", - " if val:\n", - " rows.append({\"assumption\": key, \"Forrester composite\": seed.ASSUMPTIONS[key],\n", - " f\"{CLIENT_NAME} (CRM)\": val})\n", - " CLIENT_ASSUMPTIONS[key] = val\n", - "\n", - "if rows:\n", - " display(pd.DataFrame(rows))\n", - " scale = CLIENT_ASSUMPTIONS[\"agents_fte\"] / seed.ASSUMPTIONS[\"agents_fte\"]\n", - " print(f\"Indicative scale factor vs composite: {scale:.2f}× \"\n", - " f\"(apply judgement — benefits don't all scale linearly)\")\n", - "else:\n", - " print(\"CRM has no agent/supervisor counts for this client — using the \"\n", - " \"Forrester composite organization as-is.\")" - ] - }, - { - "cell_type": "markdown", - "id": "422c2ed6", - "metadata": {}, - "source": [ - "## 4 · Pick the attachment — Proposal or Engagement\n", - "\n", - "A TEI tool must attach to exactly one of the two. Both lists below are\n", - "already filtered to the selected client." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "57dec6cf", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Proposals for Global Guardian Insurance:\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
idnamestatusopportunitydue_date
01Secure Cloud Infrastructure ModernizationDraftSecure Cloud Infrastructure Modernization2026-08-28
\n", - "
" - ], - "text/plain": [ - " id name status \\\n", - "0 1 Secure Cloud Infrastructure Modernization Draft \n", - "\n", - " opportunity due_date \n", - "0 Secure Cloud Infrastructure Modernization 2026-08-28 " - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "proposals = client.proposals_for_client(CLIENT_ID)\n", - "engagements = client.engagements_for_client(CLIENT_NAME)\n", - "\n", - "if proposals:\n", - " print(f\"Proposals for {CLIENT_NAME}:\")\n", - " display(pd.DataFrame([\n", - " {\"id\": p[\"id\"], \"name\": p.get(\"name\"), \"status\": p.get(\"status\"),\n", - " \"opportunity\": (p.get(\"opportunity\") or {}).get(\"name\"),\n", - " \"due_date\": p.get(\"due_date\")}\n", - " for p in proposals\n", - " ]))\n", - "if engagements:\n", - " print(f\"Engagements for {CLIENT_NAME}:\")\n", - " display(pd.DataFrame([\n", - " {\"id\": e[\"id\"], \"name\": e.get(\"name\"), \"status\": e.get(\"status\"),\n", - " \"start\": e.get(\"start_date\"), \"end\": e.get(\"end_date\")}\n", - " for e in engagements\n", - " ]))\n", - "if not proposals and not engagements:\n", - " print(f\"{CLIENT_NAME} has no proposals or engagements yet — \"\n", - " \"the next cell can create a sandbox opportunity + proposal.\")" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "19336bcc", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Auto-selected proposal 1: Secure Cloud Infrastructure Modernization\n", - "Attaching via: {'proposal': 1}\n" - ] - } - ], - "source": [ - "# Set exactly ONE of these (ids from the tables above). Leave both None to\n", - "# auto-pick — single existing proposal/engagement wins; otherwise a sandbox\n", - "# opportunity + proposal is created for the client.\n", - "PROPOSAL_ID = config.PROPOSAL_ID # or e.g. 42\n", - "ENGAGEMENT_ID = config.ENGAGEMENT_ID # or e.g. 7\n", - "\n", - "if PROPOSAL_ID is None and ENGAGEMENT_ID is None:\n", - " if len(proposals) == 1 and not engagements:\n", - " PROPOSAL_ID = proposals[0][\"id\"]\n", - " print(f\"Auto-selected proposal {PROPOSAL_ID}: {proposals[0].get('name')}\")\n", - " elif len(engagements) == 1 and not proposals:\n", - " ENGAGEMENT_ID = engagements[0][\"id\"]\n", - " print(f\"Auto-selected engagement {ENGAGEMENT_ID}: {engagements[0].get('name')}\")\n", - " elif not proposals and not engagements:\n", - " opp = client.create_opportunity(\n", - " name=f\"{CLIENT_NAME} — CX Transformation (sandbox)\",\n", - " client_id=CLIENT_ID,\n", - " description=\"Created by Palladium 00_provision for the Amazon Connect TEI.\",\n", - " )\n", - " prop = client.create_proposal(\n", - " name=f\"{CLIENT_NAME} — Amazon Connect TEI (sandbox)\",\n", - " opportunity_id=opp[\"id\"],\n", - " status=\"Draft\",\n", - " )\n", - " PROPOSAL_ID = prop[\"id\"]\n", - " print(f\"Created opportunity {opp['id']} and proposal {PROPOSAL_ID} for {CLIENT_NAME}.\")\n", - " else:\n", - " raise SystemExit(\"Multiple options — set PROPOSAL_ID or ENGAGEMENT_ID above and re-run.\")\n", - "\n", - "assert (PROPOSAL_ID is None) != (ENGAGEMENT_ID is None), \\\n", - " \"Set exactly one of PROPOSAL_ID / ENGAGEMENT_ID.\"\n", - "attach = {\"proposal\": PROPOSAL_ID} if PROPOSAL_ID else {\"engagement\": ENGAGEMENT_ID}\n", - "print(f\"Attaching via: {attach}\")" - ] - }, - { - "cell_type": "markdown", - "id": "0056bce9", - "metadata": {}, - "source": [ - "## 5 · Tool instance (find or create) & seed the published values" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "017ae9db", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Created tool pkrsQ9SRf654 attached to {'proposal': 1}\n" - ] - } - ], - "source": [ - "from core.tei_client import AthenaAPIError\n", - "\n", - "def _report_id_of(t):\n", - " r = t.get(\"report\")\n", - " return r.get(\"id\") if isinstance(r, dict) else r\n", - "\n", - "def _matches_attachment(t):\n", - " if PROPOSAL_ID is not None:\n", - " opp = t.get(\"opportunity\") or {}\n", - " return t.get(\"proposal\") == PROPOSAL_ID or opp.get(\"proposal_id\") == PROPOSAL_ID\n", - " eng = t.get(\"engagement\")\n", - " eng_id = eng.get(\"id\") if isinstance(eng, dict) else eng\n", - " return eng_id == ENGAGEMENT_ID\n", - "\n", - "candidates = [t for t in client.list_tools() if _report_id_of(t) == REPORT_ID]\n", - "tool = next((t for t in candidates if _matches_attachment(t)),\n", - " candidates[0] if len(candidates) == 1 else None)\n", - "\n", - "if tool is None:\n", - " try:\n", - " tool = client.create_tool(\n", - " report_public_id=REPORT_ID,\n", - " name=f\"{CLIENT_NAME} — Amazon Connect TEI\",\n", - " **attach,\n", - " )\n", - " print(f\"Created tool {tool['id']} attached to {attach}\")\n", - " except AthenaAPIError as e:\n", - " if e.status_code == 409: # DUPLICATE_INSTANCE\n", - " raise SystemExit(\n", - " \"An active tool already exists for this report + attachment. \"\n", - " \"Find it with client.list_tools() or pick a different proposal/engagement.\"\n", - " ) from e\n", - " raise\n", - "else:\n", - " print(f\"Found existing tool {tool['id']} (status: {tool.get('status')})\")\n", - "\n", - "TOOL_ID = tool[\"id\"]" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "20e2a736", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Pushed values for 8 fields.\n" - ] - } - ], - "source": [ - "payload = []\n", - "for b in seed.BENEFITS: # nominal; Athena risk-adjusts via the field definition\n", - " payload.append({\n", - " \"field_key\": b[\"field_key\"],\n", - " \"year_values\": b[\"year_values\"],\n", - " \"notes\": b[\"notes\"],\n", - " })\n", - "for c in seed.COSTS: # risk-adjusted UP client-side (Forrester methodology)\n", - " factor = 1 + c[\"risk_adjustment\"]\n", - " payload.append({\n", - " \"field_key\": c[\"field_key\"],\n", - " \"year_values\": {y: round(v * factor, 2) for y, v in c[\"year_values\"].items()},\n", - " \"initial\": round(c[\"initial\"] * factor, 2),\n", - " \"notes\": c[\"notes\"],\n", - " })\n", - "\n", - "client.update_values(TOOL_ID, payload)\n", - "print(f\"Pushed values for {len(payload)} fields.\")" - ] - }, - { - "cell_type": "markdown", - "id": "697794fd", - "metadata": {}, - "source": [ - "## 6 · Calculate & verify against the published study" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "b7ac5d24", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "════════════════════════════════════════════════════════\n", - " TEI Financial Summary\n", - "════════════════════════════════════════════════════════\n", - " Total Benefits (PV): $ 101,696,568\n", - " Total Costs (PV): $ 22,874,326\n", - "────────────────────────────────────────────────────────\n", - " Net Present Value: $ 78,822,242\n", - " ROI: 345%\n", - " Payback: 1.0 months\n", - "════════════════════════════════════════════════════════\n" - ] - } - ], - "source": [ - "summary = client.calculate(TOOL_ID)\n", - "client.print_summary(TOOL_ID)" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "13d84001", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
metricpublishedathenadiff
0total_benefits_pv101,696,791101,696,568-0.00%
1total_costs_pv22,983,07622,874,326-0.47%
2net_present_value78,713,71578,822,242+0.14%
3roi_percentage342345+0.76%
\n", - "
" - ], - "text/plain": [ - " metric published athena diff\n", - "0 total_benefits_pv 101,696,791 101,696,568 -0.00%\n", - "1 total_costs_pv 22,983,076 22,874,326 -0.47%\n", - "2 net_present_value 78,713,715 78,822,242 +0.14%\n", - "3 roi_percentage 342 345 +0.76%" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Payback: 1 months (published: <6 months)\n", - "✅ Verified — Athena reproduces the published Forrester totals.\n" - ] - } - ], - "source": [ - "# Published Forrester totals (3-yr risk-adjusted PV @ 10%)\n", - "PUBLISHED = {\n", - " \"total_benefits_pv\": 101_696_791,\n", - " \"total_costs_pv\": 22_983_076,\n", - " \"net_present_value\": 78_713_715,\n", - " \"roi_percentage\": 342,\n", - "}\n", - "# Tolerance: Athena discounts Year-0 'initial' amounts as Year 1 (Forrester\n", - "# leaves Year 0 undiscounted) — expected drift is ~$0.1M on costs (≈0.15%).\n", - "TOLERANCE = 0.02\n", - "\n", - "rows, ok = [], True\n", - "for key, expected in PUBLISHED.items():\n", - " actual = float(summary.get(key) or 0)\n", - " diff = (actual - expected) / expected\n", - " rows.append({\"metric\": key, \"published\": f\"{expected:,.0f}\",\n", - " \"athena\": f\"{actual:,.0f}\", \"diff\": f\"{diff:+.2%}\"})\n", - " ok &= abs(diff) <= TOLERANCE\n", - "\n", - "display(pd.DataFrame(rows))\n", - "payback = summary.get(\"payback_period_months\")\n", - "print(f\"Payback: {payback} months (published: <6 months)\")\n", - "assert ok, f\"Server totals drifted more than {TOLERANCE:.0%} from the published study — investigate before proceeding.\"\n", - "print(\"✅ Verified — Athena reproduces the published Forrester totals.\")" - ] - }, - { - "cell_type": "markdown", - "id": "b48b6131", - "metadata": {}, - "source": [ - "## 7 · Save a baseline version & persist IDs" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "148bdb2a", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Saved version 1 (baseline).\n", - "Saved to /Users/robert/git/palladium/.env:\n", - " PALLADIUM_REPORT_PUBLIC_ID=xsUTbjh4iDnJ\n", - " PALLADIUM_TOOL_PUBLIC_ID=pkrsQ9SRf654\n", - " PALLADIUM_PROPOSAL_ID=1\n" - ] - } - ], - "source": [ - "if not client.list_versions(TOOL_ID):\n", - " client.save_version(TOOL_ID, note=\"Baseline — published Forrester TEI figures (Feb 2026), moderate scenario.\")\n", - " print(\"Saved version 1 (baseline).\")\n", - "\n", - "ids = {\n", - " \"PALLADIUM_REPORT_PUBLIC_ID\": REPORT_ID,\n", - " \"PALLADIUM_TOOL_PUBLIC_ID\": TOOL_ID,\n", - "}\n", - "if PROPOSAL_ID is not None:\n", - " ids[\"PALLADIUM_PROPOSAL_ID\"] = str(PROPOSAL_ID)\n", - "if ENGAGEMENT_ID is not None:\n", - " ids[\"PALLADIUM_ENGAGEMENT_ID\"] = str(ENGAGEMENT_ID)\n", - "\n", - "env_path = update_env(**ids)\n", - "print(f\"Saved to {env_path}:\")\n", - "for k, v in ids.items():\n", - " print(f\" {k}={v}\")" - ] - }, - { - "cell_type": "markdown", - "id": "571b48c3", - "metadata": {}, - "source": [ - "## Done\n", - "\n", - "The sandbox now has a live, calculated Amazon Connect TEI tool attached to\n", - "the selected client's proposal/engagement — with the client's CRM profile\n", - "(industry, agent counts, revenue) flowing into the tool automatically.\n", - "\n", - "- **Continue the analysis** → `01_benefits.ipynb` → `04_export.ipynb` (they pick up the IDs from `.env` via `config.py`)\n", - "- **Interactive editing** → `make app` / `streamlit run app/main.py` — the tool appears in the sidebar\n", - "- **CLI sanity check** → `python -m palladium summary $PALLADIUM_TOOL_PUBLIC_ID`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e9285087-5a2d-4a8d-856c-802474432892", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.7" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/studies/202602_AmazonConnect/notebooks/01_benefits.ipynb b/studies/202602_AmazonConnect/notebooks/01_benefits.ipynb deleted file mode 100644 index ee3c881..0000000 --- a/studies/202602_AmazonConnect/notebooks/01_benefits.ipynb +++ /dev/null @@ -1,1333 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "231c773a", - "metadata": {}, - "source": [ - "# 01 — Benefits Analysis\n", - "\n", - "**Study:** Forrester *Total Economic Impact™ Of Amazon Connect* (Feb 2026)\n", - "\n", - "Quantify the five benefit categories Forrester identified for the\n", - "composite organization, push them into Athena, and verify the totals\n", - "match the published study (Benefits PV ≈ **$101.7M**)." - ] - }, - { - "cell_type": "markdown", - "id": "110d7e61", - "metadata": {}, - "source": [ - "## Setup\n", - "\n", - "We add the project root to `sys.path` so the notebook can import `core` and\n", - "the study's local modules without `pip install -e .`." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "c83c2758", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Project root: /Users/robert/git/palladium\n", - "Study root: /Users/robert/git/palladium/studies/202602_AmazonConnect\n" - ] - } - ], - "source": [ - "import sys\n", - "from pathlib import Path\n", - "\n", - "ROOT = Path.cwd().resolve()\n", - "while ROOT != ROOT.parent and not (ROOT / 'core').is_dir():\n", - " ROOT = ROOT.parent\n", - "if str(ROOT) not in sys.path:\n", - " sys.path.insert(0, str(ROOT))\n", - "\n", - "STUDY = ROOT / 'studies' / '202602_AmazonConnect'\n", - "if str(STUDY) not in sys.path:\n", - " sys.path.insert(0, str(STUDY))\n", - "print(f'Project root: {ROOT}')\n", - "print(f'Study root: {STUDY}')" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "c371ef85", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Study: 202602_AmazonConnect • discount rate 10% • 3-year horizon
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import config\n", - "import seed_data\n", - "from core.calculations import npv, risk_adjust_benefit\n", - "from core.notebook_helpers import charts, display, tables\n", - "\n", - "display.alert(\n", - " f'Study: {config.STUDY_SLUG} • discount rate {config.DISCOUNT_RATE:.0%} '\n", - " f'• {config.ANALYSIS_YEARS}-year horizon',\n", - " 'info',\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "fd94503d", - "metadata": {}, - "source": [ - "## Benefits — nominal & risk-adjusted\n", - "\n", - "Forrester quantifies five benefit categories:\n", - "\n", - "| Ref | Benefit | Y1 | Y2 | Y3 | Risk Adj |\n", - "|---|---|---|---|---|---|\n", - "| At | AI-driven contact resolution efficiency | $13.9M | $23.9M | $37.8M | 15% |\n", - "| Bt | AI-powered content & sentiment analysis | $4.6M | $5.4M | $6.3M | 15% |\n", - "| Ct | AI-enabled forecasting & supervision | $6.7M | $9.1M | $12.4M | 15% |\n", - "| Dt | Data-driven profit lift (conversion +20%) | $1.2M | $1.6M | $2.0M | 20% |\n", - "| Et | Legacy solution cost savings | $6.2M | $8.0M | $10.4M | 20% |\n", - "\n", - "All five are seeded in `seed_data.BENEFITS` with full source notes." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "6177ea7c", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
 field_keylabelcategoryrisk_adjustmentYear 1Year 1 (RA)Year 2Year 2 (RA)Year 3Year 3 (RA)TotalTotal (RA)
0ai_contact_resolutionAI-driven contact resolution efficiencyProductivity0.150000$13,911,040$11,824,384$23,932,480$20,342,608$37,797,760$32,128,096$75,641,280$64,295,088
1ai_content_sentimentAI-powered content and sentiment analysis savingsProductivity0.150000$4,586,620$3,898,627$5,358,412$4,554,650$6,291,680$5,347,928$16,236,712$13,801,205
2ai_forecasting_supervisionAI-enabled forecasting, agent scheduling, and supervisionProductivity0.150000$6,651,680$5,653,928$9,133,760$7,763,696$12,391,712$10,532,955$28,177,152$23,950,579
3data_driven_profit_liftData-driven profit lift with increased conversionRevenue0.200000$1,200,000$960,000$1,560,000$1,248,000$2,028,000$1,622,400$4,788,000$3,830,400
4legacy_solution_savingsLegacy solution cost savingsCost Savings0.200000$6,177,600$4,942,080$8,030,880$6,424,704$10,440,144$8,352,115$24,648,624$19,718,899
\n" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df = tables.benefits_table(seed_data.BENEFITS)\n", - "df.style.format({col: '${:,.0f}' for col in df.columns if col not in ('field_key','label','category','risk_adjustment')})" - ] - }, - { - "cell_type": "markdown", - "id": "573f12d8", - "metadata": {}, - "source": [ - "## Local validation against the PDF\n", - "\n", - "Re-derive the per-benefit risk-adjusted PV and confirm we land on Forrester's\n", - "**$101,696,791** total within rounding." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "8cf32003", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
 BenefitY1 (RA)Y2 (RA)Y3 (RA)PV
0AI-driven contact resolution efficiency$11,824,384$20,342,608$32,128,096$51,699,827
1AI-powered content and sentiment analysis savings$3,898,627$4,554,650$5,347,928$11,326,358
2AI-enabled forecasting, agent scheduling, and supervision$5,653,928$7,763,696$10,532,955$19,469,777
3Data-driven profit lift with increased conversion$960,000$1,248,000$1,622,400$3,123,065
4Legacy solution cost savings$4,942,080$6,424,704$8,352,115$16,077,540
5TOTAL$27,279,019$40,333,658$57,983,494$101,696,568
\n" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import pandas as pd\n", - "\n", - "rows = []\n", - "for b in seed_data.BENEFITS:\n", - " rf = b['risk_adjustment']\n", - " yr = [b['year_values'][str(y)] for y in (1, 2, 3)]\n", - " yr_ra = [risk_adjust_benefit(v, rf) for v in yr]\n", - " pv = npv(yr_ra, config.DISCOUNT_RATE)\n", - " rows.append({\n", - " 'Benefit': b['label'],\n", - " 'Y1 (RA)': yr_ra[0],\n", - " 'Y2 (RA)': yr_ra[1],\n", - " 'Y3 (RA)': yr_ra[2],\n", - " 'PV': pv,\n", - " })\n", - "df_check = pd.DataFrame(rows)\n", - "df_check.loc[len(df_check)] = ['TOTAL', df_check['Y1 (RA)'].sum(), df_check['Y2 (RA)'].sum(), df_check['Y3 (RA)'].sum(), df_check['PV'].sum()]\n", - "df_check.style.format({c: '${:,.0f}' for c in df_check.columns if c != 'Benefit'})" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "3ded50c8", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Computed Benefits PV: $101,696,568
Forrester target: $101,696,791
Δ = $-223 (rounding)
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "expected_pv = 101_696_791\n", - "computed_pv = df_check.iloc[-1]['PV']\n", - "delta = computed_pv - expected_pv\n", - "kind = 'success' if abs(delta) < 1_000 else 'warning'\n", - "display.alert(\n", - " f'Computed Benefits PV: ${computed_pv:,.0f}
'\n", - " f'Forrester target: ${expected_pv:,.0f}
'\n", - " f'Δ = ${delta:,.0f} (rounding)',\n", - " kind,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "a5ad453a", - "metadata": {}, - "source": [ - "## Visualize\n", - "\n", - "Horizontal bar chart of risk-adjusted three-year totals — mirrors the PDF p.6\n", - "*Benefits (Three-Year)* graphic." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "452b8408", - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.plotly.v1+json": { - "config": { - "plotlyServerURL": "https://plot.ly" - }, - "data": [ - { - "marker": { - "color": "#2E7D32" - }, - "orientation": "h", - "text": [ - "$64.3M", - "$13.8M", - "$24.0M", - "$3.8M", - "$19.7M" - ], - "textposition": "auto", - "type": "bar", - "x": [ - 64295088, - 13801205.2, - 23950579.2, - 3830400, - 19718899.2 - ], - "y": [ - "AI-driven contact resolution efficiency", - "AI-powered content and sentiment analysis savings", - "AI-enabled forecasting, agent scheduling, and supervision", - "Data-driven profit lift with increased conversion", - "Legacy solution cost savings" - ] - } - ], - "layout": { - "font": { - "color": "#1F2937", - "family": "Helvetica, Arial, sans-serif" - }, - "legend": { - "font": { - "color": "#1F2937", - "family": "Helvetica, Arial, sans-serif" - } - }, - "margin": { - "b": 40, - "l": 40, - "r": 20, - "t": 60 - }, - "template": { - "data": { - "bar": [ - { - "error_x": { - "color": "#2a3f5f" - }, - "error_y": { - "color": "#2a3f5f" - }, - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "bar" - } - ], - "barpolar": [ - { - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "barpolar" - } - ], - "carpet": [ - { - "aaxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "baxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "type": "carpet" - } - ], - "choropleth": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "choropleth" - } - ], - "contour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "contour" - } - ], - "contourcarpet": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "contourcarpet" - } - ], - "heatmap": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "heatmap" - } - ], - "histogram": [ - { - "marker": { - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "histogram" - } - ], - "histogram2d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "histogram2d" - } - ], - "histogram2dcontour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "histogram2dcontour" - } - ], - "mesh3d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "mesh3d" - } - ], - "parcoords": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "parcoords" - } - ], - "pie": [ - { - "automargin": true, - "type": "pie" - } - ], - "scatter": [ - { - "fillpattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - }, - "type": "scatter" - } - ], - "scatter3d": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatter3d" - } - ], - "scattercarpet": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattercarpet" - } - ], - "scattergeo": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattergeo" - } - ], - "scattergl": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattergl" - } - ], - "scattermap": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattermap" - } - ], - "scattermapbox": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattermapbox" - } - ], - "scatterpolar": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolar" - } - ], - "scatterpolargl": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolargl" - } - ], - "scatterternary": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterternary" - } - ], - "surface": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "surface" - } - ], - "table": [ - { - "cells": { - "fill": { - "color": "#EBF0F8" - }, - "line": { - "color": "white" - } - }, - "header": { - "fill": { - "color": "#C8D4E3" - }, - "line": { - "color": "white" - } - }, - "type": "table" - } - ] - }, - "layout": { - "annotationdefaults": { - "arrowcolor": "#2a3f5f", - "arrowhead": 0, - "arrowwidth": 1 - }, - "autotypenumbers": "strict", - "coloraxis": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "colorscale": { - "diverging": [ - [ - 0, - "#8e0152" - ], - [ - 0.1, - "#c51b7d" - ], - [ - 0.2, - "#de77ae" - ], - [ - 0.3, - "#f1b6da" - ], - [ - 0.4, - "#fde0ef" - ], - [ - 0.5, - "#f7f7f7" - ], - [ - 0.6, - "#e6f5d0" - ], - [ - 0.7, - "#b8e186" - ], - [ - 0.8, - "#7fbc41" - ], - [ - 0.9, - "#4d9221" - ], - [ - 1, - "#276419" - ] - ], - "sequential": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "sequentialminus": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ] - }, - "colorway": [ - "#636efa", - "#EF553B", - "#00cc96", - "#ab63fa", - "#FFA15A", - "#19d3f3", - "#FF6692", - "#B6E880", - "#FF97FF", - "#FECB52" - ], - "font": { - "color": "#2a3f5f" - }, - "geo": { - "bgcolor": "white", - "lakecolor": "white", - "landcolor": "#E5ECF6", - "showlakes": true, - "showland": true, - "subunitcolor": "white" - }, - "hoverlabel": { - "align": "left" - }, - "hovermode": "closest", - "mapbox": { - "style": "light" - }, - "paper_bgcolor": "white", - "plot_bgcolor": "#E5ECF6", - "polar": { - "angularaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "bgcolor": "#E5ECF6", - "radialaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "scene": { - "xaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - }, - "yaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - }, - "zaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - } - }, - "shapedefaults": { - "line": { - "color": "#2a3f5f" - } - }, - "ternary": { - "aaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "baxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "bgcolor": "#E5ECF6", - "caxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "title": { - "x": 0.05 - }, - "xaxis": { - "automargin": true, - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "zerolinewidth": 2 - }, - "yaxis": { - "automargin": true, - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "zerolinewidth": 2 - } - } - }, - "title": { - "font": { - "color": "#1F2937", - "family": "Helvetica Neue, Arial, sans-serif" - }, - "text": "Benefits (Three-Year)" - }, - "xaxis": { - "tickformat": "$,.0f" - }, - "yaxis": { - "autorange": "reversed" - } - } - }, - "image/png": "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fihAQNMPG40iI4AAAggggAACCCCAAAIIIIAAAgggEFUFCGhG1Zan3ggggAACCCCAAAIIIIAAAggggAACCPihAAFNP2w0iowAAggggAACCCCAAAIIIIAAAggggEBUFSCgGVVbnnojgAACCCCAAAIIIIAAAggggAACCCDghwIENP2w0SgyAggggAACCCCAAAIIIIAAAggggAACUVWAgGZUbXnqjQACCCCAAAIIIIAAAggggAACCCCAgB8KEND0w0ajyAgggAACCCCAAAIIIIAAAggggAACCERVAQKaUbXlqTcCCCCAAAIIIIAAAggggAACCCCAAAJ+KEBA0w8bjSIjgAACCCCAAAIIIIAAAggggAACCCAQVQUIaEbVlqfeCCCAAAIIIIAAAggggAACCCCAAAII+KEAAU0/bDSKjAACCCCAAAIIIIAAAggggAACCCCAQFQVIKAZVVueeiOAAAIIIIAAAggggAACCCCAAAIIIOCHAgQ0/bDRKDICCCCAAAIIIIAAAggggAACCCCAAAJRVYCAZlRteeqNAAIIIIAAAggggAACCCCAAAIIIICAHwoQ0PTDRqPICCCAAAIIIIAAAggggAACCCCAAAIIRFUBAppRteWpNwIIIIAAAggggAACCCCAAAIIIIAAAn4oQEDTDxuNIiOAAAIIIIAAAggggAACCCCAAAIIIBBVBYKjasWpNwIIIOAIHDpxydnkG4F7FggIEEmRMKb8e+ryPd/LDQi4CySMG02uXL0pl67ecD/MNgL3JBAtOEASxI4ux89euaf7uBiBsAJJE8SQM+evyrUbt8KeYh+BcAvEihEkMYID5fSFa+G+hwsR8CSQMlFMOXL6stzijyRPPH5xLHWSWBFaTnpoRignmSGAAAIIIIAAAggggAACCCCAAAIIIIDAwxQgoPkwdckbAQQQQAABBBBAAAEEEEAAAQQQQAABBCJUgIBmhHKSGQIIIIAAAggggAACCCCAAAIIIIAAAgg8TAECmg9Tl7wRQAABBBBAAAEEEEAAAQQQQAABBBBAIEIFAm6ZFKE5khkCCCDgRwJr/94qZy6e96MSU9TIKBAjWqBcuXYzMhaNMvmRQHBQgNw0fy27yavkR60W+YqqC5Xpu3TtOn/Fj3yt418l0gWmrpsFgfh/i/7VbpGttIGmC1Wg+YNJ3yUSAg8iEJX/vp08XkpJHj/F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UhsEEIimQIbUqeX8xfPRPIvkCCCAAAIIIIAAAggggAACCCAQVwLMoRlX8lwXAQQQQAABBBBAAAEEEEAAAQQQQAABBKItQEAz2mScgAACCCCAAAIIIIAAAggggAACCCCAAAJxJUBAM67kuS4CCCCAAAIIIIAAAggggAACCCCAAAIIRFuAgGa0yTgBAQQQQAABBBBAAAEEEEAAAQQQQAABBOJKgIBmXMlzXQQQQAABBBBAAAEEEEAAAQQQQAABBBCItgABzWiTcQICCCCAAAIIIIAAAggggAACCCCAAAIIxJUAAc24kue6CCCAAAIIIIAAAggggAACCCCAAAIIIBBtAQKa0SbjBAQQQAABBBBAAAEEEEAAAQQQQAABBBCIKwECmnElz3URQCBeCFy+ci1elINCBK6AyyXCfRS47UfJEUAAAQQQQAABBBBAIPAEQgOvyJQYAQQQiDmBqas+k22H/o65DMkpKAUShYTINY1ssiEQDYHK+e+R8nkrR+MMkiKAAAIIIIAAAggggIAKENDkPkAAgaAWWL5lifyxb11QG1B5BBCIG4GsabMT0Iwbeq6KAAIIIIAAAgggEOACDDkP8Aak+AgggAACCCCAAAIIIIAAAggggAACCASTAAHNYGpt6ooAAggggAACCCCAAAIIIIAAAggggECACxDQDPAGpPgIIIAAAggggAACCCCAAAIIIIAAAggEkwABzWBqbeqKAAIIIIAAAggggAACCCCAAAIIIIBAgAsQ0AzwBqT4CCCAAAIIIIAAAggggAACCCCAAAIIBJMAAc1gam3qigACCCCAAAIIIIAAAggggAACCCCAQIALENAM8Aak+AgggAACCCCAAAIIIIAAAggggAACCASTAAHNYGpt6ooAAggggAACCCCAAAIIIIAAAggggECACxDQDPAGpPgIIIAAAggggAACCCCAAAIIIIAAAggEkwABzWBqbeqKAAIIIIAAAggggAACCCCAAAIIIIBAgAsQ0AzwBqT4CCCAAAIIIIAAAggggAACCCCAAAIIBJMAAc1gam3qigACCCCAAAIIIIAAAggggAACCCCAQIALENAM8Aak+AgggAACCCCAAAIIIIAAAggggAACCASTAAHNYGpt6ooAAggggAACCCCAAAIIIIAAAggggECACxDQDPAGpPgIIIAAAggggAACCCCAAAIIIIAAAggE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AAIIIIAAAggggAACCCCAAAIIIIBAFAUIaEYRimQIIIAAAggggAACCCCAAAIIIIAAAgggEPcCBDTjvg0oAQIIIIAAAggggAACCCCAAAIIIIAAAghEUYCAZhShSIYAAggggAACCCCAAAIIIIAAAggggAACcS9AQDPu24ASIIAAAggggAACCCCAAAIIIIAAAggggEAUBQhoRhGKZAgggAACCCCAAAIIIIAAAggggAACCCAQ9wIENOO+DSgBAggggAACCCCAAAIIIIAAAggggAACCERRgIBmFKFIhgACCCCAAAIIIIAAAggggAACCCCAAAJxL0BAM+7bgBIggAACCCCAAAIIIIAAAggggAACCCCAQBQFCGhGEYpkCCCAAAIIIIAAAggggAACCCCAAAIIIBD3AgQ0474NKAECCCCAAAIIIIAAAggggAACCCCAAAIIRFGAgGYUoUiGAAIIIIAAAggggAACCCCAAAIIIIAAAnEvQEAz7tuAEiCAAAIIIIAAAggggAACCCCAAAIIIIBAFAUIaEYRimQIIIAAAggggAACCCCAAAIIIIAAAgggEPcCBDTjvg0oAQIIIIAAAggggAACCCCAAAIIIIAAAghEUYCAZhShSIYAAggggAACCCCAAAIIIIAAAggggAACcS9AQDPu24ASIIAAAggggAACCCCAAAIIIIAAAggggEAUBQhoRhGKZAgggAACCCCAAAIIIIAAAggggAACCCAQ9wIENOO+DSgBAggggAACCCCAAAIIIIAAAggggAACCERRgIBmFKFIhgACCCCAAAIIIIAAAggggAACCCCAAAJxL0BAM+7bgBIggAACCCCAAAIIIIAAAggggAACCCCAQBQFCGhGEYpkCCCAAAIIIIAAAggggAACCCCAAAIIIBD3AgQ0474NKAECCCCAAAIIIIAAAggggAACCCCAAAIIRFHg/9B6hxOMlIJWAAAAAElFTkSuQmCC" - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "charts.benefits_bar(seed_data.BENEFITS).show()" - ] - }, - { - "cell_type": "markdown", - "id": "1c4591f5", - "metadata": {}, - "source": [ - "## Push to Athena\n", - "\n", - "When `config.TOOL_PUBLIC_ID` is set, persist the seed values to the live\n", - "TEI tool. Otherwise this cell is a no-op so the notebook still runs\n", - "offline." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "d10a54b6", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
No TOOL_PUBLIC_ID set in config.py — skipped Athena push. Set PALLADIUM_TOOL_PUBLIC_ID in your environment or edit config.py to enable.
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "if config.TOOL_PUBLIC_ID:\n", - " from core.tei_client import TEIClient\n", - "\n", - " client = TEIClient()\n", - " result = client.update_values(config.TOOL_PUBLIC_ID, seed_data.BENEFITS)\n", - " display.alert(f'Pushed {len(seed_data.BENEFITS)} benefit rows to '\n", - " f'tool {config.TOOL_PUBLIC_ID}.', 'success')\n", - "else:\n", - " display.alert(\n", - " 'No TOOL_PUBLIC_ID set in config.py — skipped Athena push. '\n", - " 'Set PALLADIUM_TOOL_PUBLIC_ID in your environment '\n", - " 'or edit config.py to enable.',\n", - " 'info',\n", - " )" - ] - }, - { - "cell_type": "markdown", - "id": "78693c14", - "metadata": {}, - "source": [ - "---\n", - "\n", - "Continue with [`02_costs.ipynb`](02_costs.ipynb) →" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.7" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/studies/202602_AmazonConnect/notebooks/02_costs.ipynb b/studies/202602_AmazonConnect/notebooks/02_costs.ipynb deleted file mode 100644 index 8c48d08..0000000 --- a/studies/202602_AmazonConnect/notebooks/02_costs.ipynb +++ /dev/null @@ -1,1197 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "1a76b7ed", - "metadata": {}, - "source": [ - "# 02 — Costs Analysis\n", - "\n", - "**Study:** Forrester TEI™ Of Amazon Connect (Feb 2026)\n", - "\n", - "Three cost categories, three-year horizon, 10% discount rate.\n", - "Target risk-adjusted PV = **$22,983,076**." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "46446223", - "metadata": {}, - "outputs": [], - "source": [ - "import sys\n", - "from pathlib import Path\n", - "\n", - "ROOT = Path.cwd().resolve()\n", - "while ROOT != ROOT.parent and not (ROOT / 'core').is_dir():\n", - " ROOT = ROOT.parent\n", - "if str(ROOT) not in sys.path:\n", - " sys.path.insert(0, str(ROOT))\n", - "STUDY = ROOT / 'studies' / '202602_AmazonConnect'\n", - "if str(STUDY) not in sys.path:\n", - " sys.path.insert(0, str(STUDY))" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "4ec64198", - "metadata": {}, - "outputs": [], - "source": [ - "import config\n", - "import seed_data\n", - "from core.calculations import npv, risk_adjust_cost\n", - "from core.notebook_helpers import charts, display, tables" - ] - }, - { - "cell_type": "markdown", - "id": "26f1d385", - "metadata": {}, - "source": [ - "## Costs — nominal & risk-adjusted\n", - "\n", - "| Ref | Cost | Initial | Y1 | Y2 | Y3 | Risk Adj |\n", - "|---|---|---|---|---|---|---|\n", - "| Ft | Amazon Connect usage | — | $6.5M | $8.0M | $9.8M | ↑5% |\n", - "| Gt | Implementation & migration | $1.09M | $188K | $188K | — | ↑10% |\n", - "| Ht | Ongoing management | — | $256K | $187K | $187K | ↑15% |\n", - "\n", - "Note **costs are risk-adjusted *upward*** (higher risk → higher modelled cost)." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "9635f334", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
 field_keylabelcategoryrisk_adjustmentInitialInitial (RA)Year 1Year 1 (RA)Year 2Year 2 (RA)Year 3Year 3 (RA)TotalTotal (RA)
0amazon_connect_usageAmazon Connect usage costSubscription0.050000$0$0$6,456,448$6,779,270$7,951,164$8,348,722$9,832,961$10,324,609$24,240,573$25,452,602
1implementation_migrationImplementation and migration costImplementation0.100000$1,087,500$1,196,250$188,333$207,166$188,333$207,166$0$0$1,464,166$1,610,583
2ongoing_managementOngoing managementOperations0.150000$0$0$256,200$294,630$187,200$215,280$187,200$215,280$630,600$725,190
\n" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df = tables.costs_table(seed_data.COSTS)\n", - "df.style.format({c: '${:,.0f}' for c in df.columns if c not in ('field_key','label','category','risk_adjustment')})" - ] - }, - { - "cell_type": "markdown", - "id": "0667d1da", - "metadata": {}, - "source": [ - "## Local validation\n", - "\n", - "Reproduce the **$22,983,076** Costs PV from the PDF Cash Flow Analysis." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "3e35a794", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
 CostInitial (RA)Y1 (RA)Y2 (RA)Y3 (RA)PV
0Amazon Connect usage cost$0$6,779,270$8,348,722$10,324,609$20,819,775
1Implementation and migration cost$1,196,250$207,166$207,166$0$1,555,795
2Ongoing management$0$294,630$215,280$215,280$607,506
3TOTAL$1,196,250$7,281,067$8,771,168$10,539,889$22,983,076
\n" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import pandas as pd\n", - "\n", - "rows = []\n", - "for c in seed_data.COSTS:\n", - " rf = c['risk_adjustment']\n", - " init_ra = risk_adjust_cost(c.get('initial') or 0, rf)\n", - " yr = [c['year_values'][str(y)] for y in (1, 2, 3)]\n", - " yr_ra = [risk_adjust_cost(v, rf) for v in yr]\n", - " pv = npv(yr_ra, config.DISCOUNT_RATE, initial=init_ra)\n", - " rows.append({\n", - " 'Cost': c['label'],\n", - " 'Initial (RA)': init_ra,\n", - " 'Y1 (RA)': yr_ra[0],\n", - " 'Y2 (RA)': yr_ra[1],\n", - " 'Y3 (RA)': yr_ra[2],\n", - " 'PV': pv,\n", - " })\n", - "df_check = pd.DataFrame(rows)\n", - "totals = df_check.drop(columns='Cost').sum()\n", - "df_check.loc[len(df_check)] = ['TOTAL'] + totals.tolist()\n", - "df_check.style.format({c: '${:,.0f}' for c in df_check.columns if c != 'Cost'})" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "4109784e", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Computed Costs PV: $22,983,076
Forrester target: $22,983,076
Δ = $-0
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "expected_pv = 22_983_076\n", - "computed_pv = df_check.iloc[-1]['PV']\n", - "delta = computed_pv - expected_pv\n", - "kind = 'success' if abs(delta) < 1_000 else 'warning'\n", - "display.alert(\n", - " f'Computed Costs PV: ${computed_pv:,.0f}
'\n", - " f'Forrester target: ${expected_pv:,.0f}
'\n", - " f'Δ = ${delta:,.0f}',\n", - " kind,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "dd1b3c04", - "metadata": {}, - "source": [ - "## Cost mix\n", - "\n", - "Most of the three-year cost (~90%) is Amazon Connect *usage* (Ft) —\n", - "consistent with the PDF's framing that consumption-based pricing dominates,\n", - "with implementation a one-time investment." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "90e9b5e2", - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.plotly.v1+json": { - "config": { - "plotlyServerURL": "https://plot.ly" - }, - "data": [ - { - "hole": 0.35, - "labels": [ - "Amazon Connect usage cost", - "Implementation and migration cost", - "Ongoing management" - ], - "type": "pie", - "values": [ - 25452601.650000002, - 1610582.6, - 725190 - ] - } - ], - "layout": { - "margin": { - "b": 40, - "l": 40, - "r": 20, - "t": 60 - }, - "template": { - "data": { - "bar": [ - { - "error_x": { - "color": "#2a3f5f" - }, - "error_y": { - "color": "#2a3f5f" - }, - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "bar" - } - ], - "barpolar": [ - { - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "barpolar" - } - ], - "carpet": [ - { - "aaxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "baxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "type": "carpet" - } - ], - "choropleth": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "choropleth" - } - ], - "contour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "contour" - } - ], - "contourcarpet": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "contourcarpet" - } - ], - "heatmap": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "heatmap" - } - ], - "histogram": [ - { - "marker": { - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "histogram" - } - ], - "histogram2d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "histogram2d" - } - ], - "histogram2dcontour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "histogram2dcontour" - } - ], - "mesh3d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "mesh3d" - } - ], - "parcoords": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "parcoords" - } - ], - "pie": [ - { - "automargin": true, - "type": "pie" - } - ], - "scatter": [ - { - "fillpattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - }, - "type": "scatter" - } - ], - "scatter3d": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatter3d" - } - ], - "scattercarpet": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattercarpet" - } - ], - "scattergeo": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattergeo" - } - ], - "scattergl": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattergl" - } - ], - "scattermap": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattermap" - } - ], - "scattermapbox": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattermapbox" - } - ], - "scatterpolar": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolar" - } - ], - "scatterpolargl": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolargl" - } - ], - "scatterternary": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterternary" - } - ], - "surface": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "surface" - } - ], - "table": [ - { - "cells": { - "fill": { - "color": "#EBF0F8" - }, - "line": { - "color": "white" - } - }, - "header": { - "fill": { - "color": "#C8D4E3" - }, - "line": { - "color": "white" - } - }, - "type": "table" - } - ] - }, - "layout": { - "annotationdefaults": { - "arrowcolor": "#2a3f5f", - "arrowhead": 0, - "arrowwidth": 1 - }, - "autotypenumbers": "strict", - "coloraxis": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "colorscale": { - "diverging": [ - [ - 0, - "#8e0152" - ], - [ - 0.1, - "#c51b7d" - ], - [ - 0.2, - "#de77ae" - ], - [ - 0.3, - "#f1b6da" - ], - [ - 0.4, - "#fde0ef" - ], - [ - 0.5, - "#f7f7f7" - ], - [ - 0.6, - "#e6f5d0" - ], - [ - 0.7, - "#b8e186" - ], - [ - 0.8, - "#7fbc41" - ], - [ - 0.9, - "#4d9221" - ], - [ - 1, - "#276419" - ] - ], - "sequential": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "sequentialminus": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ] - }, - "colorway": [ - "#636efa", - "#EF553B", - "#00cc96", - "#ab63fa", - "#FFA15A", - "#19d3f3", - "#FF6692", - "#B6E880", - "#FF97FF", - "#FECB52" - ], - "font": { - "color": "#2a3f5f" - }, - "geo": { - "bgcolor": "white", - "lakecolor": "white", - "landcolor": "#E5ECF6", - "showlakes": true, - "showland": true, - "subunitcolor": "white" - }, - "hoverlabel": { - "align": "left" - }, - "hovermode": "closest", - "mapbox": { - "style": "light" - }, - "paper_bgcolor": "white", - "plot_bgcolor": "#E5ECF6", - "polar": { - "angularaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "bgcolor": "#E5ECF6", - "radialaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "scene": { - "xaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - }, - "yaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - }, - "zaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - } - }, - "shapedefaults": { - "line": { - "color": "#2a3f5f" - } - }, - "ternary": { - "aaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "baxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "bgcolor": "#E5ECF6", - "caxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "title": { - "x": 0.05 - }, - "xaxis": { - "automargin": true, - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "zerolinewidth": 2 - }, - "yaxis": { - "automargin": true, - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "zerolinewidth": 2 - } - } - }, - "title": { - "text": "Cost Breakdown (Three-Year, Risk-Adjusted)" - } - } - }, - "image/png": "iVBORw0KGgoAAAANSUhEUgAABTQAAAF5CAYAAAChnqWvAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAFNKADAAQAAAABAAABeQAAAADSesO5AABAAElEQVR4AeydB3iTVRuGnw6g7L333sjeS0GWCoiK4I+CAxFRARVBQEWcCAoIIgoKCMgSZMiUpewte++9d6HQpP/7nvKFNG3StLR0Pee6Qr5x5n2+lPbJO3xCpICFBEiABEiABEiABEiABEiABEiABEiABEiABEiABBIAAd8EMEdOkQRIgARIgARIgARIgARIgARIgARIgARIgARIgAQMAQqafBBIgARIgARIgARIgARIgARIgARIgARIgARIgAQSDAEKmglmqzhREiABEiABEiABEiABEiABEiABEiABEiABEiABCpp8BkiABEiABEiABEiABEiABEiABEiABEiABEiABBIMAQqaCWarOFESIAESIAESIAESIAESIAESIAESIAESIAESIAEKmnwGSIAESIAESIAESIAESIAESIAESIAESIAESIAEEgwBCpoJZqs4URIgARIgARIgARIgARIgARIgARIgARIgARIgAQqafAZIgARIgARIgARIgARIgARIgARIgARIgARIgAQSDAEKmglmqzhREiABEiABEiABEiABEiABEiABEiABEiABEiABCpp8BkiABEiABEiABEiABEiABEiABEiABEiABEiABBIMAQqaCWarOFESIAESIAESIAESIAESIAESIAESIAESIAESIAEKmnwGSIAESIAESIAESIAESIAESIAESIAESIAESIAEEgwBCpoJZqs4URIgARIgARIgARIgARIgARIgARIgARIgARIgAQqafAZIgARIgARIgARIgARIgARIgARIgARIgARIgAQSDAEKmglmqzhREiABEiABEiABEiABEiABEiABEiABEiABEiABCpqRPAM3A2/hwOGTOH/xCux2eyS1eduZwMjfZmPmgpXOl7w+DrwVhBHjZmLxik1et4lvFf/+d6NZw9pNO6M8tVUbdpi2Fy5djXJbNohdAiEhIbh2/SZuBt6O0kCbtu01e3rqzIUotYvpyv+s+c/M48q1G2G6vnM32Kzrzp27Ya4nhBPXNR0+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As2SFk63CRAgQIAAAQIECBAgQIAAAQIECNRRQKBZx6obMwECBAgQIECAAAECBAgQIECAAIGSCgg0S1o43SZAgAABAgQIECBAgAABAgQIECBQRwGBZh2rbswECBAgQIAAAQIECBAgQIAAAQIESiog0Cxp4XSbAAECBAgQIECAAAECBAgQIECAQB0FBJp1rLoxEyBAgAABAgQIECBAgAABAgQIECipgECzpIXTbQIECBAgQIAAAQIECBAgQIAAAQJ1FBBo1rHqxkyAAAECBAgQIECAAAECBAgQIECgpAICzZIWTrcJECBAgAABAgQIECBAgAABAgQI1FFAoFnHqhszAQIECBAgQIAAAQIECBAgQIAAgZIKCDRLWjjdJkCAAAECBAgQIECAAAECBAgQIFBHAYFmHatuzAQIECBAgAABAgQIECBAgAABAgRKKiDQLGnhdJsAAQIECBAgQIAAAQIECBAgQIBAHQUEmnWsujETIECAAAECBAgQIECAAAECBAgQKKmAQLOkhdNtAgQIECBAgAABAgQIECBAgAABAnUUEGjWserGTIAAAQIECBAgQIAAAQIECBAgQKCkAgLNkhZOtwkQIECAAAECBAgQIECAAAECBAjUUUCgWceqGzMBAgQIECBAgAABAgQIECBAgACBkgoINEtaON0mQIAAAQIECBAgQIAAAQIECBAgUEcBgWYdq27MBAgQIECAAAECBAgQIECAAAECBEoqINAsaeF0mwABAgQIECBAgAABAgQIECBAgEAdBQSaday6MRMgQIAAAQIECBAgQIAAAQIECBAoqYBAs6SF020CBAgQIECAAAECBAgQIECAAAECdRT4v9IuL6nrkIjwAAAAAElFTkSuQmCC" - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "charts.cost_breakdown_pie(seed_data.COSTS).show()" - ] - }, - { - "cell_type": "markdown", - "id": "3d15ae10", - "metadata": {}, - "source": [ - "## Push to Athena" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "03547040", - "metadata": {}, - "outputs": [], - "source": [ - "if config.TOOL_PUBLIC_ID:\n", - " from core.tei_client import TEIClient\n", - "\n", - " client = TEIClient()\n", - " client.update_values(config.TOOL_PUBLIC_ID, seed_data.COSTS)\n", - " display.alert(f'Pushed {len(seed_data.COSTS)} cost rows to '\n", - " f'tool {config.TOOL_PUBLIC_ID}.', 'success')\n", - "else:\n", - " display.alert('No TOOL_PUBLIC_ID set — skipped Athena push.', 'info')" - ] - }, - { - "cell_type": "markdown", - "id": "6f5befbb", - "metadata": {}, - "source": [ - "Continue with [`03_business_case.ipynb`](03_business_case.ipynb) →" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.7" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/studies/202602_AmazonConnect/notebooks/03_business_case.ipynb b/studies/202602_AmazonConnect/notebooks/03_business_case.ipynb deleted file mode 100644 index b05e827..0000000 --- a/studies/202602_AmazonConnect/notebooks/03_business_case.ipynb +++ /dev/null @@ -1,2996 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "4173501f", - "metadata": {}, - "source": [ - "# 03 — Business Case\n", - "\n", - "Combine the benefits and costs into the consolidated TEI summary,\n", - "render the Cash Flow chart, and run scenario analysis. This notebook\n", - "should reproduce the headline numbers from the PDF Financial Summary:\n", - "\n", - "* **NPV $78.7M • ROI 342% • Payback <6 months**" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "3cc4b453", - "metadata": {}, - "outputs": [], - "source": [ - "import sys\n", - "from pathlib import Path\n", - "\n", - "ROOT = Path.cwd().resolve()\n", - "while ROOT != ROOT.parent and not (ROOT / 'core').is_dir():\n", - " ROOT = ROOT.parent\n", - "if str(ROOT) not in sys.path:\n", - " sys.path.insert(0, str(ROOT))\n", - "STUDY = ROOT / 'studies' / '202602_AmazonConnect'\n", - "if str(STUDY) not in sys.path:\n", - " sys.path.insert(0, str(STUDY))" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "62c56628", - "metadata": {}, - "outputs": [], - "source": [ - "import config\n", - "import seed_data\n", - "from core.export import build_report_data\n", - "from core.export.report_data import _compute_summary\n", - "from core.notebook_helpers import charts, display, tables" - ] - }, - { - "cell_type": "markdown", - "id": "11fdc7c3", - "metadata": {}, - "source": [ - "## Local summary (no Athena round-trip)\n", - "\n", - "Compute the moderate-case TEI summary directly from `seed_data` so the\n", - "notebook produces results even before the Athena tool is provisioned." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "7d295b06", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Forrester composite — moderate case
NPV
$78.7M
ROI
342%
Payback
<6 months (0.7)
Benefits PV
$101.7M
Costs PV
$23.0M
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "summary = _compute_summary(\n", - " seed_data.BENEFITS,\n", - " seed_data.COSTS,\n", - " config.DISCOUNT_RATE,\n", - " config.ANALYSIS_YEARS,\n", - ")\n", - "# `_compute_summary` returns roi_pct; expose it as `roi` for kpi_cards.\n", - "summary['roi'] = summary.get('roi_pct')\n", - "display.kpi_cards(summary, title='Forrester composite — moderate case')" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "c3fc75fb", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
 YearBenefitsCostsNetCumulative
01$27,279,019$7,281,067$19,997,952$18,801,702
12$40,333,658$8,771,168$31,562,490$50,364,192
23$57,983,494$10,539,889$47,443,605$97,807,797
\n" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df_cash = tables.cashflow_table(summary)\n", - "df_cash.style.format({c: '${:,.0f}' for c in df_cash.columns if c != 'Year'})" - ] - }, - { - "cell_type": "markdown", - "id": "dd58e4c8", - "metadata": {}, - "source": [ - "## Cash flow chart\n", - "\n", - "Mirrors the chart on PDF page 25: stacked benefits/costs by year +\n", - "cumulative-net line." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "5d293439", - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.plotly.v1+json": { - "config": { - "plotlyServerURL": "https://plot.ly" - }, - "data": [ - { - "marker": { - "color": "#2E7D32" - }, - "name": "Total benefits", - "type": "bar", - "x": [ - "Initial", - "Year 1", - "Year 2", - "Year 3" - ], - "y": [ - 0, - 27279019, - 40333658.2, - 57983494.400000006 - ] - }, - { - "marker": { - "color": "#C62828" - }, - "name": "Total costs", - "type": "bar", - "x": [ - "Initial", - "Year 1", - "Year 2", - "Year 3" - ], - "y": [ - -1196250, - -7281066.7, - -8771168.5, - -10539889.05 - ] - }, - { - "line": { - "color": "#616161", - "width": 3 - }, - "mode": "lines+markers", - "name": "Cumulative net benefits", - "type": "scatter", - "x": [ - "Initial", - "Year 1", - "Year 2", - "Year 3" - ], - "y": [ - -1196250, - 18801702.3, - 50364192, - 97807797.35000001 - ] - } - ], - "layout": { - "barmode": "relative", - "font": { - "color": "#1F2937", - "family": "Helvetica, Arial, sans-serif" - }, - "legend": { - "font": { - "color": "#1F2937", - "family": "Helvetica, Arial, sans-serif" - }, - "orientation": "h", - "y": -0.15 - }, - "margin": { - "b": 40, - "l": 40, - "r": 20, - "t": 60 - }, - "template": { - "data": { - "bar": [ - { - "error_x": { - "color": "#2a3f5f" - }, - "error_y": { - "color": "#2a3f5f" - }, - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "bar" - } - ], - "barpolar": [ - { - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "barpolar" - } - ], - "carpet": [ - { - "aaxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "baxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "type": "carpet" - } - ], - "choropleth": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "choropleth" - } - ], - "contour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "contour" - } - ], - "contourcarpet": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "contourcarpet" - } - ], - "heatmap": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "heatmap" - } - ], - "histogram": [ - { - "marker": { - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "histogram" - } - ], - "histogram2d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "histogram2d" - } - ], - "histogram2dcontour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "histogram2dcontour" - } - ], - "mesh3d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "mesh3d" - } - ], - "parcoords": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "parcoords" - } - ], - "pie": [ - { - "automargin": true, - "type": "pie" - } - ], - "scatter": [ - { - "fillpattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - }, - "type": "scatter" - } - ], - "scatter3d": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatter3d" - } - ], - "scattercarpet": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattercarpet" - } - ], - "scattergeo": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattergeo" - } - ], - "scattergl": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattergl" - } - ], - "scattermap": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattermap" - } - ], - "scattermapbox": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattermapbox" - } - ], - "scatterpolar": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolar" - } - ], - "scatterpolargl": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolargl" - } - ], - "scatterternary": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterternary" - } - ], - "surface": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "surface" - } - ], - "table": [ - { - "cells": { - "fill": { - "color": "#EBF0F8" - }, - "line": { - "color": "white" - } - }, - "header": { - "fill": { - "color": "#C8D4E3" - }, - "line": { - "color": "white" - } - }, - "type": "table" - } - ] - }, - "layout": { - "annotationdefaults": { - "arrowcolor": "#2a3f5f", - "arrowhead": 0, - "arrowwidth": 1 - }, - "autotypenumbers": "strict", - "coloraxis": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "colorscale": { - "diverging": [ - [ - 0, - "#8e0152" - ], - [ - 0.1, - "#c51b7d" - ], - [ - 0.2, - "#de77ae" - ], - [ - 0.3, - "#f1b6da" - ], - [ - 0.4, - "#fde0ef" - ], - [ - 0.5, - "#f7f7f7" - ], - [ - 0.6, - "#e6f5d0" - ], - [ - 0.7, - "#b8e186" - ], - [ - 0.8, - "#7fbc41" - ], - [ - 0.9, - "#4d9221" - ], - [ - 1, - "#276419" - ] - ], - "sequential": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "sequentialminus": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ] - }, - "colorway": [ - "#636efa", - "#EF553B", - "#00cc96", - "#ab63fa", - "#FFA15A", - "#19d3f3", - "#FF6692", - "#B6E880", - "#FF97FF", - "#FECB52" - ], - "font": { - "color": "#2a3f5f" - }, - "geo": { - "bgcolor": "white", - "lakecolor": "white", - "landcolor": "#E5ECF6", - "showlakes": true, - "showland": true, - "subunitcolor": "white" - }, - "hoverlabel": { - "align": "left" - }, - "hovermode": "closest", - "mapbox": { - "style": "light" - }, - "paper_bgcolor": "white", - "plot_bgcolor": "#E5ECF6", - "polar": { - "angularaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "bgcolor": "#E5ECF6", - "radialaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "scene": { - "xaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - }, - "yaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - }, - "zaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - } - }, - "shapedefaults": { - "line": { - "color": "#2a3f5f" - } - }, - "ternary": { - "aaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "baxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "bgcolor": "#E5ECF6", - "caxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "title": { - "x": 0.05 - }, - "xaxis": { - "automargin": true, - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "zerolinewidth": 2 - }, - "yaxis": { - "automargin": true, - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "zerolinewidth": 2 - } - } - }, - "title": { - "font": { - "color": "#1F2937", - "family": "Helvetica Neue, Arial, sans-serif" - }, - "text": "Cash Flow Analysis (Risk-Adjusted)" - }, - "yaxis": { - "tickformat": "$,.0f" - } - } - }, - "image/png": "iVBORw0KGgoAAAANSUhEUgAABTQAAAF5CAYAAAChnqWvAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAFNKADAAQAAAABAAABeQAAAADSesO5AABAAElEQVR4AezdB3xUVdrH8Se9AKG3VEpIQhfsvWPFAmLBgsraRbFjA3tvr21FXbtixcauqGCvYKMmoadSAwnp/T3PCTNMwkyYhIG039lPmJl7z9xz7vfG3eXvKX7VpggFAQQQQAABBBBAAAEEEEAAAQQQQAABBBBoAQL+LaCPdBEBBBBAAAEEEEAAAQQQQAABBBBAAAEEELACBJr8IiCAAAIIIIAAAggggAACCCCAAAIIIIBAixEg0Gwxj4qOIoAAAggggAACCCCAAAIIIIAAAggggACBJr8DCCCAAAIIIIAAAggggAACCCCAAAIIINBiBAg0W8yjoqMIIIAAAggggAACCCCAAAIIIIAAAgggQKDJ7wACCCCAAAIIIIAAAggggAACCCCAAAIItBgBAs0W86joKAIIIIAAAggggAACCCCAAAIIIIAAAggQaPI7gAACCCCAAAIIIIAAAggggAACCCCAAAItRoBAs8U8KjqKAAIIIIAAAggggAACCCCAAAIIIIAAAgSa/A4ggAACCCCAAAIIIIAAAggggAACCCCAQIsRINBsMY+KjiKAAAIIIIAAAggggAACCCCAAAIIIIAAgSa/AwgggAACCCCAAAIIIIAAAggggAACCCDQYgQINFvMo6KjCCCAAAIIIIAAAggggAACCCCAAAIIIECgye8AAggggAACCCCAAAIIIIAAAggggAACCLQYAQLNFvOo6CgCCCCAAAIIIIAAAggggAACCCCAAAIIEGjyO4AAAggggAACCCCAAAIIIIAAAggggAACLUaAQLOeR1VSUiJ//r1Qfpv/l2zYmFNPzV0/VV1d3aiL6Pfq+9GLOs43qgEff2lP9WV3tKPX9EXJy9sqX839QUrLyuzlHH11ffXUjqOOp/N1jze0ft3vu35u7LX0e66l7mfXc83tvfZ1S26efV763wcUBBBAAAEEEEAAAQQQQAABBBBoegECTTfPYNWadDnjvMtk8L5Hy9hzL5WzJ1wp+x1+kpw7cZIsTVnu5hu7dujxp1+U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" - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "charts.cashflow_chart(\n", - " summary['yearly_breakdown'],\n", - " initial_cost=summary.get('initial_costs', 0),\n", - ").show()" - ] - }, - { - "cell_type": "markdown", - "id": "3b4b7b39", - "metadata": {}, - "source": [ - "## Waterfall: Benefits PV → Costs PV → NPV" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "04012e0f", - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.plotly.v1+json": { - "config": { - "plotlyServerURL": "https://plot.ly" - }, - "data": [ - { - "decreasing": { - "marker": { - "color": "#C62828" - } - }, - "increasing": { - "marker": { - "color": "#2E7D32" - } - }, - "measure": [ - "relative", - "relative", - "total" - ], - "text": [ - "$101.7M", - "$-23.0M", - "$78.7M" - ], - "textposition": "outside", - "totals": { - "marker": { - "color": "#1565C0" - } - }, - "type": "waterfall", - "x": [ - "Benefits PV", - "Costs PV", - "NPV" - ], - "y": [ - 101696567.55071375, - -22983075.77535687, - 78713491.77535687 - ] - } - ], - "layout": { - "font": { - "color": "#1F2937", - "family": "Helvetica, Arial, sans-serif" - }, - "legend": { - "font": { - "color": "#1F2937", - "family": "Helvetica, Arial, sans-serif" - } - }, - "template": { - "data": { - "bar": [ - { - "error_x": { - "color": "#2a3f5f" - }, - "error_y": { - "color": "#2a3f5f" - }, - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "bar" - } - ], - "barpolar": [ - { - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "barpolar" - } - ], - "carpet": [ - { - "aaxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "baxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "type": "carpet" - } - ], - "choropleth": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "choropleth" - } - ], - "contour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "contour" - } - ], - "contourcarpet": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "contourcarpet" - } - ], - "heatmap": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "heatmap" - } - ], - "histogram": [ - { - "marker": { - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "histogram" - } - ], - "histogram2d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "histogram2d" - } - ], - "histogram2dcontour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "histogram2dcontour" - } - ], - "mesh3d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "mesh3d" - } - ], - "parcoords": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "parcoords" - } - ], - "pie": [ - { - "automargin": true, - "type": "pie" - } - ], - "scatter": [ - { - "fillpattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - }, - "type": "scatter" - } - ], - "scatter3d": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatter3d" - } - ], - "scattercarpet": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattercarpet" - } - ], - "scattergeo": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattergeo" - } - ], - "scattergl": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattergl" - } - ], - "scattermap": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattermap" - } - ], - "scattermapbox": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattermapbox" - } - ], - "scatterpolar": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolar" - } - ], - "scatterpolargl": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolargl" - } - ], - "scatterternary": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterternary" - } - ], - "surface": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "surface" - } - ], - "table": [ - { - "cells": { - "fill": { - "color": "#EBF0F8" - }, - "line": { - "color": "white" - } - }, - "header": { - "fill": { - "color": "#C8D4E3" - }, - "line": { - "color": "white" - } - }, - "type": "table" - } - ] - }, - "layout": { - "annotationdefaults": { - "arrowcolor": "#2a3f5f", - "arrowhead": 0, - "arrowwidth": 1 - }, - "autotypenumbers": "strict", - "coloraxis": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "colorscale": { - "diverging": [ - [ - 0, - "#8e0152" - ], - [ - 0.1, - "#c51b7d" - ], - [ - 0.2, - "#de77ae" - ], - [ - 0.3, - "#f1b6da" - ], - [ - 0.4, - "#fde0ef" - ], - [ - 0.5, - "#f7f7f7" - ], - [ - 0.6, - "#e6f5d0" - ], - [ - 0.7, - "#b8e186" - ], - [ - 0.8, - "#7fbc41" - ], - [ - 0.9, - "#4d9221" - ], - [ - 1, - "#276419" - ] - ], - "sequential": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "sequentialminus": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ] - }, - "colorway": [ - "#636efa", - "#EF553B", - "#00cc96", - "#ab63fa", - "#FFA15A", - "#19d3f3", - "#FF6692", - "#B6E880", - "#FF97FF", - "#FECB52" - ], - "font": { - "color": "#2a3f5f" - }, - "geo": { - "bgcolor": "white", - "lakecolor": "white", - "landcolor": "#E5ECF6", - "showlakes": true, - "showland": true, - "subunitcolor": "white" - }, - "hoverlabel": { - "align": "left" - }, - "hovermode": "closest", - "mapbox": { - "style": "light" - }, - "paper_bgcolor": "white", - "plot_bgcolor": "#E5ECF6", - "polar": { - "angularaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "bgcolor": "#E5ECF6", - "radialaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "scene": { - "xaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - }, - "yaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - }, - "zaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - } - }, - "shapedefaults": { - "line": { - "color": "#2a3f5f" - } - }, - "ternary": { - "aaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "baxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "bgcolor": "#E5ECF6", - "caxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "title": { - "x": 0.05 - }, - "xaxis": { - "automargin": true, - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "zerolinewidth": 2 - }, - "yaxis": { - "automargin": true, - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "zerolinewidth": 2 - } - } - }, - "title": { - "font": { - "color": "#1F2937", - "family": "Helvetica Neue, Arial, sans-serif" - }, - "text": "TEI Waterfall" - }, - "yaxis": { - "tickformat": "$,.0f" - } - } - }, - "image/png": "iVBORw0KGgoAAAANSUhEUgAABTQAAAF5CAYAAAChnqWvAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAFNKADAAQAAAABAAABeQAAAADSesO5AABAAElEQVR4AezdB5xUxf0A8B8dG1hBehFRwRJ7LIAFxd57jTVixSS2xBqNmpgY/5bYo7FhjT12AbE3NBp7Q4pYUJCuCP83D3fhgDtp6t7ud/K527fvzZs3853L4v1uSp2pWQqJAAECBAgQIECAAAECBAgQIECAAAECtUCgbi2ooyoSIECAAAECBAgQIECAAAECBAgQIEAgFxDQ9INAgAABAgQIECBAgAABAgQIECBAgECtERDQrDVdpaIECBAgQIAAAQIECBAgQIAAAQIECAho+hkgQIAAAQIECBAgQIAAAQIECBAgQKDWCAho1pquUlECBAgQIECAAAECBAgQIECAAAECBAQ0/QwQIECAAAECBAgQIECAAAECBAgQIFBrBAQ0a01XqSgBAgQIECBAgAABAgQIECBAgAABAgKafgYIECBAgAABAgQIECBAgAABAgQIEKg1AgKataarVJQAAQIECBAgQIAAAQIECBAgQIAAAQFNPwMECBAgQIAAAQIECBAgQIAAAQIECNQaAQHNWtNVKkqAAAECBAgQIECAAAECBAgQIECAgICmnwECBAgQIECAAAECBAgQIECAAAECBGqNgIBmrekqFSVAgAABAgQIECBAgAABAgQIECBAQEDTzwABAgQIECBAgAABAgQIECBAgAABArVGQECz1nSVihIgQIAAAQIECBAgQIAAAQIECBAgIKDpZ4AAAQIECBAgQIAAAQIECBAgQIAAgVojIKBZa7pKRQkQIECAAAECBAgQIECAAAECBAgQEND0M0CAAAECBAgQIECAAAECBAgQIECAQK0RENCsNV2logQIECBAgAABAgQIECBAgAABAgQICGj6GSBAgAABAgQIECBAgAABAgQIECBAoNYICGjWmq5SUQIECBAgQIAAAQIECBAgQIAAAQIEBDT9DBAgQIAAAQIECBAgQIAAAQIECBAgUGsEBDRrTVepKAECBAgQIECAAAECBAgQIECAAAECApp+BggQIECAAAECBAgQIECAAAECBAgQqDUCApq1pqtUlAABAgQIECBAgAABAgQIECBAgAABAU0/AwQIECBAgAABAgQIECBAgAABAgQI1BoBAc1a01UqSoAAAQIECBAgQIAAAQIECBAgQICAgKafAQIECBAgQIAAAQIECBAgQIAAAQIEao2AgGat6SoVJUCAAAECBAgQIECAAAECBAgQIEBAQNPPAAECBAgQIECAAAECBAgQIECAAAECtUZAQLPWdJWKEiBAgAABAgQIECBAgAABAgQIECAgoOlngAABAgQIECBAgAABAgQIECBAgACBWiMgoFlrukpFCRAgQIAAAQIECBAgQIAAAQIECBAQ0PQzQIAAAQIECBAgQIAAAQIECBAgQIBArREQ0Kw1XaWiBAgQIECAAAECBAgQIECAAAECBAgIaPoZIECAAAECBAgQIECAAAECBAgQIECg1ggIaM7QVVOnTo0f+ipkn5t8hXtm95rKqS7N67XqylvQ5ydOmhTDP/l0jostmBVumPl94bxXAgQIECBAgAABAgQIECBAgAABAtUJCGh+L/On8y6MDl3X+8Gve//zSOyyz69rzLfdbgfkpf739TfzfCeccvZs/R8f8FR+/dSz/jrL9d33651fu+SKf81ybeud94/lVtkgvh4zdpZrszsxZNjw6PfE0zFm7LjZXZ6nc8eeeHqsvn6vWH/T7ePDjz6eozLW3HDL+NWvjy3mnfl98YIDAgQIECBAgAABAgQIECBAgAABAtUI1K/mfMWdXmv11WLKd1OK7X5x0H/j1dfeiM037R5tWrUsnu/YoV1MmTIt33577RIN6s9KuOyyzYr5azpYc/VVo27duvH8i69UyTZ23Lh46ZX/5ucGPvVcHHHo/sXro78eE2+89U78YpUu0WSxRYvnazp44OF+cfZ5F8V9t/8rVu6yQk1Z5+jak08/H3fe82Bs3H396NWzRyy5xOJzdF/BrZB55veF814JECBAgAABAgQIECBAgAABAgQIVCcwazSuupxlfj4F5tJXIf31/y7LA5p77LJ9bNJjg8LpKq8n/fbIWGihxlXOzc2bpk0Wi1W6rpg/Z/Tor6Np0yb57c8891JMnvxdHih8cdCrMW7c+FhkkYXza8+/OCifFt99w1/OzaMWaN4PBk8bkdn74P1inbV+sUDLVhgBAgQIECBAgAABAgQIECBAgACBmgRMOa9J5ye4tsEv18qf8sLL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s/U7vxo1OpZtvkxWn8Z5UZ99/kW+WVHT73dQn5/y3UuAAAECBAgQIECAAAECBAgQIEBAQNPPAAECBAgQIECAAAECBAgQIECAAAECtUag+vnUtaYJKkqAAAECBAgQIECAAAECBAgQIECAQKUICGhWSk9rJwECBAgQIECAAAECBAgQIECAAIEyEBDQLINO1AQCBAgQIECAAAECBAgQIECAAAEClSIgoFkpPa2dBAgQIECAAAECBAgQIECAAAECBMpAQECzDDpREwgQIECAAAECBAgQIECAAAECBAhUioCAZqX0tHYSIECAAAECBAgQIECAAAECBAgQKAMBAc0y6ERNIECAAAECBAgQIECAAAECBAgQIFApAgKaldLT2kmAAAECBAgQIECAAAECBAgQIECgDAQENMugEzWBAAECBAgQIECAAAECBAgQIECAQKUICGhWSk9rJwECBAgQIECAAAECBAgQIECAAIEyEBDQLINO1AQCBAgQIECAAAECBAgQIECAAAEClSIgoFkpPa2dBAgQIECAAAECBAgQIECAAAECBMpAQECzDDpREwgQIECAAAECBAgQIECAAAECBAhUioCAZqX0tHYSIECAAAECBAgQIECAAAECBAgQKAMBAc0y6ERNIECAAAECBAgQIECAAAECBAgQIFApAgKaldLT2kmAAAECBAgQIECAAAECBAgQIECgDAQENMugEzWBAAECBAgQIECAAAECBAgQIECAQKUICGhWSk9rJwECBAgQIECAAAECBAgQIECAAIEyEBDQLINO1AQCBAgQIECAAAECBAgQIECAAAEClSIgoFkpPa2dBAgQIECAAAECBAgQIECAAAECBMpAQECzDDpREwgQIECAAAECBAgQIECAAAECBAhUioCAZqX0tHYSIECAAAECBAgQIECAAAECBAgQKAMBAc0y6ERNIECAAAECBAgQIECAAAECBAgQIFApAgKaldLT2kmAAAECBAgQIECAAAECBAgQIECgDAQENMugEzWBAAECBAgQIECAAAECBAgQIECAQKUICGhWSk9rJwECBAgQIECAAAECBAgQIECAAIEyEBDQLINO1AQCBAgQIECAAAECBAgQIECAAAEClSIgoFkpPa2dBAgQIECAAAECBAgQIECAAAECBMpAQECzDDpREwgQIECAAAECBAgQIECAAAECBAhUioCAZqX0tHYSIECAAAECBAgQIECAAAECBAgQKAMBAc0y6ERNIECAAAECBAgQIECAAAECBAgQIFApAgKaldLT2kmAAAECBAgQIECAAAECBAgQIECgDAQENMugEzWBAAECBAgQIECAAAECBAgQIECAQKUICGhWSk9rJwECBAgQIECAAAECBAgQIECAAIEyEBDQLINO1AQCBAgQIECAAAECBAgQIECAAAEClSIgoFkpPa2dBAgQIECAAAECBAgQIECAAAECBMpAQECzDDpREwgQIECAAAECBAgQIECAAAECBAhUioCAZqX0tHYSIECAAAECBAgQIECAAAECBAgQKAMBAc0y6ERNIECAAAECBAgQIECAAAECBAgQIFApAgKaldLT2kmAAAECBAgQIECAAAECBAgQIECgDAQENMugEzWBAAECBAgQIECAAAECBAgQIECAQKUICGhWSk9rJwECBAgQIECAAAECBAgQIECAAIEyEBDQLINO1AQCBAgQIECAAAECBAgQIECAAAEClSIgoFkpPa2dBAgQIECAAAECBAgQIECAAAECBMpAQECzDDpREwgQIECAAAECBAgQIECAAAECBAhUioCAZqX0tHYSIECAAAECBAgQIECAAAECBAgQKAMBAc0y6ERNIECAAAECBAgQIECAAAECBAgQIFApAgKaldLT2kmAAAECBAgQIECAAAECBAgQIECgDATql0EbSrIJw0dOKMl6qRQBAgQIECBAgAABAgQIECBAgMDPK9ByqYV+3grU8qcboVnLO1D1CRAgQIAAAQIECBAgQIAAAQIECFSSgIBmJfW2thIgQIAAAQIECBAgQIAAAQIECBCo5QICmrW8A1WfAAECBAgQIECAAAECBAgQIECAQCUJCGhWUm9rKwECBAgQIECAAAECBAgQIECAAIFaLiCgWcs7UPUJECBAgAABAgQIECBAgAABAgQIVJKAgGYl9ba2EiBAgAABAgQIECBAgAABAgQIEKjlAgKatbwDVZ8AAQIECBAgQIAAAQIECBAgQIBAJQkIaFZSb2srAQIECBAgQIAAAQIECBAgQIAAgVouIKBZyztQ9QkQIECAAAECBAgQIECAAAECBAhUkoCAZiX1trYSIECAAAECBAgQIECAAAECBAgQqOUCApq1vANVnwABAgQIECBAgAABAgQIECBAgEAlCQhoVlJvayuBGgQGDXol3nzr7RpyuESAAAECBAgQIECAAAECBAgQ+PkF6v/8VVADAgR+ToGxY8fGbXfcGXffc280qN8gttl6y9h9t12icePGxWrddfc98dWo0XHA/vsWz40fPyFuve32eOXV/0arVi1j7z33iJYtWxSvT506NU7/459ipx23j9VWXaV4vnCQynzl1dcKb4uvu+y8Yzz99DNx7XU3xBGHH5aVu3vx2siRX8b2O+0azZs3iztu7Vs874AAAQIECBAgQIAAAQIECBCoHAEjNCunr7WUwGwFbrjp5njxxZei56abxCabbBSPPt4vC27el+d959334pp/XR8XXXJpfPTRR/m5wre/nv/3uOPOu6LbhhvEpEmToveRR0cKcqbUr/+AOPNP58Yjjz4Wo0aNKtxS5XWZZZaJjh07FL8aNmgQ/QcMiMaNGsXU73M+3q9/lXsGPDEwpkyZEilYKhEgQIAAAQIECBAgQIAAAQKVKWCEZmX2u1YTKAq8+NLLscH668VSSy4ZTZs2ic036xlffvllfv2NN96IN998K5os1qSYPx2MGTM2Hnzokbjiskti5a5dYvLkybFxz17x5FNPZ/dvGk8MfDLGjRsfdetW/zeT9Mz0ldJ3330XvY84OvocfWR06rRcPJYFMpfPXt9++534ZMSIaLHssnm+FChdYYXOMXr06Py9bwQIECBAgAABAgQIECBAgEDlCVQfbag8Cy0mUJEC3bMRljffcls2MvPx+HrMmFguGzW59lpr5hY7bL9d/OXcPxXfF4CGDhuWH664wgr5a/369WPZ5svG0KFD8/ennfKH/L402nJO0o3ZKNHxEybEdttuU8zedPGmsWo2Vb1//yfyc199NSqbov5qPiK0mMkBAQIECBAgQIAAAQIECBAgUHECApoV1+UaTKCqwG677hx77bFbvPfe+3HOuefFQYf2juHDP6maaaZ3n3zySSy0UOOoX79e8Upa13L8+PHF93N6MC675/ob+8Zhhx5cdURnNqt84x7dozDtfMDAgdG5c+do3qzZnBYtHwECBAgQIECAAAECBAgQIFCGAgKaZdipmkRgbgTS5j/777dPFlA8JPbZe88YP25cFmC8qcYiGmUjLydMmJitnflNMd/EbB3N1q1bFd/P6cH99z+QT3XfcIP1Z7llox7d4o1syvunn34W/foNyAOcs2RyggABAgQIECBAgAAB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Q4dOG+WZLnbvtmE83m9A4ZY8uJnOSQQIECBAgAABApUrIKBZuX2v5QQIECBAgACBWQR223XnbDTkbvkaluece14cdGjvfLRlWlszjd5MX2+88WYerFxzjdWzqeb18yngv+59ZBb87BjrrLNWXmaagp6CnCec+IdsWvqz+ajKb775psrzPvnkk1hoocb5dPXChebNm2VTzscX3kaP7hvm085HfPppjBo1OnvWK7FR927F6w4IECBAgAABAgQqT8CU88rrcy0mQIAAAQIECFQrkDb/2X+/fWKJJZaINIJy4MAn4/obb8qnkR/d57f5fe3atom+N16XrWE5NS665NK47fY7Yucdd4zehx0adetO/3t5Gqn58IP35aM0jzn2dzHgiYH5FPbCwxs1ahQTJkzM1s78Jg+QpvMTs6ns6b5CWnrppWPllbtG//5PxMILLxydOnWKFi2WLVz2SoAAAQIECBAgUIECApoV2OmaTIAAAQIECBCoTuBXBx4SJ514fH65a5eVok2b1nHpZVfEcb89Nh596D/5+bp16+Svf/nr3+PZZ5+Ly/9xcXTJ8hZSWgPz+htuissvvTgPcKYp62kH88KGQYV8aRp6SmnTn/bt2uabBg0fPjxbP7Pqbugb9+ieTTvvnwc007FEgAABAgQIECBQ2QLT/4Re2Q5aT4AAAQIECBAgkAmkEZa33Hp7TJg4IR89OWjQq9Ghffv8/MILL5QFFReKNIozTUG/+557Y++99ohG2fv3P/gw/0obCK3ctWv8L5uWfvsdd8bEiROjf7ZZ0LBhw6Nnz02yjX++i+uuvzHfAX255Trmoy1vvKlvjMummV9x1T/znc6X61g1oLnRRt3j9f+9Ec+/8GJsJKDp55QAAQIECBAgUPECRmhW/I8AAAIECBAgQIDAdIEjj+gdJ5x0crb7+MN5ELNpkyZxyUUXTM/w/dEbb76VH51/wYVVru2z955xeDb1fNdddop07YILL44lsx3TD/jVftGubds8wHnZFVdFu2xEZtts6voZp50Sx/72+Lj/Pw9m084bxSl/OCkWXXTRqJP9L6X0mkZyrrTiCnmwM92TgqT5tWlZ8mPfCBAgQIAAAQIEKkegTrb20dTKae5P19LhIyf8dA+biyeNGD08Drh2t7m4Q1YCBAiUvkCnZivERXteXfoVVUMCtURg2ijKG6JxtmHPbrvsUmXTnrlpwpdffRVffTUqOnZoH3XqVB99nDx5cgwe/HE+vb1hw4Zz8wh5CRBYQAJ7Xvx6vDls+oZcC6hYxRAgQOBnFbj/uNWi1ZKNftY6VPfwlkstVN0l5+dAwAjNOUCShQABAgQIECBQSQJph/LNN+sZ9bLXdDyvaclsY6H09UMp7ZSepp9LBAgQIECAAAECBOZEQEBzTpTkIUCAAAECBAhUmMCMO41XWNM1lwABAgQIECBAoMQFbApU4h2kegQIECBAgAABAgQIECBAgAABAgQITBcQ0Jxu4YgAAQIECBAgQIAAAQIECBAgQIAAgRIXENAs8Q5SPQIECBAgQIAAAQIECBAgQIAAAQIEpgsIaE63cESAAAECBAgQIECAAAECBAgQIECAQIkLCGiWeAepHgECBAgQIECAAAECBAgQIECAAAEC0wUENKdbOCJAgAABAgQIECBAgAABAgQIECBAoMQFBDRLvINUjwABAgQIECBAgAABAgQIECBAgACB6QICmtMtHBEgQIAAAQIECBAgQIAAAQIECBAgUOICApol3kGqR4AAAQIECBAgQIAAAQIECBAgQIDAdAEBzekWjggQIECAAAECBAgQIECAAAECBAgQKHEBAc0S7yDVI0CAAAECBAgQIECAAAECBAgQIEBguoCA5nQLRwQIECBAgAABAgQIECBAgAABAgQIlLiAgGaJd5DqESBAgAABAgQIECBAgAABAgQIECAwXUBAc7qFIwIECBAgQIAAAQIECBAgQIAAAQIESlxAQLPEO0j1CBAgQIAAAQIECBAgQIAAAQIECBCYLiCgOd3CEQECBAgQIECAAAECBAgQIECAAAECJS4goFniHaR6BAgQIECAAAECBAgQIECAAAECBAhMFxDQnG7hiAABAgQIECBAgAABAgQIECBAgACBEhcQ0CzxDlI9AgQIECBAgAABAgQIECBAgAABAgSmCwhoTrdwRIAAAQIECBAgQIAAAQIECBAgQIBAiQsIaJZ4B6keAQIECBAgQIAAAQIECBAgQIAAAQLTBQQ0p1s4IkCAAAECBAgQIECAAAECBAgQIECgxAUENEu8g1SPAAECBAgQIECAAAECBAgQIECAAIHpAgKa0y0cESBAgAABAgQIECBAgAABAgQIECBQ4gILPKA56Ztv4l833lbizVY9AgQIECBAgAABAgQIECBAgAAB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fuj+swQz0/WZN+Qp3NOgQf18WnnhfXpNu4W3XLZZlfOzy1e4p2nTJpG+ZpfSqM2Z0wsvvxp7775TldOzy5cyzOtzqxTuDQECBAgQIECAAAECBAgQIECAAAEC8y2wwAOa9evXj1+uvcZ8VyyNlDwqm0r+Y6VjjzzkxypauQQIECBAgAABAgQIECBAgAABAgQI/EgCC2xToB+pfoolQIAAAQIECBAgQIAAAQIECBAgQIBAUUBAs0jhgAABAgQIECBAgAABAgQIECBAgACBUhcQ0Cz1HlI/AgQIECBAgAABAgQIECBAgAABAgSKAgKaRQoHBAgQIECAAAECBAgQIECAAAECBAiUuoCAZqn3kPoRIECAAAECBAgQIECAAAECBAgQIFAUENAsUjggQIAAAQIECBAgQIAAAQIECBAgQKDUBQQ0S72H1I8AAQIECBAgQIAAAQIECBAgQIAAgaKAgGaRwgEBAgQIECBAgAABAgQIECBAgAABAqUuIKBZ6j2kfgQIECBAgAABAgQIECBAgAABAgQIFAUENIsUDggQIECAAAECBAgQIECAAAECBAgQKHUBAc1S7yH1I0CAAAECBAgQIECAAAECBAgQIECgKCCgWaRwQIAAAQIECBAgQIAAAQIECBAgQIBAqQsIaJZ6D6kfAQIECBAgQIAAAQIECBAgQIAAAQJFAQHNIoUDAgQIECBAgAABAgQIECBAgAABAgRKXUBAs9R7SP0IECBAgAABAgQIECBAgAABAgQIECgKCGgWKRwQIECAAAECBAgQIECAAAECBAgQIFDqAgKapd5D6keAAAECBAgQIECAAAECBAgQIECAQFFAQLNI4YAAAQIECBAgQIAAAQIECBAgQIAAgVIXENAs9R5SPwIECBAgQIAAAQIECBAgQIAAAQIEigICmkUKBwQIECBAgAABAgQIECBAgAABAgQIlLqAgGap95D6ESBAgAABAgQIECBAgAABAgQIECBQFBDQLFI4IECAAAECBAgQIECAAAECBAgQIECg1AUENEu9h9SPAAECBAgQIECAAAECBAgQIECAAIGigIBmkcIBAQIECBAgQIAAAQIECBAgQIAAAQKlLiCgWeo9pH4ECBAgQIAAAQIECBAgQIAAAQIECBQFBDSLFA4IECBAgAABAgQIECBAgAABAgQIECh1AQHNUu8h9SNAgAABAgQIECBAgAABAgQIECBAoCggoFmkcECAAAECBAgQIECAAAECBAgQIECAQKkLCGiWeg+pHwECBAgQIECAAAECBAgQIECAAAECRQEBzSKFAwIECBAgQIAAAQIECBAgQIAAAQIESl1AQLPUe0j9CBAgQIAAAQIECBAgQIAAAQIECBAoCghoFikcECBAgAABAgQIECBAgAABAgQIECBQ6gICmqXeQ+pHgAABAgQIECBAgAABAgQIECBAgEBRQECzSOGAAAECBAgQIECAAAECBAgQIECAAIFSFxDQLPUeUj8CBAgQIECAAAECBAgQIECAAAECBIoCAppFCgcECBAgQIAAAQIECBAgQIAAAQIECJS6gIBmqfeQ+hEgQIAAAQIECBAgQIAAAQIECBAgUBQQ0CxSOCBAgAABAgQIECBAgAABAgQIECBAZXHScQAAGiJJREFUoNQFBDRLvYfUjwABAgQIECBAgAABAgQIECBAgACBooCAZpHCAQECBAgQIECAAAECBAgQIECAAAECpS4goFnqPaR+BAgQIECAAAECBAgQIECAAAECBAgUBQQ0ixQOCBAgQIAAAQIECBAgQIAAAQIECBAodQEBzVLvIfUjQIAAAQIECBAgQIAAAQIECBAgQKAoIKBZpHBAgAABAgQIECBAgAABAgQIECBAgECpCwholnoPqR8BAgQIECBAgAABAgQIECBAgAABAkUBAc0ihQMCBAgQIECAAAECBAgQIECAAAECBEpdQECz1HtI/QgQIECAAAECBAgQIECAAAECBAgQKAoIaBYpHBAgQIAAAQIECBAgQIAAAQIECBAgUOoCApql3kPqR4AAAQIECBAgQIAAAQIECBAgQIBAUUBAs0jhgAABAgQIECBAgAABAgQIECBAgACBUhcQ0Cz1HlI/AgQIECBAgAABAgQIECBAgAABAgSKAgKaRQoHBAgQIECAAAECBAgQIECAAAECBAiUuoCAZqn3kPoRIECAAAECBAgQIECAAAECBAgQIFAUENAsUjggQIAAAQIECBAgQIAAAQIECBAgQKDUBQQ0S72H1I8AAQIECBAgQIAAAQIECBAgQIAAgaKAgGaRwgEBAgQIECBAgAABAgQIECBAgAABAqUuIKBZ6j2kfgQIECBAgAABAgQIECBAgAABAgQIFAUENIsUDggQIECAAAECBAgQIECAAAECBAgQKHUBAc1S7yH1I0CAAAECBAgQIECAAAECBAgQIECgKCCgWaRwQIAAAQIECBAgQIAAAQIECBAgQIBAqQsIaJZ6D6kfAQIECBAgQIAAAQIECBAgQIAAAQJFAQHNIoUDAgQIECBAgAABAgQIECBAgAABAgRKXUBAs9R7SP0IECBAgAABAgQIECBAgAABAgQIECgKCGgWKRwQIECAAAECBAgQIECAAAECBAgQIFDqAgKapd5D6keAAAECBAgQIECAAAECBAgQIECAQFFAQLNI4YAAAQIECBAgQIAAAQIECBAgQIAAgVIXENAs9R5SPwIECBAgQIAAAQIECBAgQIAAAQIEigICmkUKBwQIECBAgAABAgQIECBAgAABAgQIlLqAgGap95D6ESBAgAABAgQIECBAgAABAgQIECBQFBDQLFI4IECAAAECBAgQIECAAAECBAgQIECg1AUENOewh6689qY5zCkbAQIECBAgQIAAAQIECBAgQIAAAQI/lkD9H6vgcin3rXfei6uu7Rv3PvBo9B/4TOy7586xRc+N8ua9/e77cUPff8fgIUNjnbVWj8MO2ifq10daLn2vHQQIECBAgAABAgQIECBAgAABAqUnYIRmDX0yderUOLzP76Nli+axStcVY7utNo9jTzg9hg0fEV+NGh37H9on3n7v/dhpuy3jnvsfjpP/eF4NpblEgAABAgQIECBAgAABAgQIECBAgMD8ChhOWIPgJyM+iw8++jh23HaLeO1/b8XuO28byyy9ZHz77bfxwMPPRp06deLW6y7LS0gjM39z4hlx6ol9YuGFF6qhVJcIECBAgAABAgQIECBAgAABAgQIEJhXAQHNGuTSyMyuK3WOo353aowZOzZGfz0mNumxQX7HTbfdFaut3KV4d/t2beKbLNA5fMSn0alj+2i5VGkGNafUbVysswMCBAiUi0CD+nVL9nO3XIy1gwABAgTKW6BBPZP3yruHtY5AZQo0W6KR3xPKtOsFNH+gYy/+21nx94uvjAce6Rdrd9sqdsyml//5zN/H0GGfRJMmixbvbtVy2fx43LjxxXOleNB6iVbx6h9fKsWqqRMBAgQIECBAgAABAj+TwKMnr/kzPdljCRAgQIDA3Av4M9wPmHVo3zYu/OuZsd46a8YfT/ld3Prve+OpZ16IhRo3jpFfjirePWHCxPy4XZtWxXMOCBAgQIAAAQIECBAg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AIFKERDQrJSe1k4CBAgQIECAAAECBAgQIECAAAECZSAgoFkGnagJBAgQIECAAAECBAgQIECAAAECBCpFQECzUnpaOwkQIECAAAECBAgQIECAAAECBAiUgYCAZhl0oiYQIECAAAECBAgQIECAAAECBAgQqBQBAc1K6WntJECAAAECBAgQIECAAAECBAgQIFAGAgKaZdCJmkCAAAECBAgQIECAAAECBAgQIECgUgQENCulp7WTAAECBAgQIECAAAECBAgQIECAQBkICGiWQSdqAgECBAgQIECAAAECBAgQIECAAIFKERDQrJSe1k4CBAgQIECAAAECBAgQIECAAAECZSAgoFkGnagJBAgQIECAAAECBAgQIECAAAECBCpFQECzUnpaOwkQIECAAAECBAgQIECAAAECBAiUgYCAZhl0oiYQIECAAAECBAgQIECAAAECBAgQqBQBAc1K6WntJECAAAECBAgQIECAAAECBAgQIFAGAgKaZdCJmkCAAAECBAgQIECAAAECBAgQIECgUgQENCulp7WTAAECBAgQIECAAAECBAgQIECAQBkICGiWQSdqAgECBAgQIECAAAECBAgQIECAAIFKERDQrJSe1k4CBAgQIECAAAECBAgQIECAAAECZSAgoFkGnagJBAgQIECAAAECBAgQIECAAAECBCpFQECzUnpaOwkQIECAAAECBAgQIECAAAECBAiUgYCAZhl0oiYQIECAAAECBAgQIECAAAECBAgQqBQBAc1K6WntJECAAAECBAgQIECAAAECBAgQIFAGAgKaZdCJmkCAAAECBAgQIECAAAECBAgQIECgUgQENCulp7WTAAECBAgQIECAAAECBAgQIECAQBkICGiWQSdqAgECBAgQIECAAAECBAgQIECAAIFKERDQrJSe1k4CBAgQIECAAAECBAgQIECAAAECZSAgoFkGnagJBAgQIECAAAECBAgQIECAAAECBCpFQECzUnpaOwkQIECAAAECBAgQIECAAAECBAiUgYCAZhl0oiYQIECAAAECBAgQIECAAAECBAgQqBQBAc1K6WntJECAAAECBAgQIECAAAECBAgQIFAGAgKaZdCJmkCAAAECBAgQIECAAAECBAgQIECgUgQENCulp7WTAAECBAgQIECAAAECBAgQIECAQBkICGiWQSdqAgECBAgQIECAAAECBAgQIECAAIFKERDQrJSe1k4CBAgQIECAAAECBAgQIECAAAECZSAgoFkGnagJBAgQIECAAAECBAgQIECAAAECBCpFQECzUnpaOwkQIECAAAECBAgQIECAAAECBAiUgYCAZhl0oiYQIECAAAECBAgQIECAAAECBAgQqBQBAc1K6WntJECAAAECBAgQIECAAAECBAgQIFAGAgKaZdCJmkCAAAECBAgQIECAAIH/b8eOCQAAABCE9W9tD1kE5wcBAgQIECBQERA0K0/bSYAAAQIECBAgQIAAAQIECBAgQOBAQNA8ONEEAgQIECBAgAABAgQIECBAgAABAhUBQbPytJ0ECBAgQIAAAQIECBAgQIAAAQIEDgQEzYMTTSBAgAABAgQIECBAgAABAgQIECBQERA0K0/bSYAAAQIECBAgQIAAAQIECBAgQOBAQNA8ONEEAgQIECBAgAABAgQIECBAgAABAhUBQbPytJ0ECBAgQIAAAQIECBAgQIAAAQIEDgQEzYMTTSBAgAABAgQIECBAgAABAgQIECBQERA0K0/bSYAAAQIECBAgQIAAAQIECBAgQOBAQNA8ONEEAgQIECBAgAABAgQIECBAgAABAhUBQbPytJ0ECBAgQIAAAQIECBAgQIAAAQIEDgQEzYMTTSBAgAABAgQIECBAgAABAgQIECBQERA0K0/bSYAAAQIECBAgQIAAAQIECBAgQOBAQNA8ONEEAgQIECBAgAABAgQIECBAgAABAhUBQbPytJ0ECBAgQIAAAQIECBAgQIAAAQIEDgQEzYMTTSBAgAABAgQIECBAgAABAgQIECBQERA0K0/bSYAAAQIECBAgQIAAAQIECBAgQOBAQNA8ONEEAgQIECBAgAABAgQIECBAgAABAhUBQbPytJ0ECBAgQIAAAQIECBAgQIAAAQIEDgQEzYMTTSBAgAABAgQIECBAgAABAgQIECBQERhxB3Shzhmo8QAAAABJRU5ErkJggg==" - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "charts.waterfall([\n", - " ('Benefits PV', summary['total_benefits_pv']),\n", - " ('Costs PV', -summary['total_costs_pv']),\n", - " ('NPV', summary['npv']),\n", - "]).show()" - ] - }, - { - "cell_type": "markdown", - "id": "b48db610", - "metadata": {}, - "source": [ - "## Scenario analysis\n", - "\n", - "Apply the default Palladium multipliers (see `core.calculations.SCENARIOS`):\n", - "\n", - "* **Conservative** — 80% adoption, +10pp risk on benefits / -10pp on costs\n", - "* **Moderate** — base case (= the published Forrester study)\n", - "* **Aggressive** — 115% adoption, -5pp risk on benefits / +5pp on costs" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "1fb9aa20", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
 ScenarioBenefits PVCosts PVNPVROI %Payback (mo)
0conservative$71,672,868$17,437,916$54,234,951311%0.800000
1moderate$101,696,568$22,983,076$78,713,492342%0.700000
2aggressive$123,911,705$27,682,369$96,229,337348%0.700000
\n" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from core.calculations import apply_scenario\n", - "import pandas as pd\n", - "\n", - "scenario_summaries = {}\n", - "for name in ('conservative', 'moderate', 'aggressive'):\n", - " sb = apply_scenario(seed_data.BENEFITS, name, table='benefits')\n", - " sc = apply_scenario(seed_data.COSTS, name, table='costs')\n", - " scenario_summaries[name] = _compute_summary(sb, sc, config.DISCOUNT_RATE, config.ANALYSIS_YEARS)\n", - "\n", - "scen_df = pd.DataFrame([\n", - " {\n", - " 'Scenario': k,\n", - " 'Benefits PV': v['total_benefits_pv'],\n", - " 'Costs PV': v['total_costs_pv'],\n", - " 'NPV': v['npv'],\n", - " 'ROI %': v['roi_pct'],\n", - " 'Payback (mo)': round(v['payback_months'], 1) if v['payback_months'] is not None else None,\n", - " }\n", - " for k, v in scenario_summaries.items()\n", - "])\n", - "scen_df.style.format({\n", - " 'Benefits PV': '${:,.0f}', 'Costs PV': '${:,.0f}', 'NPV': '${:,.0f}', 'ROI %': '{:,.0f}%'\n", - "})" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "0ff81b9d", - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.plotly.v1+json": { - "config": { - "plotlyServerURL": "https://plot.ly" - }, - "data": [ - { - "marker": { - "color": "#2E7D32" - }, - "name": "Benefits PV", - "type": "bar", - "x": [ - "conservative", - "moderate", - "aggressive" - ], - "y": [ - 71672867.64838466, - 101696567.55071375, - 123911705.40270472 - ] - }, - { - "marker": { - "color": "#C62828" - }, - "name": "Costs PV", - "type": "bar", - "x": [ - "conservative", - "moderate", - "aggressive" - ], - "y": [ - 17437916.33959429, - 22983075.77535687, - 27682368.613918103 - ] - }, - { - "marker": { - "color": "#1565C0" - }, - "name": "NPV", - "type": "bar", - "x": [ - "conservative", - "moderate", - "aggressive" - ], - "y": [ - 54234951.30879037, - 78713491.77535687, - 96229336.78878662 - ] - } - ], - "layout": { - "barmode": "group", - "font": { - "color": "#1F2937", - "family": "Helvetica, Arial, sans-serif" - }, - "legend": { - "font": { - "color": "#1F2937", - "family": "Helvetica, Arial, sans-serif" - }, - "orientation": "h", - "y": -0.15 - }, - "template": { - "data": { - "bar": [ - { - "error_x": { - "color": "#2a3f5f" - }, - "error_y": { - "color": "#2a3f5f" - }, - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "bar" - } - ], - "barpolar": [ - { - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "barpolar" - } - ], - "carpet": [ - { - "aaxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "baxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "type": "carpet" - } - ], - "choropleth": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "choropleth" - } - ], - "contour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "contour" - } - ], - "contourcarpet": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "contourcarpet" - } - ], - "heatmap": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "heatmap" - } - ], - "histogram": [ - { - "marker": { - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "histogram" - } - ], - "histogram2d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "histogram2d" - } - ], - "histogram2dcontour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "histogram2dcontour" - } - ], - "mesh3d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "mesh3d" - } - ], - "parcoords": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "parcoords" - } - ], - "pie": [ - { - "automargin": true, - "type": "pie" - } - ], - "scatter": [ - { - "fillpattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - }, - "type": "scatter" - } - ], - "scatter3d": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatter3d" - } - ], - "scattercarpet": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattercarpet" - } - ], - "scattergeo": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattergeo" - } - ], - "scattergl": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattergl" - } - ], - "scattermap": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattermap" - } - ], - "scattermapbox": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattermapbox" - } - ], - "scatterpolar": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolar" - } - ], - "scatterpolargl": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolargl" - } - ], - "scatterternary": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterternary" - } - ], - "surface": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "surface" - } - ], - "table": [ - { - "cells": { - "fill": { - "color": "#EBF0F8" - }, - "line": { - "color": "white" - } - }, - "header": { - "fill": { - "color": "#C8D4E3" - }, - "line": { - "color": "white" - } - }, - "type": "table" - } - ] - }, - "layout": { - "annotationdefaults": { - "arrowcolor": "#2a3f5f", - "arrowhead": 0, - "arrowwidth": 1 - }, - "autotypenumbers": "strict", - "coloraxis": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "colorscale": { - "diverging": [ - [ - 0, - "#8e0152" - ], - [ - 0.1, - "#c51b7d" - ], - [ - 0.2, - "#de77ae" - ], - [ - 0.3, - "#f1b6da" - ], - [ - 0.4, - "#fde0ef" - ], - [ - 0.5, - "#f7f7f7" - ], - [ - 0.6, - "#e6f5d0" - ], - [ - 0.7, - "#b8e186" - ], - [ - 0.8, - "#7fbc41" - ], - [ - 0.9, - "#4d9221" - ], - [ - 1, - "#276419" - ] - ], - "sequential": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "sequentialminus": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ] - }, - "colorway": [ - "#636efa", - "#EF553B", - "#00cc96", - "#ab63fa", - "#FFA15A", - "#19d3f3", - "#FF6692", - "#B6E880", - "#FF97FF", - "#FECB52" - ], - "font": { - "color": "#2a3f5f" - }, - "geo": { - "bgcolor": "white", - "lakecolor": "white", - "landcolor": "#E5ECF6", - "showlakes": true, - "showland": true, - "subunitcolor": "white" - }, - "hoverlabel": { - "align": "left" - }, - "hovermode": "closest", - "mapbox": { - "style": "light" - }, - "paper_bgcolor": "white", - "plot_bgcolor": "#E5ECF6", - "polar": { - "angularaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "bgcolor": "#E5ECF6", - "radialaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "scene": { - "xaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - }, - "yaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - }, - "zaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - } - }, - "shapedefaults": { - "line": { - "color": "#2a3f5f" - } - }, - "ternary": { - "aaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "baxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "bgcolor": "#E5ECF6", - "caxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "title": { - "x": 0.05 - }, - "xaxis": { - "automargin": true, - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "zerolinewidth": 2 - }, - "yaxis": { - "automargin": true, - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "zerolinewidth": 2 - } - } - }, - "title": { - "font": { - "color": "#1F2937", - "family": "Helvetica Neue, Arial, sans-serif" - }, - "text": "Scenario Comparison" - }, - "yaxis": { - "tickformat": "$,.0f" - } - } - }, - "image/png": "iVBORw0KGgoAAAANSUhEUgAABTQAAAF5CAYAAAChnqWvAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAFNKADAAQAAAABAAABeQAAAADSesO5AABAAElEQVR4AezdBXwcVf4A8F+9tLSFQik1KO5uh7sf7g7Fvbg7HHbw53CHw+3ww92hOHeHQ0sFKaUtdf/Pm97m0pKkSUjobvJ9fJqdnXnz5s33LdndX540mZKlkAgQIECAAAECBAgQIECAAAECBAgQIFACAk1LoI6qSIAAAQIECBAgQIAAAQIECBAgQIAAgVxAQNMLgQABAgQIECBAgAABAgQIECBAgACBkhEQ0CyZplJRAgQIECBAgAABAgQIECBAgAABAgQENL0GCBAgQIAAAQIECBAgQIAAAQIECBAoGQEBzZJpKhUlQIAAAQIECBAgQIAAAQIECBAgQEBA02uAAAECBAgQIECAAAECBAgQIECAAIGSERDQLJmmUlECBAgQIECAAAECBAgQIECAAAECBAQ0vQYIECBAgAABAgQIECBAgAABAgQIECgZAQHNkmkqFSVAgAABAgQIECBAgAABAgQIECBAQEDTa4AAAQIECBAgQIAAAQIECBAgQIAAgZIRENAsmaZSUQIECBAgQIAAAQIECBAgQIAAAQIEBDS9BggQIECAAAECBAgQIECAAAECBAgQKBkBAc2SaSoVJUCAAAECBAgQIECAAAECBAgQIEBAQNNrgAABAgQIECBAgAABAgQIECBAgACBkhEQ0CyZplJRAgQIECBAgAABAgQIECBAgAABAgQENL0GCBAgQIAAAQIECBAgQIAAAQIECBAoGQEBzZJpKhUlQIAAAQIECBAgQIAAAQIECBAgQEBA02uAAAECBAgQIECAAAECBAgQIECAAIGSERDQLJmmUlECBAgQIECAAAECBAgQIECAAAECBAQ0vQYIECBAgAABAgQIECBAgAABAgQIECgZAQHNkmkqFSVAgAABAgQIECBAgAABAgQIECBAQEDTa4AAAQIECBAgQIAAAQIECBAgQIAAgZIRENAsmaZSUQIECBAgQIAAAQIECBAgQIAAAQIEBDS9BggQIECAAAECBAgQIECAAAECBAgQKBkBAc2SaSoVJUCAAAEC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AQIECBAgQIDAHy7w23Gyf3gVXJBA7QTWW2f1mDubL3PeHt1rV4CzCBAgQIAAAQIECBAgQIAAAQIESk7AkPOSazIVJkCAAAECBAgQIECAAAECBAgQINB4BQw5b7xt784JECBAgAABAgQIECBAgAABAgQIlJyAgGbJNZkKEyBAgAABAgQIECBAgAABAgQIEGi8AgKajbft3TkBAgQIECBAgAABAgQIECBAgACBkhMQ0Cy5JlNhAgQIECBAgAABAgQIECBAgAABAo1XQECz8ba9OydAgAABAgQIECBAgAABAgQIECBQcgICmiXXZCpMgAABAgQIECBAgAABAgQIECBAoPEKCGg23rZ35wQIECBAgAABAgQIECBAgAABAgRKTkBAs+SaTIUJECBAgAABAgQIECBAgAABAgQINF4BAc3G2/bunAABAgQIECBAgAABAgQIECBAgEDJCQhollyTqTABAgQIECBAgAABAgQIECBAgACBxisgoNl4296dEyBAgAABAgQIECBAgAABAgQIECg5AQHNkmsyFSZAgAABAgQIECBAgAABAgQIECDQeAUENBtv27tzAgQIECBAgAABAgQIECBAgAABAiUnIKBZck2mwgQIECBAgAABAgQIECBAgAABAgQar4CAZuNte3dOgAABAgQIECBAgAABAgQIECBAoOQEBDRLrslUmAABAgQIECBAgAABAgQIECBAgEDjFRDQbLxt784JECBAgAABAgQIECBAgAABAgQIlJyAgGbJNZkKEyBAgAABAgQIECBAgAABAgQIEGi8AgKajbft3TkBAgQIECBAgAABAgQIECBAgACBkhMQ0Cy5JlNhAgQIECBAgAABAgQIECBAgAABAo1XQECz8ba9OydAgAABAgQIECBAgAABAgQIECBQcgICmiXXZCpMgAABAgQIECBAgAABAgQIECBAoPEKCGg23rZ35wQIECBAgAABAgQIECBAgAABAgRKTkBAs+SaTIUJECBAgAABAgQIECBAgAABAgQINF4BAc3G2/bunAABAgQIECBAgAABAgQIECBAgEDJCQhollyTqTABAgQIECBAgAABAgQIECBAgACBxisgoNl4296dEyBAgAABAgQIECBAgAABAgQIECg5AQHNkmsyFSZAgAABAgQIECBAgAABAgQIECDQeAUENBtv27tzAgQIECBAgAABAgQIECBAgAABAiUnIKBZck2mwgQIECBAgAABAgQIECBAgAABAgQar4CAZuNte3dOgAABAgQIECBAgAABAgQIECBAoOQEBDRLrslUmAABAgQIECBAgAABAgQIECBAgEDjFRDQbLxt784JECBAgAABAgQIECBAgAABAgQIlJyAgGbJNZkKEyBAgAABAgQIECBAgAABAgQIEGi8AgKajbft3TkBAgQIECBAgAABAgQIECBAgACBkhMQ0Cy5JlNhAgQIECBAgAABAgQIECBAgAABAo1XQECz8ba9OydAgAABAgQIECBAgAABAgQIECBQcgICmiXXZCpMgAABAgQIECBAgAABAgQIECBAoPEKCGg23rZ35wQIECBAgAABAgQIECBAgAABAgRKTkBAs+SaTIUJECBAgAABAgQIECBAgAABAgQINF4BAc3G2/bunAABAgQIECBAgAABAgQIECBAgEDJCQhollyTqTABAgQIECBAgAABAgQIECBAgACBxisgoNl4296dEyBAgAABAgQIECBAgAABAgQIECg5AQHNkmsyFSZAgAABAgQIECBAgAABAgQIECDQeAUENBtv27tzAgQIECBAgAABAgQIECBAgAABAiUn0LzkalwiFR40ZEyJ1FQ1CRAgQIAAAQIECBAgQIAAAQIE/kiBrnPM8kdersFdSw/NBtekbogAAQIECBAgQIAAAQIECBAgQIBAwxUQ0Gy4bevOCBAgQIAAAQIECBAgQIAAAQIECDQ4AQHNBtekbogAAQIECBAgQIAAAQIECBAgQIBAwxUQ0Gy4bevOCBAgQIAAAQIECBAgQIAAAQIECDQ4AQHNBtekbogAAQIECBAgQIAAAQIECBAgQIBAwxUQ0Gy4bevOCBAgQIAAAQIECBAgQIAAAQIECDQ4AQHNBtekbogAAQIECBAgQIAAAQIECBAgQIBAwxUQ0Gy4bevOCBAgQIAAAQIECBAgQIAAAQIECDQ4geYN7o7cEAECBAgQIECAAAECBAjUSGDY6KExafLEGp0j8x8j0Kxp85itzex/zMVchQABAiUiIKBZIg2lmgQIECBAgAABAgQIEKgvgde/eike+/jB+ipeub9DYKWeq8a+axzyO0pwKgECBBqegIBmw2tTd0SAAAECBAgQIECAAIEaCQweOTj6Dfm2RufI/McILNt9hT/mQq5CgACBEhIwh2YJNZaqEiBAgAABAgQIECBAgAABAgQIEGjsAgKajf0V4P4JECBAgAABAgQIECBAgAABAgQIlJCAgGYJNZaqEiBAgAABAgQIECBAgAABAgQIEGjsAgKajf0V4P4JECBAgAABAgQIECBAgAABAgQIlJCAgGYJNZaqEiBAgAABAgQIECBAgAABAgQIEGjsAgKajf0V4P4JECBAgAABAgQIECBAgAABAgQIlJCAgGYJNZaqEiBAgAABAgQIECBAgAABAgQIEGjsAgKajf0V4P4JECBAgAABAgQIECBAgAABAgQIlJCAgGYJNZaqEiBAgAABAgQIECBAgAABAgQIEGjsAgKajf0V4P4JECBAgAABAgQIECBAgAABAgQIlJCAgGYJNZaqEiBAgAABAgQIECBAgAABAgQIEGjsAgKajf0V4P4JECBAgAABAgQIECBAgAABAgQIlJCAgGYJNZaqEiBAgAABAgQIECBAgAABAgQIEGjsAgKajf0V4P4JECBAgAABAgQIECBAgAABAgQIlJCAgGYJNZaqEiBAgAABAgQIECBAgAABAgQIEGjsAgKajf0V4P4JECBAgAABAgQIECBAgAABAgQIlJCAgGYJNZaqEiBAgAABAgQIECBAgAABAgQIEGjsAgKajf0V4P4JECBAgAABAgQIECBAgAABAgQIlJCAgGYJNZaqEiBAgAABAgQIECBAgAABAgQIEGjsAgKajf0V4P4JECBAgAABAgQIECBAgAABAgQIlJCAgGYJNZaqEiBAgAABAgQIECBAgAABAgQIEGjsAgKajf0V4P4JECBAgAABAgQIECBAgAABAgQIlJCAgGYJNZaqEiBAgAABAgQIECBAgAABAgQIEGjsAgKajf0V4P4JECBAgAABAgQIECBAgAABAgQIlJCAgGYJNZaqEiBAgAABAgQIECBAgAABAgQIEGjsAgKajf0V4P4JECBAgAABAgQIECBAgAABAgQIlJCAgGYJNZaqEiBAgAABAgQIECBAgAABAgQIEGjsAgKajf0V4P4JECBAgAABAgQIECBAgAABAgQIlJCAgGYJNZaqEiBAgAABAgQIECBAgAABAgQIEGjsArUOaN5w612N3c79EyBAgAABAgQIECBAgAABAgQIECDwBws0r+n1Pvviq7jx1rvjsSefi5defTP22GW72GSDdcqKmTJlSvQ+/ozYfedtY6UV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5m7TcG/SnREgQIAAAQIhoOlFQIAAAQIECBAgQKAGAhMnT4l3vv41vh08tgZnyfpHCDRtErHZcnP8EZdyDQIECBAgQGAmChhyPhPxXZoAAQIECBAgQIAAAQIECBAgQIAAgZoJCGjWzEtuAgQIECBAgAABAgQIECBAgAABAgRmooCA5kzEd2kCBAgQIECAAAECBAgQIECAAAECBGomIKBZMy+5CRAgQIAAAQIECBAgQIAAAQIECBCYiQICmjMR36UJECBAgAABAgQIECBAgAABAgQIEKiZgIBmzbzkJkCAAAECBAgQIECAAAECBAgQIEBgJgoIaM5EfJcmQIAAAQIECBAgQIAAAQIECBAgQKBmAgKaNfOSmwABAgQIECBAgAABAgQIECBAgACBmSjQfCZe26VngsD4iePix19/zK48ZSZc3SVnJNCudbuYrU3HGWVznAABAgQIECBAgAABAgQIECDQaAUENBtZ048aNyoueebcGDp6SCO789K43aM3OkVAszSaSi0JECBAgAABAgQIECBAgACBmSQgoDmT4GfmZcdPGh8/jUi9NKViE5gyRc/ZYmsT9SFAgAABAgQIECBAgAABAgSKS8AcmsXVHmpDgAABAgQIECBAgAABAgQIECBAgEAVAgKaVeA4RIAAAQIECBAgQIAAAQIECBAgQIBAcQkIaBZXe6gNAQIECBAgQIAAAQIECBAgQIAAAQJVCAhoVoHjEAECBAgQIECAAAECBAgQIECAAAECxSUgoFlc7aE2BAgQIECAAAECBAgQIECAAAECBAhUISCgWQWOQwQIECBAgAABAgQIECBAgAABAgQIFJeAgGZxtYfaECBAgAABAgQIECBAgAABAgQIECBQhYCAZhU4DhEgQIAAAQIECBAgQIAAAQIECBAgUFwCAprF1R5qQ4AAAQIECBAgQIAAAQIECBAgQIBAFQICmlXgOESAAAECBAgQIECAAAECBAgQIECAQHEJCGgWV3uoDQECBAgQIECAAAECBAgQIECAAAECVQgIaFaB4xABAgQIECBAgAABAgQIECBAgAABAsUlIKBZXO2hNgQIECBAgAABAgQIECBAgAABAgQIVCEgoFkFjkMECBAgQIAAAQIECBAgQIAAAQIECBSXgIBmcbWH2hAgQIAAAQIECBAgQIAAAQIECBAgUIWAgGYVOA4RIECAAAECBAgQIECAAAECBAgQIFBcAgKaxdUeakOAAAECBAgQIECAAAECBAgQIECAQBUCAppV4DhEgAABAgQIECBAgAABAgQIECBAgEBxCQhoFld7qA0BAgQIECBAgAABAgQIECBAgAABAlUICGhWgeMQAQIECBAgQIAAAQIECBAgQIAAAQLFJSCgWVztoTYECBAgQIAAAQIECBAgQIAAAQIECFQhIKBZBY5DBAgQIECAAAECBAgQIECAAAECBAgUl4CAZnG1h9oQIECAAAECBAgQIECAAAECBAgQIFCFgIBmFTgOESBAgAABAgQIECBAgAABAgQIECBQXALNi6s6akOAAIHiFXjyw5/jlc+HFW8FG3HN1l+iY2ywZMdGLODWCRAgQIAAAQIECBAg0HgE6jygOW78+Ljn/kdir912aDyK7pQAgUYh8HH/UfHkh780insttZvsOlsrAc1SazT1JUCAAAECBAgQIECAQC0F6jSg+fiTz8Wd9z4YH/3r0/jPZ1/G/vvsGgvO3zOGDhseZ/7l0mmquMPWm8caq60co0aNjptvvzfeefeDmHee7nFgr92jR/eu0+RNT6rK9/mXX8cddz8Y/foPiJVXXC4O2nf3aN586q2lOj3+1PPRrFnT2GaLTWKDddf8TdlpR2X5anvdCi9iJwECBAgQIECAAAECBAgQIECAAAECv0ugzubQ/PenX8SJp/8ldttp21hmqcVjSvbf8aeel1fu62/6xptvvxfLLLlY2b+OHWfPj516zkVx210PxIbrrxVjx46LHfY4MA9eTn9XleVLwdK9Dugdn3/1dWy75abx6D+fiVPPvjg//bkXX43eJ5wRXeaeK1bJAp2HHn1qvPTqm9MXHVXlq811f3MBOwgQIECAAAECBAgQIECAAAECBAgQqBOBOuuh+fpbfaJ7t66x9pqrxjPPvxxnnHhUPPXcSzFx4sTo+92AWGqJRaPXnjtPU+nhv46Ihx59Kh68+8ZYfpklY8L2E2PR5deO5156LbbafKOyvFXlSz0omzRpEvfddm2eP/XMPPrEs+L0E3vHLXfcF3vtukOclm2n9OY778Xd9z0c62R1LJ8qy7dcVqfK6lfVddu0maV88bYJECBAgAABAgQIECBAgAABAgQIEKgjgTrrobnRemvFZ198FSedcX6MGDkqWrduFdtttVk+9DsFNL/8+tvYfLs9Y8c9D4qHH386D3T2y/antHQW7EypRYvm0a3r3NG3X//8eeFHVfn6ftc/6/W5eCFr9Jy3R4yfMCEG/fBj9Os3IJZZutyxeXrEt9OVnU6sLF9tr1tWGRsECBAgQIAAAQIECBAgQIAAAQIECNSpQJ310EyBxFuv+7+49sbb460+78cq62wRZ558dPx50w3ygGGq9T577JQHNk/IhqKnYGGaXzP1ZizMd5nydOvSOUaOGpU2y1L/AYMqzTdw0A/Rvv2sZXlTQDSlESNGxsDvs2Pt2pUd65qVPWr06LLnaWPy5MmV5qvNdVPPzZS6dGydPxbbj8lRZ01ebLfWIOrTsnnTon3tNAjg33ETEyZOjmwqXqlIBZo1bRKdOrSM5hqpRi30xY9e1DUC+4Mzt2/T3HvCH2xe3cuNHDepulnlmwkCrVr4PFVT9omTsm8J2XupVJwCTZs2jTnbt4wW2XcFqfgEWvYbUXyVUqMygfZtfZ4qw2hgG3Ua3UpDuVdYbuk44PDjo/NcneKs8y/N58Y8/+wTs0BAs5hllqlBvh9+HBz/zBbqOfGYQ2P06DExdty4aN2qVU47JptHs2fWk7J8SudVlu+XX4bFkOxfIY0ZMzbfnC8LsLZs2TKGDv3fsXSdeXp0K2TNH9ObQ2X5anPdef9b/ve/TK3HNBcrgifDR00sglqoQmUC47OgWbG+diqrc2Pan33Wl4pUYNLkKTF4+PgirV3xVmvcBC/q4m2diF9HT/SeUKQNlNpGKl6B9LvN56mat8/E7L1UKk6B1Ann5199zinO1olI3+Gk4hX4NYuBfN+0OOMzXecwXeHveeXU2Z94Lrz06rjq+r/ndek0R8c465Rj8kDjRx//J554+oUY/POQsnp2z3pRzj5bh0g9JlMaMPD7/DH9ov6u/8BYeMH58ueFH1Xl65KVkXpSFtK3fb+LTnN2jNmy8lNvz++mO7bwgvMXspY9VpavttctK9gGAQIECBAgQIAAAQIECBAgQIAAAQJ1KlBnAc0O7dvF/Q89HmlF85Reee2tfDj3fD175CuL9z7+jJg0aVJ8/K9P45FsJfJNN1o3Fl14wWwhoS5x3U135MPML7n8ury35iLZ/tSbMgVIv8kClFXlS3N3fvHVN/HsC69E/4GD4rKrb4wVll06r0NaOf2eBx7Jg6kvvPx6PJ71Cl1huaXyY6kO6ZyUKstX2+vmhfpBgAABAgQIECBAgAABAgQIECBAgECdC9TZkPOdt98yX9V86533zVcdf/r5V+KEow/JekvOEYcftE8cfuxpsfiK68W4LFC50grLxNZ/3ji/mcv/ek7stf+ReTA0LSR06flnZPNezhrDhg2Piy+7JhaYf96Yv+c8UVm+pZdcLI44uFc2zP2EmDJlSsw7T/e46tK/5GUfcVCveKfPB7HSWpvnz9MiRVtuNnX19Hv/8WjM2XH22DALiFaVrzbXrfNWUiABAgQIECBAgAABAgQIECBAgAABArlAnQU00xDvh++5Kb748ps496K/xfVXXJitdD51zszFFlkonnvsnnw4eQpaztVpzjL+5ZdZMt5//en4+tu+MV8WuGyVzXuZUipvlx22jsKclJXlS3mPPvyA2HfPnWPwkF/yhYbSvpTatm0TD2V1SgsQpe05s6HwhXTIfnvmixfNKF9trlu4hkcCBAgQIECAAAECBAgQIECAAAECBOpWoM4CmoVqzT/fPHHIAXuVBTML+9Pj9AvyFI61aNE8H1ZeeJ4e02rhXeeea5r9FeUrnNOhQ/tI/ypKqdfm9KnP+x/FbjttO83uivKlDLW97jSFe0KAAAECBAgQIECAAAECBAgQIECAwO8WqPOAZvPmzeNPKy3/uyuWelQeng0lr6901GH711fRyiVAgAABAgQIECBAgAABAgQIECBAoJ4E6mxRoHqqn2IJECBAgAABAgQIECBAgAABAgQIECBQJiCgWUZhgwABAgQIECBAgAABAgQIECBAgACBYhcQ0Cz2FlI/AgQIECBAgAABAgQIECBAgAABAgTKBAQ0yyhsECBAgAABAgQIECBAgAABAgQIECBQ7AICmsXeQupHgAABAgQIECBAgAABAgQIECBAgECZgIBmGYUNAgQIECBAgAABAgQIECBAgAABAgSKXUBAs9hbSP0IECBAgAABAgQIECBAgAABAgQIECgTENAso7BBgAABAgQIECBAgAABAgQIECBAgECxCwhoFnsLqR8BAgQIECBAgAABAgQIECBAgAABAmUCApplFDYIECBAgAABAgQIECBAgAABAgQIECh2AQHNYm8h9SNAgAABAgQIECBAgAABAgQIECBAoExAQLOMwgYBAgQIECBAgAABAgQIECBAgAABAsUuIKBZ7C2kfgQIECBAgAABAgQIECBAgAABAgQIlAkIaJZR2CBAgAABAgQIECBAgAABAgQIECBAoNgFBDSLvYXUjwABAgQIECBAgAABAgQIECBAgACBMgEBzTIKGwQIECBAgAABAgQIECBAgAABAgQIFLuAgGaxt5D6ESBAgAABAgQIECBAgAABAgQIECBQJiCgWUZhgwABAgQIECBAgAABAgQIECBAgACBYhcQ0Cz2FlI/AgQIECBAgAABAgQIECBAgAABAgTKBAQ0yyhsECBAgAABAgQIECBAgAABAgQIECBQ7AICmsXeQupHgAABAgQIECBAgAABAgQIECBAgECZgIBmGYUNAgQIECBAgAABAgQIECBAgAABAgSKXUBAs9hbSP0IECBAgAABAgQIECBAgAABAgQIECgTENAso7BBgAABAgQIECBAgAABAgQIECBAgECxCwhoFnsLqR8BAgQIECBAgAABAgQIECBAgAABAmUCApplFDYIECBAgAABAgQIECBAgEBxCTRt4mt7cbWI2hAgUAwCzYuhEupAgAABAgQIECBAgAABAgQI/FZgwVZzx9Abr4kpE8b/9qA9M11gypo7zfQ6qACBxiggoNkYW909EyBAgAABAgQIECBAgEBJCDSbEjHm5Rdiwrdfl0R9G1slp6y2fWO7ZfdLoCgE9F0vimZQCQIECBAgQIAAAQIECBAgQIAAAQIEqiMgoFkdJXkIECBAgAABAgQIECBAgAABAgQIECgKAQHNomgGlSBAgAABAgQIECBAgAABAgQIECBAoDoCAprVUZKHAAECBAgQIECAAAECBAgQIECAAIGiEBDQLIpmUAkCBAgQIECAAAECBAgQIECAAAECBKojYJXz6ijJQ4AAAQIECBD4AwVmb9Mx2nz+Tfza98U/8KouVV2BiYuuVN2s8hEgQIAAAQIECNSDgIBmPaAqkgABAgQIECDwewRaNW8d4956M0bde+fvKca59SQw8aSLspLnqqfSFUuAAAECBAgQIDAjAUPOZyTkOAECBAgQIECAAAECBAgQIECAAAECRSMgoFk0TaEiBAgQIECAAAECBAgQIECAAAECBAjMSEBAc0ZCjhMgQIAAAQIECBAgQIAAAQIECBAgUDQCAppF0xQqQoAAAQIECBAgQIAAAQIECBAgQIDAjAQENGck5DgBAgQIECBAgAABAgQIECBAgAABAkUjIKBZNE2hIgQIECBAgAABAgQIECBAgAABAgQIzEig+YwyOE6AwB8n0HFc0xj3+ad/3AVdqdoCTWeZJWLKlGrnl5EAAQIECBAgQIAAAQIECBCoHwEBzfpxVSqBWgm0HToqfjrzmFqd66T6FWi1zPIRKx9avxdROgECBAgQIECAAAECBAgQIDBDAQHNGRLJQOCPE5g8cUJMHj7sj7ugK1VfYPKkLK8emtUHk5MAAQIECBAgQIAAAQIECNSPgDk068dVqQQIECBAgAABAgQIECBAgAABAgQI1IOAgGY9oCqSAAECBAgQIECAAAECBAgQIECAAIH6ERDQrB9XpRIgQIAAAQIECBAgQIAAAQIECBAgUA8CApr1gKpIAgQIECBAgAABAgQIECBAgAABAgTqR0BAs35clUqAAAECBAgQIECAAAECBAgQIECAQD0ICGjWA6oiCRAgQIAAAQIECBAgQIAAAQIECBCoHwEBzfpxVSoBAgQIECBAgAABAgQIECBAgAABAvUgIKBZD6iKJECAAAECBAgQIECAAAECBAgQIECgfgQENOvHVakECBAgQIAAAQIECBAgQIAAAQIECNSDgIBmPaAqkgABAgQIECBAgAABAgQIECBAgACB+hEQ0KwfV6USIECAAAECBAgQIECAAAECBAgQIFAPAgKa9YCqSAIECBAgQIAAAQIECBAgQIAAAQIE6kdAQLN+XJVKgAABAgQIECBAgAABAgQIECBAgEA9CAho1gOqIgkQIECAAAECBAgQIECAAAECBAgQqB8BAc36cVUqAQIECBAgQIAAAQIECBAgQIAAAQL1ICCgWQ+oiiRAgAABAgQIECBAgAABAgQIECBAoH4EBDTrx1WpBAgQIECAAAECBAgQIECAAAECBAjUg4CAZj2gKpIAAQIECBAgQIAAAQIECBAgQIAAgfoRENCsH1elEiBAgAABAgQIECBAgAABAgQIECBQDwICmtVEveHWu6qZUzYCBAgQIECAAAECBAgQIECAAAECBOpLoHl9FdxQyv3si6/ixlvvjseefC5eevXN2GOX7WKTDdbJb+/zL7+OO+5+MPr1HxArr7hcHLTv7tG8OdKG0vbugwABAgQIECBAgAABAgQIECBAoPgE9NCsok2mTJkSh/Q+Obp26RxLLbFobLnZRnHUCWfGwEE/xNBhw2OvA3rH5199HdtuuWk8+s9n4tSzL66iNIcIECBAgAABAgQI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4oE49eplVbFjBR09erTZYn6kPM4uNTJHbv3Pju5ZNzRrbg5tOJMrMrPDdhq/v3SZH3pMRvttu/fGLT9/PgYP1/3zNfDRmXF9/6yhX9tzAgQIECBAgAABAgQIECBAYJIKSGgeRxOXueV9rx+Y0Ij6pp14XCf9JvRlJlnw4UOHY/DAwepRd5XO1z3T6pLC1Rd9hwYOHj4ar//rSPW37+6eEu/qtSC9GkwgAQIECBAgQIAAAQIECBA4jgUkNI/jyTE0AgQIECBAgAABAgQIECBAgAABAgSGC4zd4WV4nN8IECBAgAABAgQIECBAgAABAgQIECDQuoCEZutTYAAECBAgQIAAAQIECBAgQIAAAQIECNQKSGjWSokjQIAAAQIECBAgQIAAAQIECBAgQKB1AQnN1qfAAAgQIECAAAECBAgQIECAAAECBAgQqBWQ0KyVEkeAAAECBAgQIECAAAECBAgQIECAQOsCEpqtT4EBECBAgAABAgQIECBAgAABAgQIECBQKyChWSsljgABAgQIECBAgAABAgQIECBAgACB1gUkNFufAgMgQIAAAQIECBAgQIAAAQIECBAgQKBWQEKzVkocAQIECBAgQIAAAQIECBAgQIAAAQKtC0hotj4FBkCAAAECBAgQIECAAAECBAgQIECAQK2AhGatlDgCBAgQIECAAAECBAgQIECAAAECBFoXkNBsfQoMgAABAgQIECBAgAABAgQIECBAgACBWgEJzVopcQQIECBAgAABAgQIECBAgAABAgQItC4godn6FBgAAQIECBAgQIAAAQIECBAgQIAAAQK1AhKatVLiCBAgQIAAAQIECBAgQIAAAQIECBBoXUBCs/UpMAACBAgQIECAAAECBAgQIECAAAECBGoFJDRrpcQRIECAAAECBAgQIECAAAECBAgQINC6gIRm61NgAAQIECBAgAABAgQIECBAgAABAgQI1ApIaNZKiSNAgAABAgQIECBAgAABAgQIECBAoHUBCc3Wp8AACBAgQIAAAQIECBAgQIAAAQIECBCoFZDQrJUSR4AAAQIECBAgQIAAAQIECBAgQIBA6wISmq1PgQEQIECAAAECBAgQIECAAAECBAgQIFArIKFZKyWOAAECBAgQIECAAAECBAgQIECAAIHWBSQ0W58CAyBAgAABAgQIECBAgAABAgQIECBAoFZAQrNWShwBAgQIECBAgAABAgQIECBAgAABAq0LSGi2PgUGQIAAAQIECBAgQIAAAQIECBAgQIBArYCEZq2UOAIECBAgQIAAAQIECBAgQIAAAQIEWheQ0Gx9CgyAAAECBAgQIECAAAECBAgQIECAAIFagf8AINxPgm/1EDIAAAAASUVORK5CYII=" - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "charts.scenario_comparison(scenario_summaries).show()" - ] - }, - { - "cell_type": "markdown", - "id": "270745bf", - "metadata": {}, - "source": [ - "## Cross-check vs Athena (optional)\n", - "\n", - "When `TOOL_PUBLIC_ID` is set, ask Athena to recalculate the summary on\n", - "the server side and confirm it matches our local computation." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "c8239dbd", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Set TOOL_PUBLIC_ID to compare Athena vs local.
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "if config.TOOL_PUBLIC_ID:\n", - " from core.tei_client import TEIClient\n", - "\n", - " client = TEIClient()\n", - " client.calculate(config.TOOL_PUBLIC_ID)\n", - " server_summary = client.get_summary(config.TOOL_PUBLIC_ID)\n", - " display.kpi_cards(server_summary, title='Athena server-side summary')\n", - "else:\n", - " display.alert('Set TOOL_PUBLIC_ID to compare Athena vs local.', 'info')" - ] - }, - { - "cell_type": "markdown", - "id": "794848f5", - "metadata": {}, - "source": [ - "Continue with [`04_export.ipynb`](04_export.ipynb) →" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4ac0231c-5b57-4544-a464-148d2e74332c", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.7" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/studies/202602_AmazonConnect/notebooks/04_export.ipynb b/studies/202602_AmazonConnect/notebooks/04_export.ipynb deleted file mode 100644 index 4c60212..0000000 --- a/studies/202602_AmazonConnect/notebooks/04_export.ipynb +++ /dev/null @@ -1,195 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "15a4163e", - "metadata": {}, - "source": [ - "# 04 — Export for the report pipeline\n", - "\n", - "Build the structured JSON envelope consumed by the html2docx report\n", - "generation pipeline (Peitho). Output goes to `exports/export.json`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "18f02ef8", - "metadata": {}, - "outputs": [], - "source": [ - "import sys\n", - "from pathlib import Path\n", - "\n", - "ROOT = Path.cwd().resolve()\n", - "while ROOT != ROOT.parent and not (ROOT / 'core').is_dir():\n", - " ROOT = ROOT.parent\n", - "if str(ROOT) not in sys.path:\n", - " sys.path.insert(0, str(ROOT))\n", - "STUDY = ROOT / 'studies' / '202602_AmazonConnect'\n", - "if str(STUDY) not in sys.path:\n", - " sys.path.insert(0, str(STUDY))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7d91c01d", - "metadata": {}, - "outputs": [], - "source": [ - "import json\n", - "from datetime import datetime, timezone\n", - "\n", - "import config\n", - "import seed_data\n", - "from core import __version__\n", - "from core.calculations import apply_scenario\n", - "from core.export.report_data import _compute_summary\n", - "from core.notebook_helpers import display" - ] - }, - { - "cell_type": "markdown", - "id": "cff0b35b", - "metadata": {}, - "source": [ - "## Build the envelope\n", - "\n", - "Two paths:\n", - "\n", - "* **Live** — `core.export.build_report_data(client, public_id)` pulls\n", - " authoritative values + summary from Athena and stamps it.\n", - "* **Local** — when no `TOOL_PUBLIC_ID` is configured, build the envelope\n", - " directly from `seed_data` so this notebook is always runnable." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "19416ff3", - "metadata": {}, - "outputs": [], - "source": [ - "if config.TOOL_PUBLIC_ID:\n", - " from core.export import build_report_data\n", - " from core.tei_client import TEIClient\n", - "\n", - " client = TEIClient()\n", - " envelope = build_report_data(\n", - " client,\n", - " config.TOOL_PUBLIC_ID,\n", - " include_scenarios=True,\n", - " study_slug=config.STUDY_SLUG,\n", - " )\n", - " source = 'live (Athena)'\n", - "else:\n", - " summary = _compute_summary(\n", - " seed_data.BENEFITS, seed_data.COSTS, config.DISCOUNT_RATE, config.ANALYSIS_YEARS\n", - " )\n", - " summary['roi'] = summary.get('roi_pct')\n", - " scenarios = {}\n", - " for name in ('conservative', 'moderate', 'aggressive'):\n", - " sb = apply_scenario(seed_data.BENEFITS, name, table='benefits')\n", - " sc = apply_scenario(seed_data.COSTS, name, table='costs')\n", - " scenarios[name] = _compute_summary(sb, sc, config.DISCOUNT_RATE, config.ANALYSIS_YEARS)\n", - " envelope = {\n", - " 'metadata': {\n", - " 'study_slug': config.STUDY_SLUG,\n", - " 'tool_public_id': '',\n", - " 'tool_name': 'Amazon Connect TEI (local seed)',\n", - " 'report_name': 'Total Economic Impact™ Of Amazon Connect',\n", - " 'report_vendor': 'AWS',\n", - " 'report_version': '1.0',\n", - " 'generated_at': datetime.now(timezone.utc).isoformat(),\n", - " 'generator': f'palladium core {__version__} (offline)',\n", - " },\n", - " 'report': {\n", - " 'name': 'Total Economic Impact™ Of Amazon Connect',\n", - " 'vendor': 'AWS',\n", - " 'version': '1.0',\n", - " 'discount_rate': config.DISCOUNT_RATE,\n", - " 'analysis_period_years': config.ANALYSIS_YEARS,\n", - " },\n", - " 'values': {'benefits': seed_data.BENEFITS, 'costs': seed_data.COSTS},\n", - " 'summary': summary,\n", - " 'scenarios': scenarios,\n", - " 'assumptions': seed_data.ASSUMPTIONS,\n", - " }\n", - " source = 'offline seed data'\n", - "\n", - "display.alert(f'Envelope built from {source}.', 'info')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "98e94d07", - "metadata": {}, - "outputs": [], - "source": [ - "out_path = STUDY / 'exports' / 'export.json'\n", - "out_path.parent.mkdir(parents=True, exist_ok=True)\n", - "out_path.write_text(json.dumps(envelope, indent=2, default=str))\n", - "size_kb = out_path.stat().st_size / 1024\n", - "display.alert(f'Wrote {out_path.relative_to(ROOT)} ({size_kb:.1f} KB).', 'success')" - ] - }, - { - "cell_type": "markdown", - "id": "d09cad64", - "metadata": {}, - "source": [ - "## Envelope shape\n", - "\n", - "Top-level keys consumed by the report pipeline:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "841f12a1", - "metadata": {}, - "outputs": [], - "source": [ - "for key in envelope:\n", - " sub = envelope[key]\n", - " if isinstance(sub, dict):\n", - " print(f' {key}: dict with keys {list(sub.keys())}')\n", - " elif isinstance(sub, list):\n", - " print(f' {key}: list[{len(sub)}]')\n", - " else:\n", - " print(f' {key}: {type(sub).__name__}')" - ] - }, - { - "cell_type": "markdown", - "id": "17d6d0ce", - "metadata": {}, - "source": [ - "Done. Hand off `exports/export.json` to **Peitho** / **html2docx** to produce the final Word report." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.7" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/studies/202602_TEI_Amazon_Connect/README.md b/studies/202602_TEI_Amazon_Connect/README.md new file mode 100644 index 0000000..43f32f8 --- /dev/null +++ b/studies/202602_TEI_Amazon_Connect/README.md @@ -0,0 +1,97 @@ +# 202602 — Amazon Connect TEI + +Self-contained reproduction of the Forrester *Total Economic Impact™ Of +Amazon Connect* study (February 2026, commissioned by AWS), built on the +[Mercury Notebook Deliverable Pattern](../../docs/Mercury_Notebook_Pattern_V1-00.md) +as **Variant 4 — TEI composite reproduction**: Forrester's composite +organization is the never-edited verbatim anchor, the in-notebook gate +proves the engine reproduces the published totals, and 🟡 client drivers +rescale the composite live. + +## Source + +The full Forrester study is at +[`docs/202602_TEI Report Amazon Connect.pdf`](docs/202602_TEI%20Report%20Amazon%20Connect.pdf). + +Published composite totals (3-yr risk-adjusted PV @ 10%), reproduced by +`teicalc` to within the PDF's own table rounding (benefits PV lands $223 +low; costs PV $0.22 low): + +| Metric | Published | Engine | +|---|---|---| +| Benefits PV | **$101,696,791** | $101,696,568 | +| Costs PV | **$22,983,076** | $22,983,076 | +| NPV | **$78,713,715** | $78,713,492 | +| ROI | **342%** | 342.48% | +| Payback | **<6 months** | 0.7 months | + +## Composite organization (the verbatim anchor 🟢) + +* Global B2C, ~$10B revenue (Y1), 30% YoY growth +* 2,000 contact-center agents, 200 supervisors +* 20M annual contacts (75% calls, 25% chat) +* 10-min average handle time + +## Client overlay (🟡) + +A first-order linear rescale — "the composite at your size", not "your +TEI". Each published row scales with the driver that dominates its PDF +derivation: + +| Row | Driver | Confidence | +|---|---|---| +| AI contact resolution · content/sentiment | contacts | 🟡 | +| Forecasting/supervision · legacy savings | agents | 🟡 | +| Data-driven profit lift | contacts | 🔴 proxy (revenue-driven in the PDF) | +| Amazon Connect usage | contacts | 🟡 | +| Implementation · ongoing management | fixed | 🟡 project-based | + +The client growth rate re-bases the composite's Y1→Y3 trajectory (which +embeds 30% YoY). At composite scale the overlay is the identity — the +gate asserts it. + +## Layout + +``` +202602_TEI_Amazon_Connect/ +├── teicalc/ ← ALL math (stdlib-only) — notebooks hold none +│ ├── anchor.py ← Forrester's tables, VERBATIM, never edited +│ ├── model.py ← NPV/ROI/payback, risk adjustment, compute_summary +│ ├── overlay.py ← ClientDrivers + driver map + overlay_rows +│ ├── scenarios.py ← conservative / moderate / aggressive +│ └── staging.py ← on_stage()/backstage() (Mercury vs nbconvert) +├── notebooks/business_case.ipynb ← THE deliverable +├── scripts/export_report.py +├── tests/ ← hand-checked pinned acceptance numbers +├── config.toml ← Mercury theme (NTT DATA brand) +├── pyproject.toml ← full toolchain as core deps — no requirements.txt +├── docs/ ← the Forrester PDF +└── exports/ ← generated .html/.md; gitignored +``` + +## Run + +```bash +python -m venv .venv && source .venv/bin/activate +pip install -e ".[dev]" +``` + +| Task | Command | +|---|---| +| Tests | `pytest` | +| Serve (the stage) | `mercury --working-dir notebooks/` (run from this project root so `config.toml` loads) | +| Analyst view (backstage) | `jupyter lab` | +| Headless check | `jupyter nbconvert --to notebook --execute --inplace notebooks/business_case.ipynb` | +| Export for LLMs | `python scripts/export_report.py` | + +The data appendix (markdown tables + JSON model state) rides inside +`exports/business_case.md` — it replaces the retired `exports/export.json` +pipeline and is the payload for the Athena study-repository roadmap. + +## History + +This study previously ran on the shared `core/` package with an +Athena-workflow notebook chain (provision → push → calculate → export). +That workflow was retired when the study migrated to the pattern +(git history preserves it); the engine reproduces the same published +totals locally, pinned in `tests/`. diff --git a/studies/202602_TEI_Amazon_Connect/config.toml b/studies/202602_TEI_Amazon_Connect/config.toml new file mode 100644 index 0000000..ed084e2 --- /dev/null +++ b/studies/202602_TEI_Amazon_Connect/config.toml @@ -0,0 +1,81 @@ +# Mercury app-shell theme — NTT DATA brand (light), modern surfaces. +# See docs/brand.md for the source palette. +# +# Loaded from the directory where you launch `mercury` (this project root); +# restart the server to apply changes. Only keys in mercury/config.py +# CSS_VARIABLE_MAP emit a CSS variable — anything else in DEFAULT_THEME is +# either derived or component-baked (e.g. success/warning/danger, slider +# track, widget bg) and silently no-ops here. Omitted keys are derived +# from the ones below. + +[main] +title = "Amazon Connect TEI — Business Case" +favicon_emoji = "📊" +footer = "Amazon Connect TEI study (Forrester, Feb 2026)" +notebooks_button_label = "Analyses" + +[welcome] +header = "Amazon Connect TEI" +message = """ +Interactive reproduction of Forrester's *Total Economic Impact™ Of Amazon +Connect* composite ($78.7M NPV · 342% ROI). The published study is the +verbatim anchor; tune the 🟡 client drivers live to rescale the composite +to your organization, then export the personalized report source with +`python scripts/export_report.py`. +""" + +[theme] +# ── Type — Georgia headings, Arial body. Both web-safe system fonts, +# so no font_url / network fetch. Georgia ships only normal+bold, so +# heading weight is 700 (the default 800 would render as faux-bold). ── +font_family = "Arial, 'Helvetica Neue', Helvetica, sans-serif" +heading_font_family = "Georgia, 'Times New Roman', Times, serif" +font_size = "15px" +font_weight = "normal" +heading_font_weight = "700" + +# ── Text — NTT ink scale ── +text_color = "#2e404d" # body +muted_text_color = "#586671" # captions / secondary + +# ── Surfaces — white content floating on a soft neutral canvas (depth). +# For a strictly-white page instead, set background_color = "#ffffff". ── +background_color = "#f4f5f6" # outer page +content_background_color = "#ffffff" # notebook column +surface_color = "#ffffff" +card_background_color = "#f8f8f8" # brand card +border_color = "#d5d9db" # brand border +border_radius = "10px" # modern rounding + +# ── Accents — Future Blue. primary_color also drives the Run button + focus. ── +primary_color = "#0072bc" +accent_color = "#0072bc" +focus_border_color = "#0072bc" +hover_background_color = "#eef5fb" # light blue tint +selected_background_color = "#dcecfa" + +# ── Sidebar — clean white, hairline divider ── +sidebar_background_color = "#ffffff" +sidebar_text_color = "#2e404d" +sidebar_title_color = "#151d2c" +sidebar_shadow = "1px 0 0 #d5d9db" + +# ── Top bar — deep NTT navy (brand heading-primary) ── +topbar_background_color = "#151d2c" +topbar_text_color = "#ffffff" +topbar_border_color = "rgba(255,255,255,0.08)" + +# ── Footer ── +footer_background_color = "#ffffff" +footer_text_color = "#586671" +footer_border_color = "#d5d9db" + +# ── Run button — subtle brand-blue gradient (else derives from primary) ── +run_button_background = "linear-gradient(180deg, #0087dc 0%, #0072bc 100%)" +run_button_background_hover = "linear-gradient(180deg, #1a93e6 0%, #0079c8 100%)" +run_button_text_color = "#ffffff" + +# ── Depth — soft, navy-tinted shadows (modern) ── +shadow_sm = "0 1px 2px rgba(21,29,44,0.05)" +shadow_md = "0 6px 18px rgba(21,29,44,0.08)" +shadow_lg = "0 16px 40px rgba(21,29,44,0.10)" diff --git a/studies/202602_AmazonConnect/docs/202602_TEI Report Amazon Connect.pdf b/studies/202602_TEI_Amazon_Connect/docs/202602_TEI Report Amazon Connect.pdf similarity index 100% rename from studies/202602_AmazonConnect/docs/202602_TEI Report Amazon Connect.pdf rename to studies/202602_TEI_Amazon_Connect/docs/202602_TEI Report Amazon Connect.pdf diff --git a/studies/202602_AmazonConnect/exports/.gitkeep b/studies/202602_TEI_Amazon_Connect/exports/.gitkeep similarity index 100% rename from studies/202602_AmazonConnect/exports/.gitkeep rename to studies/202602_TEI_Amazon_Connect/exports/.gitkeep diff --git a/studies/202602_TEI_Amazon_Connect/notebooks/business_case.ipynb b/studies/202602_TEI_Amazon_Connect/notebooks/business_case.ipynb new file mode 100644 index 0000000..ac0ed73 --- /dev/null +++ b/studies/202602_TEI_Amazon_Connect/notebooks/business_case.ipynb @@ -0,0 +1,6946 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "cell-0", + "metadata": {}, + "source": [ + "# Amazon Connect TEI — Business Case\n", + "\n", + "Reproduction of Forrester's *Total Economic Impact™ Of Amazon Connect*\n", + "(February 2026, commissioned by AWS) — and a live personalization of it.\n", + "The published composite organization is the **verbatim anchor** (never\n", + "edited); the verification gate proves this notebook reproduces the\n", + "published **$78.7M NPV · 342% ROI · <6-month payback**; the client drivers\n", + "then rescale the composite to your organization.\n", + "\n", + "**This notebook is the deliverable** — served interactively with Mercury,\n", + "exported via nbconvert as the report source (Mercury Notebook Pattern,\n", + "Variant 4).\n", + "\n", + "| Layer | What it is | Confidence |\n", + "|---|---|---|\n", + "| Verbatim anchor | Forrester's composite tables, unedited | 🟢 published |\n", + "| Client overlay | first-order linear rescale by your drivers | 🟡 estimated |\n", + "| Scenario | adoption × risk stress | 🟡 estimated |\n", + "\n", + "Confidence legend: 🟢 confirmed/published · 🟡 estimated (stated assumption) · 🔴 unknown (flagged)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "cell-1", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-09T18:15:41.740701Z", + "iopub.status.busy": "2026-07-09T18:15:41.740233Z", + "iopub.status.idle": "2026-07-09T18:15:42.174061Z", + "shell.execute_reply": "2026-07-09T18:15:42.173079Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "teicalc loaded — window 2026–2028 · published NPV $78.7M · ROI 342%\n" + ] + } + ], + "source": [ + "# ── Setup ──────────────────────────────────────────────────────────\n", + "import sys, pathlib\n", + "_ROOT = pathlib.Path.cwd()\n", + "if not (_ROOT / \"teicalc\").exists(): # notebook lives in notebooks/\n", + " _ROOT = _ROOT.parent\n", + "sys.path.insert(0, str(_ROOT))\n", + "\n", + "import pandas as pd\n", + "import plotly.graph_objects as go\n", + "\n", + "import mercury as mr\n", + "\n", + "# Single source of truth — all math lives in the study package; only\n", + "# presentation (and Mercury input widgets) lives here.\n", + "from teicalc import (\n", + " ASSUMPTIONS, BENEFITS_VERBATIM, COSTS_VERBATIM, PUBLISHED,\n", + " YEARS, X_LABELS,\n", + " BENEFIT_DRIVERS, COST_DRIVERS, COMPOSITE, ClientDrivers,\n", + " SCENARIOS, apply_scenario, compute_summary, growth_multiplier,\n", + " money, html_money, overlay_rows,\n", + ")\n", + "from teicalc.staging import backstage\n", + "\n", + "pd.options.display.float_format = \"{:,.0f}\".format\n", + "\n", + "# ── Chart chrome (dataviz reference palette, light surface) ─────────\n", + "INK, INK2, MUTED = \"#0b0b0b\", \"#52514e\", \"#898781\"\n", + "SURFACE, GRID, BASELINE = \"#fcfcfb\", \"#e1e0d9\", \"#c3c2b7\"\n", + "CUMULATIVE, CONTEXT = \"#52514e\", \"#c3c2b7\" # neutral line; de-emphasized context series\n", + "FONT_STACK = 'system-ui, -apple-system, \"Segoe UI\", sans-serif'\n", + "\n", + "# Fixed row colors — color follows the entity across every figure.\n", + "BENEFIT_COLOR = {\n", + " \"ai_contact_resolution\": \"#2a78d6\", # blue\n", + " \"ai_content_sentiment\": \"#1baf7a\", # aqua\n", + " \"ai_forecasting_supervision\": \"#4a3aa7\", # violet\n", + " \"data_driven_profit_lift\": \"#eda100\", # yellow\n", + " \"legacy_solution_savings\": \"#008300\", # green\n", + "}\n", + "COST_COLOR = {\n", + " \"amazon_connect_usage\": \"#e34948\", # red\n", + " \"implementation_migration\": \"#eda100\", # yellow\n", + " \"ongoing_management\": \"#4a3aa7\", # violet\n", + "}\n", + "BEN_TOTAL, COST_TOTAL, NPV_COLOR = \"#1baf7a\", \"#e34948\", \"#2a78d6\"\n", + "\n", + "\n", + "def tei_layout(fig, title, subtitle=None, height=460):\n", + " t = f\"{title}\"\n", + " if subtitle:\n", + " t += f\"
{subtitle}\"\n", + " fig.update_layout(\n", + " title=dict(text=t, font=dict(size=16, color=INK), x=0.02, xanchor=\"left\"),\n", + " paper_bgcolor=SURFACE, plot_bgcolor=SURFACE,\n", + " font=dict(family=FONT_STACK, size=12, color=INK2),\n", + " legend=dict(orientation=\"h\", yanchor=\"top\", y=-0.10, x=0,\n", + " font=dict(size=11, color=INK2)),\n", + " xaxis=dict(type=\"category\", showgrid=False, linecolor=BASELINE,\n", + " tickfont=dict(color=MUTED)),\n", + " yaxis=dict(gridcolor=GRID, zerolinecolor=BASELINE, zerolinewidth=1.5,\n", + " tickformat=\"$~s\", tickfont=dict(color=MUTED)),\n", + " hovermode=\"x unified\", bargap=0.45, height=height,\n", + " margin=dict(t=70, r=30, b=80, l=70),\n", + " )\n", + " return fig\n", + "\n", + "\n", + "def bar(x, y, name, color):\n", + " return go.Bar(x=x, y=y, name=name,\n", + " marker=dict(color=color, line=dict(width=2, color=SURFACE)),\n", + " hovertemplate=\"%{fullData.name}: %{y:$,.0f}\")\n", + "\n", + "\n", + "def cum_line(x, y, name, color=CUMULATIVE, dash=None):\n", + " return go.Scatter(x=x, y=y, name=name, mode=\"lines+markers\",\n", + " line=dict(color=color, width=2, dash=dash),\n", + " marker=dict(size=8, line=dict(width=2, color=SURFACE)),\n", + " hovertemplate=\"%{fullData.name}: %{y:$,.0f}\")\n", + "\n", + "\n", + "backstage(f\"teicalc loaded — window {YEARS[0]}–{YEARS[-1]} · published \"\n", + " f\"NPV {money(PUBLISHED['npv'])} · ROI {PUBLISHED['roi_pct']}%\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "cell-2", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-09T18:15:42.176402Z", + "iopub.status.busy": "2026-07-09T18:15:42.175865Z", + "iopub.status.idle": "2026-07-09T18:15:42.192559Z", + "shell.execute_reply": "2026-07-09T18:15:42.191936Z" + } + }, + "outputs": [ + { + "data": { + "application/mercury+json": { + "model_id": "0833fb2c5bd3466aba5ff466dec6ff1b", + "position": "sidebar", + "widget": "MarkdownWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "0833fb2c5bd3466aba5ff466dec6ff1b", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "MarkdownWidget(value='
{label}'\n", + " for n, label in _TOC)\n", + "_toc = mr.Markdown(\n", + " text=(f'Jump to section'\n", + " f'
    {_items}
'),\n", + " position=\"sidebar\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "cell-3", + "metadata": {}, + "source": [ + "\n", + "## 1 · The Forrester composite (verbatim anchor 🟢)\n", + "\n", + "Forrester's composite organization: a global B2C company with **$10B\n", + "year-1 revenue growing 30% YoY**, **2,000 contact-center agents** plus 200\n", + "supervisors, **20M annual contacts** (75% calls / 25% chat), and a\n", + "10-minute legacy average handle time.\n", + "\n", + "TEI methodology, carried verbatim into the engine: benefits are\n", + "risk-adjusted **down** (×(1−rf)), costs **up** (×(1+rf)); the initial\n", + "investment sits at time 0 undiscounted; year flows discount at end-of-year\n", + "(10%, 3 years). Payback runs on risk-adjusted *undiscounted* flows, per the\n", + "PDF's Cash Flow Analysis tables.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "cell-4", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-09T18:15:42.194666Z", + "iopub.status.busy": "2026-07-09T18:15:42.194415Z", + "iopub.status.idle": "2026-07-09T18:15:42.210841Z", + "shell.execute_reply": "2026-07-09T18:15:42.210047Z" + } + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Value 🟢
Assumption
agents fte2,000
supervisors fte200
annual contacts y120,000,000
growth rate30%
call share75%
aht legacy minutes10 min
agent salary$45,760
supervisor salary$55,800
discount rate10%
analysis years3 years
\n", + "
" + ], + "text/plain": [ + " Value 🟢\n", + "Assumption \n", + "agents fte 2,000\n", + "supervisors fte 200\n", + "annual contacts y1 20,000,000\n", + "growth rate 30%\n", + "call share 75%\n", + "aht legacy minutes 10 min\n", + "agent salary $45,760\n", + "supervisor salary $55,800\n", + "discount rate 10%\n", + "analysis years 3 years" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Published 🟢
Metric
Benefits PV (risk-adjusted)$101,696,791
Costs PV (risk-adjusted)$22,983,076
NPV$78,713,715
ROI342%
Payback<6 months
\n", + "
" + ], + "text/plain": [ + " Published 🟢\n", + "Metric \n", + "Benefits PV (risk-adjusted) $101,696,791\n", + "Costs PV (risk-adjusted) $22,983,076\n", + "NPV $78,713,715\n", + "ROI 342%\n", + "Payback <6 months" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "engine reproduction Δ vs PDF (Forrester table rounding): benefits -223.45 · costs -0.22 · npv -223.22\n" + ] + } + ], + "source": [ + "# ── Composite assumptions & published financial summary (🟢) ─────────\n", + "composite = compute_summary(BENEFITS_VERBATIM, COSTS_VERBATIM,\n", + " PUBLISHED[\"discount_rate\"])\n", + "\n", + "_fmt = {\n", + " \"agents_fte\": \"{:,}\", \"supervisors_fte\": \"{:,}\",\n", + " \"annual_contacts_y1\": \"{:,}\", \"growth_rate\": \"{:.0%}\",\n", + " \"call_share\": \"{:.0%}\", \"aht_legacy_minutes\": \"{} min\",\n", + " \"agent_salary\": \"${:,}\", \"supervisor_salary\": \"${:,}\",\n", + " \"discount_rate\": \"{:.0%}\", \"analysis_years\": \"{} years\",\n", + "}\n", + "assumptions_df = pd.DataFrame(\n", + " [{\"Assumption\": k.replace(\"_\", \" \"), \"Value 🟢\": _fmt[k].format(v)}\n", + " for k, v in ASSUMPTIONS.items()])\n", + "display(assumptions_df.set_index(\"Assumption\"))\n", + "\n", + "published_df = pd.DataFrame([\n", + " {\"Metric\": \"Benefits PV (risk-adjusted)\", \"Published 🟢\": f\"${PUBLISHED['benefits_pv']:,}\"},\n", + " {\"Metric\": \"Costs PV (risk-adjusted)\", \"Published 🟢\": f\"${PUBLISHED['costs_pv']:,}\"},\n", + " {\"Metric\": \"NPV\", \"Published 🟢\": f\"${PUBLISHED['npv']:,}\"},\n", + " {\"Metric\": \"ROI\", \"Published 🟢\": f\"{PUBLISHED['roi_pct']}%\"},\n", + " {\"Metric\": \"Payback\", \"Published 🟢\": \"<6 months\"},\n", + "])\n", + "display(published_df.set_index(\"Metric\"))\n", + "\n", + "backstage(f\"engine reproduction Δ vs PDF (Forrester table rounding): \"\n", + " f\"benefits {composite['benefits_pv'] - PUBLISHED['benefits_pv']:+,.2f} · \"\n", + " f\"costs {composite['costs_pv'] - PUBLISHED['costs_pv']:+,.2f} · \"\n", + " f\"npv {composite['npv'] - PUBLISHED['npv']:+,.2f}\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "cell-5", + "metadata": {}, + "source": [ + "\n", + "## 2 · Client inputs (overlay 🟡)\n", + "\n", + "The overlay is a **first-order linear rescale** of Forrester's composite —\n", + "it answers *\"what does the composite look like at your size?\"*, not *\"what\n", + "is your TEI?\"*. Each published row scales with the driver that dominates\n", + "its derivation in the PDF; project-based costs stay fixed. The client\n", + "growth rate re-bases the composite's Y1→Y3 trajectory (which embeds 30%\n", + "YoY).\n", + "\n", + "| Published row | Scales with | Confidence |\n", + "|---|---|---|\n", + "| AI-driven contact resolution efficiency | contacts | 🟡 |\n", + "| AI-powered content & sentiment analysis | contacts | 🟡 |\n", + "| AI-enabled forecasting, scheduling & supervision | agents | 🟡 |\n", + "| Data-driven profit lift | contacts | 🔴 proxy — revenue-driven in the PDF |\n", + "| Legacy solution cost savings | agents | 🟡 |\n", + "| Amazon Connect usage | contacts | 🟡 |\n", + "| Implementation & migration | fixed | 🟡 project-based |\n", + "| Ongoing management | fixed | 🟡 |\n", + "\n", + "*Change any input in the sidebar — every table, figure and KPI below\n", + "recomputes. The assertions in §7 hold at any setting.*\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "cell-6", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-09T18:15:42.213716Z", + "iopub.status.busy": "2026-07-09T18:15:42.213491Z", + "iopub.status.idle": "2026-07-09T18:15:42.227389Z", + "shell.execute_reply": "2026-07-09T18:15:42.226903Z" + } + }, + "outputs": [ + { + "data": { + "application/mercury+json": { + "model_id": "ace9c00dc3a84babb5b29ae61e2be62c", + "position": "sidebar", + "widget": "NumberInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "ace9c00dc3a84babb5b29ae61e2be62c", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "01c230d30aed4aa58c5a005c44e65f84", + "position": "sidebar", + "widget": "NumberInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "01c230d30aed4aa58c5a005c44e65f84", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "d4ccace17e824e4a85c55ff6ef95afb0", + "position": "sidebar", + "widget": "NumberInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "d4ccace17e824e4a85c55ff6ef95afb0", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "eb0056195e9b444dbb8ef3c08e744446", + "position": "sidebar", + "widget": "SelectWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "eb0056195e9b444dbb8ef3c08e744446", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "b1e82327c29a44a8a4a45e8100b3d857", + "position": "sidebar", + "widget": "SelectWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "b1e82327c29a44a8a4a45e8100b3d857", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# ── Client drivers (Mercury sidebar — widgets only, NO other output) ─\n", + "# NB: Mercury re-executes only cells BELOW a changed widget's cell, so\n", + "# this cell constructs widgets ONLY — .value is read downstream.\n", + "_agents_w = mr.NumberInput(label=\"Contact-center agents (FTE) — composite 2,000\",\n", + " value=2_000, min=50, max=50_000, step=50)\n", + "_contacts_w = mr.NumberInput(label=\"Annual contacts, year 1 — composite 20M\",\n", + " value=20_000_000, min=100_000, max=500_000_000,\n", + " step=1_000_000)\n", + "_growth_w = mr.NumberInput(label=\"Contact growth (%/yr) — composite 30\",\n", + " value=30, min=0, max=100, step=5)\n", + "_discount_w = mr.Select(label=\"Discount rate\", value=\"10% (Forrester)\",\n", + " choices=[\"8%\", \"10% (Forrester)\", \"12%\"])\n", + "_scenario_w = mr.Select(label=\"Scenario\", value=\"moderate\",\n", + " choices=[\"conservative\", \"moderate\", \"aggressive\"])\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "cell-7", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-09T18:15:42.229494Z", + "iopub.status.busy": "2026-07-09T18:15:42.229335Z", + "iopub.status.idle": "2026-07-09T18:15:42.234902Z", + "shell.execute_reply": "2026-07-09T18:15:42.234410Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Client frame: 2,000 agents · 20M contacts (+30%/yr) · moderate scenario → NPV $78.7M · ROI 342% · payback 0.7 months (~Jan 2026)\n", + "scale factors — agents 1.00× · contacts 1.00× · growth re-base Y3 1.000×\n" + ] + } + ], + "source": [ + "# ── Client overlay state (re-runs on any change to the widgets above) ─\n", + "AGENTS_FTE = int(_agents_w.value)\n", + "CONTACTS_Y1 = int(_contacts_w.value)\n", + "GROWTH_RATE = float(_growth_w.value) / 100 # widget holds a % integer\n", + "DISCOUNT_RATE = {\"8%\": 0.08, \"10% (Forrester)\": 0.10,\n", + " \"12%\": 0.12}[str(_discount_w.value)]\n", + "SCENARIO = str(_scenario_w.value)\n", + "\n", + "DRIVERS = ClientDrivers(agents_fte=AGENTS_FTE, annual_contacts_y1=CONTACTS_Y1,\n", + " growth_rate=GROWTH_RATE, discount_rate=DISCOUNT_RATE)\n", + "overlay_benefits, overlay_costs = overlay_rows(DRIVERS)\n", + "client_benefits = apply_scenario(overlay_benefits, SCENARIO)\n", + "client_costs = apply_scenario(overlay_costs, SCENARIO)\n", + "client = compute_summary(client_benefits, client_costs, DISCOUNT_RATE)\n", + "\n", + "_at_default = (DRIVERS == COMPOSITE and SCENARIO == \"moderate\")\n", + "\n", + "print(f\"Client frame: {AGENTS_FTE:,} agents · {CONTACTS_Y1 / 1e6:,.0f}M contacts \"\n", + " f\"(+{GROWTH_RATE:.0%}/yr) · {SCENARIO} scenario → NPV {money(client['npv'])} · \"\n", + " f\"ROI {client['roi_pct']:.0f}% · payback {client['payback_label']}\")\n", + "backstage(f\"scale factors — agents {AGENTS_FTE / ASSUMPTIONS['agents_fte']:.2f}× · \"\n", + " f\"contacts {CONTACTS_Y1 / ASSUMPTIONS['annual_contacts_y1']:.2f}× · \"\n", + " f\"growth re-base Y3 {growth_multiplier(3, GROWTH_RATE):.3f}×\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "cell-8", + "metadata": {}, + "source": [ + "\n", + "## 3 · Benefits\n", + "\n", + "Five benefit streams (Forrester refs At–Et), risk-adjusted down 15–20%.\n", + "Half the total is AI-driven contact-resolution efficiency; all five phase\n", + "up with the growth trajectory across the window.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "cell-9", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-09T18:15:42.236799Z", + "iopub.status.busy": "2026-07-09T18:15:42.236657Z", + "iopub.status.idle": "2026-07-09T18:15:42.247373Z", + "shell.execute_reply": "2026-07-09T18:15:42.246802Z" + } + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
DriverRisk adj2026202720283-yr RAPV
Benefit
AI-driven contact resolution efficiencycontacts-15%11,824,38420,342,60832,128,09664,295,08851,699,827
AI-powered content and sentiment analysis savingscontacts-15%3,898,6274,554,6505,347,92813,801,20511,326,358
AI-enabled forecasting, agent scheduling, and supervisionagents-15%5,653,9287,763,69610,532,95523,950,57919,469,777
Data-driven profit lift with increased conversioncontacts-20%960,0001,248,0001,622,4003,830,4003,123,065
Legacy solution cost savingsagents-20%4,942,0806,424,7048,352,11519,718,89916,077,540
TOTAL27,279,01940,333,65857,983,494125,596,172101,696,568
\n", + "
" + ], + "text/plain": [ + " Driver Risk adj \\\n", + "Benefit \n", + "AI-driven contact resolution efficiency contacts -15% \n", + "AI-powered content and sentiment analysis savings contacts -15% \n", + "AI-enabled forecasting, agent scheduling, and s... agents -15% \n", + "Data-driven profit lift with increased conversion contacts -20% \n", + "Legacy solution cost savings agents -20% \n", + "TOTAL \n", + "\n", + " 2026 2027 \\\n", + "Benefit \n", + "AI-driven contact resolution efficiency 11,824,384 20,342,608 \n", + "AI-powered content and sentiment analysis savings 3,898,627 4,554,650 \n", + "AI-enabled forecasting, agent scheduling, and s... 5,653,928 7,763,696 \n", + "Data-driven profit lift with increased conversion 960,000 1,248,000 \n", + "Legacy solution cost savings 4,942,080 6,424,704 \n", + "TOTAL 27,279,019 40,333,658 \n", + "\n", + " 2028 3-yr RA \\\n", + "Benefit \n", + "AI-driven contact resolution efficiency 32,128,096 64,295,088 \n", + "AI-powered content and sentiment analysis savings 5,347,928 13,801,205 \n", + "AI-enabled forecasting, agent scheduling, and s... 10,532,955 23,950,579 \n", + "Data-driven profit lift with increased conversion 1,622,400 3,830,400 \n", + "Legacy solution cost savings 8,352,115 19,718,899 \n", + "TOTAL 57,983,494 125,596,172 \n", + "\n", + " PV \n", + "Benefit \n", + "AI-driven contact resolution efficiency 51,699,827 \n", + "AI-powered content and sentiment analysis savings 11,326,358 \n", + "AI-enabled forecasting, agent scheduling, and s... 19,469,777 \n", + "Data-driven profit lift with increased conversion 3,123,065 \n", + "Legacy solution cost savings 16,077,540 \n", + "TOTAL 101,696,568 " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# ── Benefits table — client overlay, risk-adjusted ───────────────────\n", + "_ben_rows = client[\"rows\"][\"benefits\"]\n", + "benefits_df = pd.DataFrame([{\n", + " \"Benefit\": r[\"label\"],\n", + " \"Driver\": BENEFIT_DRIVERS[r[\"field_key\"]],\n", + " \"Risk adj\": f\"-{r['risk_adjustment']:.0%}\",\n", + " **{str(y): r[\"ra_by_year\"][y] for y in YEARS},\n", + " \"3-yr RA\": r[\"three_yr_ra\"],\n", + " \"PV\": r[\"pv\"],\n", + "} for r in _ben_rows]).set_index(\"Benefit\")\n", + "benefits_df.loc[\"TOTAL\"] = [\"\", \"\"] + [client[\"benefits_by_year\"][y] for y in YEARS] \\\n", + " + [sum(r[\"three_yr_ra\"] for r in _ben_rows), client[\"benefits_pv\"]]\n", + "if not _at_default: # published composite beside the overlay for reference\n", + " benefits_df[\"Composite PV 🟢\"] = \\\n", + " [r[\"pv\"] for r in composite[\"rows\"][\"benefits\"]] + [composite[\"benefits_pv\"]]\n", + "display(benefits_df)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "cell-10", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-09T18:15:42.249508Z", + "iopub.status.busy": "2026-07-09T18:15:42.249351Z", + "iopub.status.idle": "2026-07-09T18:15:43.253962Z", + "shell.execute_reply": "2026-07-09T18:15:43.253381Z" + } + }, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "hovertemplate": "%{fullData.name}: %{y:$,.0f}", + "marker": { + "color": "#2a78d6", + "line": { + "color": "#fcfcfb", + "width": 2 + } + }, + "name": "AI-driven contact resolution efficiency", + "type": "bar", + "x": [ + "2026", + "2027", + "2028" + ], + "y": [ + 11824384.0, + 20342608.0, + 32128096.0 + ] + }, + { + "hovertemplate": "%{fullData.name}: %{y:$,.0f}", + "marker": { + "color": "#1baf7a", + "line": { + "color": "#fcfcfb", + "width": 2 + } + }, + "name": "AI-powered content and sentiment analysis savings", + "type": "bar", + "x": [ + "2026", + "2027", + "2028" + ], + "y": [ + 3898627.0, + 4554650.2, + 5347928.0 + ] + }, + { + "hovertemplate": "%{fullData.name}: %{y:$,.0f}", + "marker": { + "color": "#4a3aa7", + "line": { + "color": "#fcfcfb", + "width": 2 + } + }, + "name": "AI-enabled forecasting, agent scheduling, and supervision", + "type": "bar", + "x": [ + "2026", + "2027", + "2028" + ], + "y": [ + 5653928.0, + 7763696.0, + 10532955.2 + ] + }, + { + "hovertemplate": "%{fullData.name}: %{y:$,.0f}", + "marker": { + "color": "#eda100", + "line": { + "color": "#fcfcfb", + "width": 2 + } + }, + "name": "Data-driven profit lift with increased conversion", + "type": "bar", + "x": [ + "2026", + "2027", + "2028" + ], + "y": [ + 960000.0, + 1248000.0, + 1622400.0 + ] + }, + { + "hovertemplate": "%{fullData.name}: %{y:$,.0f}", + "marker": { + "color": "#008300", + "line": { + "color": "#fcfcfb", + "width": 2 + } + }, + "name": "Legacy solution cost savings", + "type": "bar", + "x": [ + "2026", + "2027", + "2028" + ], + "y": [ + 4942080.0, + 6424704.0, + 8352115.2 + ] + } + ], + "layout": { + "bargap": 0.45, + "barmode": "stack", + "font": { + "color": "#52514e", + "family": "system-ui, -apple-system, \"Segoe UI\", sans-serif", + "size": 12 + }, + "height": 480, + "hovermode": "x unified", + "legend": { + "font": { + "color": "#52514e", + "size": 11 + }, + "orientation": "h", + "x": 0, + "y": -0.1, + "yanchor": "top" + }, + "margin": { + "b": 80, + "l": 70, + "r": 30, + "t": 70 + }, + "paper_bgcolor": "#fcfcfb", + "plot_bgcolor": "#fcfcfb", + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermap": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermap" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "#E5ECF6", + "showlakes": true, + "showland": true, + "subunitcolor": "white" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + } + } + }, + "title": { + "font": { + "color": "#0b0b0b", + "size": 16 + }, + "text": "Benefits by year (risk-adjusted)
stacked by benefit stream — client overlay", + "x": 0.02, + "xanchor": "left" + }, + "xaxis": { + "linecolor": "#c3c2b7", + "showgrid": false, + "tickfont": { + "color": "#898781" + }, + "type": "category" + }, + "yaxis": { + "gridcolor": "#e1e0d9", + "tickfont": { + "color": "#898781" + }, + "tickformat": "$~s", + "zerolinecolor": "#c3c2b7", + "zerolinewidth": 1.5 + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig = go.Figure()\n", + "_x = [str(y) for y in YEARS]\n", + "for r in client[\"rows\"][\"benefits\"]:\n", + " fig.add_trace(bar(_x, [r[\"ra_by_year\"][y] for y in YEARS],\n", + " r[\"label\"], BENEFIT_COLOR[r[\"field_key\"]]))\n", + "if not _at_default: # composite yearly total as de-emphasized context\n", + " fig.add_trace(cum_line(_x, [composite[\"benefits_by_year\"][y] for y in YEARS],\n", + " \"Forrester composite total\", CONTEXT, dash=\"dot\"))\n", + "fig.update_layout(barmode=\"stack\")\n", + "tei_layout(fig, \"Benefits by year (risk-adjusted)\",\n", + " subtitle=\"stacked by benefit stream — client overlay\", height=480)\n", + "fig.show()\n" + ] + }, + { + "cell_type": "markdown", + "id": "cell-11", + "metadata": {}, + "source": [ + "\n", + "## 4 · Costs\n", + "\n", + "Three cost lines, risk-adjusted **up** 5–15%. Consumption-priced Amazon\n", + "Connect usage is ~90% of costs PV — the cost side scales with contact\n", + "volume, not seats. Implementation carries the only time-0 outlay\n", + "($1.09M nominal → $1.20M risk-adjusted, undiscounted in the *Initial*\n", + "column).\n" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "cell-12", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-09T18:15:43.257431Z", + "iopub.status.busy": "2026-07-09T18:15:43.257260Z", + "iopub.status.idle": "2026-07-09T18:15:43.268554Z", + "shell.execute_reply": "2026-07-09T18:15:43.267833Z" + } + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
DriverRisk adjInitial202620272028PV
Cost
Amazon Connect usage costcontacts+5%06,779,2708,348,72210,324,60920,819,775
Implementation and migration costfixed+10%1,196,250207,166207,16601,555,795
Ongoing managementfixed+15%0294,630215,280215,280607,506
TOTAL1,196,2507,281,0678,771,16810,539,88922,983,076
\n", + "
" + ], + "text/plain": [ + " Driver Risk adj Initial 2026 \\\n", + "Cost \n", + "Amazon Connect usage cost contacts +5% 0 6,779,270 \n", + "Implementation and migration cost fixed +10% 1,196,250 207,166 \n", + "Ongoing management fixed +15% 0 294,630 \n", + "TOTAL 1,196,250 7,281,067 \n", + "\n", + " 2027 2028 PV \n", + "Cost \n", + "Amazon Connect usage cost 8,348,722 10,324,609 20,819,775 \n", + "Implementation and migration cost 207,166 0 1,555,795 \n", + "Ongoing management 215,280 215,280 607,506 \n", + "TOTAL 8,771,168 10,539,889 22,983,076 " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# ── Costs table — client overlay, risk-adjusted ──────────────────────\n", + "_cost_rows = client[\"rows\"][\"costs\"]\n", + "costs_df = pd.DataFrame([{\n", + " \"Cost\": r[\"label\"],\n", + " \"Driver\": COST_DRIVERS[r[\"field_key\"]],\n", + " \"Risk adj\": f\"+{r['risk_adjustment']:.0%}\",\n", + " \"Initial\": r[\"initial_ra\"],\n", + " **{str(y): r[\"ra_by_year\"][y] for y in YEARS},\n", + " \"PV\": r[\"pv\"],\n", + "} for r in _cost_rows]).set_index(\"Cost\")\n", + "costs_df.loc[\"TOTAL\"] = [\"\", \"\", client[\"initial_costs\"]] \\\n", + " + [client[\"costs_by_year\"][y] for y in YEARS] + [client[\"costs_pv\"]]\n", + "if not _at_default:\n", + " costs_df[\"Composite PV 🟢\"] = \\\n", + " [r[\"pv\"] for r in composite[\"rows\"][\"costs\"]] + [composite[\"costs_pv\"]]\n", + "display(costs_df)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "cell-13", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-09T18:15:43.270331Z", + "iopub.status.busy": "2026-07-09T18:15:43.270194Z", + "iopub.status.idle": "2026-07-09T18:15:43.287522Z", + "shell.execute_reply": "2026-07-09T18:15:43.286918Z" + } + }, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "hovertemplate": "%{fullData.name}: %{y:$,.0f}", + "marker": { + "color": "#e34948", + "line": { + "color": "#fcfcfb", + "width": 2 + } + }, + "name": "Amazon Connect usage cost", + "type": "bar", + "x": [ + "Initial", + "2026", + "2027", + "2028" + ], + "y": [ + 0.0, + 6779270.4, + 8348722.2, + 10324609.05 + ] + }, + { + "hovertemplate": "%{fullData.name}: %{y:$,.0f}", + "marker": { + "color": "#eda100", + "line": { + "color": "#fcfcfb", + "width": 2 + } + }, + "name": "Implementation and migration cost", + "type": "bar", + "x": [ + "Initial", + "2026", + "2027", + "2028" + ], + "y": [ + 1196250.0, + 207166.30000000002, + 207166.30000000002, + 0.0 + ] + }, + { + "hovertemplate": "%{fullData.name}: %{y:$,.0f}", + "marker": { + "color": "#4a3aa7", + "line": { + "color": "#fcfcfb", + "width": 2 + } + }, + "name": "Ongoing management", + "type": "bar", + "x": [ + "Initial", + "2026", + "2027", + "2028" + ], + "y": [ + 0.0, + 294630.0, + 215279.99999999997, + 215279.99999999997 + ] + } + ], + "layout": { + "bargap": 0.45, + "barmode": "stack", + "font": { + "color": "#52514e", + "family": "system-ui, -apple-system, \"Segoe UI\", sans-serif", + "size": 12 + }, + "height": 460, + "hovermode": "x unified", + "legend": { + "font": { + "color": "#52514e", + "size": 11 + }, + "orientation": "h", + "x": 0, + "y": -0.1, + "yanchor": "top" + }, + "margin": { + "b": 80, + "l": 70, + "r": 30, + "t": 70 + }, + "paper_bgcolor": "#fcfcfb", + "plot_bgcolor": "#fcfcfb", + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermap": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermap" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "#E5ECF6", + "showlakes": true, + "showland": true, + "subunitcolor": "white" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + } + } + }, + "title": { + "font": { + "color": "#0b0b0b", + "size": 16 + }, + "text": "Costs by year (risk-adjusted)
Initial = undiscounted time-0 outlay (implementation)", + "x": 0.02, + "xanchor": "left" + }, + "xaxis": { + "linecolor": "#c3c2b7", + "showgrid": false, + "tickfont": { + "color": "#898781" + }, + "type": "category" + }, + "yaxis": { + "gridcolor": "#e1e0d9", + "tickfont": { + "color": "#898781" + }, + "tickformat": "$~s", + "zerolinecolor": "#c3c2b7", + "zerolinewidth": 1.5 + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig = go.Figure()\n", + "for r in client[\"rows\"][\"costs\"]:\n", + " fig.add_trace(bar(X_LABELS,\n", + " [r[\"initial_ra\"]] + [r[\"ra_by_year\"][y] for y in YEARS],\n", + " r[\"label\"], COST_COLOR[r[\"field_key\"]]))\n", + "fig.update_layout(barmode=\"stack\")\n", + "tei_layout(fig, \"Costs by year (risk-adjusted)\",\n", + " subtitle=\"Initial = undiscounted time-0 outlay (implementation)\")\n", + "fig.show()\n" + ] + }, + { + "cell_type": "markdown", + "id": "cell-14", + "metadata": {}, + "source": [ + "\n", + "## 5 · Business case\n", + "\n", + "The left column is Forrester's published Financial Summary, verbatim. The\n", + "right column is the client overlay at the sidebar's drivers. At the\n", + "defaults the engine reproduces the published totals to within the PDF's\n", + "own table rounding — the gate in §7 enforces it. Payback lands under a\n", + "month because the composite's $1.2M initial outlay is small against\n", + "~$20M of year-1 net benefit; Forrester publishes it simply as\n", + "\"<6 months\", and sub-month precision is a full-year-aggregation artifact,\n", + "not a forecast.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "cell-15", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-09T18:15:43.291216Z", + "iopub.status.busy": "2026-07-09T18:15:43.291061Z", + "iopub.status.idle": "2026-07-09T18:15:43.298783Z", + "shell.execute_reply": "2026-07-09T18:15:43.298192Z" + } + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Forrester composite (published 🟢)Client overlay (🟡)
Benefits PV$101,696,791$101,696,568
Costs PV$22,983,076$22,983,076
NPV$78,713,715$78,713,492
ROI342%342%
Payback<6 months0.7 months (~Jan 2026)
Discount rate10%10%
\n", + "
" + ], + "text/plain": [ + " Forrester composite (published 🟢) Client overlay (🟡)\n", + "Benefits PV $101,696,791 $101,696,568\n", + "Costs PV $22,983,076 $22,983,076\n", + "NPV $78,713,715 $78,713,492\n", + "ROI 342% 342%\n", + "Payback <6 months 0.7 months (~Jan 2026)\n", + "Discount rate 10% 10%" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "engine composite NPV $78,713,491.78 vs published $78,713,715 (Δ -223.22)\n" + ] + } + ], + "source": [ + "# ── KPIs — published composite beside the client overlay ─────────────\n", + "kpis_fmt = pd.DataFrame({\n", + " \"Forrester composite (published 🟢)\": {\n", + " \"Benefits PV\": f\"${PUBLISHED['benefits_pv']:,}\",\n", + " \"Costs PV\": f\"${PUBLISHED['costs_pv']:,}\",\n", + " \"NPV\": f\"${PUBLISHED['npv']:,}\",\n", + " \"ROI\": f\"{PUBLISHED['roi_pct']}%\",\n", + " \"Payback\": \"<6 months\",\n", + " \"Discount rate\": f\"{PUBLISHED['discount_rate']:.0%}\",\n", + " },\n", + " \"Client overlay (🟡)\": {\n", + " \"Benefits PV\": f\"${client['benefits_pv']:,.0f}\",\n", + " \"Costs PV\": f\"${client['costs_pv']:,.0f}\",\n", + " \"NPV\": f\"${client['npv']:,.0f}\",\n", + " \"ROI\": f\"{client['roi_pct']:.0f}%\",\n", + " \"Payback\": client[\"payback_label\"],\n", + " \"Discount rate\": f\"{DISCOUNT_RATE:.0%}\",\n", + " },\n", + "})\n", + "display(kpis_fmt)\n", + "backstage(f\"engine composite NPV ${composite['npv']:,.2f} vs published \"\n", + " f\"${PUBLISHED['npv']:,} (Δ {composite['npv'] - PUBLISHED['npv']:+,.2f})\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "cell-16", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-09T18:15:43.302934Z", + "iopub.status.busy": "2026-07-09T18:15:43.302786Z", + "iopub.status.idle": "2026-07-09T18:15:43.324633Z", + "shell.execute_reply": "2026-07-09T18:15:43.324079Z" + } + }, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "hovertemplate": "%{fullData.name}: %{y:$,.0f}", + "marker": { + "color": "#1baf7a", + "line": { + "color": "#fcfcfb", + "width": 2 + } + }, + "name": "Benefits (risk-adjusted)", + "type": "bar", + "x": [ + "Initial", + "2026", + "2027", + "2028" + ], + "y": [ + 0, + 27279019.0, + 40333658.2, + 57983494.400000006 + ] + }, + { + "hovertemplate": "%{fullData.name}: %{y:$,.0f}", + "marker": { + "color": "#e34948", + "line": { + "color": "#fcfcfb", + "width": 2 + } + }, + "name": "Costs (risk-adjusted)", + "type": "bar", + "x": [ + "Initial", + "2026", + "2027", + "2028" + ], + "y": [ + -1196250.0, + -7281066.7, + -8771168.5, + -10539889.05 + ] + }, + { + "hovertemplate": "%{fullData.name}: %{y:$,.0f}", + "line": { + "color": "#52514e", + "width": 2 + }, + "marker": { + "line": { + "color": "#fcfcfb", + "width": 2 + }, + "size": 8 + }, + "mode": "lines+markers", + "name": "Cumulative net", + "type": "scatter", + "x": [ + "Initial", + "2026", + "2027", + "2028" + ], + "y": [ + -1196250.0, + 18801702.3, + 50364192.0, + 97807797.35000001 + ] + } + ], + "layout": { + "annotations": [ + { + "align": "left", + "bgcolor": "#fcfcfb", + "bordercolor": "#e1e0d9", + "borderwidth": 1, + "font": { + "color": "#0b0b0b", + "size": 12 + }, + "showarrow": false, + "text": "NPV $78.7M · ROI 342% · payback 0.7 months (~Jan 2026)", + "x": 0.02, + "xref": "paper", + "y": 0.98, + "yref": "paper" + } + ], + "bargap": 0.45, + "barmode": "relative", + "font": { + "color": "#52514e", + "family": "system-ui, -apple-system, \"Segoe UI\", sans-serif", + "size": 12 + }, + "height": 460, + "hovermode": "x unified", + "legend": { + "font": { + "color": "#52514e", + "size": 11 + }, + "orientation": "h", + "x": 0, + "y": -0.1, + "yanchor": "top" + }, + "margin": { + "b": 80, + "l": 70, + "r": 30, + "t": 70 + }, + "paper_bgcolor": "#fcfcfb", + "plot_bgcolor": "#fcfcfb", + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermap": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermap" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "#E5ECF6", + "showlakes": true, + "showland": true, + "subunitcolor": "white" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + } + } + }, + "title": { + "font": { + "color": "#0b0b0b", + "size": 16 + }, + "text": "Cash flow — risk-adjusted
benefits up, costs down; initial outlay undiscounted at time 0", + "x": 0.02, + "xanchor": "left" + }, + "xaxis": { + "linecolor": "#c3c2b7", + "showgrid": false, + "tickfont": { + "color": "#898781" + }, + "type": "category" + }, + "yaxis": { + "gridcolor": "#e1e0d9", + "tickfont": { + "color": "#898781" + }, + "tickformat": "$~s", + "zerolinecolor": "#c3c2b7", + "zerolinewidth": 1.5 + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# ── Cash flow — mirrors the PDF's Cash Flow Chart (p.25) ─────────────\n", + "fig = go.Figure()\n", + "fig.add_trace(bar(X_LABELS,\n", + " [0] + [client[\"benefits_by_year\"][y] for y in YEARS],\n", + " \"Benefits (risk-adjusted)\", BEN_TOTAL))\n", + "fig.add_trace(bar(X_LABELS,\n", + " [-client[\"initial_costs\"]] + [-client[\"costs_by_year\"][y] for y in YEARS],\n", + " \"Costs (risk-adjusted)\", COST_TOTAL))\n", + "fig.add_trace(cum_line(X_LABELS,\n", + " [-client[\"initial_costs\"]] + [client[\"cumulative_net_by_year\"][y] for y in YEARS],\n", + " \"Cumulative net\"))\n", + "fig.update_layout(barmode=\"relative\")\n", + "fig.add_annotation(\n", + " x=0.02, y=0.98, xref=\"paper\", yref=\"paper\", showarrow=False, align=\"left\",\n", + " text=(f\"NPV {html_money(client['npv'])} · ROI {client['roi_pct']:.0f}% · \"\n", + " f\"payback {client['payback_label']}\"),\n", + " font=dict(size=12, color=INK), bgcolor=SURFACE,\n", + " bordercolor=GRID, borderwidth=1)\n", + "tei_layout(fig, \"Cash flow — risk-adjusted\",\n", + " subtitle=\"benefits up, costs down; initial outlay undiscounted at time 0\")\n", + "fig.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "cell-17", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-09T18:15:43.329401Z", + "iopub.status.busy": "2026-07-09T18:15:43.329247Z", + "iopub.status.idle": "2026-07-09T18:15:43.348656Z", + "shell.execute_reply": "2026-07-09T18:15:43.348131Z" + } + }, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "connector": { + "line": { + "color": "#e1e0d9" + } + }, + "decreasing": { + "marker": { + "color": "#e34948" + } + }, + "increasing": { + "marker": { + "color": "#1baf7a" + } + }, + "measure": [ + "relative", + "relative", + "total" + ], + "text": [ + "$101.7M", + "-$23.0M", + "$78.7M" + ], + "textposition": "outside", + "totals": { + "marker": { + "color": "#2a78d6" + } + }, + "type": "waterfall", + "x": [ + "Benefits PV", + "Costs PV", + "NPV" + ], + "y": [ + 101696567.55071373, + -22983075.775356874, + 0 + ] + } + ], + "layout": { + "bargap": 0.45, + "font": { + "color": "#52514e", + "family": "system-ui, -apple-system, \"Segoe UI\", sans-serif", + "size": 12 + }, + "height": 420, + "hovermode": "x unified", + "legend": { + "font": { + "color": "#52514e", + "size": 11 + }, + "orientation": "h", + "x": 0, + "y": -0.1, + "yanchor": "top" + }, + "margin": { + "b": 80, + "l": 70, + "r": 30, + "t": 70 + }, + "paper_bgcolor": "#fcfcfb", + "plot_bgcolor": "#fcfcfb", + "showlegend": false, + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermap": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermap" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "#E5ECF6", + "showlakes": true, + "showland": true, + "subunitcolor": "white" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + } + } + }, + "title": { + "font": { + "color": "#0b0b0b", + "size": 16 + }, + "text": "Present value walk — client overlay
discounted at 10%, 3 years", + "x": 0.02, + "xanchor": "left" + }, + "xaxis": { + "linecolor": "#c3c2b7", + "showgrid": false, + "tickfont": { + "color": "#898781" + }, + "type": "category" + }, + "yaxis": { + "gridcolor": "#e1e0d9", + "tickfont": { + "color": "#898781" + }, + "tickformat": "$~s", + "zerolinecolor": "#c3c2b7", + "zerolinewidth": 1.5 + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig = go.Figure(go.Waterfall(\n", + " x=[\"Benefits PV\", \"Costs PV\", \"NPV\"],\n", + " measure=[\"relative\", \"relative\", \"total\"],\n", + " y=[client[\"benefits_pv\"], -client[\"costs_pv\"], 0],\n", + " text=[html_money(client[\"benefits_pv\"]), html_money(-client[\"costs_pv\"]),\n", + " html_money(client[\"npv\"])],\n", + " textposition=\"outside\",\n", + " connector=dict(line=dict(color=GRID)),\n", + " increasing=dict(marker=dict(color=BEN_TOTAL)),\n", + " decreasing=dict(marker=dict(color=COST_TOTAL)),\n", + " totals=dict(marker=dict(color=NPV_COLOR)),\n", + "))\n", + "fig.update_layout(showlegend=False)\n", + "tei_layout(fig, \"Present value walk — client overlay\",\n", + " subtitle=f\"discounted at {'{:.0%}'.format(DISCOUNT_RATE)}, 3 years\",\n", + " height=420)\n", + "fig.show()\n" + ] + }, + { + "cell_type": "markdown", + "id": "cell-18", + "metadata": {}, + "source": [ + "\n", + "## 6 · Scenarios (🟡)\n", + "\n", + "Scenarios stress the overlay on two levers: **adoption** scales every\n", + "nominal value (including the initial outlay), and **risk delta** widens or\n", + "narrows the TEI risk adjustments — added to benefit risk, subtracted from\n", + "cost risk, clamped at zero.\n", + "\n", + "One counterintuitive consequence, worth stating: the **conservative**\n", + "scenario *lowers* costs PV as well as benefits — 80% adoption shrinks the\n", + "consumption-priced usage cost, and the clamp caps how much extra padding\n", + "the risk delta can add back. The case direction is still conservative:\n", + "NPV and ROI both fall.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "cell-19", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-09T18:15:43.353547Z", + "iopub.status.busy": "2026-07-09T18:15:43.353383Z", + "iopub.status.idle": "2026-07-09T18:15:43.362921Z", + "shell.execute_reply": "2026-07-09T18:15:43.362320Z" + } + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
AdoptionRisk ΔBenefits PVCosts PVNPVROI %Payback (months)
Scenario
conservative80%+10%71,672,86817,437,91654,234,9513111
moderate100%+0%101,696,56822,983,07678,713,4923421
aggressive115%-5%123,911,70527,682,36996,229,3373481
\n", + "
" + ], + "text/plain": [ + " Adoption Risk Δ Benefits PV Costs PV NPV ROI % \\\n", + "Scenario \n", + "conservative 80% +10% 71,672,868 17,437,916 54,234,951 311 \n", + "moderate 100% +0% 101,696,568 22,983,076 78,713,492 342 \n", + "aggressive 115% -5% 123,911,705 27,682,369 96,229,337 348 \n", + "\n", + " Payback (months) \n", + "Scenario \n", + "conservative 1 \n", + "moderate 1 \n", + "aggressive 1 " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# ── Scenario sweep over the client overlay ───────────────────────────\n", + "scen_summaries = {\n", + " s: compute_summary(apply_scenario(overlay_benefits, s),\n", + " apply_scenario(overlay_costs, s), DISCOUNT_RATE)\n", + " for s in SCENARIOS\n", + "}\n", + "scen_df = pd.DataFrame([{\n", + " \"Scenario\": s,\n", + " \"Adoption\": f\"{SCENARIOS[s]['adoption']:.0%}\",\n", + " \"Risk Δ\": f\"{SCENARIOS[s]['risk_delta']:+.0%}\",\n", + " \"Benefits PV\": r[\"benefits_pv\"],\n", + " \"Costs PV\": r[\"costs_pv\"],\n", + " \"NPV\": r[\"npv\"],\n", + " \"ROI %\": round(r[\"roi_pct\"], 1),\n", + " \"Payback (months)\": round(r[\"payback_months\"], 2)\n", + " if r[\"payback_months\"] is not None else float(\"nan\"),\n", + "} for s, r in scen_summaries.items()]).set_index(\"Scenario\")\n", + "display(scen_df)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "cell-20", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-09T18:15:43.366882Z", + "iopub.status.busy": "2026-07-09T18:15:43.366731Z", + "iopub.status.idle": "2026-07-09T18:15:43.383646Z", + "shell.execute_reply": "2026-07-09T18:15:43.383094Z" + } + }, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "hovertemplate": "%{fullData.name}: %{y:$,.0f}", + "marker": { + "color": "#1baf7a", + "line": { + "color": "#fcfcfb", + "width": 2 + } + }, + "name": "Benefits PV", + "type": "bar", + "x": [ + "conservative", + "moderate", + "aggressive" + ], + "y": [ + 71672867.64838466, + 101696567.55071373, + 123911705.40270472 + ] + }, + { + "hovertemplate": "%{fullData.name}: %{y:$,.0f}", + "marker": { + "color": "#e34948", + "line": { + "color": "#fcfcfb", + "width": 2 + } + }, + "name": "Costs PV", + "type": "bar", + "x": [ + "conservative", + "moderate", + "aggressive" + ], + "y": [ + 17437916.33959429, + 22983075.775356874, + 27682368.613918103 + ] + }, + { + "hovertemplate": "%{fullData.name}: %{y:$,.0f}", + "marker": { + "color": "#2a78d6", + "line": { + "color": "#fcfcfb", + "width": 2 + } + }, + "name": "NPV", + "type": "bar", + "x": [ + "conservative", + "moderate", + "aggressive" + ], + "y": [ + 54234951.30879037, + 78713491.77535686, + 96229336.78878662 + ] + } + ], + "layout": { + "bargap": 0.45, + "barmode": "group", + "font": { + "color": "#52514e", + "family": "system-ui, -apple-system, \"Segoe UI\", sans-serif", + "size": 12 + }, + "height": 420, + "hovermode": "x unified", + "legend": { + "font": { + "color": "#52514e", + "size": 11 + }, + "orientation": "h", + "x": 0, + "y": -0.1, + "yanchor": "top" + }, + "margin": { + "b": 80, + "l": 70, + "r": 30, + "t": 70 + }, + "paper_bgcolor": "#fcfcfb", + "plot_bgcolor": "#fcfcfb", + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermap": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermap" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "#E5ECF6", + "showlakes": true, + "showland": true, + "subunitcolor": "white" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + } + } + }, + "title": { + "font": { + "color": "#0b0b0b", + "size": 16 + }, + "text": "Scenario comparison — client overlay
adoption × risk-delta stress on the same drivers", + "x": 0.02, + "xanchor": "left" + }, + "xaxis": { + "linecolor": "#c3c2b7", + "showgrid": false, + "tickfont": { + "color": "#898781" + }, + "type": "category" + }, + "yaxis": { + "gridcolor": "#e1e0d9", + "tickfont": { + "color": "#898781" + }, + "tickformat": "$~s", + "zerolinecolor": "#c3c2b7", + "zerolinewidth": 1.5 + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig = go.Figure()\n", + "_scen = list(scen_summaries)\n", + "for _name, _key, _color in [(\"Benefits PV\", \"benefits_pv\", BEN_TOTAL),\n", + " (\"Costs PV\", \"costs_pv\", COST_TOTAL),\n", + " (\"NPV\", \"npv\", NPV_COLOR)]:\n", + " fig.add_trace(bar(_scen, [scen_summaries[s][_key] for s in _scen],\n", + " _name, _color))\n", + "fig.update_layout(barmode=\"group\")\n", + "tei_layout(fig, \"Scenario comparison — client overlay\",\n", + " subtitle=\"adoption × risk-delta stress on the same drivers\",\n", + " height=420)\n", + "fig.show()\n" + ] + }, + { + "cell_type": "markdown", + "id": "cell-21", + "metadata": {}, + "source": [ + "\n", + "## 7 · Verification & assertions\n", + "\n", + "The gate re-derives the case from the engine and asserts: the verbatim\n", + "anchor is intact; the engine reproduces Forrester's published totals\n", + "within table rounding (±$1,000); the overlay is the identity at composite\n", + "scale; and the structural identities hold at **any** widget setting. It\n", + "must pass in a headless `nbconvert --execute` run — that is this study's\n", + "regression check.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "cell-22", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-09T18:15:43.387984Z", + "iopub.status.busy": "2026-07-09T18:15:43.387815Z", + "iopub.status.idle": "2026-07-09T18:15:43.399773Z", + "shell.execute_reply": "2026-07-09T18:15:43.399196Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "All assertions passed.\n", + " reproduction Δ vs PDF: benefits -223.45 · costs -0.22 · npv -223.22\n" + ] + } + ], + "source": [ + "def _approx(got, want, tol=0.5):\n", + " assert abs(got - want) <= tol, f\"got {got:,.2f}, want {want:,.2f}\"\n", + "\n", + "\n", + "# ── Anchor integrity — the verbatim record is intact (unconditional) ─\n", + "_approx(BENEFITS_VERBATIM[0][\"year_values\"][\"1\"], 13_911_040)\n", + "_approx(COSTS_VERBATIM[1][\"initial\"], 1_087_500)\n", + "assert ASSUMPTIONS[\"agents_fte\"] == 2_000\n", + "assert ASSUMPTIONS[\"annual_contacts_y1\"] == 20_000_000\n", + "assert (COMPOSITE.agents_fte, COMPOSITE.annual_contacts_y1) == (2_000, 20_000_000)\n", + "\n", + "# ── Published reproduction — engine defaults, explicit args ──────────\n", + "_c = compute_summary(BENEFITS_VERBATIM, COSTS_VERBATIM, 0.10)\n", + "_approx(_c[\"benefits_pv\"], PUBLISHED[\"benefits_pv\"], tol=1_000) # Δ −223.45 (PDF rounding)\n", + "_approx(_c[\"costs_pv\"], PUBLISHED[\"costs_pv\"], tol=1_000) # Δ −0.22\n", + "_approx(_c[\"npv\"], PUBLISHED[\"npv\"], tol=1_000) # Δ −223.22\n", + "assert round(_c[\"roi_pct\"]) == PUBLISHED[\"roi_pct\"] # 342.48 → 342\n", + "assert _c[\"payback_months\"] < PUBLISHED[\"payback_months_max\"] # \"<6 months\"\n", + "_approx(_c[\"payback_months\"], 0.72, tol=0.01)\n", + "_approx(_c[\"initial_costs\"], 1_196_250)\n", + "_approx(_c[\"benefits_by_year\"][2026], 27_279_019, tol=1)\n", + "_approx(_c[\"costs_by_year\"][2028], 10_539_889.05, tol=1)\n", + "\n", + "# ── Overlay identity + scaling behaviour (explicit args) ─────────────\n", + "_ob, _oc = overlay_rows(COMPOSITE)\n", + "_id = compute_summary(_ob, _oc, 0.10)\n", + "_approx(_id[\"benefits_pv\"], _c[\"benefits_pv\"], tol=0.01) # identity at composite\n", + "_hb, _ = overlay_rows(ClientDrivers(agents_fte=1_000))\n", + "_approx(next(r for r in _hb if r[\"field_key\"] == \"ai_forecasting_supervision\")\n", + " [\"year_values\"][\"1\"], 6_651_680 / 2) # agents-driven halves\n", + "_approx(next(r for r in _hb if r[\"field_key\"] == \"ai_contact_resolution\")\n", + " [\"year_values\"][\"1\"], 13_911_040) # contacts-driven unmoved\n", + "\n", + "# ── Scenario pin (explicit args) ─────────────────────────────────────\n", + "_s = compute_summary(apply_scenario(BENEFITS_VERBATIM, \"conservative\"),\n", + " apply_scenario(COSTS_VERBATIM, \"conservative\"), 0.10)\n", + "_approx(_s[\"npv\"], 54_234_951.31, tol=1)\n", + "\n", + "# ── Structural ties — hold at ANY widget state (unconditional) ───────\n", + "_approx(client[\"npv\"], client[\"benefits_pv\"] - client[\"costs_pv\"], tol=0.01)\n", + "_approx(client[\"roi_pct\"], client[\"npv\"] / client[\"costs_pv\"] * 100, tol=0.01)\n", + "for _y in YEARS:\n", + " _approx(client[\"net_by_year\"][_y],\n", + " client[\"benefits_by_year\"][_y] - client[\"costs_by_year\"][_y], tol=0.01)\n", + "_approx(client[\"cumulative_net_by_year\"][YEARS[-1]],\n", + " sum(client[\"net_by_year\"].values()) - client[\"initial_costs\"], tol=0.01)\n", + "_approx(sum(r[\"pv\"] for r in client[\"rows\"][\"benefits\"]), client[\"benefits_pv\"], tol=0.01)\n", + "_approx(sum(r[\"pv\"] for r in client[\"rows\"][\"costs\"]), client[\"costs_pv\"], tol=0.01)\n", + "\n", + "# ── Live state — only when the sidebar sits at the composite defaults ─\n", + "if _at_default:\n", + " _approx(client[\"benefits_pv\"], 101_696_567.55, tol=1) # engine-exact\n", + " _approx(client[\"npv\"], PUBLISHED[\"npv\"], tol=1_000)\n", + " _approx(client[\"payback_months\"], 0.72, tol=0.01)\n", + "\n", + "backstage(\"All assertions passed.\")\n", + "backstage(f\" reproduction Δ vs PDF: benefits \"\n", + " f\"{_c['benefits_pv'] - PUBLISHED['benefits_pv']:+,.2f} · \"\n", + " f\"costs {_c['costs_pv'] - PUBLISHED['costs_pv']:+,.2f} · \"\n", + " f\"npv {_c['npv'] - PUBLISHED['npv']:+,.2f}\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "cell-23", + "metadata": {}, + "source": [ + "\n", + "## 8 · Data appendix — for the machines\n", + "\n", + "Everything below renders **backstage only** (JupyterLab / nbconvert\n", + "exports): markdown tables plus one JSON block of model state. Carried in\n", + "the exports, this is the payload a downstream LLM — or, on the roadmap,\n", + "Athena as the study repository — consumes directly. On the Mercury stage\n", + "it stays hidden.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "cell-24", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-09T18:15:43.404067Z", + "iopub.status.busy": "2026-07-09T18:15:43.403921Z", + "iopub.status.idle": "2026-07-09T18:15:43.419260Z", + "shell.execute_reply": "2026-07-09T18:15:43.418439Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "#### Composite organization (verbatim assumptions 🟢)\n", + "\n", + "| Assumption | Value 🟢 |\n", + "|:-------------------|:-----------|\n", + "| agents fte | 2,000 |\n", + "| supervisors fte | 200 |\n", + "| annual contacts y1 | 20,000,000 |\n", + "| growth rate | 30% |\n", + "| call share | 75% |\n", + "| aht legacy minutes | 10 min |\n", + "| agent salary | $45,760 |\n", + "| supervisor salary | $55,800 |\n", + "| discount rate | 10% |\n", + "| analysis years | 3 years |\n", + "\n", + "#### Benefits — client overlay (risk-adjusted $)\n", + "\n", + "| Benefit | Driver | Risk adj | 2026 | 2027 | 2028 | 3-yr RA | PV |\n", + "|:----------------------------------------------------------|:---------|:-----------|-----------:|-----------:|-----------:|------------:|------------:|\n", + "| AI-driven contact resolution efficiency | contacts | -15% | 11,824,384 | 20,342,608 | 32,128,096 | 64,295,088 | 51,699,827 |\n", + "| AI-powered content and sentiment analysis savings | contacts | -15% | 3,898,627 | 4,554,650 | 5,347,928 | 13,801,205 | 11,326,358 |\n", + "| AI-enabled forecasting, agent scheduling, and supervision | agents | -15% | 5,653,928 | 7,763,696 | 10,532,955 | 23,950,579 | 19,469,777 |\n", + "| Data-driven profit lift with increased conversion | contacts | -20% | 960,000 | 1,248,000 | 1,622,400 | 3,830,400 | 3,123,065 |\n", + "| Legacy solution cost savings | agents | -20% | 4,942,080 | 6,424,704 | 8,352,115 | 19,718,899 | 16,077,540 |\n", + "| TOTAL | | | 27,279,019 | 40,333,658 | 57,983,494 | 125,596,172 | 101,696,568 |\n", + "\n", + "#### Costs — client overlay (risk-adjusted $)\n", + "\n", + "| Cost | Driver | Risk adj | Initial | 2026 | 2027 | 2028 | PV |\n", + "|:----------------------------------|:---------|:-----------|----------:|----------:|----------:|-----------:|-----------:|\n", + "| Amazon Connect usage cost | contacts | +5% | 0 | 6,779,270 | 8,348,722 | 10,324,609 | 20,819,775 |\n", + "| Implementation and migration cost | fixed | +10% | 1,196,250 | 207,166 | 207,166 | 0 | 1,555,795 |\n", + "| Ongoing management | fixed | +15% | 0 | 294,630 | 215,280 | 215,280 | 607,506 |\n", + "| TOTAL | | | 1,196,250 | 7,281,067 | 8,771,168 | 10,539,889 | 22,983,076 |\n", + "\n", + "#### KPIs — published composite vs client overlay\n", + "\n", + "| | Forrester composite (published 🟢) | Client overlay (🟡) |\n", + "|:--------------|:-------------------------------------|:-----------------------|\n", + "| Benefits PV | $101,696,791 | $101,696,568 |\n", + "| Costs PV | $22,983,076 | $22,983,076 |\n", + "| NPV | $78,713,715 | $78,713,492 |\n", + "| ROI | 342% | 342% |\n", + "| Payback | <6 months | 0.7 months (~Jan 2026) |\n", + "| Discount rate | 10% | 10% |\n", + "\n", + "#### Scenarios (client overlay)\n", + "\n", + "| Scenario | Adoption | Risk Δ | Benefits PV | Costs PV | NPV | ROI % | Payback (months) |\n", + "|:-------------|:-----------|:---------|--------------:|-----------:|-----------:|--------:|-------------------:|\n", + "| conservative | 80% | +10% | 71,672,868 | 17,437,916 | 54,234,951 | 311 | 1 |\n", + "| moderate | 100% | +0% | 101,696,568 | 22,983,076 | 78,713,492 | 342 | 1 |\n", + "| aggressive | 115% | -5% | 123,911,705 | 27,682,369 | 96,229,337 | 348 | 1 |\n", + "\n", + "#### Model state (JSON)\n", + "\n", + "```json\n", + "{\n", + " \"study\": \"202602_TEI_Amazon_Connect\",\n", + " \"source\": \"Forrester TEI of Amazon Connect (Feb 2026, commissioned by AWS)\",\n", + " \"published\": {\n", + " \"benefits_pv\": 101696791,\n", + " \"costs_pv\": 22983076,\n", + " \"npv\": 78713715,\n", + " \"roi_pct\": 342,\n", + " \"payback_months_max\": 6,\n", + " \"discount_rate\": 0.1,\n", + " \"analysis_years\": 3\n", + " },\n", + " \"reproduction\": {\n", + " \"benefits_pv\": 101696567.55,\n", + " \"costs_pv\": 22983075.78,\n", + " \"npv\": 78713491.78,\n", + " \"roi_pct\": 342.48,\n", + " \"payback_months\": 0.72\n", + " },\n", + " \"client\": {\n", + " \"drivers\": {\n", + " \"agents_fte\": 2000,\n", + " \"annual_contacts_y1\": 20000000,\n", + " \"growth_rate\": 0.3,\n", + " \"discount_rate\": 0.1,\n", + " \"scenario\": \"moderate\"\n", + " },\n", + " \"benefits_by_year\": {\n", + " \"2026\": 27279019,\n", + " \"2027\": 40333658,\n", + " \"2028\": 57983494\n", + " },\n", + " \"costs_by_year\": {\n", + " \"2026\": 7281067,\n", + " \"2027\": 8771168,\n", + " \"2028\": 10539889\n", + " },\n", + " \"net_by_year\": {\n", + " \"2026\": 19997952,\n", + " \"2027\": 31562490,\n", + " \"2028\": 47443605\n", + " },\n", + " \"cumulative_net_by_year\": {\n", + " \"2026\": 18801702,\n", + " \"2027\": 50364192,\n", + " \"2028\": 97807797\n", + " },\n", + " \"initial_costs\": 1196250,\n", + " \"kpis\": {\n", + " \"benefits_pv\": 101696568,\n", + " \"costs_pv\": 22983076,\n", + " \"npv\": 78713492,\n", + " \"roi_pct\": 342.48,\n", + " \"payback_months\": 0.72,\n", + " \"payback_label\": \"0.7 months (~Jan 2026)\"\n", + " },\n", + " \"scenarios\": {\n", + " \"conservative\": {\n", + " \"benefits_pv\": 71672868,\n", + " \"costs_pv\": 17437916,\n", + " \"npv\": 54234951,\n", + " \"roi_pct\": 311.02\n", + " },\n", + " \"moderate\": {\n", + " \"benefits_pv\": 101696568,\n", + " \"costs_pv\": 22983076,\n", + " \"npv\": 78713492,\n", + " \"roi_pct\": 342.48\n", + " },\n", + " \"aggressive\": {\n", + " \"benefits_pv\": 123911705,\n", + " \"costs_pv\": 27682369,\n", + " \"npv\": 96229337,\n", + " \"roi_pct\": 347.62\n", + " }\n", + " }\n", + " },\n", + " \"driver_map\": {\n", + " \"benefits\": {\n", + " \"ai_contact_resolution\": \"contacts\",\n", + " \"ai_content_sentiment\": \"contacts\",\n", + " \"ai_forecasting_supervision\": \"agents\",\n", + " \"data_driven_profit_lift\": \"contacts\",\n", + " \"legacy_solution_savings\": \"agents\"\n", + " },\n", + " \"costs\": {\n", + " \"amazon_connect_usage\": \"contacts\",\n", + " \"implementation_migration\": \"fixed\",\n", + " \"ongoing_management\": \"fixed\"\n", + " }\n", + " }\n", + "}\n", + "```\n" + ] + } + ], + "source": [ + "# ── Data appendix — LLM-readable dump of every model output ──────────\n", + "# Renders backstage only (JupyterLab / nbconvert exports) — hidden on\n", + "# the Mercury stage, where the narrative and figures carry the story.\n", + "import json as _json\n", + "\n", + "\n", + "def _section(title, df, **kw):\n", + " backstage(f\"\\n#### {title}\\n\")\n", + " backstage(df.to_markdown(floatfmt=\",.0f\", **kw))\n", + "\n", + "\n", + "_section(\"Composite organization (verbatim assumptions 🟢)\",\n", + " assumptions_df, index=False)\n", + "_section(\"Benefits — client overlay (risk-adjusted $)\", benefits_df)\n", + "_section(\"Costs — client overlay (risk-adjusted $)\", costs_df)\n", + "_section(\"KPIs — published composite vs client overlay\", kpis_fmt)\n", + "_section(\"Scenarios (client overlay)\", scen_df)\n", + "\n", + "backstage(\"\\n#### Model state (JSON)\\n\")\n", + "backstage(\"```json\")\n", + "backstage(_json.dumps({\n", + " \"study\": \"202602_TEI_Amazon_Connect\",\n", + " \"source\": \"Forrester TEI of Amazon Connect (Feb 2026, commissioned by AWS)\",\n", + " \"published\": PUBLISHED,\n", + " \"reproduction\": {\n", + " \"benefits_pv\": round(composite[\"benefits_pv\"], 2),\n", + " \"costs_pv\": round(composite[\"costs_pv\"], 2),\n", + " \"npv\": round(composite[\"npv\"], 2),\n", + " \"roi_pct\": round(composite[\"roi_pct\"], 2),\n", + " \"payback_months\": round(composite[\"payback_months\"], 2),\n", + " },\n", + " \"client\": {\n", + " \"drivers\": {\n", + " \"agents_fte\": AGENTS_FTE,\n", + " \"annual_contacts_y1\": CONTACTS_Y1,\n", + " \"growth_rate\": GROWTH_RATE,\n", + " \"discount_rate\": DISCOUNT_RATE,\n", + " \"scenario\": SCENARIO,\n", + " },\n", + " \"benefits_by_year\": {str(y): round(client[\"benefits_by_year\"][y]) for y in YEARS},\n", + " \"costs_by_year\": {str(y): round(client[\"costs_by_year\"][y]) for y in YEARS},\n", + " \"net_by_year\": {str(y): round(client[\"net_by_year\"][y]) for y in YEARS},\n", + " \"cumulative_net_by_year\": {str(y): round(client[\"cumulative_net_by_year\"][y]) for y in YEARS},\n", + " \"initial_costs\": round(client[\"initial_costs\"]),\n", + " \"kpis\": {\n", + " \"benefits_pv\": round(client[\"benefits_pv\"]),\n", + " \"costs_pv\": round(client[\"costs_pv\"]),\n", + " \"npv\": round(client[\"npv\"]),\n", + " \"roi_pct\": round(client[\"roi_pct\"], 2),\n", + " \"payback_months\": round(client[\"payback_months\"], 2)\n", + " if client[\"payback_months\"] is not None else None,\n", + " \"payback_label\": client[\"payback_label\"],\n", + " },\n", + " \"scenarios\": {\n", + " s: {\"benefits_pv\": round(r[\"benefits_pv\"]),\n", + " \"costs_pv\": round(r[\"costs_pv\"]),\n", + " \"npv\": round(r[\"npv\"]),\n", + " \"roi_pct\": round(r[\"roi_pct\"], 2)}\n", + " for s, r in scen_summaries.items()\n", + " },\n", + " },\n", + " \"driver_map\": {\"benefits\": BENEFIT_DRIVERS, \"costs\": COST_DRIVERS},\n", + "}, indent=2))\n", + "backstage(\"```\")\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.13.7" + }, + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "state": { + "01c230d30aed4aa58c5a005c44e65f84": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.number.NumberInputWidget", + "_css": "\n .mljar-number-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-number-label {\n padding-top: 6px;\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-number-field-row {\n display: flex;\n align-items: stretch;\n width: 100%;\n min-height: 40px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n overflow: hidden;\n }\n\n .mljar-number-input {\n flex: 1 1 auto;\n min-width: 0;\n min-height: 100%;\n padding: 7px 10px;\n border: 0;\n border-radius: 0;\n background: #ffffff;\n box-sizing: border-box;\n background-color: #ffffff !important;\n color: #0f172a !important;\n font: inherit;\n line-height: 1.2;\n -moz-appearance: textfield;\n }\n\n .mljar-number-input::-webkit-outer-spin-button,\n .mljar-number-input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n }\n\n .mljar-number-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-number-input:focus {\n outline: none;\n }\n\n .mljar-number-field-row:focus-within {\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-number-field-row:focus-within .mljar-number-controls {\n border-left-color: #007bff;\n }\n\n .mljar-number-controls {\n display: flex;\n align-items: stretch;\n flex: 0 0 auto;\n border-left: 1px solid #cfd1d5;\n background: #f1f1f2;\n }\n\n .mljar-number-step-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 38px;\n min-width: 38px;\n min-height: 100%;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: #0f172a;\n font: inherit;\n font-size: 18px;\n font-weight: 700;\n line-height: 1;\n cursor: pointer;\n padding: 0;\n user-select: none;\n -webkit-user-select: none;\n touch-action: manipulation;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-number-step-up {\n border-left: 1px solid #cfd1d5;\n }\n\n .mljar-number-step-btn:hover {\n background: #f3f3f4;\n }\n\n .mljar-number-step-btn:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:focus-visible {\n outline: none;\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:disabled {\n background: #f5f5f5;\n color: #aaa;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-number-field-row {\n min-height: 44px;\n }\n\n .mljar-number-input {\n min-height: 44px;\n padding: 8px 12px;\n }\n\n .mljar-number-step-btn {\n font-size: 19px;\n width: 44px;\n min-width: 44px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-number-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-number-label\");\n\n const fieldRow = document.createElement(\"div\");\n fieldRow.classList.add(\"mljar-number-field-row\");\n\n const input = document.createElement(\"input\");\n input.type = \"number\";\n input.classList.add(\"mljar-number-input\");\n\n const decrementBtn = document.createElement(\"button\");\n decrementBtn.type = \"button\";\n decrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-down\");\n decrementBtn.textContent = \"-\";\n decrementBtn.setAttribute(\"aria-label\", \"Decrease value\");\n\n const incrementBtn = document.createElement(\"button\");\n incrementBtn.type = \"button\";\n incrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-up\");\n incrementBtn.textContent = \"+\";\n incrementBtn.setAttribute(\"aria-label\", \"Increase value\");\n\n const controls = document.createElement(\"div\");\n controls.classList.add(\"mljar-number-controls\");\n\n controls.appendChild(decrementBtn);\n controls.appendChild(incrementBtn);\n fieldRow.appendChild(input);\n fieldRow.appendChild(controls);\n\n container.appendChild(topLabel);\n container.appendChild(fieldRow);\n el.appendChild(container);\n\n function clamp(val, min, max) {\n if (Number.isFinite(min) && val < min) return min;\n if (Number.isFinite(max) && val > max) return max;\n return val;\n }\n\n function normalizeStep(step) {\n return Number.isFinite(step) && step > 0 ? step : 1;\n }\n\n function snapToStep(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = Math.round((value - base) / safeStep);\n const snapped = base + steps * safeStep;\n const precision = Math.max(\n 0,\n (String(safeStep).split(\".\")[1] || \"\").length\n );\n\n return Number(snapped.toFixed(precision + 2));\n }\n\n function isOnStepGrid(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = (value - base) / safeStep;\n const nearest = Math.round(steps);\n const epsilon = Math.max(1e-9, safeStep * 1e-9);\n\n return Math.abs(steps - nearest) <= epsilon;\n }\n\n function getCurrentBounds() {\n return {\n min: Number(model.get(\"min\")),\n max: Number(model.get(\"max\")),\n };\n }\n\n function isTransientDraft(raw) {\n return raw === \"\" || raw === \"-\" || raw === \".\" || raw === \"-.\";\n }\n\n let isEditing = false;\n const INPUT_COMMIT_DEBOUNCE_MS = 400;\n\n function clearPendingDraftCommit() {\n if (debounceTimer) clearTimeout(debounceTimer);\n pendingDraftValue = null;\n }\n\n function parseDraftValue(rawValue) {\n const raw = String(rawValue).trim();\n if (isTransientDraft(raw)) {\n return { kind: \"transient\" };\n }\n\n const value = Number(raw);\n if (!Number.isFinite(value)) {\n return { kind: \"invalid\" };\n }\n\n return { kind: \"number\", value };\n }\n\n function commitValue(nextValue, saveNow = true) {\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n const parsed = parseDraftValue(nextValue);\n if (parsed.kind !== \"number\") {\n syncFromModel();\n return;\n }\n\n let v = parsed.value;\n v = clamp(v, min, max);\n v = snapToStep(v, min, step);\n v = clamp(v, min, max);\n input.value = String(v);\n model.set(\"value\", v);\n\n if (saveNow) {\n model.save_changes();\n }\n }\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter number\";\n\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const step = Number(model.get(\"step\"));\n\n if (Number.isFinite(min)) input.min = String(min); else input.removeAttribute(\"min\");\n if (Number.isFinite(max)) input.max = String(max); else input.removeAttribute(\"max\");\n if (Number.isFinite(step)) input.step = String(step); else input.removeAttribute(\"step\");\n\n const v = Number(model.get(\"value\"));\n if (!isEditing) {\n input.value = Number.isFinite(v) ? String(v) : \"\";\n }\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n incrementBtn.disabled = disabled;\n decrementBtn.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n let debounceTimer = null;\n let pendingDraftValue = null;\n input.addEventListener(\"focus\", () => {\n isEditing = true;\n });\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n\n const parsed = parseDraftValue(input.value);\n if (parsed.kind !== \"number\") {\n clearPendingDraftCommit();\n return;\n }\n\n const v = parsed.value;\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n if (Number.isFinite(min) && v < min) {\n clearPendingDraftCommit();\n return;\n }\n if (Number.isFinite(max) && v > max) {\n clearPendingDraftCommit();\n return;\n }\n if (!isOnStepGrid(v, min, step)) {\n clearPendingDraftCommit();\n return;\n }\n\n pendingDraftValue = v;\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n if (pendingDraftValue === null) return;\n model.set(\"value\", pendingDraftValue);\n model.save_changes();\n pendingDraftValue = null;\n }, INPUT_COMMIT_DEBOUNCE_MS);\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n clearPendingDraftCommit();\n commitValue(input.value, true);\n });\n\n input.addEventListener(\"keydown\", event => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n input.blur();\n }\n });\n\n incrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base + step, min, step));\n });\n\n decrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base - step, min, step));\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:step\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Annual contacts, year 1 — composite 20M", + "layout": "IPY_MODEL_cc4716028c0c4335b1d70f4e29e905f6", + "layout_path": null, + "max": 500000000.0, + "min": 100000.0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "step": 1000000.0, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": 20000000.0 + } + }, + "0833fb2c5bd3466aba5ff466dec6ff1b": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HTMLModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "2.0.0", + "_view_name": "HTMLView", + "cell_id": "", + "description": "", + "description_allow_html": false, + "layout": "IPY_MODEL_ae315fb739f643f7a1fbe0f3678a6002", + "layout_path": null, + "placeholder": "​", + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "style": "IPY_MODEL_f9174ef9b9674e9d8c64bd888d70130b", + "tabbable": null, + "tooltip": null, + "value": "" + } + }, + "48a9c76ed0fb498984234409f404ac3f": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "ace9c00dc3a84babb5b29ae61e2be62c": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.number.NumberInputWidget", + "_css": "\n .mljar-number-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-number-label {\n padding-top: 6px;\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-number-field-row {\n display: flex;\n align-items: stretch;\n width: 100%;\n min-height: 40px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n overflow: hidden;\n }\n\n .mljar-number-input {\n flex: 1 1 auto;\n min-width: 0;\n min-height: 100%;\n padding: 7px 10px;\n border: 0;\n border-radius: 0;\n background: #ffffff;\n box-sizing: border-box;\n background-color: #ffffff !important;\n color: #0f172a !important;\n font: inherit;\n line-height: 1.2;\n -moz-appearance: textfield;\n }\n\n .mljar-number-input::-webkit-outer-spin-button,\n .mljar-number-input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n }\n\n .mljar-number-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-number-input:focus {\n outline: none;\n }\n\n .mljar-number-field-row:focus-within {\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-number-field-row:focus-within .mljar-number-controls {\n border-left-color: #007bff;\n }\n\n .mljar-number-controls {\n display: flex;\n align-items: stretch;\n flex: 0 0 auto;\n border-left: 1px solid #cfd1d5;\n background: #f1f1f2;\n }\n\n .mljar-number-step-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 38px;\n min-width: 38px;\n min-height: 100%;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: #0f172a;\n font: inherit;\n font-size: 18px;\n font-weight: 700;\n line-height: 1;\n cursor: pointer;\n padding: 0;\n user-select: none;\n -webkit-user-select: none;\n touch-action: manipulation;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-number-step-up {\n border-left: 1px solid #cfd1d5;\n }\n\n .mljar-number-step-btn:hover {\n background: #f3f3f4;\n }\n\n .mljar-number-step-btn:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:focus-visible {\n outline: none;\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:disabled {\n background: #f5f5f5;\n color: #aaa;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-number-field-row {\n min-height: 44px;\n }\n\n .mljar-number-input {\n min-height: 44px;\n padding: 8px 12px;\n }\n\n .mljar-number-step-btn {\n font-size: 19px;\n width: 44px;\n min-width: 44px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-number-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-number-label\");\n\n const fieldRow = document.createElement(\"div\");\n fieldRow.classList.add(\"mljar-number-field-row\");\n\n const input = document.createElement(\"input\");\n input.type = \"number\";\n input.classList.add(\"mljar-number-input\");\n\n const decrementBtn = document.createElement(\"button\");\n decrementBtn.type = \"button\";\n decrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-down\");\n decrementBtn.textContent = \"-\";\n decrementBtn.setAttribute(\"aria-label\", \"Decrease value\");\n\n const incrementBtn = document.createElement(\"button\");\n incrementBtn.type = \"button\";\n incrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-up\");\n incrementBtn.textContent = \"+\";\n incrementBtn.setAttribute(\"aria-label\", \"Increase value\");\n\n const controls = document.createElement(\"div\");\n controls.classList.add(\"mljar-number-controls\");\n\n controls.appendChild(decrementBtn);\n controls.appendChild(incrementBtn);\n fieldRow.appendChild(input);\n fieldRow.appendChild(controls);\n\n container.appendChild(topLabel);\n container.appendChild(fieldRow);\n el.appendChild(container);\n\n function clamp(val, min, max) {\n if (Number.isFinite(min) && val < min) return min;\n if (Number.isFinite(max) && val > max) return max;\n return val;\n }\n\n function normalizeStep(step) {\n return Number.isFinite(step) && step > 0 ? step : 1;\n }\n\n function snapToStep(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = Math.round((value - base) / safeStep);\n const snapped = base + steps * safeStep;\n const precision = Math.max(\n 0,\n (String(safeStep).split(\".\")[1] || \"\").length\n );\n\n return Number(snapped.toFixed(precision + 2));\n }\n\n function isOnStepGrid(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = (value - base) / safeStep;\n const nearest = Math.round(steps);\n const epsilon = Math.max(1e-9, safeStep * 1e-9);\n\n return Math.abs(steps - nearest) <= epsilon;\n }\n\n function getCurrentBounds() {\n return {\n min: Number(model.get(\"min\")),\n max: Number(model.get(\"max\")),\n };\n }\n\n function isTransientDraft(raw) {\n return raw === \"\" || raw === \"-\" || raw === \".\" || raw === \"-.\";\n }\n\n let isEditing = false;\n const INPUT_COMMIT_DEBOUNCE_MS = 400;\n\n function clearPendingDraftCommit() {\n if (debounceTimer) clearTimeout(debounceTimer);\n pendingDraftValue = null;\n }\n\n function parseDraftValue(rawValue) {\n const raw = String(rawValue).trim();\n if (isTransientDraft(raw)) {\n return { kind: \"transient\" };\n }\n\n const value = Number(raw);\n if (!Number.isFinite(value)) {\n return { kind: \"invalid\" };\n }\n\n return { kind: \"number\", value };\n }\n\n function commitValue(nextValue, saveNow = true) {\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n const parsed = parseDraftValue(nextValue);\n if (parsed.kind !== \"number\") {\n syncFromModel();\n return;\n }\n\n let v = parsed.value;\n v = clamp(v, min, max);\n v = snapToStep(v, min, step);\n v = clamp(v, min, max);\n input.value = String(v);\n model.set(\"value\", v);\n\n if (saveNow) {\n model.save_changes();\n }\n }\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter number\";\n\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const step = Number(model.get(\"step\"));\n\n if (Number.isFinite(min)) input.min = String(min); else input.removeAttribute(\"min\");\n if (Number.isFinite(max)) input.max = String(max); else input.removeAttribute(\"max\");\n if (Number.isFinite(step)) input.step = String(step); else input.removeAttribute(\"step\");\n\n const v = Number(model.get(\"value\"));\n if (!isEditing) {\n input.value = Number.isFinite(v) ? String(v) : \"\";\n }\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n incrementBtn.disabled = disabled;\n decrementBtn.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n let debounceTimer = null;\n let pendingDraftValue = null;\n input.addEventListener(\"focus\", () => {\n isEditing = true;\n });\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n\n const parsed = parseDraftValue(input.value);\n if (parsed.kind !== \"number\") {\n clearPendingDraftCommit();\n return;\n }\n\n const v = parsed.value;\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n if (Number.isFinite(min) && v < min) {\n clearPendingDraftCommit();\n return;\n }\n if (Number.isFinite(max) && v > max) {\n clearPendingDraftCommit();\n return;\n }\n if (!isOnStepGrid(v, min, step)) {\n clearPendingDraftCommit();\n return;\n }\n\n pendingDraftValue = v;\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n if (pendingDraftValue === null) return;\n model.set(\"value\", pendingDraftValue);\n model.save_changes();\n pendingDraftValue = null;\n }, INPUT_COMMIT_DEBOUNCE_MS);\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n clearPendingDraftCommit();\n commitValue(input.value, true);\n });\n\n input.addEventListener(\"keydown\", event => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n input.blur();\n }\n });\n\n incrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base + step, min, step));\n });\n\n decrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base - step, min, step));\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:step\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Contact-center agents (FTE) — composite 2,000", + "layout": "IPY_MODEL_ce0e81f1ea384a79897a9eb663bda565", + "layout_path": null, + "max": 50000.0, + "min": 50.0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "step": 50.0, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": 2000.0 + } + }, + "ae315fb739f643f7a1fbe0f3678a6002": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "b0de84b09c5743b9a4e7a5dbdf1973d9": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "b1e82327c29a44a8a4a45e8100b3d857": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.select.SelectWidget", + "_css": "\n .mljar-select-container {\n position: relative;\n display: flex;\n flex-direction: column;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: visible;\n }\n\n .mljar-select-label {\n padding-top: 6px;\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-select-control {\n position: relative;\n display: flex;\n align-items: center;\n cursor: default;\n overflow: visible;\n }\n\n .mljar-select-container.is-open {\n z-index: 20;\n }\n\n .mljar-select-widget-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 36px 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n line-height: 1.4;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n\n appearance: none !important;\n background-color: #ffffff !important;\n color: #0f172a !important;\n cursor: default;\n }\n\n .mljar-select-widget-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n cursor: text;\n }\n\n .mljar-select-caret {\n position: absolute;\n right: 12px;\n top: 50%;\n width: 8px;\n height: 8px;\n border-right: 1.5px solid #0f172a;\n border-bottom: 1.5px solid #0f172a;\n transform: translateY(-65%) rotate(45deg);\n pointer-events: auto;\n opacity: 0.5;\n transition: transform 0.18s ease, opacity 0.18s ease;\n }\n\n .mljar-select-container.is-open .mljar-select-caret {\n opacity: 1;\n transform: translateY(-35%) rotate(225deg);\n }\n\n .mljar-select-dropdown {\n display: none;\n position: fixed;\n z-index: 10000;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);\n overflow: hidden;\n }\n\n .mljar-select-list {\n max-height: 260px;\n overflow-y: auto;\n }\n\n .mljar-select-option {\n display: block;\n width: 100%;\n padding: 9px 10px;\n border: 0;\n background: transparent;\n color: #0f172a;\n text-align: left;\n cursor: pointer;\n font: inherit;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-select-option:hover {\n background: #f3f3f4;\n }\n\n .mljar-select-option:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-option.is-selected {\n background: #e6f2ff;\n color: #007bff;\n font-weight: 600;\n }\n\n .mljar-select-option.is-selected:hover,\n .mljar-select-option.is-selected:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-empty {\n display: none;\n padding: 10px;\n color: #616673;\n font-size: 0.95em;\n }\n\n .mljar-select-widget-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-select-control.is-disabled .mljar-select-caret {\n opacity: 0.45;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const normalize = value => String(value ?? \"\").toLowerCase().trim();\n const getChoices = () =>\n Array.isArray(model.get(\"choices\")) ? [...model.get(\"choices\")] : [];\n const isDisabled = () => !!model.get(\"disabled\");\n const isHidden = () => !!model.get(\"hidden\");\n\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-select-container\");\n\n if (model.get(\"label\")) {\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-select-label\");\n topLabel.innerHTML = model.get(\"label\");\n container.appendChild(topLabel);\n }\n\n const control = document.createElement(\"div\");\n control.classList.add(\"mljar-select-control\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-select-widget-input\");\n input.autocomplete = \"off\";\n input.spellcheck = false;\n\n const caret = document.createElement(\"div\");\n caret.classList.add(\"mljar-select-caret\");\n\n control.appendChild(input);\n control.appendChild(caret);\n\n const dropdown = document.createElement(\"div\");\n dropdown.classList.add(\"mljar-select-dropdown\");\n\n const list = document.createElement(\"div\");\n list.classList.add(\"mljar-select-list\");\n\n const emptyState = document.createElement(\"div\");\n emptyState.classList.add(\"mljar-select-empty\");\n emptyState.textContent = \"No matches\";\n\n dropdown.appendChild(list);\n dropdown.appendChild(emptyState);\n\n container.appendChild(control);\n el.appendChild(container);\n\n let isOpen = false;\n let filteredChoices = [];\n let lastCommittedValue = \"\";\n let isEditing = false;\n document.body.appendChild(dropdown);\n\n const updateDropdownPosition = () => {\n if (!isOpen) {\n return;\n }\n const rect = control.getBoundingClientRect();\n dropdown.style.top = `${rect.bottom + 6}px`;\n dropdown.style.left = `${rect.left}px`;\n dropdown.style.width = `${rect.width}px`;\n };\n\n const setOpen = next => {\n if (isDisabled()) {\n isOpen = false;\n } else {\n isOpen = !!next;\n }\n container.classList.toggle(\"is-open\", isOpen);\n dropdown.style.display = isOpen ? \"block\" : \"none\";\n if (isOpen) {\n updateDropdownPosition();\n }\n };\n\n const updateDisabledState = () => {\n const disabled = isDisabled();\n input.disabled = disabled;\n control.classList.toggle(\"is-disabled\", disabled);\n };\n\n const updateHiddenState = () => {\n container.style.display = isHidden() ? \"none\" : \"\";\n };\n\n const syncInputWithValue = () => {\n const value = model.get(\"value\") || \"\";\n lastCommittedValue = value;\n if (!isEditing) {\n input.value = value;\n }\n };\n\n const filterChoices = query => {\n const normalizedQuery = normalize(query);\n const allChoices = getChoices();\n if (!normalizedQuery) {\n return allChoices;\n }\n return allChoices.filter(choice =>\n normalize(choice).includes(normalizedQuery)\n );\n };\n\n const renderList = () => {\n list.innerHTML = \"\";\n filteredChoices.forEach(choice => {\n const option = document.createElement(\"button\");\n option.type = \"button\";\n option.classList.add(\"mljar-select-option\");\n if (choice === model.get(\"value\")) {\n option.classList.add(\"is-selected\");\n }\n option.textContent = choice;\n option.addEventListener(\"mousedown\", event => {\n event.preventDefault();\n event.stopPropagation();\n model.set(\"value\", choice);\n model.save_changes();\n isEditing = false;\n syncInputWithValue();\n renderList();\n setOpen(false);\n });\n list.appendChild(option);\n });\n\n const hasMatches = filteredChoices.length > 0;\n list.style.display = hasMatches ? \"block\" : \"none\";\n emptyState.style.display = hasMatches ? \"none\" : \"block\";\n };\n\n const refreshList = () => {\n filteredChoices = filterChoices(input.value);\n renderList();\n };\n\n const openWithCurrentQuery = () => {\n isEditing = true;\n input.value = \"\";\n refreshList();\n setOpen(true);\n };\n\n const closeDropdown = () => {\n isEditing = false;\n setOpen(false);\n input.value = lastCommittedValue;\n };\n\n control.addEventListener(\"click\", event => {\n event.stopPropagation();\n if (isDisabled()) {\n return;\n }\n if (event.target === caret && isOpen) {\n closeDropdown();\n input.blur();\n return;\n }\n openWithCurrentQuery();\n input.focus();\n });\n\n input.addEventListener(\"input\", () => {\n if (isDisabled()) {\n return;\n }\n refreshList();\n setOpen(true);\n });\n\n input.addEventListener(\"focus\", () => {\n if (isDisabled()) {\n return;\n }\n openWithCurrentQuery();\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n input.value = lastCommittedValue;\n });\n\n const handleDocumentClick = event => {\n if (!container.contains(event.target) && !dropdown.contains(event.target)) {\n closeDropdown();\n }\n };\n\n document.addEventListener(\"click\", handleDocumentClick);\n window.addEventListener(\"resize\", updateDropdownPosition);\n document.addEventListener(\"scroll\", updateDropdownPosition, true);\n\n model.on(\"change:value\", () => {\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:choices\", () => {\n const choices = getChoices();\n if (!choices.includes(model.get(\"value\")) && choices.length > 0) {\n model.set(\"value\", choices[0]);\n model.save_changes();\n return;\n }\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:disabled\", () => {\n updateDisabledState();\n if (isDisabled()) {\n closeDropdown();\n }\n });\n\n model.on(\"change:hidden\", () => {\n updateHiddenState();\n });\n\n updateDisabledState();\n updateHiddenState();\n syncInputWithValue();\n refreshList();\n setOpen(false);\n\n return () => {\n dropdown.remove();\n document.removeEventListener(\"click\", handleDocumentClick);\n window.removeEventListener(\"resize\", updateDropdownPosition);\n document.removeEventListener(\"scroll\", updateDropdownPosition, true);\n };\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "choices": [ + "conservative", + "moderate", + "aggressive" + ], + "disabled": false, + "hidden": false, + "label": "Scenario", + "layout": "IPY_MODEL_b0de84b09c5743b9a4e7a5dbdf1973d9", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "moderate" + } + }, + "cc4716028c0c4335b1d70f4e29e905f6": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "ce0e81f1ea384a79897a9eb663bda565": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "d4ccace17e824e4a85c55ff6ef95afb0": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.number.NumberInputWidget", + "_css": "\n .mljar-number-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-number-label {\n padding-top: 6px;\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-number-field-row {\n display: flex;\n align-items: stretch;\n width: 100%;\n min-height: 40px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n overflow: hidden;\n }\n\n .mljar-number-input {\n flex: 1 1 auto;\n min-width: 0;\n min-height: 100%;\n padding: 7px 10px;\n border: 0;\n border-radius: 0;\n background: #ffffff;\n box-sizing: border-box;\n background-color: #ffffff !important;\n color: #0f172a !important;\n font: inherit;\n line-height: 1.2;\n -moz-appearance: textfield;\n }\n\n .mljar-number-input::-webkit-outer-spin-button,\n .mljar-number-input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n }\n\n .mljar-number-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-number-input:focus {\n outline: none;\n }\n\n .mljar-number-field-row:focus-within {\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-number-field-row:focus-within .mljar-number-controls {\n border-left-color: #007bff;\n }\n\n .mljar-number-controls {\n display: flex;\n align-items: stretch;\n flex: 0 0 auto;\n border-left: 1px solid #cfd1d5;\n background: #f1f1f2;\n }\n\n .mljar-number-step-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 38px;\n min-width: 38px;\n min-height: 100%;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: #0f172a;\n font: inherit;\n font-size: 18px;\n font-weight: 700;\n line-height: 1;\n cursor: pointer;\n padding: 0;\n user-select: none;\n -webkit-user-select: none;\n touch-action: manipulation;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-number-step-up {\n border-left: 1px solid #cfd1d5;\n }\n\n .mljar-number-step-btn:hover {\n background: #f3f3f4;\n }\n\n .mljar-number-step-btn:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:focus-visible {\n outline: none;\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:disabled {\n background: #f5f5f5;\n color: #aaa;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-number-field-row {\n min-height: 44px;\n }\n\n .mljar-number-input {\n min-height: 44px;\n padding: 8px 12px;\n }\n\n .mljar-number-step-btn {\n font-size: 19px;\n width: 44px;\n min-width: 44px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-number-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-number-label\");\n\n const fieldRow = document.createElement(\"div\");\n fieldRow.classList.add(\"mljar-number-field-row\");\n\n const input = document.createElement(\"input\");\n input.type = \"number\";\n input.classList.add(\"mljar-number-input\");\n\n const decrementBtn = document.createElement(\"button\");\n decrementBtn.type = \"button\";\n decrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-down\");\n decrementBtn.textContent = \"-\";\n decrementBtn.setAttribute(\"aria-label\", \"Decrease value\");\n\n const incrementBtn = document.createElement(\"button\");\n incrementBtn.type = \"button\";\n incrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-up\");\n incrementBtn.textContent = \"+\";\n incrementBtn.setAttribute(\"aria-label\", \"Increase value\");\n\n const controls = document.createElement(\"div\");\n controls.classList.add(\"mljar-number-controls\");\n\n controls.appendChild(decrementBtn);\n controls.appendChild(incrementBtn);\n fieldRow.appendChild(input);\n fieldRow.appendChild(controls);\n\n container.appendChild(topLabel);\n container.appendChild(fieldRow);\n el.appendChild(container);\n\n function clamp(val, min, max) {\n if (Number.isFinite(min) && val < min) return min;\n if (Number.isFinite(max) && val > max) return max;\n return val;\n }\n\n function normalizeStep(step) {\n return Number.isFinite(step) && step > 0 ? step : 1;\n }\n\n function snapToStep(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = Math.round((value - base) / safeStep);\n const snapped = base + steps * safeStep;\n const precision = Math.max(\n 0,\n (String(safeStep).split(\".\")[1] || \"\").length\n );\n\n return Number(snapped.toFixed(precision + 2));\n }\n\n function isOnStepGrid(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = (value - base) / safeStep;\n const nearest = Math.round(steps);\n const epsilon = Math.max(1e-9, safeStep * 1e-9);\n\n return Math.abs(steps - nearest) <= epsilon;\n }\n\n function getCurrentBounds() {\n return {\n min: Number(model.get(\"min\")),\n max: Number(model.get(\"max\")),\n };\n }\n\n function isTransientDraft(raw) {\n return raw === \"\" || raw === \"-\" || raw === \".\" || raw === \"-.\";\n }\n\n let isEditing = false;\n const INPUT_COMMIT_DEBOUNCE_MS = 400;\n\n function clearPendingDraftCommit() {\n if (debounceTimer) clearTimeout(debounceTimer);\n pendingDraftValue = null;\n }\n\n function parseDraftValue(rawValue) {\n const raw = String(rawValue).trim();\n if (isTransientDraft(raw)) {\n return { kind: \"transient\" };\n }\n\n const value = Number(raw);\n if (!Number.isFinite(value)) {\n return { kind: \"invalid\" };\n }\n\n return { kind: \"number\", value };\n }\n\n function commitValue(nextValue, saveNow = true) {\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n const parsed = parseDraftValue(nextValue);\n if (parsed.kind !== \"number\") {\n syncFromModel();\n return;\n }\n\n let v = parsed.value;\n v = clamp(v, min, max);\n v = snapToStep(v, min, step);\n v = clamp(v, min, max);\n input.value = String(v);\n model.set(\"value\", v);\n\n if (saveNow) {\n model.save_changes();\n }\n }\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter number\";\n\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const step = Number(model.get(\"step\"));\n\n if (Number.isFinite(min)) input.min = String(min); else input.removeAttribute(\"min\");\n if (Number.isFinite(max)) input.max = String(max); else input.removeAttribute(\"max\");\n if (Number.isFinite(step)) input.step = String(step); else input.removeAttribute(\"step\");\n\n const v = Number(model.get(\"value\"));\n if (!isEditing) {\n input.value = Number.isFinite(v) ? String(v) : \"\";\n }\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n incrementBtn.disabled = disabled;\n decrementBtn.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n let debounceTimer = null;\n let pendingDraftValue = null;\n input.addEventListener(\"focus\", () => {\n isEditing = true;\n });\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n\n const parsed = parseDraftValue(input.value);\n if (parsed.kind !== \"number\") {\n clearPendingDraftCommit();\n return;\n }\n\n const v = parsed.value;\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n if (Number.isFinite(min) && v < min) {\n clearPendingDraftCommit();\n return;\n }\n if (Number.isFinite(max) && v > max) {\n clearPendingDraftCommit();\n return;\n }\n if (!isOnStepGrid(v, min, step)) {\n clearPendingDraftCommit();\n return;\n }\n\n pendingDraftValue = v;\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n if (pendingDraftValue === null) return;\n model.set(\"value\", pendingDraftValue);\n model.save_changes();\n pendingDraftValue = null;\n }, INPUT_COMMIT_DEBOUNCE_MS);\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n clearPendingDraftCommit();\n commitValue(input.value, true);\n });\n\n input.addEventListener(\"keydown\", event => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n input.blur();\n }\n });\n\n incrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base + step, min, step));\n });\n\n decrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base - step, min, step));\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:step\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Contact growth (%/yr) — composite 30", + "layout": "IPY_MODEL_48a9c76ed0fb498984234409f404ac3f", + "layout_path": null, + "max": 100.0, + "min": 0.0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "step": 5.0, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": 30.0 + } + }, + "d67347bf93954b6abc75a466c3259dd3": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "eb0056195e9b444dbb8ef3c08e744446": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.select.SelectWidget", + "_css": "\n .mljar-select-container {\n position: relative;\n display: flex;\n flex-direction: column;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: visible;\n }\n\n .mljar-select-label {\n padding-top: 6px;\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-select-control {\n position: relative;\n display: flex;\n align-items: center;\n cursor: default;\n overflow: visible;\n }\n\n .mljar-select-container.is-open {\n z-index: 20;\n }\n\n .mljar-select-widget-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 36px 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n line-height: 1.4;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n\n appearance: none !important;\n background-color: #ffffff !important;\n color: #0f172a !important;\n cursor: default;\n }\n\n .mljar-select-widget-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n cursor: text;\n }\n\n .mljar-select-caret {\n position: absolute;\n right: 12px;\n top: 50%;\n width: 8px;\n height: 8px;\n border-right: 1.5px solid #0f172a;\n border-bottom: 1.5px solid #0f172a;\n transform: translateY(-65%) rotate(45deg);\n pointer-events: auto;\n opacity: 0.5;\n transition: transform 0.18s ease, opacity 0.18s ease;\n }\n\n .mljar-select-container.is-open .mljar-select-caret {\n opacity: 1;\n transform: translateY(-35%) rotate(225deg);\n }\n\n .mljar-select-dropdown {\n display: none;\n position: fixed;\n z-index: 10000;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);\n overflow: hidden;\n }\n\n .mljar-select-list {\n max-height: 260px;\n overflow-y: auto;\n }\n\n .mljar-select-option {\n display: block;\n width: 100%;\n padding: 9px 10px;\n border: 0;\n background: transparent;\n color: #0f172a;\n text-align: left;\n cursor: pointer;\n font: inherit;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-select-option:hover {\n background: #f3f3f4;\n }\n\n .mljar-select-option:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-option.is-selected {\n background: #e6f2ff;\n color: #007bff;\n font-weight: 600;\n }\n\n .mljar-select-option.is-selected:hover,\n .mljar-select-option.is-selected:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-empty {\n display: none;\n padding: 10px;\n color: #616673;\n font-size: 0.95em;\n }\n\n .mljar-select-widget-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-select-control.is-disabled .mljar-select-caret {\n opacity: 0.45;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const normalize = value => String(value ?? \"\").toLowerCase().trim();\n const getChoices = () =>\n Array.isArray(model.get(\"choices\")) ? [...model.get(\"choices\")] : [];\n const isDisabled = () => !!model.get(\"disabled\");\n const isHidden = () => !!model.get(\"hidden\");\n\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-select-container\");\n\n if (model.get(\"label\")) {\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-select-label\");\n topLabel.innerHTML = model.get(\"label\");\n container.appendChild(topLabel);\n }\n\n const control = document.createElement(\"div\");\n control.classList.add(\"mljar-select-control\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-select-widget-input\");\n input.autocomplete = \"off\";\n input.spellcheck = false;\n\n const caret = document.createElement(\"div\");\n caret.classList.add(\"mljar-select-caret\");\n\n control.appendChild(input);\n control.appendChild(caret);\n\n const dropdown = document.createElement(\"div\");\n dropdown.classList.add(\"mljar-select-dropdown\");\n\n const list = document.createElement(\"div\");\n list.classList.add(\"mljar-select-list\");\n\n const emptyState = document.createElement(\"div\");\n emptyState.classList.add(\"mljar-select-empty\");\n emptyState.textContent = \"No matches\";\n\n dropdown.appendChild(list);\n dropdown.appendChild(emptyState);\n\n container.appendChild(control);\n el.appendChild(container);\n\n let isOpen = false;\n let filteredChoices = [];\n let lastCommittedValue = \"\";\n let isEditing = false;\n document.body.appendChild(dropdown);\n\n const updateDropdownPosition = () => {\n if (!isOpen) {\n return;\n }\n const rect = control.getBoundingClientRect();\n dropdown.style.top = `${rect.bottom + 6}px`;\n dropdown.style.left = `${rect.left}px`;\n dropdown.style.width = `${rect.width}px`;\n };\n\n const setOpen = next => {\n if (isDisabled()) {\n isOpen = false;\n } else {\n isOpen = !!next;\n }\n container.classList.toggle(\"is-open\", isOpen);\n dropdown.style.display = isOpen ? \"block\" : \"none\";\n if (isOpen) {\n updateDropdownPosition();\n }\n };\n\n const updateDisabledState = () => {\n const disabled = isDisabled();\n input.disabled = disabled;\n control.classList.toggle(\"is-disabled\", disabled);\n };\n\n const updateHiddenState = () => {\n container.style.display = isHidden() ? \"none\" : \"\";\n };\n\n const syncInputWithValue = () => {\n const value = model.get(\"value\") || \"\";\n lastCommittedValue = value;\n if (!isEditing) {\n input.value = value;\n }\n };\n\n const filterChoices = query => {\n const normalizedQuery = normalize(query);\n const allChoices = getChoices();\n if (!normalizedQuery) {\n return allChoices;\n }\n return allChoices.filter(choice =>\n normalize(choice).includes(normalizedQuery)\n );\n };\n\n const renderList = () => {\n list.innerHTML = \"\";\n filteredChoices.forEach(choice => {\n const option = document.createElement(\"button\");\n option.type = \"button\";\n option.classList.add(\"mljar-select-option\");\n if (choice === model.get(\"value\")) {\n option.classList.add(\"is-selected\");\n }\n option.textContent = choice;\n option.addEventListener(\"mousedown\", event => {\n event.preventDefault();\n event.stopPropagation();\n model.set(\"value\", choice);\n model.save_changes();\n isEditing = false;\n syncInputWithValue();\n renderList();\n setOpen(false);\n });\n list.appendChild(option);\n });\n\n const hasMatches = filteredChoices.length > 0;\n list.style.display = hasMatches ? \"block\" : \"none\";\n emptyState.style.display = hasMatches ? \"none\" : \"block\";\n };\n\n const refreshList = () => {\n filteredChoices = filterChoices(input.value);\n renderList();\n };\n\n const openWithCurrentQuery = () => {\n isEditing = true;\n input.value = \"\";\n refreshList();\n setOpen(true);\n };\n\n const closeDropdown = () => {\n isEditing = false;\n setOpen(false);\n input.value = lastCommittedValue;\n };\n\n control.addEventListener(\"click\", event => {\n event.stopPropagation();\n if (isDisabled()) {\n return;\n }\n if (event.target === caret && isOpen) {\n closeDropdown();\n input.blur();\n return;\n }\n openWithCurrentQuery();\n input.focus();\n });\n\n input.addEventListener(\"input\", () => {\n if (isDisabled()) {\n return;\n }\n refreshList();\n setOpen(true);\n });\n\n input.addEventListener(\"focus\", () => {\n if (isDisabled()) {\n return;\n }\n openWithCurrentQuery();\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n input.value = lastCommittedValue;\n });\n\n const handleDocumentClick = event => {\n if (!container.contains(event.target) && !dropdown.contains(event.target)) {\n closeDropdown();\n }\n };\n\n document.addEventListener(\"click\", handleDocumentClick);\n window.addEventListener(\"resize\", updateDropdownPosition);\n document.addEventListener(\"scroll\", updateDropdownPosition, true);\n\n model.on(\"change:value\", () => {\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:choices\", () => {\n const choices = getChoices();\n if (!choices.includes(model.get(\"value\")) && choices.length > 0) {\n model.set(\"value\", choices[0]);\n model.save_changes();\n return;\n }\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:disabled\", () => {\n updateDisabledState();\n if (isDisabled()) {\n closeDropdown();\n }\n });\n\n model.on(\"change:hidden\", () => {\n updateHiddenState();\n });\n\n updateDisabledState();\n updateHiddenState();\n syncInputWithValue();\n refreshList();\n setOpen(false);\n\n return () => {\n dropdown.remove();\n document.removeEventListener(\"click\", handleDocumentClick);\n window.removeEventListener(\"resize\", updateDropdownPosition);\n document.removeEventListener(\"scroll\", updateDropdownPosition, true);\n };\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "choices": [ + "8%", + "10% (Forrester)", + "12%" + ], + "disabled": false, + "hidden": false, + "label": "Discount rate", + "layout": "IPY_MODEL_d67347bf93954b6abc75a466c3259dd3", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "10% (Forrester)" + } + }, + "f9174ef9b9674e9d8c64bd888d70130b": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HTMLStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "HTMLStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "StyleView", + "background": null, + "description_width": "", + "font_size": null, + "text_color": null + } + } + }, + "version_major": 2, + "version_minor": 0 + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/studies/202602_TEI_Amazon_Connect/pyproject.toml b/studies/202602_TEI_Amazon_Connect/pyproject.toml new file mode 100644 index 0000000..afaf081 --- /dev/null +++ b/studies/202602_TEI_Amazon_Connect/pyproject.toml @@ -0,0 +1,36 @@ +[build-system] +requires = ["setuptools>=68"] +build-backend = "setuptools.build_meta" + +[project] +name = "teicalc" +version = "0.1.0" +description = "Amazon Connect TEI (Forrester, Feb 2026) — composite reproduction + client overlay" +requires-python = ">=3.10" +# The notebook is the deliverable (served with Mercury, exported via +# nbconvert, tables via tabulate) — the whole toolchain is a required +# runtime dependency, not an extra. `pip install -e .` must be enough. +dependencies = [ + "pandas>=2.0", + "plotly>=5.18", + "openpyxl>=3.1", + "mercury>=3.2", + "jupyterlab>=4.0", + "ipywidgets>=8.0", + "nbconvert>=7", + "tabulate>=0.9", +] + +[project.optional-dependencies] +dev = ["pytest>=7.4", "mypy>=1.8"] + +[tool.setuptools.packages.find] +include = ["teicalc*"] + +[tool.pytest.ini_options] +testpaths = ["tests"] +addopts = "-q" + +[tool.mypy] +strict = true +packages = ["teicalc"] diff --git a/studies/202602_TEI_Amazon_Connect/scripts/export_report.py b/studies/202602_TEI_Amazon_Connect/scripts/export_report.py new file mode 100644 index 0000000..2cf4e3d --- /dev/null +++ b/studies/202602_TEI_Amazon_Connect/scripts/export_report.py @@ -0,0 +1,47 @@ +"""Export the deliverable notebooks as LLM-readable report sources. + +Executes each notebook fresh (widget defaults — or whatever defaults you edit in), +then writes both formats to exports/: + + exports/.html — human-reviewable, tables render + exports/.md — leanest LLM input + +Plotly figures export as JavaScript an LLM cannot read; each notebook's +machine-readable appendix section carries every number behind them. + +Run from the project root: python scripts/export_report.py [name-filter] +An optional argument exports only notebooks whose filename contains it. +""" +from __future__ import annotations + +import subprocess +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parent.parent +NOTEBOOKS = [ + ROOT / "notebooks" / "business_case.ipynb", +] +EXPORTS = ROOT / "exports" + + +def main() -> None: + picked = [nb for nb in NOTEBOOKS + if len(sys.argv) < 2 or sys.argv[1] in nb.name] + if not picked: + sys.exit(f"no notebook matches {sys.argv[1]!r}") + EXPORTS.mkdir(exist_ok=True) + for nb in picked: + for fmt in ("html", "markdown"): + subprocess.run( + [sys.executable, "-m", "nbconvert", "--execute", + "--to", fmt, "--output-dir", str(EXPORTS), str(nb)], + check=True, cwd=ROOT, + ) + for p in sorted(EXPORTS.iterdir()): + if p.suffix in (".html", ".md"): + print(f"wrote {p.relative_to(ROOT)} ({p.stat().st_size / 1024:,.0f} KB)") + + +if __name__ == "__main__": + main() diff --git a/studies/202602_TEI_Amazon_Connect/teicalc/__init__.py b/studies/202602_TEI_Amazon_Connect/teicalc/__init__.py new file mode 100644 index 0000000..7344fae --- /dev/null +++ b/studies/202602_TEI_Amazon_Connect/teicalc/__init__.py @@ -0,0 +1,56 @@ +""" +teicalc — self-contained engine for the Amazon Connect TEI study +(Forrester, February 2026). Mercury Notebook Pattern, Variant 4: +verbatim composite anchor → published-totals gate → client overlay. +""" + +from .anchor import ASSUMPTIONS, BENEFITS_VERBATIM, COSTS_VERBATIM, PUBLISHED +from .model import ( + X_LABELS, + YEAR_INDEX, + YEARS, + benefits_by_year, + by_calendar, + compute_summary, + costs_by_year, + discount_factor, + html_money, + initial_costs, + money, + month_label, + npv, + payback_label, + payback_months, + payback_years, + present_value, + risk_adjust_benefit, + risk_adjust_cost, + risk_adjusted_rows, + roi_pct, +) +from .overlay import ( + BENEFIT_DRIVERS, + COMPOSITE, + COST_DRIVERS, + ClientDrivers, + growth_multiplier, + overlay_rows, + scale_factor, +) +from .scenarios import SCENARIOS, apply_scenario + +__version__ = "0.1.0" + +__all__ = [ + "ASSUMPTIONS", "BENEFITS_VERBATIM", "COSTS_VERBATIM", "PUBLISHED", + "YEARS", "YEAR_INDEX", "X_LABELS", + "by_calendar", "month_label", + "discount_factor", "present_value", "npv", "roi_pct", + "payback_years", "payback_months", "payback_label", + "risk_adjust_benefit", "risk_adjust_cost", "risk_adjusted_rows", + "benefits_by_year", "costs_by_year", "initial_costs", + "compute_summary", "money", "html_money", + "ClientDrivers", "COMPOSITE", "BENEFIT_DRIVERS", "COST_DRIVERS", + "scale_factor", "growth_multiplier", "overlay_rows", + "SCENARIOS", "apply_scenario", +] diff --git a/studies/202602_AmazonConnect/seed_data.py b/studies/202602_TEI_Amazon_Connect/teicalc/anchor.py similarity index 75% rename from studies/202602_AmazonConnect/seed_data.py rename to studies/202602_TEI_Amazon_Connect/teicalc/anchor.py index 5ddc000..1f2d2c2 100644 --- a/studies/202602_AmazonConnect/seed_data.py +++ b/studies/202602_TEI_Amazon_Connect/teicalc/anchor.py @@ -1,29 +1,24 @@ """ -Seed dataset for the Amazon Connect TEI (Forrester, Feb 2026). +The verbatim anchor — Forrester *Total Economic Impact™ Of Amazon Connect* +(February 2026, commissioned by AWS). -Each row uses the friendly value shape accepted by -``core.tei_client.TEIClient.update_values`` (see ``_rows_from_value``), -so it can be passed straight to -``client.update_values(public_id, BENEFITS + COSTS)``. +VERBATIM, do not edit. These are Forrester's published composite-organization +tables and financial summary, transplanted unchanged from the study PDF +(``docs/202602_TEI Report Amazon Connect.pdf``). Client personalization +lives in :mod:`teicalc.overlay`; scenario stress lives in +:mod:`teicalc.scenarios` — both deep-copy, neither mutates this record. -Numbers are the *nominal* (pre-risk-adjustment) values from the PDF — -risk adjustment is stored as a factor and applied by Athena's -calculator (or, locally, by ``core.calculations.risk_adjust_*``). - -References for the totals (from the PDF): - - Benefits (3-yr risk-adjusted PV @ 10%): $101,696,791 - Costs (3-yr risk-adjusted PV @ 10%): $ 22,983,076 - NPV $ 78,713,715 - ROI 342% - Payback <6 months +Rows keep Forrester's own year-index keys (``"1"``/``"2"``/``"3"``); +:mod:`teicalc.model` maps them to calendar years (2026–2028). Values are +*nominal* (pre-risk-adjustment); the risk factor is stored per row and +applied by the model (benefits ×(1−rf), costs ×(1+rf), per the TEI +methodology). """ from __future__ import annotations -#: 3-year nominal benefit cashflows. Risk adjustment factor is stored -#: separately; calculator applies it. -BENEFITS: list[dict] = [ +#: 3-year nominal benefit cashflows — 🟢 published. +BENEFITS_VERBATIM: list[dict] = [ { "field_key": "ai_contact_resolution", "table": "benefits", @@ -95,9 +90,9 @@ BENEFITS: list[dict] = [ ] -#: Costs include an "initial" (year-0, undiscounted) component for -#: implementation. Cost risk adjustments are applied *upward*. -COSTS: list[dict] = [ +#: Costs include an ``initial`` (year-0, undiscounted) component for +#: implementation. Cost risk adjustments are applied *upward*. 🟢 published. +COSTS_VERBATIM: list[dict] = [ { "field_key": "amazon_connect_usage", "table": "costs", @@ -143,7 +138,7 @@ COSTS: list[dict] = [ ] -#: Top-line composite assumptions — for the 03_business_case narrative. +#: Composite-organization drivers — 🟢 published (PDF "Composite Organization"). ASSUMPTIONS: dict = { "agents_fte": 2_000, "supervisors_fte": 200, @@ -158,6 +153,15 @@ ASSUMPTIONS: dict = { } -def all_values() -> list[dict]: - """Return BENEFITS + COSTS — handy single-call payload for update_values.""" - return BENEFITS + COSTS +#: The PDF's Financial Summary — the gate's reproduction target. 🟢 published. +#: The engine reproduces these to within Forrester's own table rounding +#: (benefits PV lands $223 low; costs PV $0.22 low). +PUBLISHED: dict = { + "benefits_pv": 101_696_791, + "costs_pv": 22_983_076, + "npv": 78_713_715, + "roi_pct": 342, + "payback_months_max": 6, # published as "<6 months" + "discount_rate": 0.10, + "analysis_years": 3, +} diff --git a/studies/202602_TEI_Amazon_Connect/teicalc/model.py b/studies/202602_TEI_Amazon_Connect/teicalc/model.py new file mode 100644 index 0000000..34ca59b --- /dev/null +++ b/studies/202602_TEI_Amazon_Connect/teicalc/model.py @@ -0,0 +1,267 @@ +""" +Finance engine — the single source of truth for every number in the notebook. + +Transplanted from the retired shared ``core/calculations`` and +``core/export/report_data.py`` so the study is self-contained (Mercury +Notebook Pattern, Required §2/§7). Conventions match the Forrester TEI +methodology: + +* The *Initial* investment is **not** discounted — it occurs at time zero. +* Year-N cash flows are discounted at the end of the year: + ``PV = CF_n / (1 + r) ** n``. +* Benefits are risk-adjusted *down* (``×(1−rf)``), costs *up* (``×(1+rf)``). +* Payback runs on risk-adjusted **undiscounted** flows (the PDF's + "<6 months" uses the Cash Flow Analysis table's nominal RA rows). + +Everything this module returns for display is keyed by **calendar year** +(Forrester Year 1/2/3 → 2026/2027/2028); ``initial`` stays a Year-0 scalar +and never appears inside a ``*_by_year`` dict. + +This module is stdlib-only on purpose — the repo-root test suite imports it +without the study's venv. +""" + +from __future__ import annotations + +import math +from collections.abc import Iterable, Sequence +from copy import deepcopy + +# ── Timeline ───────────────────────────────────────────────────────── + +YEARS: list[int] = [2026, 2027, 2028] # Forrester Year 1/2/3; window opens Jan 2026 +YEAR_INDEX: dict[int, int] = {y: i for i, y in enumerate(YEARS, start=1)} +X_LABELS: list[str] = ["Initial"] + [str(y) for y in YEARS] + +_MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] + + +def month_label(m: int) -> str: + """Calendar label for a 1-indexed month from Jan of YEARS[0].""" + return f"{_MONTHS[(m - 1) % 12]} {YEARS[0] + (m - 1) // 12}" + + +def by_calendar(year_values: dict[str, float]) -> dict[int, float]: + """Map Forrester's ``{"1": v, …}`` year-index keys to calendar years.""" + return {YEARS[int(k) - 1]: float(v or 0) for k, v in year_values.items()} + + +# ── Discounting primitives ─────────────────────────────────────────── + + +def discount_factor(year_index: int, discount_rate: float) -> float: + """``1 / (1 + r) ** n``. Year 0 → 1.0 (no discount).""" + if year_index < 0: + raise ValueError("year_index must be >= 0") + return 1.0 / ((1.0 + discount_rate) ** year_index) + + +def present_value(amount: float, year_index: int, discount_rate: float) -> float: + """Discount ``amount`` from end-of-year ``year_index`` to present.""" + return amount * discount_factor(year_index, discount_rate) + + +def npv(cashflows: Iterable[float], discount_rate: float, + initial: float = 0.0) -> float: + """``initial + Σ CF_n / (1 + r)^n`` — initial undiscounted (TEI).""" + return initial + sum( + present_value(float(cf), n, discount_rate) + for n, cf in enumerate(cashflows, start=1) + ) + + +def roi_pct(benefits_pv: float, costs_pv: float) -> float: + """``(Benefits − Costs) / Costs`` as a percentage; 0 when costs ≤ 0.""" + if costs_pv <= 0: + return 0.0 + return (benefits_pv - costs_pv) / costs_pv * 100.0 + + +# ── Payback ────────────────────────────────────────────────────────── + + +def payback_years(initial_cost: float, + yearly_net: Sequence[float]) -> float | None: + """ + Years until cumulative net benefits cover the initial cost, with linear + interpolation inside the crossing year. ``None`` if never reached. + """ + remaining = float(initial_cost) + if remaining <= 0: + return 0.0 + for i, cf in enumerate(yearly_net): + cf = float(cf) + if cf <= 0: + remaining += -cf # a net-loss year widens the gap + continue + if cf >= remaining: + return i + remaining / cf + remaining -= cf + return None + + +def payback_months(initial_cost: float, + yearly_net: Sequence[float]) -> float | None: + """Same as :func:`payback_years`, in months.""" + yrs = payback_years(initial_cost, yearly_net) + return yrs * 12.0 if yrs is not None else None + + +def payback_label(months: float | None) -> str: + """Human label: ``"0.7 months (~Jan 2026)"`` / ``"immediate"`` / ``"beyond 2028"``.""" + if months is None: + return f"beyond {YEARS[-1]}" + if months <= 0: + return "immediate" + return f"{months:.1f} months (~{month_label(max(1, math.ceil(months)))})" + + +# ── Risk adjustment (TEI: benefits down, costs up) ─────────────────── + + +def risk_adjust_benefit(amount: float, risk_factor: float) -> float: + """``amount × (1 − rf)``, rf clamped to [0, 1].""" + rf = max(0.0, min(1.0, float(risk_factor))) + return amount * (1.0 - rf) + + +def risk_adjust_cost(amount: float, risk_factor: float) -> float: + """``amount × (1 + rf)``, rf clamped to [0, 1].""" + rf = max(0.0, min(1.0, float(risk_factor))) + return amount * (1.0 + rf) + + +def risk_adjusted_rows(rows: list[dict], table: str) -> list[dict]: + """Deep-copied rows with the per-row risk factor applied to every value.""" + adjust = risk_adjust_benefit if table == "benefits" else risk_adjust_cost + out: list[dict] = [] + for raw in rows: + row = deepcopy(raw) + rf = float(row.get("risk_adjustment") or 0.0) + row["year_values"] = { + k: adjust(float(v or 0), rf) for k, v in row["year_values"].items() + } + if row.get("initial"): + # Only costs carry an initial; TEI adjusts it upward like the years. + row["initial"] = risk_adjust_cost(float(row["initial"]), rf) \ + if table == "costs" else float(row["initial"]) + out.append(row) + return out + + +# ── Aggregation (calendar-keyed) ───────────────────────────────────── + + +def _totals_by_year(ra_rows: list[dict]) -> dict[int, float]: + totals = {y: 0.0 for y in YEARS} + for row in ra_rows: + for y, v in by_calendar(row["year_values"]).items(): + totals[y] += v + return totals + + +def benefits_by_year(rows: list[dict]) -> dict[int, float]: + """Risk-adjusted benefit totals per calendar year.""" + return _totals_by_year(risk_adjusted_rows(rows, "benefits")) + + +def costs_by_year(rows: list[dict]) -> dict[int, float]: + """Risk-adjusted cost totals per calendar year (excludes ``initial``).""" + return _totals_by_year(risk_adjusted_rows(rows, "costs")) + + +def initial_costs(rows: list[dict]) -> float: + """Risk-adjusted Year-0 outlay (undiscounted).""" + return sum( + float(row.get("initial") or 0) + for row in risk_adjusted_rows(rows, "costs") + ) + + +# ── Composite summary ──────────────────────────────────────────────── + + +def compute_summary(benefits: list[dict], costs: list[dict], + discount_rate: float = 0.10) -> dict: + """ + The full business-case readout for one set of value rows. + + Returns KPIs (``benefits_pv``/``costs_pv``/``npv``/``roi_pct``/ + ``payback_months``/``payback_label``/``initial_costs``/nominal totals), + calendar-keyed schedules (``benefits_by_year``/``costs_by_year``/ + ``net_by_year``/``cumulative_net_by_year`` — cumulative subtracts the + initial outlay), and a per-row breakdown under ``rows``. + """ + ben_ra = risk_adjusted_rows(benefits, "benefits") + cost_ra = risk_adjusted_rows(costs, "costs") + + ben_by = _totals_by_year(ben_ra) + cost_by = _totals_by_year(cost_ra) + initial = sum(float(r.get("initial") or 0) for r in cost_ra) + + benefits_pv = npv([ben_by[y] for y in YEARS], discount_rate) + costs_pv = npv([cost_by[y] for y in YEARS], discount_rate, initial=initial) + + net_by = {y: ben_by[y] - cost_by[y] for y in YEARS} + cum, cum_by = -initial, {} + for y in YEARS: + cum += net_by[y] + cum_by[y] = cum + + pb_months = payback_months(initial, [net_by[y] for y in YEARS]) + + def _row_breakdown(ra_rows: list[dict], table: str) -> list[dict]: + out = [] + for row in ra_rows: + ra_by = by_calendar(row["year_values"]) + init_ra = float(row.get("initial") or 0) + entry = { + "field_key": row["field_key"], + "label": row["label"], + "category": row["category"], + "risk_adjustment": row["risk_adjustment"], + "ra_by_year": ra_by, + "three_yr_ra": sum(ra_by.values()), + "pv": npv([ra_by[y] for y in YEARS], discount_rate, + initial=init_ra if table == "costs" else 0.0), + } + if table == "costs": + entry["initial_ra"] = init_ra + out.append(entry) + return out + + return { + "discount_rate": discount_rate, + "benefits_pv": benefits_pv, + "costs_pv": costs_pv, + "npv": benefits_pv - costs_pv, + "roi_pct": roi_pct(benefits_pv, costs_pv), + "payback_months": pb_months, + "payback_label": payback_label(pb_months), + "initial_costs": initial, + "benefits_nominal": sum(ben_by.values()), + "costs_nominal": sum(cost_by.values()) + initial, + "benefits_by_year": ben_by, + "costs_by_year": cost_by, + "net_by_year": net_by, + "cumulative_net_by_year": cum_by, + "rows": { + "benefits": _row_breakdown(ben_ra, "benefits"), + "costs": _row_breakdown(cost_ra, "costs"), + }, + } + + +# ── Display helpers ────────────────────────────────────────────────── + + +def money(v: float) -> str: + sign, a = ("-" if v < 0 else ""), abs(v) + return f"{sign}${a/1e6:,.1f}M" if a >= 1e6 else f"{sign}${a/1e3:,.0f}K" + + +def html_money(v: float) -> str: + """Plotly text with two or more bare ``$`` triggers MathJax math mode — + annotations holding several amounts must use the HTML entity instead.""" + return money(v).replace("$", "$") diff --git a/studies/202602_TEI_Amazon_Connect/teicalc/overlay.py b/studies/202602_TEI_Amazon_Connect/teicalc/overlay.py new file mode 100644 index 0000000..e6546e0 --- /dev/null +++ b/studies/202602_TEI_Amazon_Connect/teicalc/overlay.py @@ -0,0 +1,107 @@ +""" +Client overlay — Variant 4's personalization layer. + +The verbatim anchor is Forrester's *composite organization* (2,000 agents, +20M contacts, 30% growth). This module rescales that composite to a client's +size: a 🟡 **first-order linear rescale**, answering "what does the composite +look like at your scale?", not "what is your TEI?". + +Each verbatim row is tied to the driver that dominates its derivation in the +PDF (see ``BENEFIT_DRIVERS``/``COST_DRIVERS``); rows scale linearly with +their driver, project-based costs stay fixed. The client's growth rate +re-bases the composite's Y1→Y3 trajectory (which embeds 30% YoY). + +``overlay_rows(COMPOSITE)`` is the identity — it reproduces the verbatim +numbers exactly, so headless widget defaults form the published-study +reproduction the gate expects. The anchor is never mutated: every function +deep-copies. +""" + +from __future__ import annotations + +from copy import deepcopy +from dataclasses import dataclass + +from .anchor import ASSUMPTIONS, BENEFITS_VERBATIM, COSTS_VERBATIM + + +@dataclass(frozen=True) +class ClientDrivers: + """Client inputs; defaults are the Forrester composite (identity overlay).""" + + agents_fte: int = ASSUMPTIONS["agents_fte"] # 2,000 (+200 supervisors at 10:1) + annual_contacts_y1: int = ASSUMPTIONS["annual_contacts_y1"] # 20M + growth_rate: float = ASSUMPTIONS["growth_rate"] # 0.30 YoY + discount_rate: float = ASSUMPTIONS["discount_rate"] # 0.10 + + +COMPOSITE = ClientDrivers() + + +#: 🟡 Which driver each verbatim row scales with, per its PDF derivation. +BENEFIT_DRIVERS: dict[str, str] = { + "ai_contact_resolution": "contacts", # AHT × volume → contact-driven + "ai_content_sentiment": "contacts", # per-call summaries/QA → contact-driven + "ai_forecasting_supervision": "agents", # FTE optimization + supervisor span + "data_driven_profit_lift": "contacts", # 🔴 proxy — revenue-driven in the PDF; + # outbound volume is the nearest linear driver + "legacy_solution_savings": "agents", # $/agent-month licences (supervisors follow 10:1) +} +COST_DRIVERS: dict[str, str] = { + "amazon_connect_usage": "contacts", # per-minute/per-message consumption + "implementation_migration": "fixed", # project-based — does not scale + "ongoing_management": "fixed", # small fixed team +} + + +def scale_factor(driver: str, d: ClientDrivers) -> float: + """Linear size ratio vs the composite for one driver kind.""" + if driver == "contacts": + return d.annual_contacts_y1 / ASSUMPTIONS["annual_contacts_y1"] + if driver == "agents": + return d.agents_fte / ASSUMPTIONS["agents_fte"] + if driver == "fixed": + return 1.0 + raise KeyError(f"Unknown driver: {driver!r}") + + +def growth_multiplier(year_index: int, growth_rate: float) -> float: + """ + Re-base the composite's Y1→Y3 trajectory on the client's growth. + + The verbatim year values already embed the composite's 30% YoY growth; + dividing it out and compounding the client's rate preserves the + composite's *shape* while adopting the client's slope. Year 1 → 1.0. + """ + composite_g = ASSUMPTIONS["growth_rate"] + return ((1.0 + growth_rate) / (1.0 + composite_g)) ** (year_index - 1) + + +def overlay_rows(d: ClientDrivers = COMPOSITE) -> tuple[list[dict], list[dict]]: + """ + Deep-copied (benefits, costs) rows rescaled to the client's drivers. + + Non-fixed rows: ``year_values[n] ×= scale_factor × growth_multiplier(n)``. + Fixed rows keep their year values and ``initial`` unchanged (no growth + re-base either — they are project/team costs, not volume costs). + Risk factors, labels, and notes are untouched. + """ + + def _apply(rows: list[dict], drivers: dict[str, str]) -> list[dict]: + out = [] + for raw in rows: + row = deepcopy(raw) + driver = drivers[row["field_key"]] + if driver != "fixed": + s = scale_factor(driver, d) + row["year_values"] = { + k: float(v) * s * growth_multiplier(int(k), d.growth_rate) + for k, v in row["year_values"].items() + } + if row.get("initial"): + row["initial"] = float(row["initial"]) * s + out.append(row) + return out + + return (_apply(BENEFITS_VERBATIM, BENEFIT_DRIVERS), + _apply(COSTS_VERBATIM, COST_DRIVERS)) diff --git a/studies/202602_TEI_Amazon_Connect/teicalc/scenarios.py b/studies/202602_TEI_Amazon_Connect/teicalc/scenarios.py new file mode 100644 index 0000000..48c4d36 --- /dev/null +++ b/studies/202602_TEI_Amazon_Connect/teicalc/scenarios.py @@ -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 diff --git a/studies/202602_TEI_Amazon_Connect/teicalc/staging.py b/studies/202602_TEI_Amazon_Connect/teicalc/staging.py new file mode 100644 index 0000000..2ec7bec --- /dev/null +++ b/studies/202602_TEI_Amazon_Connect/teicalc/staging.py @@ -0,0 +1,29 @@ +""" +Stage vs backstage — is this notebook render stakeholder-facing? + +The Mercury CLI (``mercury --working-dir …``) exports ``MERCURY_CONFIG_DIR`` +into the server process so the widget library can locate ``config.toml`` +(see ``mercury/config.py``); every kernel that server spawns inherits it. +JupyterLab and nbconvert kernels don't have it. That makes the variable a +reliable signal for "the audience is looking" (the stage) versus an +analyst session or a headless export run (backstage). + +Diagnostics routed through :func:`backstage` stay visible in JupyterLab +and land in the nbconvert exports (where the machine-readable appendix +must appear for LLM consumption) but never render in the Mercury app. +""" + +from __future__ import annotations + +import os + + +def on_stage() -> bool: + """True when running under the Mercury app (stakeholder-facing).""" + return os.getenv("MERCURY_CONFIG_DIR") is not None + + +def backstage(*args, **kwargs) -> None: + """``print`` that renders only backstage (JupyterLab, nbconvert).""" + if not on_stage(): + print(*args, **kwargs) diff --git a/studies/202602_TEI_Amazon_Connect/tests/conftest.py b/studies/202602_TEI_Amazon_Connect/tests/conftest.py new file mode 100644 index 0000000..c743302 --- /dev/null +++ b/studies/202602_TEI_Amazon_Connect/tests/conftest.py @@ -0,0 +1,7 @@ +"""Make teicalc importable even without the study venv active (the normal +setup is ``pip install -e ".[dev]"`` into the study-local ``.venv/``).""" + +import pathlib +import sys + +sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent.parent)) diff --git a/studies/202602_TEI_Amazon_Connect/tests/test_anchor.py b/studies/202602_TEI_Amazon_Connect/tests/test_anchor.py new file mode 100644 index 0000000..7f8f389 --- /dev/null +++ b/studies/202602_TEI_Amazon_Connect/tests/test_anchor.py @@ -0,0 +1,95 @@ +"""The verbatim anchor is Forrester's published record — pinned value by +value, and proven immutable under every engine code path.""" + +from copy import deepcopy + +from teicalc import ( + ASSUMPTIONS, + BENEFITS_VERBATIM, + COMPOSITE, + COSTS_VERBATIM, + PUBLISHED, + ClientDrivers, + apply_scenario, + compute_summary, + overlay_rows, +) + + +def _row(rows, key): + return next(r for r in rows if r["field_key"] == key) + + +def test_benefit_rows_verbatim(): + assert [r["field_key"] for r in BENEFITS_VERBATIM] == [ + "ai_contact_resolution", + "ai_content_sentiment", + "ai_forecasting_supervision", + "data_driven_profit_lift", + "legacy_solution_savings", + ] + expected = { + "ai_contact_resolution": ({"1": 13_911_040, "2": 23_932_480, "3": 37_797_760}, 0.15), + "ai_content_sentiment": ({"1": 4_586_620, "2": 5_358_412, "3": 6_291_680}, 0.15), + "ai_forecasting_supervision": ({"1": 6_651_680, "2": 9_133_760, "3": 12_391_712}, 0.15), + "data_driven_profit_lift": ({"1": 1_200_000, "2": 1_560_000, "3": 2_028_000}, 0.20), + "legacy_solution_savings": ({"1": 6_177_600, "2": 8_030_880, "3": 10_440_144}, 0.20), + } + for key, (years, rf) in expected.items(): + row = _row(BENEFITS_VERBATIM, key) + assert row["year_values"] == years + assert row["risk_adjustment"] == rf + assert row["table"] == "benefits" + + +def test_cost_rows_verbatim(): + expected = { + "amazon_connect_usage": ({"1": 6_456_448, "2": 7_951_164, "3": 9_832_961}, 0.05, 0), + "implementation_migration": ({"1": 188_333, "2": 188_333, "3": 0}, 0.10, 1_087_500), + "ongoing_management": ({"1": 256_200, "2": 187_200, "3": 187_200}, 0.15, 0), + } + for key, (years, rf, initial) in expected.items(): + row = _row(COSTS_VERBATIM, key) + assert row["year_values"] == years + assert row["risk_adjustment"] == rf + assert row["initial"] == initial + assert row["table"] == "costs" + + +def test_assumptions_and_published(): + assert ASSUMPTIONS["agents_fte"] == 2_000 + assert ASSUMPTIONS["supervisors_fte"] == 200 + assert ASSUMPTIONS["annual_contacts_y1"] == 20_000_000 + assert ASSUMPTIONS["growth_rate"] == 0.30 + assert ASSUMPTIONS["discount_rate"] == 0.10 + assert ASSUMPTIONS["analysis_years"] == 3 + + assert PUBLISHED["benefits_pv"] == 101_696_791 + assert PUBLISHED["costs_pv"] == 22_983_076 + assert PUBLISHED["npv"] == 78_713_715 + assert PUBLISHED["roi_pct"] == 342 + assert PUBLISHED["payback_months_max"] == 6 + + # The composite drivers ARE the anchor assumptions. + assert COMPOSITE.agents_fte == ASSUMPTIONS["agents_fte"] + assert COMPOSITE.annual_contacts_y1 == ASSUMPTIONS["annual_contacts_y1"] + assert COMPOSITE.growth_rate == ASSUMPTIONS["growth_rate"] + assert COMPOSITE.discount_rate == ASSUMPTIONS["discount_rate"] + + +def test_anchor_is_never_mutated(): + """Exercise every engine code path, then prove the record unchanged.""" + ben_snap = deepcopy(BENEFITS_VERBATIM) + cost_snap = deepcopy(COSTS_VERBATIM) + + overlay_rows() + overlay_rows(ClientDrivers(agents_fte=137, annual_contacts_y1=1_000_000, + growth_rate=0.0)) + for scenario in ("conservative", "moderate", "aggressive"): + apply_scenario(BENEFITS_VERBATIM, scenario) + apply_scenario(COSTS_VERBATIM, scenario) + compute_summary(BENEFITS_VERBATIM, COSTS_VERBATIM, 0.10) + compute_summary(BENEFITS_VERBATIM, COSTS_VERBATIM, 0.08) + + assert BENEFITS_VERBATIM == ben_snap + assert COSTS_VERBATIM == cost_snap diff --git a/studies/202602_TEI_Amazon_Connect/tests/test_model.py b/studies/202602_TEI_Amazon_Connect/tests/test_model.py new file mode 100644 index 0000000..cf5a089 --- /dev/null +++ b/studies/202602_TEI_Amazon_Connect/tests/test_model.py @@ -0,0 +1,123 @@ +"""Engine pins — every number hand-checked before pinning. + +RA_benefit = v×(1−rf), 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) diff --git a/studies/202602_TEI_Amazon_Connect/tests/test_overlay.py b/studies/202602_TEI_Amazon_Connect/tests/test_overlay.py new file mode 100644 index 0000000..5f9a410 --- /dev/null +++ b/studies/202602_TEI_Amazon_Connect/tests/test_overlay.py @@ -0,0 +1,96 @@ +"""Client-overlay pins — identity at the composite, linear per-driver +scaling, growth re-basing, and copy semantics.""" + +import dataclasses + +import pytest + +from teicalc import ( + BENEFIT_DRIVERS, + BENEFITS_VERBATIM, + COMPOSITE, + COST_DRIVERS, + COSTS_VERBATIM, + ClientDrivers, + compute_summary, + growth_multiplier, + overlay_rows, + scale_factor, +) + + +def _row(rows, key): + return next(r for r in rows if r["field_key"] == key) + + +def test_identity_at_composite(): + """overlay_rows(COMPOSITE) reproduces the verbatim study to the cent.""" + ob, oc = overlay_rows(COMPOSITE) + got = compute_summary(ob, oc, 0.10) + want = compute_summary(BENEFITS_VERBATIM, COSTS_VERBATIM, 0.10) + assert got["benefits_pv"] == pytest.approx(want["benefits_pv"], abs=0.01) + assert got["costs_pv"] == pytest.approx(want["costs_pv"], abs=0.01) + assert got["npv"] == pytest.approx(want["npv"], abs=0.01) + + +def test_driver_map_covers_every_row(): + assert set(BENEFIT_DRIVERS) == {r["field_key"] for r in BENEFITS_VERBATIM} + assert set(COST_DRIVERS) == {r["field_key"] for r in COSTS_VERBATIM} + + +def test_scale_factor(): + d = ClientDrivers(agents_fte=1_000, annual_contacts_y1=40_000_000) + assert scale_factor("agents", d) == pytest.approx(0.5) + assert scale_factor("contacts", d) == pytest.approx(2.0) + assert scale_factor("fixed", d) == 1.0 + with pytest.raises(KeyError): + scale_factor("revenue", d) + + +def test_half_agents_halves_agent_rows_only(): + ob, oc = overlay_rows(ClientDrivers(agents_fte=1_000)) + assert _row(ob, "ai_forecasting_supervision")["year_values"]["1"] == \ + pytest.approx(6_651_680 / 2) + assert _row(ob, "legacy_solution_savings")["year_values"]["1"] == \ + pytest.approx(6_177_600 / 2) + # Contact-driven and fixed rows unmoved. + assert _row(ob, "ai_contact_resolution")["year_values"]["1"] == \ + pytest.approx(13_911_040) + assert _row(oc, "amazon_connect_usage")["year_values"]["1"] == \ + pytest.approx(6_456_448) + assert _row(oc, "implementation_migration")["initial"] == 1_087_500 + + +def test_double_contacts_doubles_usage_only(): + _, oc = overlay_rows(ClientDrivers(annual_contacts_y1=40_000_000)) + assert _row(oc, "amazon_connect_usage")["year_values"]["1"] == \ + pytest.approx(6_456_448 * 2) + assert _row(oc, "implementation_migration")["year_values"]["1"] == \ + pytest.approx(188_333) + assert _row(oc, "ongoing_management")["year_values"]["1"] == \ + pytest.approx(256_200) + + +def test_growth_rebase(): + assert growth_multiplier(1, 0.0) == 1.0 # Y1 always 1.0 + assert growth_multiplier(2, 0.0) == pytest.approx(1 / 1.3) + assert growth_multiplier(3, 0.0) == pytest.approx((1 / 1.3) ** 2) + assert growth_multiplier(3, 0.30) == 1.0 # composite growth = identity + + ob, oc = overlay_rows(ClientDrivers(growth_rate=0.0)) + row = _row(ob, "ai_contact_resolution") + assert row["year_values"]["1"] == pytest.approx(13_911_040) + assert row["year_values"]["2"] == pytest.approx(23_932_480 / 1.3) + assert row["year_values"]["3"] == pytest.approx(37_797_760 / 1.3**2) + # Fixed rows ignore the growth re-base too. + assert _row(oc, "ongoing_management")["year_values"]["2"] == pytest.approx(187_200) + + +def test_drivers_frozen_and_rows_are_copies(): + with pytest.raises(dataclasses.FrozenInstanceError): + COMPOSITE.agents_fte = 1 # type: ignore[misc] + ob, oc = overlay_rows(COMPOSITE) + ob[0]["year_values"]["1"] = -1 + oc[0]["year_values"]["1"] = -1 + assert BENEFITS_VERBATIM[0]["year_values"]["1"] == 13_911_040 + assert COSTS_VERBATIM[0]["year_values"]["1"] == 6_456_448 diff --git a/studies/202602_TEI_Amazon_Connect/tests/test_scenarios.py b/studies/202602_TEI_Amazon_Connect/tests/test_scenarios.py new file mode 100644 index 0000000..e5bbfea --- /dev/null +++ b/studies/202602_TEI_Amazon_Connect/tests/test_scenarios.py @@ -0,0 +1,75 @@ +"""Scenario pins — hand-checked composite results per scenario, clamp +behaviour, and copy semantics.""" + +import pytest + +from teicalc import ( + BENEFITS_VERBATIM, + COSTS_VERBATIM, + SCENARIOS, + apply_scenario, + compute_summary, +) + + +def _summary(scenario): + return compute_summary( + apply_scenario(BENEFITS_VERBATIM, scenario), + apply_scenario(COSTS_VERBATIM, scenario), + 0.10, + ) + + +def test_scenario_definitions(): + assert SCENARIOS == { + "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 test_moderate_is_identity(): + got = _summary("moderate") + want = compute_summary(BENEFITS_VERBATIM, COSTS_VERBATIM, 0.10) + assert got["benefits_pv"] == pytest.approx(want["benefits_pv"], abs=0.01) + assert got["costs_pv"] == pytest.approx(want["costs_pv"], abs=0.01) + + +def test_conservative_pins(): + s = _summary("conservative") + assert s["benefits_pv"] == pytest.approx(71_672_867.65, abs=1) + assert s["costs_pv"] == pytest.approx(17_437_916.34, abs=1) + assert s["npv"] == pytest.approx(54_234_951.31, abs=1) + assert s["roi_pct"] == pytest.approx(311.02, abs=0.01) + assert s["payback_months"] == pytest.approx(0.763, abs=0.001) + + +def test_aggressive_pins(): + s = _summary("aggressive") + assert s["benefits_pv"] == pytest.approx(123_911_705.40, abs=1) + assert s["costs_pv"] == pytest.approx(27_682_368.61, abs=1) + assert s["npv"] == pytest.approx(96_229_336.79, abs=1) + assert s["roi_pct"] == pytest.approx(347.62, abs=0.01) + assert s["payback_months"] == pytest.approx(0.705, abs=0.001) + + +def test_risk_delta_clamps_at_zero(): + """Conservative subtracts 0.10 from cost risk; usage (0.05) clamps to 0.""" + rows = apply_scenario(COSTS_VERBATIM, "conservative") + usage = next(r for r in rows if r["field_key"] == "amazon_connect_usage") + assert usage["risk_adjustment"] == 0.0 + impl = next(r for r in rows if r["field_key"] == "implementation_migration") + assert impl["risk_adjustment"] == pytest.approx(0.0) # 0.10 − 0.10 + assert impl["initial"] == pytest.approx(1_087_500 * 0.80) # adoption scales initial + + +def test_unknown_scenario_raises(): + with pytest.raises(KeyError): + apply_scenario(BENEFITS_VERBATIM, "wildly_optimistic") + + +def test_inputs_not_mutated(): + apply_scenario(BENEFITS_VERBATIM, "aggressive") + apply_scenario(COSTS_VERBATIM, "conservative") + assert BENEFITS_VERBATIM[0]["year_values"]["1"] == 13_911_040 + assert COSTS_VERBATIM[1]["initial"] == 1_087_500 diff --git a/studies/202602_TEI_Amazon_Connect/tests/test_staging.py b/studies/202602_TEI_Amazon_Connect/tests/test_staging.py new file mode 100644 index 0000000..1254fe8 --- /dev/null +++ b/studies/202602_TEI_Amazon_Connect/tests/test_staging.py @@ -0,0 +1,15 @@ +"""Stage/backstage detection — Mercury kernels carry MERCURY_CONFIG_DIR.""" + +from teicalc import staging + + +def test_backstage_prints_only_off_stage(monkeypatch, capsys): + monkeypatch.delenv("MERCURY_CONFIG_DIR", raising=False) + assert not staging.on_stage() + staging.backstage("visible") + assert capsys.readouterr().out == "visible\n" + + monkeypatch.setenv("MERCURY_CONFIG_DIR", "/tmp/app") + assert staging.on_stage() + staging.backstage("hidden") + assert capsys.readouterr().out == "" diff --git a/template/MercuryNotebook/README.md b/template/MercuryNotebook/README.md index e5e2383..5ce9439 100644 --- a/template/MercuryNotebook/README.md +++ b/template/MercuryNotebook/README.md @@ -44,4 +44,4 @@ pyproject.toml # full toolchain as core deps — no requirements.txt ``` Reference implementation (a full multi-notebook study): -`studies/202512_GenesysCX/ctm-token-calculator/`. +`studies/202607_CTM_GenesysCX/`. diff --git a/tests/conftest.py b/tests/conftest.py index f127dbf..ca51470 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -22,11 +22,16 @@ def _env(monkeypatch): @pytest.fixture def amazon_connect_seed(): - """Load the Amazon Connect study's seed data.""" - sys.path.insert(0, str(ROOT / "studies" / "202602_AmazonConnect")) + """Load the Amazon Connect study's verbatim anchor (post-migration the + study is self-contained; teicalc is stdlib-only, so importing it here + needs no study venv — the row shape matches the old seed_data).""" + from types import SimpleNamespace + + sys.path.insert(0, str(ROOT / "studies" / "202602_TEI_Amazon_Connect")) try: - import seed_data # type: ignore[import-not-found] - return seed_data + from teicalc import anchor # type: ignore[import-not-found] + return SimpleNamespace(BENEFITS=anchor.BENEFITS_VERBATIM, + COSTS=anchor.COSTS_VERBATIM) finally: # Leave the path alone — many tests will use the seed pass diff --git a/tests/test_export.py b/tests/test_export.py index 11ac922..15926ab 100644 --- a/tests/test_export.py +++ b/tests/test_export.py @@ -65,7 +65,7 @@ class TestBuildReportData: def test_envelope_shape(self, amazon_connect_seed): client = self._stub_client(amazon_connect_seed) - env = build_report_data(client, "pid", study_slug="202602_AmazonConnect") + env = build_report_data(client, "pid", study_slug="202602_TEI_Amazon_Connect") assert set(env) >= { "metadata", "report", @@ -75,7 +75,7 @@ class TestBuildReportData: "athena_export", "scenarios", } - assert env["metadata"]["study_slug"] == "202602_AmazonConnect" + assert env["metadata"]["study_slug"] == "202602_TEI_Amazon_Connect" assert env["metadata"]["proposal"] == 7 assert env["values"]["benefits"] assert env["values"]["costs"]