Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
5218a5c
feat(reports): leftover-map singular values on leftover-map graphic l…
seonghobae Aug 31, 2026
cf22fce
test(red): reconstruct report-graphic tick singular contract
seonghobae Sep 10, 2026
fcaf7a7
chore(stack): converge report tick singular lane on repaired parent
seonghobae Sep 11, 2026
97bcc8d
chore(stack): converge report tick singular lane on documented parent
seonghobae Sep 11, 2026
94a42d9
chore(stack): converge #868 onto repaired #867 head
seonghobae Sep 12, 2026
dddd9ad
chore(stack): converge #868 onto repaired #867
seonghobae Sep 12, 2026
8af935c
chore(stack): converge #868 onto repaired ancestry
seonghobae Sep 13, 2026
0988a5a
chore(stack): converge #868 onto repaired #867
seonghobae Sep 15, 2026
0a74cbb
chore(stack): converge #868 onto repaired #867
seonghobae Sep 15, 2026
eee0f6c
merge: converge v2.84.0 onto current v2.83.0 parent
seonghobae Sep 15, 2026
6c7897e
merge: converge v2.84.0 onto repaired v2.83.0 parent
seonghobae Sep 15, 2026
933d462
chore(stack): converge #868 onto repaired #867
seonghobae Sep 15, 2026
d39343a
chore(stack): converge #868 onto #867 executable state-matrix contract
seonghobae Sep 15, 2026
b25a4d1
merge(reports): converge report-axis missingness repair into graphic …
seonghobae Sep 15, 2026
12539d2
merge(reports): converge #868 onto #867 RED contract head
seonghobae Sep 15, 2026
b71b045
chore(stack): converge current #867 into #868
seonghobae Sep 15, 2026
de64a97
chore(stack): converge #868 on current #867
seonghobae Sep 15, 2026
c639835
chore(stack): converge semantic RED harness onto #868
seonghobae Sep 16, 2026
fbd637f
chore(stack): converge #867 product repair into #868
seonghobae Sep 16, 2026
3cbed78
fix(reports): project report tick singular evidence
seonghobae Sep 16, 2026
1357c37
test(reports): require report ticks to consume persisted singular evi…
seonghobae Sep 18, 2026
1fbaafc
fix(reports): wire persisted singular evidence into report tick labels
seonghobae Sep 18, 2026
208079a
test(reports): preserve comparison tick semantics after report badge …
seonghobae Sep 19, 2026
07558b5
merge: converge #868 on report contract repairs
seonghobae Sep 19, 2026
db281ce
chore(stack): converge #868 onto #867 owner stack
seonghobae Sep 20, 2026
9ff3995
chore(stack): converge #868 onto repaired #867 head
seonghobae Sep 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 36 additions & 23 deletions frontend/src/components/LeftoverMapPlot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
import {
formatLeftoverMapPlotAxisSingular,
leftoverMapComparePlotAxisBadge,
leftoverMapPlotTickAxisBadge,
leftoverSingularForAxis,
LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR,
LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR_SHARE,
Expand Down Expand Up @@ -360,30 +361,42 @@ export function LeftoverMapPlot({
>
{leftoverMapPlotAxisText(2, leftoverMapAxes, variant)}
</text>
{layout.ticks.map((tick) => (
<g
key={`tick:${tick.axis}:${tick.value}`}
className="leftover-map-plot-tick"
aria-label={
variant === "comparison"
? `${t(LEFTOVER_MAP_COMPARE_PLOT_LABEL)}: ${tf(LEFTOVER_MAP_PLOT_TICK, {
axis: tick.axis,
value: tick.label,
})}`
: tf(LEFTOVER_MAP_PLOT_TICK, { axis: tick.axis, value: tick.label })
}
>
<line x1={tick.x} y1={tick.y} x2={tick.tickX2} y2={tick.tickY2} />
<text
className="leftover-map-plot-tick-label"
x={tick.axis === 1 ? tick.x : tick.tickX2 - 2}
y={tick.axis === 1 ? tick.tickY2 + 12 : tick.y + 4}
textAnchor={tick.axis === 1 ? "middle" : "end"}
{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 (
<g
key={`tick:${tick.axis}:${tick.value}`}
className="leftover-map-plot-tick"
aria-label={tickAriaLabel}
>
{tick.label}
</text>
</g>
))}
<line x1={tick.x} y1={tick.y} x2={tick.tickX2} y2={tick.tickY2} />
<text
className="leftover-map-plot-tick-label"
x={tick.axis === 1 ? tick.x : tick.tickX2 - 2}
y={tick.axis === 1 ? tick.tickY2 + 12 : tick.y + 4}
textAnchor={tick.axis === 1 ? "middle" : "end"}
>
{tick.label}
</text>
</g>
);
})}
{layout.segments.map((segment) => (
<g key={`${segment.pairKind}:${segment.postId}:${segment.criterionCode}`}>
<line
Expand Down
19 changes: 19 additions & 0 deletions frontend/src/leftoverMapPlotAxisSingular.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ export const LEFTOVER_MAP_COMPARE_AXIS_SINGULAR_SHARE =
export const LEFTOVER_MAP_COMPARE_AXIS_SHARE =
"leftover map comparison leftover axis {axis} {share}%";

export const LEFTOVER_MAP_PLOT_TICK_SINGULAR =
"leftover-map axis {axis} tick {value} σ {singular}";

export type LeftoverMapPlotAxisSingular = {
axis_index: LeftoverMapAxis["axis_index"];
leftover_singular_value?: LeftoverMapAxis["leftover_singular_value"] | null;
Expand Down Expand Up @@ -131,3 +134,19 @@ export function leftoverMapCompareAxisBadge(
values: { axis: axis.axis_index, value: singular as string, share: share as string },
};
}

/** Project finite persisted σ onto one report-graphic tick without inventing share evidence. */
export function leftoverMapPlotTickAxisBadge(
axisIndex: number,
tickLabel: string,
leftoverSingular: number | null | undefined,
): LeftoverMapCompareAxisBadge | null {
const singular = formatLeftoverMapPlotAxisSingular(leftoverSingular);
if (singular === null) {
return null;
}
return {
template: LEFTOVER_MAP_PLOT_TICK_SINGULAR,
values: { axis: axisIndex, value: tickLabel, singular },
};
}
19 changes: 14 additions & 5 deletions tests/test_grouping_comparison_graphic_tick_contract.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Executable contract for coordinate ticks on the grouping-comparison graphic."""
"""Executable wiring contract for coordinate ticks on the grouping-comparison graphic."""

from pathlib import Path
import re
Expand All @@ -10,16 +10,25 @@


def test_comparison_graphic_names_ticks_with_distinct_accessible_copy() -> 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


Expand Down
37 changes: 37 additions & 0 deletions tests/test_leftover_map_report_tick_singular_contract.py
Original file line number Diff line number Diff line change
@@ -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]
Loading