fix base costs and import backstage in ctm notebook
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -106,3 +106,10 @@ def test_case_flows_and_kpis():
|
|||||||
inc2 = {y: -1.0 for y in a4.YEARS}
|
inc2 = {y: -1.0 for y in a4.YEARS}
|
||||||
net2 = {y: benefits[y] + 1.0 for y in a4.YEARS}
|
net2 = {y: benefits[y] + 1.0 for y in a4.YEARS}
|
||||||
assert a4.case_kpis(inc2, net2)["roi"] is None
|
assert a4.case_kpis(inc2, net2)["roi"] is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_contracted_overlays_verbatim():
|
||||||
|
assert a4.tco("ccaas_annual") == 3_200_000 # signed contract
|
||||||
|
assert a4.TCO_VERBATIM["ccaas_annual"] == 4_300_000 # deck record intact
|
||||||
|
assert a4.tco("current_annual") == a4.TCO_VERBATIM["current_annual"]
|
||||||
|
assert a4.licence_costs_by_year(12, a4.tco("ccaas_annual"))[2027] == 3_200_000
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
"""Stage/backstage detection — Mercury kernels carry MERCURY_CONFIG_DIR."""
|
||||||
|
|
||||||
|
from tokencalc 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 == ""
|
||||||
@@ -99,6 +99,19 @@ TCO_VERBATIM: dict[str, float] = {
|
|||||||
"npv_discount_rate": 0.135, # deck's benefit-NPV rate
|
"npv_discount_rate": 0.135, # deck's benefit-NPV rate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#: Actual contracted values where they differ from the deck — 🟢
|
||||||
|
#: contractual. Layered over TCO_VERBATIM, which stays the untouched
|
||||||
|
#: record of what Genesys pitched (the anchor CTM can follow);
|
||||||
|
#: presentation reads through :func:`tco`.
|
||||||
|
TCO_CONTRACTED: dict[str, float] = {
|
||||||
|
"ccaas_annual": 3_200_000, # signed licence run-rate (deck pitched $4.3M/yr)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def tco(key: str) -> float:
|
||||||
|
"""Contracted value where one exists, else the deck's verbatim anchor."""
|
||||||
|
return TCO_CONTRACTED.get(key, TCO_VERBATIM[key])
|
||||||
|
|
||||||
#: Genesys/Broadreach deployment schedule (slides 17-21), months from
|
#: Genesys/Broadreach deployment schedule (slides 17-21), months from
|
||||||
#: Jan 2026 inclusive. Benefits realize IMPL + 3 months.
|
#: Jan 2026 inclusive. Benefits realize IMPL + 3 months.
|
||||||
IMPL_MONTH = {"NA": 18, "ANZ": 21, "EMEA": 24, "ASIA": 27}
|
IMPL_MONTH = {"NA": 18, "ANZ": 21, "EMEA": 24, "ASIA": 27}
|
||||||
|
|||||||
@@ -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)
|
||||||
Reference in New Issue
Block a user