diff --git a/examples/ddd-architectural-challenges/assets/verdict_heatmap_en_t2.png b/examples/ddd-architectural-challenges/assets/verdict_heatmap_en_t2.png new file mode 100644 index 00000000..e2019e94 Binary files /dev/null and b/examples/ddd-architectural-challenges/assets/verdict_heatmap_en_t2.png differ diff --git a/examples/ddd-architectural-challenges/assets/verdict_heatmap_t2.png b/examples/ddd-architectural-challenges/assets/verdict_heatmap_t2.png new file mode 100644 index 00000000..8b9b25b4 Binary files /dev/null and b/examples/ddd-architectural-challenges/assets/verdict_heatmap_t2.png differ diff --git a/examples/ddd-architectural-challenges/verdict_heatmap.py b/examples/ddd-architectural-challenges/verdict_heatmap.py index c5c30efc..3d3095d9 100644 --- a/examples/ddd-architectural-challenges/verdict_heatmap.py +++ b/examples/ddd-architectural-challenges/verdict_heatmap.py @@ -207,7 +207,7 @@ def collect() -> tuple[dict[tuple[str, str], list[dict]], list[str]]: for g, ramp in GROUP_RAMP.items()} -def heatmap(per_arm: dict, lang: str) -> None: +def heatmap(per_arm: dict, lang: str, highlight: str | None = None) -> None: t = TEXT[lang] grid = [[sum(VAL[evals[c]] for evals in per_arm[arm]) / len(per_arm[arm]) for arm in ARM_ORDER] for c in CHECKS] @@ -248,9 +248,20 @@ def heatmap(per_arm: dict, lang: str) -> None: xycoords="axes fraction", ha="left", va="center", fontsize=8.6, color=GROUP_RAMP[group][1], rotation=270) + if highlight: + yi = CHECKS.index(highlight) + ax.add_patch(plt.Rectangle((-0.5, yi - 0.5), len(ARM_ORDER), 1.0, + fill=False, edgecolor=INK, linewidth=2.4, + zorder=6, clip_on=False)) + ax.get_yticklabels()[yi].set_fontweight("bold") + ax.get_yticklabels()[yi].set_color(INK) + fig.text(0.5, 0.015, t["scale"], ha="center", fontsize=8.2, color="#777") fig.tight_layout(rect=(0, 0.035, 0.97, 0.905)) - out = HERE / "assets" / t["out"] + name = t["out"] + if highlight: + name = name.replace(".png", f"_{highlight.lower()}.png") + out = HERE / "assets" / name fig.savefig(out, dpi=160, facecolor="white") print("saved:", out) @@ -263,3 +274,6 @@ def heatmap(per_arm: dict, lang: str) -> None: print("FLAG", fl) for lang in ("pl", "en"): heatmap(per_arm, lang) + # article/social variant: the bounty row outlined (T2 - the check + # no model met for two generations until Opus 5) + heatmap(per_arm, lang, highlight="T2") diff --git a/src/nasde_toolkit/pricing.toml b/src/nasde_toolkit/pricing.toml index 9c472288..1cbfd0cb 100644 --- a/src/nasde_toolkit/pricing.toml +++ b/src/nasde_toolkit/pricing.toml @@ -15,8 +15,10 @@ # per-step cost accounting on the 2026-07 grid. OpenAI bills no write premium, # so gpt entries omit the field (writes fall back to the base input rate). # -# Verified 2026-07-13 (Claude models re-checked against the official pricing page -# before publishing) — CONFIRM before publishing any cost figures. +# Claude models re-verified 2026-08-24 against the official pricing page (Fable 5, +# Opus 5, Opus 4.8, Sonnet 4.6 unchanged since 2026-07-13; Sonnet 5 added) — +# CONFIRM before publishing any cost figures. gpt entries not re-checked since +# 2026-06-08. [models."gpt-5.5"] input_per_1m = 5.0 @@ -37,7 +39,7 @@ input_per_1m = 5.0 output_per_1m = 25.0 cached_input_per_1m = 0.50 cache_write_per_1m = 10.0 -as_of = "2026-07-24" +as_of = "2026-08-24" source = "https://platform.claude.com/docs/en/about-claude/pricing" [models."claude-opus-4-8"] @@ -45,7 +47,7 @@ input_per_1m = 5.0 output_per_1m = 25.0 cached_input_per_1m = 0.50 cache_write_per_1m = 10.0 -as_of = "2026-07-24" +as_of = "2026-08-24" source = "https://platform.claude.com/docs/en/about-claude/pricing" [models."claude-fable-5"] @@ -53,7 +55,15 @@ input_per_1m = 10.0 output_per_1m = 50.0 cached_input_per_1m = 1.0 cache_write_per_1m = 20.0 -as_of = "2026-07-24" +as_of = "2026-08-24" +source = "https://platform.claude.com/docs/en/about-claude/pricing" + +[models."claude-sonnet-5"] +input_per_1m = 2.0 +output_per_1m = 10.0 +cached_input_per_1m = 0.20 +cache_write_per_1m = 4.0 +as_of = "2026-08-24" source = "https://platform.claude.com/docs/en/about-claude/pricing" [models."claude-sonnet-4-6"] @@ -61,5 +71,5 @@ input_per_1m = 3.0 output_per_1m = 15.0 cached_input_per_1m = 0.30 cache_write_per_1m = 6.0 -as_of = "2026-06-08" +as_of = "2026-08-24" source = "https://platform.claude.com/docs/en/about-claude/pricing" diff --git a/tests/test_evaluator.py b/tests/test_evaluator.py index 958a0625..16784213 100644 --- a/tests/test_evaluator.py +++ b/tests/test_evaluator.py @@ -282,7 +282,7 @@ def test_assessment_summary_includes_economics(tmp_path: Path) -> None: assert summary.token_usage["total_tokens"] == 1_060_000 # sonnet $3/$15/$0.30 cached (ADR-014): fresh 0.2M*3 + cached 0.8M*0.30 + 0.06M*15 = 1.74 assert summary.cost_usd == pytest.approx(1.74) - assert summary.pricing_as_of == "2026-06-08" + assert summary.pricing_as_of == "2026-08-24" assert not hasattr(summary, "cost_efficiency") # removed: arbitrary zero → use Pareto front assert not hasattr(summary, "token_efficiency") diff --git a/tests/test_pricing.py b/tests/test_pricing.py index 74f8d1ea..de9b20ef 100644 --- a/tests/test_pricing.py +++ b/tests/test_pricing.py @@ -171,6 +171,7 @@ def test_layered_three_layers_compose(tmp_path: Path, empty_user_layer: Path) -> "claude-opus-5", "claude-fable-5", "claude-opus-4-8", + "claude-sonnet-5", "claude-sonnet-4-6", "azure-gpt5", "enterprise-claude", diff --git a/tests/test_results_exporter.py b/tests/test_results_exporter.py index 5c25d2a4..f101b1d0 100644 --- a/tests/test_results_exporter.py +++ b/tests/test_results_exporter.py @@ -174,7 +174,7 @@ def test_export_includes_token_cost_economics(job_dir: Path, tmp_path: Path) -> assert usage["total_tokens"] == 1_060_000 # sonnet $3/$15/$0.30 cached (ADR-014): fresh 0.2M*3 + cached 0.8M*0.30 + 0.06M*15 = 1.74 assert metrics["cost_usd"] == pytest.approx(1.74) - assert metrics["pricing_as_of"] == "2026-06-08" + assert metrics["pricing_as_of"] == "2026-08-24" assert "cost_efficiency" not in metrics # removed: arbitrary zero → use Pareto front assert "token_efficiency" not in metrics assert metrics["reasoning_effort"] == "" # fixture set no override