feat: add master notebook library scaffolding and review tooling

Add CLAUDE.md defining the Palladium master notebook conventions and
Red Panda Approval criteria, plus a review-notebook slash command for
LLM-driven notebook review.

Expand .gitignore to block client/engagement documents and generated
exports, keeping masters client-clean while allowing text/image sources.

Normalize slider widget numeric values from floats to integers in
notebook JSON.
This commit is contained in:
2026-07-31 16:16:07 +00:00
parent 53c069fddb
commit a967f73d09
61 changed files with 4881 additions and 4257 deletions

508
README.md
View File

@@ -1,425 +1,139 @@
# Palladium
**TEI (Total Economic Impact) Calculator** — The strategic artifact that protects the business case.
**A library of master notebooks for consulting delivery** — workshop instruments and
business-case studies, built as Mercury-served Jupyter deliverables.
Palladium is a Jupyter-notebook toolkit for building Total Economic Impact analyses. Each study is a self-contained Mercury-served notebook deliverable (math in a study package, verification gate, LLM-readable exports); a small shared `core/` talks to [Athena](https://athena.nttdata.com) for client/opportunity context and server-side TEI tooling.
> *In Greek mythology, the Palladium was a sacred artifact of Athena that protected
> Troy. Whoever possessed it held strategic advantage. In our ecosystem, Palladium
> protects the deal — transforming discovery inputs into a case no CFO can ignore.*
> *In Greek mythology, the Palladium was a sacred artifact of Athena that protected Troy. Whoever possessed it held strategic advantage. In our ecosystem, Palladium protects the deal — transforming discovery inputs into a financial case no CFO can ignore.*
Every master obeys one **three-layer contract** (the always-on rules live in
[`CLAUDE.md`](CLAUDE.md)):
## Architecture
- **Mercury** is the polished, client-facing interface — the screen you share in a
workshop, remote or in person.
- **Jupyter notebook cells** are the consultant's interface — workshop **content**
and **client data** are edited in tagged cells, never in `.py` files.
- **Python modules** hold reusable logic and calculations worth calling as a module,
typed and covered by validation tests.
```
┌──────────────────────────────────────────────────────────────────┐
│ Palladium │
│ │
│ studies/YYYYMM_TEI_Vendor_Product/ ← self-contained study │
│ studies/YYYYMM_Client_EngagementName/ (own venv + engine) │
│ ├─ <studylib>/ ← ALL math, verbatim anchors │
│ ├─ notebooks/ ← THE deliverable (Mercury-served) │
│ ├─ tests/ ← pinned acceptance numbers │
│ └─ exports/ ← .html/.md + JSON appendix (for LLMs, │
│ and the Athena repository roadmap) │
│ │
│ core/ ← shared Athena toolkit (studies do NOT import it) │
│ tei_client → ──────────────────────────► Athena API │
│ calculations · export · cli · bootstrap │
└──────────────────────────────────────────────────────────────────┘
```
## Taxonomy
### Components
| Kind | What it is | Naming | Lives |
|---|---|---|---|
| **Study** | Reproduction of a dated base document (Forrester TEI or similar), personalized as an overlay | `YYYYMM_TEI_Vendor_Product` / `YYYYMM_Client_Engagement` (dated) | `studies/` |
| **Assessment** | Reusable workshop instrument (discovery workshop, diagnostic) | `Instrument_Name` (undated, living) | `assessments/` |
| **Engagement copy** | A master copied out for a client engagement — acquires client data, becomes **confidential** | `YYYYMM_Client_Instrument`, stamped at copy-time | **outside this repo** |
| Component | Purpose |
|-----------|---------|
| **`studies/`** | One self-contained folder per engagement — own venv, engine package, Mercury notebook, tests, exports |
| **`template/`** | Copy-me study scaffold — start here for new studies |
| **`core/tei_client`** | Python API client for Athena's TEI endpoints |
| **`core/calculations`** | Financial logic — NPV, ROI, payback, risk adjustment, scenarios |
| **`core/export`** | Builds the structured JSON envelope consumed by the report pipeline |
| **`core/cli`** | `python -m palladium` command-line interface |
Masters in this repo stay **client-clean**: placeholder engagement data, published or
synthetic numbers, nothing a client said. Patterns:
[Assessment](docs/Assessment_Pattern_V1-00.md) ·
[Study](docs/Study_Pattern_V1-00.md) ·
[shared Mercury mechanics](docs/Mercury_Notebook_Pattern_V1-00.md).
> **All studies follow the [Mercury Notebook Deliverable Pattern](docs/Mercury_Notebook_Pattern_V1-00.md)**:
> the notebook *is* the artifact — self-contained study package, Mercury-served,
> gate-verified, LLM-exportable. Start from [`template/MercuryNotebook/`](template/MercuryNotebook/).
> The Streamlit `app/` and `core/notebook_helpers` were retired when the last
> legacy study migrated (git history keeps them).
---
## Quick Start — Jupyter Lab first
Palladium is a **Jupyter Lab-first** environment. Everything starts from a
notebook; the CLI is a companion, not a prerequisite.
```bash
git clone https://github.com/nttdata/palladium.git
cd palladium
make setup # venv + deps + editable install (one time)
make lab # launches Jupyter Lab
```
Then open **`00_setup.ipynb`** at the repo root. It will:
1. Prompt for your Athena API key (hidden input) and save it to `.env`
2. Test the connection
3. Show what report templates and tools exist in the instance
Current target instance: **https://athena.ouranos.helu.ca** (Ouranos sandbox —
no production data, safe to experiment).
From any root-level notebook, the Athena connection is one import (pattern
studies are self-contained and never import `core`):
```python
from core.bootstrap import init
pal = init() # loads .env, builds client, tests it
pal.client.list_reports()
```
### Configuration
All credentials and IDs live in `<repo>/.env` (gitignored). `00_setup.ipynb`
writes it for you; to do it by hand:
```bash
# .env
ATHENA_BASE_URL=https://athena.ouranos.helu.ca
ATHENA_API_KEY=your-api-key-here
```
### Verify Connection
In a notebook: `init()` prints the connection status. From a shell:
```bash
python -m palladium test
```
---
## Usage
### Run a study end-to-end
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
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
```
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.
`studies/202512_TEI_Genesys_CX_Cloud/` follows the same shape (**NPV $10.8M
• ROI 266%**), with one signature input: the Genesys AI Experience token
line the published study models at $0, priced live from the client's quote.
`studies/202607_CTM_GenesysCX/` is the full multi-notebook reference
implementation.
### CLI
```bash
# Test connection
python -m palladium test
# List TEI tool instances
python -m palladium list
# List available report templates
python -m palladium reports
# Show financial summary for a tool
python -m palladium summary <public_id>
# Trigger server-side recalculation
python -m palladium calculate <public_id>
# Export for the report pipeline
python -m palladium export <public_id> -o export.json
```
### Tests
```bash
pytest tests/ -v
```
The root suite covers the API client (mocked HTTP), the financial math, and
the export envelope shape; the Amazon Connect verbatim anchor is asserted
against the published Forrester totals. Each study additionally carries its
own pinned suite (`cd studies/<slug> && pytest`).
---
## Adding a new study
Copy the template, not an existing study:
```bash
cp -r template/MercuryNotebook studies/YYYYMM_TEI_Vendor_Product
```
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.
---
## TEI Methodology
Palladium implements the Forrester TEI™ framework.
### Benefit Categories
Benefits are quantified across categories, risk-adjusted, and discounted to present value:
| Category | Examples |
|----------|----------|
| **Cost Savings** | Legacy license elimination, reduced headcount, lower telecom |
| **Productivity** | Reduced handle time, faster training, automated QA |
| **Revenue** | Improved retention, better conversion, new channel revenue |
| **Risk Reduction** | Compliance automation, reduced legal exposure, audit readiness |
### Risk Adjustment
Each benefit carries a risk-adjustment factor (050%) reflecting implementation uncertainty.
A 20% risk adjustment on a $10M benefit yields a risk-adjusted value of $8M.
**Costs** are risk-adjusted **upward** by the same factor (higher risk → higher modelled cost).
### Financial Metrics
| Metric | Description |
|--------|-------------|
| **NPV** | Net Present Value — total risk-adjusted benefits minus costs, discounted |
| **ROI** | Return on Investment — `(benefits costs) / costs × 100` |
| **Payback** | Months until cumulative benefits exceed cumulative costs |
The initial investment (year 0) is **not** discounted. Year-N cashflows are
discounted at the end of the year: `PV = CF_n / (1 + r)^n`. This matches
the Forrester methodology used in the published studies.
### Scenario Analysis
Three scenarios model uncertainty in adoption and realization
(see `core.calculations.SCENARIOS`):
| Scenario | Adoption | Risk delta | Effect |
|----------|----------|------------|--------|
| Conservative | 80% | +10pp on benefits | Lower benefits, higher modelled cost |
| Moderate | 100% | 0 | Base case (= published study) |
| Aggressive | 115% | 5pp on benefits | Higher benefits, lower padding on cost |
---
## Project Structure
## Repository layout
```
palladium/
├── 00_setup.ipynb # ← START HERE: credentials + connection
├── Makefile # make setup / lab / test
├── core/ # Shared, study-agnostic Python package
── bootstrap.py # one-import notebook setup (init, save_credentials)
│ ├── tei_client/ # Athena API client
│ ├── client.py # TEIClient with all /api/v1/tei/ methods
│ └── models.py # Optional dataclasses for typed access
── calculations/ # Pure-python financial math
├── npv.py
├── roi.py
├── payback.py
│ │ └── scenarios.py
│ ├── export/
└── report_data.py # JSON envelope for the report pipeline
│ └── cli/
│ └── main.py # `python -m palladium ...`
├── palladium/ # CLI shim (just exposes `python -m palladium`)
│ └── __main__.py
├── template/
│ └── MercuryNotebook/ # copy-me pattern scaffold (runnable)
├── studies/ # One self-contained folder per engagement
│ ├── 202512_TEI_Genesys_CX_Cloud/ # CX Cloud TEI — pattern Variant 4
│ │ ├── README.md # NPV $10.8M · ROI 266% + the $0 AI-token line
│ │ ├── teicalc/ # self-contained engine (anchor/model/overlay)
│ │ ├── notebooks/business_case.ipynb
│ │ ├── tests/ · scripts/ · config.toml · pyproject.toml
│ │ └── docs/ # Forrester PDF + Genesys token-metering notes
│ ├── 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/ # root tests for core/
│ ├── test_client.py
│ ├── test_calculations.py
│ └── test_export.py
├── Athena API.yaml # OpenAPI reference
├── .env.example
├── requirements.txt
├── pyproject.toml
└── README.md
├── CLAUDE.md # the always-on contract (rubric, layers, risk tiers)
├── assessments/
│ ├── CX_Discovery_Workshop/ # ★ reference implementation (notebook-first model)
── CX_AI_Diagnostic/ # capability diagnostic (pre-redesign: generated notebook)
├── studies/
│ ├── 202512_TEI_Genesys_CX_Cloud/ # Forrester TEI reproduction — NPV $10.8M · ROI 266%
├── 202602_TEI_Amazon_Connect/ # Forrester TEI reproduction — NPV $78.7M · ROI 342%
── 202607_CTM_GenesysCX/ # client engagement study (grandfathered — see CLAUDE.md)
├── template/MercuryNotebook/ # copy-me scaffold (py-engine model; see "Adding a master")
├── docs/ # the pattern docs, brand.md, review prompt, Athena reference
├── core/ # shared Athena toolkit (masters do NOT import it)
├── tests/ # core tests + the notebook structural suite (all masters)
├── 00_setup.ipynb # Athena credentials + connection (core layer)
└── Makefile # make setup / lab / test / check-notebooks
```
---
Each master is **self-contained**: its own engine package, venv, tests, Mercury
config, and export script — a copy of the directory runs standalone.
## Athena Integration
Palladium connects to Athena's TEI module for data persistence and cross-tool reporting.
### API Endpoints Used
All endpoints are under `/api/v1/tei/` and require `Authorization: Api-Key {key}`.
| Endpoint | Purpose |
|----------|---------|
| `GET /api/v1/tei/reports/` | List available TEI report templates |
| `GET /api/v1/tei/reports/{public_id}/` | Get a report template |
| `GET /api/v1/tei/reports/{public_id}/fields/` | Get field definitions for a template |
| `POST /api/v1/tei/tools/` | Create a new TEI tool instance |
| `GET /api/v1/tei/tools/{public_id}/` | Get instance metadata |
| `PATCH /api/v1/tei/tools/{public_id}/` | Update name/status |
| `GET /api/v1/tei/tools/{public_id}/values/` | Get current field values |
| `PUT /api/v1/tei/tools/{public_id}/values/` | Bulk-update values |
| `PATCH /api/v1/tei/tools/{public_id}/values/{field_key}/` | Patch a single value |
| `POST /api/v1/tei/tools/{public_id}/calculate/` | Trigger calculation |
| `GET /api/v1/tei/tools/{public_id}/summary/` | Get financial summary |
| `GET /api/v1/tei/tools/{public_id}/versions/` | List version snapshots |
| `POST /api/v1/tei/tools/{public_id}/versions/` | Save a new version |
| `GET /api/v1/tei/tools/{public_id}/versions/{n}/` | Get a specific version |
| `GET /api/v1/tei/tools/{public_id}/export/` | Export for the report pipeline |
| `GET /api/v1/tei/summary/` | Aggregate NPV across all tools |
### Object model
| Athena object | Notes |
|---|---|
| **Opportunity** | Top-level sales record. Owns one or more **Proposals**. |
| **Proposal** | A specific bid/offer to a client. **A TEI tool is linked to a Proposal.** |
| **Engagement** | Optional — for active client engagements. A TEI tool may also link here. |
| **TEIReport** | Template (e.g. *Amazon Connect 2026*) — defines fields, discount rate, analysis horizon. |
| **TEITool** | Instance of a Report bound to a Proposal — holds values, summaries, versions. |
### Authentication
```
Authorization: Api-Key {your-api-key}
```
API keys are provisioned in Athena's admin interface per user/service account.
### Methodology conventions (Palladium ↔ Athena)
Two places where the Forrester methodology and the Athena TEI API differ, and
how Palladium bridges them:
| Topic | Athena behaviour | Palladium convention |
|---|---|---|
| **Cost risk adjustment** | Costs are never risk-adjusted server-side | Cost values are pushed pre-multiplied by `(1 + risk_adj)`; field-level adjustment stays 0 |
| **Year-0 "Initial" costs** | No year-0 concept; non-annual values are folded into Year 1 | Each cost gets a companion non-annual `<key>_initial` field. `TEIClient` folds them back into an `initial` key on read. Athena discounts these as Year 1 (Forrester doesn't discount Year 0) — expect ≈0.15% drift on cost PV |
---
## Report Pipeline Integration
Palladium's export produces structured JSON consumed by the LLM report generation pipeline:
```
Palladium Export (JSON)
Peitho — LLM generates HTML (following HTML_DOCUMENT_FORMAT.md)
html2docx converts to native Word
Professional TEI Report (.docx)
```
The export envelope (`core.export.build_report_data`) includes:
- All benefit categories with risk-adjusted values
- All cost categories with yearly breakdown (and Initial column)
- Financial summary (NPV, ROI, payback, yearly cashflow)
- Conservative / moderate / aggressive scenario analysis
- Metadata (study slug, proposal, engagement, generator stamp)
- The raw Athena `/export/` payload for reference
---
## Version Management
Athena keeps version history for TEI tools, driven through the API
(`core.tei_client`: `save_version` / `list_versions` / `get_version`):
1. **Save Version** — Snapshots current values + summary with a descriptive note
2. **View History** — All versions with headline metrics (NPV, ROI)
3. **Compare Versions** — Side-by-side diff of value changes between any two versions
4. **Restore Version** — Load a previous version's values as the current state
Version notes should capture:
- Assumptions made and their sources
- Which scenario the version represents
- What changed since the previous version
- Client confirmations or corrections
---
## Development
### Running Tests
## Quick start — run a master
```bash
pytest tests/ -v
git clone ssh://git@git.helu.ca:22022/r/palladium.git && cd palladium
cd assessments/CX_Discovery_Workshop
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
mercury --working-dir . # the stage — share this screen with the client
jupyter lab # backstage — edit content/data cells, see the script
pytest # content + engagement + engine pins
python scripts/export_report.py # exports/*.html + LLM-ready *.md
```
Tests are designed to run without an Athena connection — HTTP is mocked
and the calculation suite uses the Amazon Connect seed data to verify the
Forrester numbers reproduce within rounding.
Every master's README carries its own specifics; the commands are the same shape in
all of them.
### Code Style
## Client engagements — copy out, never in place
A master never touches client data. To run one for a client (full checklist in the
[Assessment Pattern](docs/Assessment_Pattern_V1-00.md)):
1. **Copy** the master directory out of Palladium to your engagement location.
2. **Rename** it `YYYYMM_Client_Instrument` (e.g. `202608_Acme_CX_Discovery`).
3. **Provision** a fresh venv there (`pip install -e ".[dev]"` — copied venvs are broken).
4. **Fill the `engagement-data` cell** with the client facts.
5. **Verify**`pytest` + the headless gate stay green by design.
The copy is now **confidential**: it lives with the engagement, never merges back.
Improvements found on engagements are hand-carried to the master as clean edits.
`.gitignore` blocks client documents repo-wide — see `CLAUDE.md` § Confidentiality.
## Validation
Two mechanisms guard every master:
**Deterministic** — per master (in its venv): engine pins, content pins read from the
notebook's tagged cells, the stage/backstage test, and the in-notebook verification
gate under headless `nbconvert --execute`. Repo-wide (root venv):
`make check-notebooks` runs the kernel-free structural suite over every committed
notebook — parses, cleanly executed, tag taxonomy present ([tests/nbcheck.py](tests/nbcheck.py)
classifies every notebook; grandfathered ones skip with a recorded reason).
**LLM review** — [`docs/Notebook_Review_Prompt_V1-00.md`](docs/Notebook_Review_Prompt_V1-00.md)
hunts what deterministic checks can't: content oddities, cross-cell rot, stale
numbers, stage leakage. Run it in-repo with `/review-notebook <path>` (Claude Code),
or paste the prompt into any LLM alongside the `.ipynb` JSON.
## Adding a new master
For an **Assessment**, start from the reference implementation and its pattern doc —
`assessments/CX_Discovery_Workshop/` + [Assessment Pattern](docs/Assessment_Pattern_V1-00.md).
For a **Study**, copy `template/MercuryNotebook/` and follow the
[Study Pattern](docs/Study_Pattern_V1-00.md) (note: the template still encodes the
py-engine model; its notebook-first rework is a recorded follow-up). Either way:
underscores in names (never dashes — directories are Python packages), and register
the new notebook in [tests/nbcheck.py](tests/nbcheck.py) — the completeness test
fails until you classify it.
## Athena / core (the TEI toolkit)
The `core/` package talks to [Athena](https://athena.nttdata.com) for
client/opportunity context and server-side TEI tooling — masters do **not** import
it. Start at **`00_setup.ipynb`** (`make setup && make lab`): it prompts for the API
key, writes `.env`, and tests the connection (current target:
`https://athena.ouranos.helu.ca`, the Ouranos sandbox).
```bash
ruff check .
ruff format .
python -m palladium test | list | reports | summary <id> | calculate <id> | export <id> -o export.json
```
### Adding a New Benefit Category
The export JSON feeds the report pipeline: **Palladium → Peitho (LLM → HTML) →
html2docx → .docx**. Full API reference, object model, calculation logic, and the
Palladium↔Athena methodology bridges: [`docs/Athena_TEI.md`](docs/Athena_TEI.md) +
[`docs/Athena API.yaml`](docs/Athena%20API.yaml). Root tests (`make test`) cover the
client (mocked HTTP), the financial math, the export envelope — and the notebook
structural suite.
1. Define the field in Athena's TEI Report admin (field name, type, category, defaults)
2. The field automatically appears in Palladium via the API — no client changes
3. Update notebook prose if category-specific commentary is needed
4. If the report template exposes a new structure, extend the envelope in
`core/export/report_data.py`
---
## Dependencies
| Package | Version | Purpose |
|---------|---------|---------|
| `requests` | ≥2.31 | HTTP client for Athena API |
| `python-dotenv` | ≥1.0 | Environment configuration |
| `jupyter` | ≥1.0 | Notebook environment |
| `pandas` | ≥2.0 | Data manipulation |
| `plotly` | ≥5.18 | Interactive visualizations |
| `numpy` | ≥1.26 | Financial calculations |
| `pytest` | ≥7.4 | Testing |
| `ruff` | ≥0.1 | Linting and formatting |
---
## Related Projects
## Related projects
| Project | Relationship |
|---------|-------------|