diff --git a/frontend/src/components/LeftoverMapPlot.tsx b/frontend/src/components/LeftoverMapPlot.tsx
index 4fc42abd6..9f63b5d5e 100644
--- a/frontend/src/components/LeftoverMapPlot.tsx
+++ b/frontend/src/components/LeftoverMapPlot.tsx
@@ -30,6 +30,7 @@ import {
import {
formatLeftoverMapPlotAxisSingular,
leftoverMapComparePlotAxisBadge,
+ leftoverMapPlotTickAxisBadge,
leftoverSingularForAxis,
LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR,
LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR_SHARE,
@@ -360,30 +361,42 @@ export function LeftoverMapPlot({
>
{leftoverMapPlotAxisText(2, leftoverMapAxes, variant)}
- {layout.ticks.map((tick) => (
-
-
- {
+ const reportTickBadge =
+ variant === "report"
+ ? leftoverMapPlotTickAxisBadge(
+ tick.axis,
+ tick.label,
+ leftoverSingularForAxis(leftoverMapAxes, tick.axis),
+ )
+ : null;
+ const tickAriaLabel =
+ variant === "comparison"
+ ? `${t(LEFTOVER_MAP_COMPARE_PLOT_LABEL)}: ${tf(LEFTOVER_MAP_PLOT_TICK, {
+ axis: tick.axis,
+ value: tick.label,
+ })}`
+ : reportTickBadge !== null
+ ? tf(reportTickBadge.template, reportTickBadge.values)
+ : tf(LEFTOVER_MAP_PLOT_TICK, { axis: tick.axis, value: tick.label });
+ return (
+
- {tick.label}
-
-
- ))}
+
+
+ {tick.label}
+
+
+ );
+ })}
{layout.segments.map((segment) => (
None:
- """Comparison ticks compose existing localized comparison and tick copy."""
+ """Comparison ticks keep localized comparison copy while report ticks may add persisted σ evidence."""
plot_source = PLOT_SOURCE.read_text(encoding="utf-8")
- assert "LEFTOVER_MAP_COMPARE_PLOT_LABEL" in plot_source
- assert "LEFTOVER_MAP_PLOT_TICK" in plot_source
+ # v2.84 adds a report-only evidence badge. Comparison ticks must keep the
+ # existing localized comparison + generic tick composition rather than
+ # inheriting report evidence or introducing a comparison-only translation.
+ assert "leftoverMapPlotTickAxisBadge" in plot_source
+ assert "leftoverSingularForAxis(leftoverMapAxes, tick.axis)" in plot_source
assert re.search(
- r'variant\s*===\s*"comparison"\s*\?\s*`\$\{t\(LEFTOVER_MAP_COMPARE_PLOT_LABEL\)\}:\s*\$\{tf\(LEFTOVER_MAP_PLOT_TICK,\s*\{\s*axis:\s*tick\.axis,\s*value:\s*tick\.label,?\s*\}\)\}`\s*:\s*tf\(LEFTOVER_MAP_PLOT_TICK,\s*\{\s*axis:\s*tick\.axis,\s*value:\s*tick\.label,?\s*\}\)',
+ r'reportTickBadge\s*=\s*variant\s*===\s*"report"\s*\?\s*leftoverMapPlotTickAxisBadge\(',
plot_source,
re.DOTALL,
)
+ assert re.search(
+ r'variant\s*===\s*"comparison"\s*\?\s*`\$\{t\(LEFTOVER_MAP_COMPARE_PLOT_LABEL\)\}:\s*\$\{tf\(LEFTOVER_MAP_PLOT_TICK,\s*\{\s*axis:\s*tick\.axis,\s*value:\s*tick\.label,?\s*\}\)\}`',
+ plot_source,
+ re.DOTALL,
+ )
+ assert "tf(reportTickBadge.template, reportTickBadge.values)" in plot_source
assert "LEFTOVER_MAP_COMPARE_PLOT_TICK" not in plot_source
diff --git a/tests/test_leftover_map_report_tick_singular_contract.py b/tests/test_leftover_map_report_tick_singular_contract.py
new file mode 100644
index 000000000..cfd1da29b
--- /dev/null
+++ b/tests/test_leftover_map_report_tick_singular_contract.py
@@ -0,0 +1,37 @@
+"""Executable contract for report-graphic tick singular-value captions."""
+
+from pathlib import Path
+
+
+ROOT = Path(__file__).resolve().parents[1]
+SINGULAR_SOURCE = ROOT / "frontend" / "src" / "leftoverMapPlotAxisSingular.ts"
+PLOT_COMPONENT_SOURCE = ROOT / "frontend" / "src" / "components" / "LeftoverMapPlot.tsx"
+
+
+def test_report_graphic_tick_keeps_persisted_singular_value_without_share() -> None:
+ """A tick may name valid persisted σ even when axis share is absent."""
+ assert SINGULAR_SOURCE.exists(), "singular-value axis helper is missing"
+ source = SINGULAR_SOURCE.read_text(encoding="utf-8")
+
+ assert "leftoverMapPlotTickAxisBadge" in source
+ assert "leftover-map axis {axis} tick {value} σ {singular}" in source
+
+
+def test_report_graphic_consumes_tick_singular_projection() -> None:
+ """The buyer-visible report graphic must consume the persisted-σ tick projection."""
+ source = PLOT_COMPONENT_SOURCE.read_text(encoding="utf-8")
+
+ assert "leftoverMapPlotTickAxisBadge" in source
+ assert "leftoverSingularForAxis(leftoverMapAxes, tick.axis)" in source
+ assert "tf(reportTickBadge.template, reportTickBadge.values)" in source
+
+
+def test_report_graphic_tick_does_not_infer_sigma_or_share() -> None:
+ """Invalid σ falls back to the ordinary tick and ticks never synthesize share."""
+ assert SINGULAR_SOURCE.exists(), "singular-value axis helper is missing"
+ source = SINGULAR_SOURCE.read_text(encoding="utf-8")
+
+ assert "formatLeftoverMapPlotAxisSingular" in source
+ assert "Number.isFinite" in source
+ assert "Math.sqrt" not in source
+ assert "leftover_share" not in source.split("leftoverMapPlotTickAxisBadge", 1)[-1][:1400]