diff --git a/AGENTS.md b/AGENTS.md
index d571f5d26..5046d3148 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -620,6 +620,15 @@ and leftover-map comparison graphic incomplete items when those helpers return u
leftover-map rank from plotted coordinates, leftover-map distance, leftover expected, leftover observed, leftover residual, leftover-map unexplained leftover, leftover-map reconstruction, leftover-map axis share, leftover-map post coverage, leftover-map item coverage,
leftover-map incomplete post coverage, leftover-map incomplete item coverage, leftover pair
count, or the count of unused axes.
+ADR 0319 captions leftover-map distance on that grouping comparison leftover-map
+graphic when formatLeftoverMapDistance returns a usable badge; a missing or
+non-finite `d` omits that leftover-map comparison graphic leftover-map distance caption and keeps
+leftover-map rank, leftover expected `E`, leftover observed `Y`, leftover residual `R`, leftover-map unexplained leftover `U`, leftover-map cross share `x`, leftover-map unexplained leftover share `s`, leftover-map explained leftover share `e`, leftover-map reconstruction `R̂`, leftover-map comparison graphic coverage,
+leftover-map comparison graphic item coverage, leftover-map comparison graphic incomplete posts,
+and leftover-map comparison graphic incomplete items when those helpers return usable integers. Do not invent
+leftover-map distance from plotted coordinates, leftover-map rank, leftover expected, leftover observed, leftover residual, leftover-map unexplained leftover, leftover-map reconstruction, leftover-map axis share, leftover-map post coverage, leftover-map item coverage,
+leftover-map incomplete post coverage, leftover-map incomplete item coverage, leftover pair
+count, or the count of unused axes.
When `R`, `R̂`, `U`, `x`,
`s`, and `e` are finite, `e + s + x = 1`. When `Y`, `E`, and `R` are
finite, `Y − E = R`. When `R`, `R̂`, and `U` are
@@ -709,6 +718,9 @@ that grouping comparison leftover-map graphic with persisted leftover expected
Grouping comparison leftover-map rank (ADR 0318) captions
that grouping comparison leftover-map graphic with persisted leftover-map rank
when formatLeftoverMapRank returns a usable badge.
+Grouping comparison leftover-map distance (ADR 0319) captions
+that grouping comparison leftover-map graphic with persisted leftover-map distance
+`d` when formatLeftoverMapDistance returns a usable badge.
Item complete-case coverage
(ADR 0282) captions the leftover-map graphic with how many scored criteria
entered the map. Item complete-case coverage on the pair list (ADR 0285)
diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md
index a800e9bd2..ab7bf2425 100644
--- a/ARCHITECTURE.md
+++ b/ARCHITECTURE.md
@@ -743,6 +743,9 @@ badge.
ADR 0318 captions leftover-map rank on that grouping
comparison leftover-map graphic when formatLeftoverMapRank returns a usable
badge.
+ADR 0319 captions leftover-map distance on that grouping
+comparison leftover-map graphic when formatLeftoverMapDistance returns a usable
+badge.
Click a post marker or a pair button
opens that post. Those ADRs are the normative mathematical, storage, and
display contracts. Leftover-map axis share
@@ -790,7 +793,8 @@ graphic (ADR 0314), leftover residual on the grouping comparison leftover-map
graphic (ADR 0315), leftover observed on the grouping comparison leftover-map
graphic (ADR 0316), leftover expected on the grouping comparison leftover-map
graphic (ADR 0317), leftover-map rank on the grouping comparison leftover-map
-graphic (ADR 0318);
+graphic (ADR 0318), leftover-map distance on the grouping comparison leftover-map
+graphic (ADR 0319);
`POST .../rebuild` scores every grouping kind (post_admin). `make seed`
folds A-100/B-200 Event Lineage fixtures (and the Riverbend calendar
post) that already have constructed IRT cells into the same shared
diff --git a/CHANGELOG.d/2.76.0-leftover-map-compare-plot-distance.md b/CHANGELOG.d/2.76.0-leftover-map-compare-plot-distance.md
new file mode 100644
index 000000000..52c2cc8ea
--- /dev/null
+++ b/CHANGELOG.d/2.76.0-leftover-map-compare-plot-distance.md
@@ -0,0 +1,15 @@
+## 2.76.0 — Leftover-map distance on grouping comparison leftover-map graphic
+
+- Caption leftover-map distance on the grouping comparison leftover-map
+ graphic (ADR 0319). After `make seed`, closest and farthest leftover pairs
+ sit above the member list with leftover-map distance `d` on that grouping
+ comparison leftover-map graphic when formatLeftoverMapDistance returns a usable
+ badge; click a post marker or a pair button opens that post. A missing or
+ non-finite `d` omits that leftover-map comparison graphic leftover-map
+ distance caption and keeps leftover-map rank. Rank-0 origin
+ cells still name `d 0.00` when that persisted leftover-map distance is finite.
+ Comparison copy uses `leftover map comparison graphic leftover-map distance {label}`
+ so it stays distinct from `leftover-map distance {label}`. This increment does not
+ caption leftover-map coordinate ticks on the comparison graphic with a distinct name.
+ Do not invent leftover-map distance from plotted coordinates. A finite negative leftover
+ is shown, never clamped. Never invent a leftover score. Never invent a theta. No new columns.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 50d1ad9c6..c9c68f5ab 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,21 @@ All notable changes to this project are documented here. Format follows
### Added
+- Period leftover pairs now name leftover-map distance on the grouping
+ comparison leftover-map graphic (ADR 0319 / v2.76.0). After `make seed`,
+ closest and farthest leftover pairs sit above the member list with leftover-map
+ distance `d` on that grouping comparison leftover-map graphic when
+ formatLeftoverMapDistance returns a usable badge; click a post marker or a pair
+ button opens that post. A missing or non-finite `d` omits that leftover-map
+ comparison graphic leftover-map distance caption and keeps leftover-map rank.
+ Rank-0 origin cells still name `d 0.00` when that persisted leftover-map distance
+ is finite. Comparison copy uses
+ `leftover map comparison graphic leftover-map distance {label}` so it stays
+ distinct from `leftover-map distance {label}`. This increment does not caption leftover-map
+ coordinate ticks on the comparison graphic with a distinct name. Do not invent leftover-map
+ distance from plotted coordinates. A finite negative leftover is shown, never clamped.
+ Never invent a leftover score or a theta. No new columns.
+
- Period leftover pairs now name leftover-map rank on the grouping
comparison leftover-map graphic (ADR 0318 / v2.75.0). After `make seed`,
closest and farthest leftover pairs sit above the member list with leftover-map
diff --git a/CLAUDE.md b/CLAUDE.md
index 7a7e3b8c3..5a57c0253 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -49,7 +49,7 @@ cutoff. Global Ask optional `knowledge_cutoff` uses the same cover
Create/start endpoint rules (ADR 0017 / 0021), tie-vs-miss similarity
(ADR 0026), R&R catalog ids (ADR 0019 / 0027), leftover pairs
-(ADR 0048–0164 / 0182 / 0185 / 0201 / 0233 / 0266 / 0267 / 0268 / 0269 / 0270 / 0271 / 0272 / 0273 / 0274 / 0275 / 0276 / 0277 / 0278 / 0279 / 0280 / 0281 / 0282 / 0283 / 0284 / 0285 / 0286 / 0287 / 0288 / 0289 / 0290 / 0291 / 0292 / 0293 / 0294 / 0295 / 0296 / 0297 / 0298 / 0299 / 0300 / 0301 / 0302 / 0303 / 0304 / 0305 / 0306 / 0307 / 0308 / 0309 / 0310 / 0311 / 0312 / 0313 / 0314 / 0315 / 0316 / 0317 / 0318), occupational construct catalog search
+(ADR 0048–0164 / 0182 / 0185 / 0201 / 0233 / 0266 / 0267 / 0268 / 0269 / 0270 / 0271 / 0272 / 0273 / 0274 / 0275 / 0276 / 0277 / 0278 / 0279 / 0280 / 0281 / 0282 / 0283 / 0284 / 0285 / 0286 / 0287 / 0288 / 0289 / 0290 / 0291 / 0292 / 0293 / 0294 / 0295 / 0296 / 0297 / 0298 / 0299 / 0300 / 0301 / 0302 / 0303 / 0304 / 0305 / 0306 / 0307 / 0308 / 0309 / 0310 / 0311 / 0312 / 0313 / 0314 / 0315 / 0316 / 0317 / 0318 / 0319), occupational construct catalog search
(ADR 0257), the text-channel embedding swap and cosine
clamp (ADR 0190), per-edge channel-score persistence (ADR 0195),
token-backed status notices (ADR 0220),
diff --git a/docs/adr/0318-leftover-map-compare-plot-rank.md b/docs/adr/0318-leftover-map-compare-plot-rank.md
index 7120ba08c..0a9d8407d 100644
--- a/docs/adr/0318-leftover-map-compare-plot-rank.md
+++ b/docs/adr/0318-leftover-map-compare-plot-rank.md
@@ -3,6 +3,9 @@
**Decision status:** Accepted
**Date:** 2026-08-31
+**Amended by:** [ADR 0319](0319-leftover-map-compare-plot-distance.md)
+(leftover-map distance on the grouping comparison leftover-map graphic)
+
Amends leftover-map rank on graphic-display pair segments
([ADR 0280](0280-leftover-map-segment-rank.md)), leftover-map rank
on grouping comparison strip pair rows
@@ -75,8 +78,9 @@ Leftover-map rank omits independently of leftover expected captions and leftover
A missing leftover-map rank omits leftover-map comparison graphic leftover-map rank and keeps
a usable leftover expected caption and a usable leftover observed caption.
-This increment does not caption leftover-map distance on the comparison graphic
-with a distinct comparison-graphic name. That leftover-map distance already sits
+This increment does not caption leftover-map coordinate ticks on the comparison graphic
+with a distinct comparison-graphic name. Leftover-map distance on that comparison
+graphic is [ADR 0319](0319-leftover-map-compare-plot-distance.md). That leftover-map distance already sits
on the period-report graphic through ADR 0271.
Do not add SQL migrations. Do not edit shipped migrations. Do not invent a leftover
diff --git a/docs/adr/0319-leftover-map-compare-plot-distance.md b/docs/adr/0319-leftover-map-compare-plot-distance.md
new file mode 100644
index 000000000..546a2b3c4
--- /dev/null
+++ b/docs/adr/0319-leftover-map-compare-plot-distance.md
@@ -0,0 +1,94 @@
+# ADR 0319 — Name leftover-map distance on the grouping comparison leftover-map graphic
+
+**Decision status:** Accepted
+**Date:** 2026-08-31
+
+Amends leftover-map distance on graphic-display pair segments
+([ADR 0271](0271-leftover-map-segment-distance.md)), leftover-map rank
+on the grouping comparison leftover-map graphic
+([ADR 0318](0318-leftover-map-compare-plot-rank.md)), leftover expected
+on the grouping comparison leftover-map graphic
+([ADR 0317](0317-leftover-map-compare-plot-expected.md)), leftover-map graphic
+display on the grouping comparison strip
+([ADR 0304](0304-leftover-map-compare-graphic.md)), leftover-map coordinates
+([ADR 0267](0267-leftover-map-coordinates.md)). Independent of leftover-map
+coordinate ticks on the grouping comparison leftover-map graphic.
+
+## Context
+
+ADR 0267 already persists leftover-map distance `d = ‖ξ_{1:2} − ζ_{1:2}‖`.
+ADR 0271 already captions period-report leftover-map pair segments with
+`leftover-map distance {label}` when that leftover-map distance is finite.
+ADR 0318 already captions leftover-map rank on the grouping comparison leftover-map
+graphic. The comparison graphic still reuses `leftover-map distance {label}`, so a
+buyer who compares leftover pairs can treat the period-report graphic caption as
+the comparison graphic leftover-map distance even after the strip names coordinates.
+Hiding a distinct comparison-graphic leftover-map distance caption lets leftover-map
+rank or leftover-map reconstruction `R̂` be read as leftover-map distance without a
+next action. When coordinates, reconstruction, and distance are finite,
+`R̂ = ξ · ζ` and `d = ‖ξ − ζ‖`; the comparison graphic must name the same persisted
+`d` the pair row already shows. A finite negative leftover is shown, never clamped.
+
+This increment captions leftover-map distance on the grouping comparison leftover-map
+graphic from already-named leftover-map distance through formatLeftoverMapDistance.
+Comparison copy uses the accessible name
+`leftover map comparison graphic leftover-map distance {label}` so it stays
+distinct from `leftover-map distance {label}` on the period-report graphic. It does
+not add columns. It does not recompute leftover-map distance from plotted pixel
+length or from coordinates. Do not invent a leftover score. Do not invent a theta.
+
+This protected increment uses **0319** so it does not collide with leftover-map
+rank on the grouping comparison leftover-map graphic (0318), leftover expected on
+that graphic (0317), leftover-map distance on pair segments (0271), leftover-map
+coordinates (0267), leftover-map graphic display (0268), leftover-map coordinate
+ticks (0270), or the dashboard stacks.
+
+## Decision
+
+On the grouping comparison leftover-map graphic, caption each pair segment
+with persisted leftover-map distance when formatLeftoverMapDistance returns a usable
+badge, next to leftover-map rank. Use the distinct accessible name
+`leftover map comparison graphic leftover-map distance {label}` so the graphic
+caption is not the period-report graphic caption (`leftover-map distance {label}`).
+A missing or non-finite `d` omits that leftover-map comparison graphic leftover-map
+distance caption and keeps leftover-map rank when formatLeftoverMapRank returns a
+usable badge, leftover expected `E`, leftover observed `Y`, leftover residual `R`, leftover-map unexplained leftover `U`, leftover-map cross share `x`, leftover-map unexplained leftover share `s`, leftover-map explained leftover share `e`, leftover-map reconstruction `R̂`, leftover-map comparison graphic coverage notes, leftover-map rank, plus the pair-row leftover-map distance badge.
+Rank-0 origin cells still name `d 0.00` when that persisted leftover-map distance is
+finite. A finite negative leftover is shown, never clamped. Do not invent leftover-map
+distance from plotted coordinates, leftover-map rank, leftover expected, leftover observed, leftover residual, leftover-map reconstruction, leftover-map unexplained leftover, leftover-map axis share, leftover-map post coverage, leftover-map item coverage, leftover-map incomplete post coverage, leftover-map incomplete item coverage, leftover pair count, or the count of unused axes. Click a post marker to open that post.
+
+Leftover-map distance omits independently of leftover-map rank captions.
+A missing leftover-map distance omits leftover-map comparison graphic leftover-map distance and keeps
+a usable leftover-map rank caption.
+
+This increment does not caption leftover-map coordinate ticks on the comparison graphic
+with a distinct comparison-graphic name. Those ticks already sit on the period-report
+graphic through ADR 0270.
+
+Do not add SQL migrations. Do not edit shipped migrations. Do not invent a leftover
+score. Do not invent a theta.
+
+## Consequences
+
+After `make seed`, grouping comparison leftover pairs that already show
+the leftover-map graphic of persisted `ξ` / `ζ` also name leftover-map
+distance on that graphic when formatLeftoverMapDistance returns a usable badge.
+Rank-0 unused axes still plot at the origin and still name `d 0.00` when that
+persisted leftover-map distance is finite. Click a post marker or a
+pair button opens that post. When coordinates, reconstruction, and distance are
+finite, `R̂ = ξ · ζ` and `d = ‖ξ − ζ‖`.
+
+## Related
+
+Independent of leftover-map coordinate ticks on the grouping comparison leftover-map graphic.
+
+## References
+
+Jeon, M., Jin, I. H., Schweinberger, M., & Baugh, S. (2021). Mapping
+unobserved item–respondent interactions: A latent space item response
+model with interaction map. *Psychometrika, 86*(2), 378–403.
+https://doi.org/10.1007/s11336-021-09762-5
+
+Gabriel, K. R. (1971). The biplot graphic display of matrices with
+application to principal component analysis. *Biometrika, 58*(3),
+453–467. https://doi.org/10.1093/biomet/58.3.453
diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md
index 14a20d511..c64dab990 100644
--- a/docs/product-technical-gap-baseline.md
+++ b/docs/product-technical-gap-baseline.md
@@ -1,5 +1,22 @@
# Product & Technical Gap Baseline
+> Exact-head loop overlay: 2026-08-31 09:25 KST. Protected `main` is
+> `cb187cadee5fb6c46d8a944815ccc154a1e028d1`. Writes work. Do not
+> self-approve. #858 leftover-map rank on the grouping comparison leftover-map
+> graphic (v2.75.0 / ADR 0318) is `4b9184f`, stacked on #857 @ `9f34d2c`. Independent
+> APPROVE is missing. Next buyer increment on this
+> cycle: leftover-map distance on the grouping comparison leftover-map
+> graphic (ADR 0319 / v2.76.0) delivered locally on
+> `feat/leftover-map-compare-plot-distance-v2760`. Caption persisted leftover-map
+> distance `d` on that comparison graphic from already-named leftover_distance.
+> Distinct accessible name `leftover map comparison graphic leftover-map
+> distance {label}`. Omit when formatLeftoverMapDistance fail-closes.
+> Do not caption leftover-map coordinate ticks on that comparison graphic with a distinct name this
+> increment. Do not invent leftover-map distance from plotted coordinates.
+> Stack onto #858. Leave open for independent review. Do not squash-merge. Do not
+> self-approve. Issues #79 and #87 stay open. Do not merge #808 without independent APPROVE.
+> Never self-approve.
+
> Exact-head loop overlay: 2026-08-31 09:19 KST. Protected `main` is
> `cb187cadee5fb6c46d8a944815ccc154a1e028d1`. Writes work. Do not
> self-approve. #857 leftover expected on the grouping comparison leftover-map
diff --git a/frontend/package.json b/frontend/package.json
index bf600eb93..3b01a52da 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,7 +1,7 @@
{
"name": "frontend",
"private": true,
- "version": "2.75.0",
+ "version": "2.76.0",
"type": "module",
"scripts": {
"dev": "vite",
diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx
index 3efd4e53a..7aa7adf09 100644
--- a/frontend/src/App.test.tsx
+++ b/frontend/src/App.test.tsx
@@ -4653,6 +4653,16 @@ describe("App, authenticated", () => {
"Leftover map comparison rank",
),
).toHaveLength(1);
+ expect(
+ within(screen.getByLabelText("Grouping comparison")).getByLabelText(
+ "leftover map comparison graphic leftover-map distance d 0.12",
+ ),
+ ).toHaveTextContent("d 0.12");
+ expect(
+ within(screen.getByLabelText("Grouping comparison")).queryByLabelText(
+ "leftover-map distance d 0.12",
+ ),
+ ).not.toBeInTheDocument();
expect(
within(screen.getByLabelText("Grouping comparison")).getAllByLabelText(
/leftover-map axis \d tick/,
diff --git a/frontend/src/components/LeftoverMapPlot.test.tsx b/frontend/src/components/LeftoverMapPlot.test.tsx
index a86a35c39..890df2bb8 100644
--- a/frontend/src/components/LeftoverMapPlot.test.tsx
+++ b/frontend/src/components/LeftoverMapPlot.test.tsx
@@ -1275,8 +1275,8 @@ describe("LeftoverMapPlot", () => {
);
expect(screen.queryByLabelText(/leftover map comparison graphic reconstruction/)).not.toBeInTheDocument();
expect(screen.queryByLabelText(/leftover-map reconstruction/)).not.toBeInTheDocument();
- expect(screen.getByLabelText("leftover-map distance d 0.12")).toBeInTheDocument();
- expect(screen.getByLabelText("leftover-map distance d 1.84")).toBeInTheDocument();
+ expect(screen.getByLabelText("leftover map comparison graphic leftover-map distance d 0.12")).toBeInTheDocument();
+ expect(screen.getByLabelText("leftover map comparison graphic leftover-map distance d 1.84")).toBeInTheDocument();
expect(screen.getByLabelText("Leftover map comparison graphic coverage")).toHaveTextContent(
"Leftover map used 2 of 3 scored posts (complete-case)",
);
@@ -1391,8 +1391,8 @@ describe("LeftoverMapPlot", () => {
expect(
screen.getByLabelText("leftover map comparison graphic reconstruction R̂ +0.25"),
).toBeInTheDocument();
- expect(screen.getByLabelText("leftover-map distance d 0.12")).toBeInTheDocument();
- expect(screen.getByLabelText("leftover-map distance d 1.84")).toBeInTheDocument();
+ expect(screen.getByLabelText("leftover map comparison graphic leftover-map distance d 0.12")).toBeInTheDocument();
+ expect(screen.getByLabelText("leftover map comparison graphic leftover-map distance d 1.84")).toBeInTheDocument();
expect(screen.getByLabelText("Leftover map comparison graphic coverage")).toHaveTextContent(
"Leftover map used 2 of 3 scored posts (complete-case)",
);
@@ -1517,8 +1517,8 @@ describe("LeftoverMapPlot", () => {
expect(
screen.getByLabelText("leftover map comparison graphic reconstruction R̂ +0.25"),
).toBeInTheDocument();
- expect(screen.getByLabelText("leftover-map distance d 0.12")).toBeInTheDocument();
- expect(screen.getByLabelText("leftover-map distance d 1.84")).toBeInTheDocument();
+ expect(screen.getByLabelText("leftover map comparison graphic leftover-map distance d 0.12")).toBeInTheDocument();
+ expect(screen.getByLabelText("leftover map comparison graphic leftover-map distance d 1.84")).toBeInTheDocument();
expect(screen.getByLabelText("Leftover map comparison graphic coverage")).toHaveTextContent(
"Leftover map used 2 of 3 scored posts (complete-case)",
);
@@ -1653,8 +1653,8 @@ describe("LeftoverMapPlot", () => {
expect(
screen.getByLabelText("leftover map comparison graphic reconstruction R̂ +0.25"),
).toBeInTheDocument();
- expect(screen.getByLabelText("leftover-map distance d 0.12")).toBeInTheDocument();
- expect(screen.getByLabelText("leftover-map distance d 1.84")).toBeInTheDocument();
+ expect(screen.getByLabelText("leftover map comparison graphic leftover-map distance d 0.12")).toBeInTheDocument();
+ expect(screen.getByLabelText("leftover map comparison graphic leftover-map distance d 1.84")).toBeInTheDocument();
expect(screen.getByLabelText("Leftover map comparison graphic coverage")).toHaveTextContent(
"Leftover map used 2 of 3 scored posts (complete-case)",
);
@@ -1799,8 +1799,8 @@ describe("LeftoverMapPlot", () => {
expect(
screen.getByLabelText("leftover map comparison graphic reconstruction R̂ +0.25"),
).toBeInTheDocument();
- expect(screen.getByLabelText("leftover-map distance d 0.12")).toBeInTheDocument();
- expect(screen.getByLabelText("leftover-map distance d 1.84")).toBeInTheDocument();
+ expect(screen.getByLabelText("leftover map comparison graphic leftover-map distance d 0.12")).toBeInTheDocument();
+ expect(screen.getByLabelText("leftover map comparison graphic leftover-map distance d 1.84")).toBeInTheDocument();
expect(screen.getByLabelText("Leftover map comparison graphic coverage")).toHaveTextContent(
"Leftover map used 2 of 3 scored posts (complete-case)",
);
@@ -1955,8 +1955,8 @@ describe("LeftoverMapPlot", () => {
expect(
screen.getByLabelText("leftover map comparison graphic reconstruction R̂ +0.25"),
).toBeInTheDocument();
- expect(screen.getByLabelText("leftover-map distance d 0.12")).toBeInTheDocument();
- expect(screen.getByLabelText("leftover-map distance d 1.84")).toBeInTheDocument();
+ expect(screen.getByLabelText("leftover map comparison graphic leftover-map distance d 0.12")).toBeInTheDocument();
+ expect(screen.getByLabelText("leftover map comparison graphic leftover-map distance d 1.84")).toBeInTheDocument();
expect(screen.getByLabelText("Leftover map comparison graphic coverage")).toHaveTextContent(
"Leftover map used 2 of 3 scored posts (complete-case)",
);
@@ -2102,7 +2102,7 @@ describe("LeftoverMapPlot", () => {
expect(
screen.getByLabelText("leftover map comparison graphic reconstruction R̂ +0.25"),
).toBeInTheDocument();
- expect(screen.getByLabelText("leftover-map distance d 0.12")).toBeInTheDocument();
+ expect(screen.getByLabelText("leftover map comparison graphic leftover-map distance d 0.12")).toBeInTheDocument();
expect(screen.getByLabelText("Leftover map comparison graphic coverage")).toHaveTextContent(
"Leftover map used 2 of 3 scored posts (complete-case)",
);
@@ -2233,7 +2233,7 @@ describe("LeftoverMapPlot", () => {
expect(
screen.getByLabelText("leftover map comparison graphic leftover residual R +0.40"),
).toHaveTextContent("R +0.40");
- expect(screen.getByLabelText("leftover-map distance d 0.12")).toBeInTheDocument();
+ expect(screen.getByLabelText("leftover map comparison graphic leftover-map distance d 0.12")).toBeInTheDocument();
expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
});
@@ -2362,7 +2362,7 @@ describe("LeftoverMapPlot", () => {
expect(
screen.getByLabelText("leftover map comparison graphic leftover residual R +0.40"),
).toHaveTextContent("R +0.40");
- expect(screen.getByLabelText("leftover-map distance d 0.12")).toBeInTheDocument();
+ expect(screen.getByLabelText("leftover map comparison graphic leftover-map distance d 0.12")).toBeInTheDocument();
expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
});
@@ -2420,4 +2420,132 @@ describe("LeftoverMapPlot", () => {
).toHaveTextContent("R 0.00");
expect(screen.getByText("leftover map comparison axis 1 (0%)")).toBeInTheDocument();
});
+
+ it("names leftover-map distance on the comparison graphic with a distinct accessible name", () => {
+ render(
+ ,
+ );
+ expect(
+ screen.getByLabelText("leftover map comparison graphic leftover-map distance d 0.12"),
+ ).toHaveTextContent("d 0.12");
+ expect(
+ screen.getByLabelText("leftover map comparison graphic leftover-map distance d 1.84"),
+ ).toHaveTextContent("d 1.84");
+ expect(screen.queryByLabelText("leftover-map distance d 0.12")).not.toBeInTheDocument();
+ expect(screen.queryByLabelText("leftover-map distance d 1.84")).not.toBeInTheDocument();
+ expect(
+ screen.getAllByLabelText("leftover map comparison graphic leftover-map rank rank 1"),
+ ).toHaveLength(2);
+ expect(
+ screen.getByLabelText("leftover map comparison graphic leftover observed Y 2.40"),
+ ).toHaveTextContent("Y 2.40");
+ expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
+ });
+
+ it("omits leftover-map comparison graphic leftover-map distance when d is missing or not usable", () => {
+ render(
+ ,
+ );
+ expect(screen.queryByLabelText(/leftover map comparison graphic leftover-map distance/)).not.toBeInTheDocument();
+ expect(screen.queryByLabelText(/^leftover-map distance/)).not.toBeInTheDocument();
+ expect(
+ screen.getAllByLabelText("leftover map comparison graphic leftover-map rank rank 1"),
+ ).toHaveLength(2);
+ expect(
+ screen.getByLabelText("leftover map comparison graphic leftover observed Y 2.40"),
+ ).toHaveTextContent("Y 2.40");
+ expect(
+ screen.getByLabelText("leftover map comparison graphic leftover residual R +0.40"),
+ ).toHaveTextContent("R +0.40");
+ expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
+ });
+
+ it("names rank-0 origin leftover-map distance on the comparison graphic when that persisted value is finite", () => {
+ render(
+ ,
+ );
+ expect(
+ screen.getByLabelText("leftover map comparison graphic leftover-map distance d 0.00"),
+ ).toHaveTextContent("d 0.00");
+ expect(screen.queryByLabelText("leftover-map distance d 0.00")).not.toBeInTheDocument();
+ expect(
+ screen.getByLabelText("leftover map comparison graphic leftover-map rank rank 0"),
+ ).toHaveTextContent("rank 0");
+ expect(
+ screen.getByLabelText("leftover map comparison graphic leftover expected E 0.00"),
+ ).toHaveTextContent("E 0.00");
+ expect(screen.getByText("leftover map comparison axis 1 (0%)")).toBeInTheDocument();
+ });
});
diff --git a/frontend/src/components/LeftoverMapPlot.tsx b/frontend/src/components/LeftoverMapPlot.tsx
index a2ee23e3f..692d4ba1f 100644
--- a/frontend/src/components/LeftoverMapPlot.tsx
+++ b/frontend/src/components/LeftoverMapPlot.tsx
@@ -42,6 +42,7 @@ import {
LEFTOVER_MAP_COMPARE_PLOT_SEGMENT_OBSERVED,
LEFTOVER_MAP_COMPARE_PLOT_SEGMENT_EXPECTED,
LEFTOVER_MAP_COMPARE_PLOT_SEGMENT_RANK,
+ LEFTOVER_MAP_COMPARE_PLOT_SEGMENT_DISTANCE,
LEFTOVER_MAP_PLOT_CAPTION,
LEFTOVER_MAP_PLOT_POST_ACTION,
LEFTOVER_MAP_PLOT_SEGMENT_CROSS_SHARE,
@@ -173,6 +174,9 @@ function leftoverMapPlotAxisText(
* labels. ADR 0318 captions leftover-map rank on that
* comparison graphic from already-named leftover-map rank
* with distinct leftover map comparison graphic leftover-map rank
+ * labels. ADR 0319 captions leftover-map distance on that
+ * comparison graphic from already-named leftover-map distance
+ * with distinct leftover map comparison graphic leftover-map distance
* labels.
* Never invent a leftover score.
*/
@@ -329,9 +333,12 @@ export function LeftoverMapPlot({
x={segment.labelX}
y={segment.labelY}
textAnchor="middle"
- aria-label={tf(LEFTOVER_MAP_PLOT_SEGMENT_DISTANCE, {
- label: segment.distanceLabel,
- })}
+ aria-label={tf(
+ variant === "comparison"
+ ? LEFTOVER_MAP_COMPARE_PLOT_SEGMENT_DISTANCE
+ : LEFTOVER_MAP_PLOT_SEGMENT_DISTANCE,
+ { label: segment.distanceLabel },
+ )}
>
{segment.distanceLabel}
diff --git a/frontend/src/components/LeftoverPairList.tsx b/frontend/src/components/LeftoverPairList.tsx
index 9ec439bff..6c8ee1e07 100644
--- a/frontend/src/components/LeftoverPairList.tsx
+++ b/frontend/src/components/LeftoverPairList.tsx
@@ -128,7 +128,8 @@ export type LeftoverPairListProps = {
* comparison leftover-map graphic, not this pair list. ADR 0317 captions leftover
* expected on that grouping comparison leftover-map graphic, not this pair list. ADR 0318
* captions leftover-map rank on that grouping comparison leftover-map graphic, not this
- * pair list. Every badge still
+ * pair list. ADR 0319 captions leftover-map distance on that grouping comparison leftover-map
+ * graphic, not this pair list. Every badge still
* renders together before opening the named post.
*/
export function LeftoverPairList({
diff --git a/frontend/src/i18n.test.ts b/frontend/src/i18n.test.ts
index 19c2964d9..5453188b5 100644
--- a/frontend/src/i18n.test.ts
+++ b/frontend/src/i18n.test.ts
@@ -103,6 +103,7 @@ describe("i18n", () => {
"Leftover map comparison expected",
"leftover map comparison graphic leftover-map rank {label}",
"Leftover map comparison rank",
+ "leftover map comparison graphic leftover-map distance {label}",
"Leftover map comparison coordinates",
"Leftover map comparison graphic",
"Leftover map comparison",
@@ -651,6 +652,23 @@ describe("i18n", () => {
},
);
+ it.each([
+ ["ko", "잔여 지도 비교 그림 거리 d 0.12"],
+ ["zh", "残差地图比较图形距离 d 0.12"],
+ ["ja", "残差マップの比較図距離 d 0.12"],
+ ["vi", "khoảng cách đồ họa so sánh bản đồ phần dư d 0.12"],
+ ] as const)(
+ "formats leftover map comparison graphic leftover-map distance in %s",
+ (locale, expected) => {
+ setLocale(locale);
+ expect(
+ tf("leftover map comparison graphic leftover-map distance {label}", {
+ label: "d 0.12",
+ }),
+ ).toBe(expected);
+ },
+ );
+
it.each([
["ko", "잔여 지도 비교 설명 잔여 점유율"],
["zh", "残差地图比较已解释残差份额"],
diff --git a/frontend/src/i18n.ts b/frontend/src/i18n.ts
index 1c7b9525d..8bc25651c 100644
--- a/frontend/src/i18n.ts
+++ b/frontend/src/i18n.ts
@@ -295,6 +295,7 @@ const TRANSLATIONS: Partial>> = {
"Leftover map comparison expected": "잔여 지도 비교 기대",
"leftover map comparison graphic leftover-map rank {label}": "잔여 지도 비교 그림 순위 {label}",
"Leftover map comparison rank": "잔여 지도 비교 순위",
+ "leftover map comparison graphic leftover-map distance {label}": "잔여 지도 비교 그림 거리 {label}",
"Leftover map comparison coordinates": "잔여 지도 비교 좌표",
"Leftover map comparison graphic": "잔여 지도 비교 그림",
"Leftover map comparison": "잔여 지도 비교",
@@ -936,6 +937,7 @@ const TRANSLATIONS: Partial>> = {
"Leftover map comparison expected": "残差地图比较期望",
"leftover map comparison graphic leftover-map rank {label}": "残差地图比较图形秩 {label}",
"Leftover map comparison rank": "残差地图比较秩",
+ "leftover map comparison graphic leftover-map distance {label}": "残差地图比较图形距离 {label}",
"Leftover map comparison coordinates": "残差地图比较坐标",
"Leftover map comparison graphic": "残差地图比较图形",
"Leftover map comparison": "残差地图比较",
@@ -1598,6 +1600,7 @@ const TRANSLATIONS: Partial>> = {
"Leftover map comparison expected": "残差マップの比較期待",
"leftover map comparison graphic leftover-map rank {label}": "残差マップの比較図階数 {label}",
"Leftover map comparison rank": "残差マップの比較階数",
+ "leftover map comparison graphic leftover-map distance {label}": "残差マップの比較図距離 {label}",
"Leftover map comparison coordinates": "残差マップの比較座標",
"Leftover map comparison graphic": "残差マップの比較図",
"Leftover map comparison": "残差マップの比較",
@@ -2239,6 +2242,7 @@ const TRANSLATIONS: Partial>> = {
"Leftover map comparison expected": "Kỳ vọng so sánh bản đồ phần dư",
"leftover map comparison graphic leftover-map rank {label}": "hạng đồ họa so sánh bản đồ phần dư {label}",
"Leftover map comparison rank": "Hạng so sánh bản đồ phần dư",
+ "leftover map comparison graphic leftover-map distance {label}": "khoảng cách đồ họa so sánh bản đồ phần dư {label}",
"Leftover map comparison coordinates": "Tọa độ so sánh bản đồ phần dư",
"Leftover map comparison graphic": "Đồ họa so sánh bản đồ phần dư",
"Leftover map comparison": "So sánh bản đồ phần dư",
diff --git a/frontend/src/leftoverMapPlotLayout.test.ts b/frontend/src/leftoverMapPlotLayout.test.ts
index 958adc229..fdc08a435 100644
--- a/frontend/src/leftoverMapPlotLayout.test.ts
+++ b/frontend/src/leftoverMapPlotLayout.test.ts
@@ -16,6 +16,7 @@ import {
LEFTOVER_MAP_COMPARE_PLOT_SEGMENT_OBSERVED,
LEFTOVER_MAP_COMPARE_PLOT_SEGMENT_EXPECTED,
LEFTOVER_MAP_COMPARE_PLOT_SEGMENT_RANK,
+ LEFTOVER_MAP_COMPARE_PLOT_SEGMENT_DISTANCE,
LEFTOVER_MAP_COMPARE_PLOT_SVG,
PLOT_HEIGHT,
PLOT_PADDING,
@@ -1191,8 +1192,11 @@ describe("formatLeftoverMapDistance", () => {
it("formats persisted leftover-map distance without inventing a leftover score", () => {
expect(formatLeftoverMapDistance(0.12)).toBe("d 0.12");
expect(formatLeftoverMapDistance(0)).toBe("d 0.00");
+ expect(formatLeftoverMapDistance(1.84)).toBe("d 1.84");
+ expect(formatLeftoverMapDistance(-0.05)).toBe("d -0.05");
expect(formatLeftoverMapDistance(null)).toBeNull();
expect(formatLeftoverMapDistance(Number.NaN)).toBeNull();
+ expect(formatLeftoverMapDistance(Number.POSITIVE_INFINITY)).toBeNull();
});
});
@@ -1336,4 +1340,16 @@ describe("leftover map comparison graphic labels", () => {
LEFTOVER_MAP_COMPARE_PLOT_SEGMENT_EXPECTED,
);
});
+
+ it("stays distinct from leftover-map distance copy", () => {
+ expect(LEFTOVER_MAP_COMPARE_PLOT_SEGMENT_DISTANCE).toBe(
+ "leftover map comparison graphic leftover-map distance {label}",
+ );
+ expect(LEFTOVER_MAP_COMPARE_PLOT_SEGMENT_DISTANCE).not.toBe(
+ "leftover-map distance {label}",
+ );
+ expect(LEFTOVER_MAP_COMPARE_PLOT_SEGMENT_DISTANCE).not.toBe(
+ LEFTOVER_MAP_COMPARE_PLOT_SEGMENT_RANK,
+ );
+ });
});
diff --git a/frontend/src/leftoverMapPlotLayout.ts b/frontend/src/leftoverMapPlotLayout.ts
index 1bcafbc94..103fa63c8 100644
--- a/frontend/src/leftoverMapPlotLayout.ts
+++ b/frontend/src/leftoverMapPlotLayout.ts
@@ -46,7 +46,8 @@
* residual on that graphic (ADR 0315), and grouping comparison leftover
* observed on that graphic (ADR 0316), and grouping comparison leftover
* expected on that graphic (ADR 0317), and grouping comparison leftover-map
- * rank on that graphic (ADR 0318) caption the pair list or the grouping comparison
+ * rank on that graphic (ADR 0318), and grouping comparison leftover-map
+ * distance on that graphic (ADR 0319) caption the pair list or the grouping comparison
* strip. ADR 0304 reuses this graphic layout on the grouping comparison
* strip. ADR 0305 captions leftover-map axis share on that comparison
* graphic from already-named leftover-map axes. ADR 0306 captions leftover-map
@@ -72,6 +73,8 @@
* already-named leftover expected.
* ADR 0318 captions leftover-map rank on that comparison graphic from
* already-named leftover-map rank.
+ * ADR 0319 captions leftover-map distance on that comparison graphic from
+ * already-named leftover-map distance.
*/
import { formatLeftoverMapCoordinatePair } from "./leftoverMapCoordinates";
@@ -107,6 +110,9 @@ export const LEFTOVER_MAP_PLOT_TICK =
export const LEFTOVER_MAP_PLOT_SEGMENT_DISTANCE =
"leftover-map distance {label}";
+export const LEFTOVER_MAP_COMPARE_PLOT_SEGMENT_DISTANCE =
+ "leftover map comparison graphic leftover-map distance {label}";
+
export const LEFTOVER_MAP_PLOT_SEGMENT_RECONSTRUCTION =
"leftover-map reconstruction {label}";
diff --git a/pyproject.toml b/pyproject.toml
index 9d6139217..a373b486b 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "lineageweave"
-version = "2.75.0"
+version = "2.76.0"
description = "Reconstructs git-branch-style lineage DAGs from scattered short records using multi-channel score fusion and LLM adjudication."
readme = "README.md"
license = { text = "MIT" }
diff --git a/uv.lock b/uv.lock
index 39b7853f1..09bd29321 100644
--- a/uv.lock
+++ b/uv.lock
@@ -685,7 +685,7 @@ wheels = [
[[package]]
name = "lineageweave"
-version = "2.75.0"
+version = "2.76.0"
source = { editable = "." }
dependencies = [
{ name = "certifi" },