diff --git a/AGENTS.md b/AGENTS.md
index 424852d97..076369b1a 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -637,6 +637,15 @@ that no persisted coordinate occupies. Do not invent leftover-map coordinate tic
distance, 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.
+ADR 0321 captions leftover-map singular values on that grouping comparison leftover-map
+graphic from already-named leftover-map axes when that persisted `σ_k` is finite and
+non-negative. Rank-0 unused axes still name leftover-map comparison graphic leftover-map
+axis `σ 0.00`. Share and singular value omit independently. Do not invent leftover-map
+singular values from leftover-map axis share, leftover-map coordinate ticks, leftover-map
+distance, leftover-map rank, leftover expected, leftover observed, leftover residual,
+leftover-map unexplained leftover, leftover-map reconstruction, 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
@@ -732,6 +741,9 @@ that grouping comparison leftover-map graphic with persisted leftover-map distan
Grouping comparison leftover-map coordinate ticks (ADR 0320) captions
that grouping comparison leftover-map graphic with persisted leftover-map coordinate
ticks at the origin and at each unique finite `ξ` / `ζ` projection.
+Grouping comparison leftover-map singular values (ADR 0321) captions
+that grouping comparison leftover-map graphic with persisted leftover-map singular
+values `σ_k` when leftoverSingularForAxis returns a usable finite non-negative value.
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 39c96edb6..d84a65f84 100644
--- a/ARCHITECTURE.md
+++ b/ARCHITECTURE.md
@@ -748,6 +748,8 @@ comparison leftover-map graphic when formatLeftoverMapDistance returns a usable
badge.
ADR 0320 captions leftover-map coordinate ticks on that grouping
comparison leftover-map graphic from already-named leftover-map coordinates.
+ADR 0321 captions leftover-map singular values on that grouping
+comparison leftover-map graphic from already-named leftover-map axes.
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
@@ -797,7 +799,8 @@ 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), leftover-map distance on the grouping comparison leftover-map
graphic (ADR 0319), leftover-map coordinate ticks on the grouping comparison leftover-map
-graphic (ADR 0320);
+graphic (ADR 0320), leftover-map singular values on the grouping comparison leftover-map
+graphic (ADR 0321);
`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.78.0-leftover-map-compare-plot-singular.md b/CHANGELOG.d/2.78.0-leftover-map-compare-plot-singular.md
new file mode 100644
index 000000000..14046ef95
--- /dev/null
+++ b/CHANGELOG.d/2.78.0-leftover-map-compare-plot-singular.md
@@ -0,0 +1,19 @@
+## 2.78.0 — Leftover-map singular values on grouping comparison leftover-map graphic
+
+- Caption leftover-map singular values on the grouping comparison leftover-map
+ graphic (ADR 0321). After `make seed`, closest and farthest leftover pairs
+ sit above the member list with leftover-map singular values `σ_k` on that
+ grouping comparison leftover-map graphic when those persisted singular values
+ are finite and non-negative; click a post marker or a pair button opens that
+ post. Rank-0 origin cells still name leftover-map comparison graphic leftover-map
+ axis `σ 0.00`. Comparison copy uses
+ `leftover map comparison graphic leftover-map axis {axis} σ {value}` so it
+ stays distinct from `leftover-map axis {axis} σ {value}`, from
+ `leftover axis {axis} σ {value}`, from
+ `leftover map comparison axis {axis} ({share}%)`, and from
+ `leftover map comparison graphic leftover-map axis {axis} tick {value}`.
+ Share and singular value omit independently. Do not invent `σ_k` from
+ leftover-map axis share. This increment does not caption leftover-map
+ singular values on leftover-axis report badges with a distinct name.
+ 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 c1acf56f5..bd2315ce4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,24 @@ All notable changes to this project are documented here. Format follows
### Added
+- Period leftover pairs now name leftover-map singular values on the grouping
+ comparison leftover-map graphic (ADR 0321 / v2.78.0). After `make seed`,
+ closest and farthest leftover pairs sit above the member list with leftover-map
+ singular values `σ_k` on that grouping comparison leftover-map graphic when
+ those persisted singular values are finite and non-negative; click a post
+ marker or a pair button opens that post. Rank-0 origin cells still name
+ leftover-map comparison graphic leftover-map axis `σ 0.00`. Comparison copy
+ uses `leftover map comparison graphic leftover-map axis {axis} σ {value}` so
+ it stays distinct from `leftover-map axis {axis} σ {value}`, from
+ `leftover axis {axis} σ {value}`, from
+ `leftover map comparison axis {axis} ({share}%)`, and from
+ `leftover map comparison graphic leftover-map axis {axis} tick {value}`.
+ Share and singular value omit independently. Do not invent `σ_k` from
+ leftover-map axis share. This increment does not caption leftover-map
+ singular values on leftover-axis report badges with a distinct name.
+ 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 coordinate ticks on the grouping
comparison leftover-map graphic (ADR 0320 / v2.77.0). After `make seed`,
closest and farthest leftover pairs sit above the member list with leftover-map
@@ -18,9 +36,8 @@ All notable changes to this project are documented here. Format follows
`leftover map comparison graphic leftover-map axis {axis} tick {value}` so it
stays distinct from `leftover-map axis {axis} tick {value}` and from
`leftover map comparison axis {axis} ({share}%)`. Do not invent evenly spaced
- ticks that no persisted coordinate occupies. This increment does not caption
- leftover-map singular values on the comparison graphic with a distinct name.
- Do not invent leftover-map coordinate ticks from leftover-map distance.
+ ticks that no persisted coordinate occupies. Leftover-map singular values on
+ the comparison graphic are ADR 0321. Do not invent leftover-map coordinate ticks from leftover-map distance.
A finite negative leftover is shown, never clamped. Never invent a leftover
score or a theta. No new columns.
diff --git a/CLAUDE.md b/CLAUDE.md
index cd8a6d9bf..8aa35a2b4 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 / 0319 / 0320), 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 / 0320 / 0321), 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/0320-leftover-map-compare-plot-ticks.md b/docs/adr/0320-leftover-map-compare-plot-ticks.md
index b4ba99385..0ead801f4 100644
--- a/docs/adr/0320-leftover-map-compare-plot-ticks.md
+++ b/docs/adr/0320-leftover-map-compare-plot-ticks.md
@@ -3,6 +3,9 @@
**Decision status:** Accepted
**Date:** 2026-08-31
+**Amended by:** [ADR 0321](0321-leftover-map-compare-plot-singular.md)
+(leftover-map singular values on the grouping comparison leftover-map graphic)
+
Amends leftover-map coordinate ticks on graphic-display axes
([ADR 0270](0270-leftover-map-coordinate-ticks.md)), leftover-map distance
on the grouping comparison leftover-map graphic
@@ -12,7 +15,7 @@ on the grouping comparison 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
-singular values on the grouping comparison leftover-map graphic.
+singular values on leftover-axis report badges.
## Context
@@ -95,7 +98,7 @@ and distance are finite, `R̂ = ξ · ζ` and `d = ‖ξ − ζ‖`.
## Related
-Independent of leftover-map singular values on the grouping comparison leftover-map graphic.
+Independent of leftover-map singular values on leftover-axis report badges.
## References
diff --git a/docs/adr/0321-leftover-map-compare-plot-singular.md b/docs/adr/0321-leftover-map-compare-plot-singular.md
new file mode 100644
index 000000000..50d096056
--- /dev/null
+++ b/docs/adr/0321-leftover-map-compare-plot-singular.md
@@ -0,0 +1,111 @@
+# ADR 0321 — Name leftover-map singular values on the grouping comparison leftover-map graphic
+
+**Decision status:** Accepted
+**Date:** 2026-08-31
+
+Amends leftover-map coordinate ticks on the grouping comparison leftover-map
+graphic ([ADR 0320](0320-leftover-map-compare-plot-ticks.md)), leftover-map
+axis share on that comparison graphic
+([ADR 0305](0305-leftover-map-compare-plot-axis-share.md)), leftover-map
+graphic display on the grouping comparison strip
+([ADR 0304](0304-leftover-map-compare-graphic.md)), leftover-map axis share
+persistence ([ADR 0148](0148-leftover-map-axis-share.md)), leftover-map
+coordinates ([ADR 0267](0267-leftover-map-coordinates.md)). Independent of
+leftover-map singular values on leftover-axis report badges.
+
+## Context
+
+ADR 0148 already persists leftover-map singular values `σ_k` on
+`report_leftover_map_axis` together with leftover-map axis share
+`σ_k² / Σ_j σ_j²`. ADR 0305 already captions the grouping comparison
+leftover-map graphic with `leftover map comparison axis {k} ({share}%)`
+when that share is finite. ADR 0320 already ticks those comparison-graphic
+axes at persisted `ξ` / `ζ` projections. The comparison graphic still
+omits `σ_k`, so a buyer who compares leftover pairs can treat leftover-map
+axis share, leftover-map distance `d`, leftover-map rank, or leftover-map
+coordinate ticks as leftover-map structure without a next action. Gabriel
+inertia share is `σ_k² / Σ_j σ_j²`; hiding the persisted singular value
+lets share be read as a leftover score. A missing, non-finite, or negative
+singular value is not a leftover score and must omit independently of
+leftover-map axis share. Rank-0 unused axes still persist `σ_k = 0`.
+A finite negative leftover is shown, never clamped. Do not invent `σ_k`
+from leftover-map axis share.
+
+This increment captions leftover-map singular values on the grouping
+comparison leftover-map graphic from already-named leftover-map axes.
+Comparison copy uses the accessible names
+`leftover map comparison graphic leftover-map axis {axis} σ {value}` and
+`leftover map comparison graphic leftover-map axis {axis} σ {value} ({share}%)`
+so they stay distinct from hyphen `leftover-map axis {axis} σ {value}`,
+from pair-list `leftover axis {axis} σ {value}`, from comparison axis-share
+`leftover map comparison axis {axis} ({share}%)`, and from comparison
+coordinate ticks
+`leftover map comparison graphic leftover-map axis {axis} tick {value}`.
+It does not add columns. Do not invent a leftover score. Do not invent a
+theta.
+
+This protected increment uses **0321** so it does not collide with leftover-map
+coordinate ticks on the grouping comparison leftover-map graphic (0320),
+leftover-map distance on that graphic (0319), leftover-map axis share on that
+graphic (0305), leftover-map singular values on leftover-axis report badges,
+or the dashboard stacks.
+
+## Decision
+
+On the grouping comparison leftover-map graphic, caption leftover-map axis 1
+and leftover-map axis 2 with persisted leftover-map singular values `σ_k`
+when that singular value is finite and non-negative. Share and singular
+value omit independently: no share and no `σ_k` keeps
+`leftover map comparison axis {k}`; share only stays
+`leftover map comparison axis {k} ({share}%)`; `σ_k` only is
+`leftover map comparison graphic leftover-map axis {k} σ {value}`; both is
+`leftover map comparison graphic leftover-map axis {k} σ {value} ({share}%)`.
+A missing, non-finite, or negative singular value omits that `σ` badge and
+does not invent `σ_k` from leftover-map axis share. Rank-0 unused axes
+still name `σ 0.00`. Click a post marker to open that post. Criterion
+markers are not post buttons.
+
+Leftover-map comparison graphic leftover-map singular values omit
+independently of leftover-map comparison graphic leftover-map axis ticks
+and leftover-map axis share. A missing singular value omits that leftover-map
+comparison graphic leftover-map axis `σ` caption and keeps a usable
+leftover-map comparison axis share caption, leftover-map comparison graphic
+leftover-map axis ticks, leftover-map distance caption, leftover-map rank
+caption, leftover expected `E`, leftover observed `Y`, leftover residual `R`,
+leftover-map unexplained leftover `U`, leftover-map reconstruction `R̂`,
+and leftover-map comparison graphic coverage notes.
+
+This increment does not caption leftover-map singular values on leftover-axis
+report badges with a distinct comparison-strip name. Those leftover singular
+values already persist on leftover-map axes through ADR 0148. This increment
+does not persist leftover-map inner product, cosine, or length.
+
+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
+singular values on that graphic when those persisted `σ_k` are finite and
+non-negative. Rank-0 unused axes still plot at the origin and still name
+leftover-map comparison graphic leftover-map axis `σ 0.00`. Click a post
+marker or a pair button opens that post. When coordinates, reconstruction,
+and distance are finite, `R̂ = ξ · ζ` and `d = ‖ξ − ζ‖`. When leftover-map
+singular values and leftover-map axis share are finite,
+leftover-map axis share is `σ_k² / Σ_j σ_j²`.
+
+## Related
+
+Independent of leftover-map singular values on leftover-axis report badges.
+
+## 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 75be1a0d4..4b02b8eca 100644
--- a/docs/product-technical-gap-baseline.md
+++ b/docs/product-technical-gap-baseline.md
@@ -1,5 +1,23 @@
# Product & Technical Gap Baseline
+> Exact-head loop overlay: 2026-08-31 10:20 KST. Protected `main` is
+> `cb187cadee5fb6c46d8a944815ccc154a1e028d1`. Writes work. Do not
+> self-approve. #860 leftover-map coordinate ticks on the grouping comparison leftover-map
+> graphic (v2.77.0 / ADR 0320) is `40fa5bd`, stacked on #859 @ `9ba8535`. Independent
+> APPROVE is missing. Next buyer increment on this
+> cycle: leftover-map singular values on the grouping comparison leftover-map
+> graphic (ADR 0321 / v2.78.0) delivered locally on
+> `feat/leftover-map-compare-plot-singular-v2780`. Caption persisted leftover-map
+> singular values `σ_k` on that comparison graphic from already-named leftover-map
+> axes. Distinct accessible name `leftover map comparison graphic leftover-map
+> axis {axis} σ {value}`. Rank-0 unused axes still name `σ 0.00`. Share and
+> singular value omit independently. Do not invent `σ_k` from leftover-map axis
+> share. Do not caption leftover-map singular values on leftover-axis report
+> badges with a distinct name this increment. Stack onto #860.
+> 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:28 KST. Protected `main` is
> `cb187cadee5fb6c46d8a944815ccc154a1e028d1`. Writes work. Do not
> self-approve. #859 leftover-map distance on the grouping comparison leftover-map
diff --git a/frontend/package.json b/frontend/package.json
index 2909efd65..336c33357 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,7 +1,7 @@
{
"name": "frontend",
"private": true,
- "version": "2.77.0",
+ "version": "2.78.0",
"type": "module",
"scripts": {
"dev": "vite",
diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx
index 313feda5b..4f3f774cb 100644
--- a/frontend/src/App.test.tsx
+++ b/frontend/src/App.test.tsx
@@ -4197,8 +4197,8 @@ describe("App, authenticated", () => {
expect(screen.getByLabelText("Leftover map comparison graphic")).toBeInTheDocument();
expect(screen.getByText("leftover-map axis 1 (82%)")).toBeInTheDocument();
expect(screen.getByText("leftover-map axis 2 (18%)")).toBeInTheDocument();
- expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
- expect(screen.getByText("leftover map comparison axis 2 (18%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 2 σ 0.86 (18%)")).toBeInTheDocument();
expect(
screen.getAllByRole("button", {
name: /open leftover-map post public post at ξ \(\+0\.50, \+0\.10\)/i,
@@ -4322,12 +4322,12 @@ describe("App, authenticated", () => {
).not.toBeInTheDocument();
expect(
within(screen.getByLabelText("Grouping comparison")).getByText(
- "leftover map comparison axis 1 (82%)",
+ "leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)",
),
).toBeInTheDocument();
expect(
within(screen.getByLabelText("Grouping comparison")).getByText(
- "leftover map comparison axis 2 (18%)",
+ "leftover map comparison graphic leftover-map axis 2 σ 0.86 (18%)",
),
).toBeInTheDocument();
expect(
diff --git a/frontend/src/components/LeftoverMapPlot.test.tsx b/frontend/src/components/LeftoverMapPlot.test.tsx
index e3717a014..40162a36b 100644
--- a/frontend/src/components/LeftoverMapPlot.test.tsx
+++ b/frontend/src/components/LeftoverMapPlot.test.tsx
@@ -843,8 +843,8 @@ describe("LeftoverMapPlot", () => {
"Leftover map comparison graphic of already-named coordinates. Click a post marker to open that post. The plot does not invent a leftover score.",
),
).toBeInTheDocument();
- expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
- expect(screen.getByText("leftover map comparison axis 2 (18%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 2 σ 0.86 (18%)")).toBeInTheDocument();
expect(screen.queryByText("leftover-map axis 1 (82%)")).not.toBeInTheDocument();
expect(screen.queryByText("leftover-map axis 2 (18%)")).not.toBeInTheDocument();
});
@@ -861,12 +861,95 @@ describe("LeftoverMapPlot", () => {
variant="comparison"
/>,
);
- expect(screen.getByText("leftover map comparison axis 1")).toBeInTheDocument();
+ expect(
+ screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84"),
+ ).toBeInTheDocument();
expect(screen.getByText("leftover map comparison axis 2")).toBeInTheDocument();
+ expect(screen.queryByText("leftover map comparison axis 1")).not.toBeInTheDocument();
expect(screen.queryByText(/leftover map comparison axis 1 \(/)).not.toBeInTheDocument();
expect(screen.queryByText(/leftover map comparison axis 2 \(/)).not.toBeInTheDocument();
expect(screen.queryByText("leftover-map axis 1")).not.toBeInTheDocument();
expect(screen.queryByText("leftover-map axis 2")).not.toBeInTheDocument();
+ expect(screen.queryByText("leftover-map axis 1 σ 1.84")).not.toBeInTheDocument();
+ });
+
+ it("names leftover-map singular values on the comparison graphic with a distinct name", () => {
+ render(
+ ,
+ );
+ expect(
+ screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)"),
+ ).toBeInTheDocument();
+ expect(
+ screen.getByText("leftover map comparison graphic leftover-map axis 2 σ 0.86 (18%)"),
+ ).toBeInTheDocument();
+ expect(screen.queryByText("leftover map comparison axis 1 (82%)")).not.toBeInTheDocument();
+ expect(screen.queryByText("leftover-map axis 1 σ 1.84 (82%)")).not.toBeInTheDocument();
+ expect(screen.queryByText("leftover axis 1 σ 1.84 82%")).not.toBeInTheDocument();
+ expect(screen.queryByText("leftover-map axis 1 (82%)")).not.toBeInTheDocument();
+ });
+
+ it("omits leftover-map comparison graphic singular values independently of leftover-map axis share", () => {
+ render(
+ ,
+ );
+ expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison axis 2 (18%)")).toBeInTheDocument();
+ expect(
+ screen.queryByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)"),
+ ).not.toBeInTheDocument();
+ expect(
+ screen.queryByText(/leftover map comparison graphic leftover-map axis 2 σ/),
+ ).not.toBeInTheDocument();
+ });
+
+ it("names rank-0 zero leftover-map singular values on the comparison graphic", () => {
+ render(
+ ,
+ );
+ expect(
+ screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 0.00 (0%)"),
+ ).toBeInTheDocument();
+ expect(
+ screen.getByText("leftover map comparison graphic leftover-map axis 2 σ 0.00 (0%)"),
+ ).toBeInTheDocument();
+ expect(screen.queryByText("leftover map comparison axis 1 (0%)")).not.toBeInTheDocument();
+ expect(screen.queryByText("leftover-map axis 1 σ 0.00 (0%)")).not.toBeInTheDocument();
});
it("names rank-0 zero leftover-map axis share on the comparison graphic", () => {
@@ -890,8 +973,8 @@ describe("LeftoverMapPlot", () => {
variant="comparison"
/>,
);
- expect(screen.getByText("leftover map comparison axis 1 (0%)")).toBeInTheDocument();
- expect(screen.getByText("leftover map comparison axis 2 (0%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 0.00 (0%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 2 σ 0.00 (0%)")).toBeInTheDocument();
});
it("names leftover-map coverage on the comparison graphic with a distinct accessible name", () => {
@@ -935,8 +1018,8 @@ describe("LeftoverMapPlot", () => {
expect(screen.queryByLabelText("Leftover map comparison incomplete posts")).not.toBeInTheDocument();
expect(screen.queryByLabelText("Leftover-map graphic incomplete items")).not.toBeInTheDocument();
expect(screen.queryByLabelText("Leftover map comparison incomplete items")).not.toBeInTheDocument();
- expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
- expect(screen.getByText("leftover map comparison axis 2 (18%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 2 σ 0.86 (18%)")).toBeInTheDocument();
});
it("omits leftover-map comparison graphic coverage when coverage is missing or not usable", () => {
@@ -954,7 +1037,7 @@ describe("LeftoverMapPlot", () => {
);
expect(screen.queryByLabelText("Leftover map comparison graphic coverage")).not.toBeInTheDocument();
expect(screen.getByLabelText("Leftover map comparison graphic")).toBeInTheDocument();
- expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
rerender(
{
"Leftover map used 2 of 2 scored criteria (complete-case)",
);
expect(screen.queryByLabelText("Leftover-map graphic coverage")).not.toBeInTheDocument();
- expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
});
it("omits leftover-map comparison graphic item coverage when item coverage is missing or not usable", () => {
@@ -1009,7 +1092,7 @@ describe("LeftoverMapPlot", () => {
);
expect(screen.queryByLabelText("Leftover map comparison graphic item coverage")).not.toBeInTheDocument();
expect(screen.queryByLabelText("Leftover-map graphic item coverage")).not.toBeInTheDocument();
- expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
rerender(
{
);
expect(screen.queryByLabelText("Leftover map comparison graphic item coverage")).not.toBeInTheDocument();
expect(screen.queryByLabelText("Leftover-map graphic item coverage")).not.toBeInTheDocument();
- expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
});
it("omits leftover-map comparison graphic incomplete posts when incomplete post coverage is missing or not usable", () => {
@@ -1067,7 +1150,7 @@ describe("LeftoverMapPlot", () => {
);
expect(screen.queryByLabelText("Leftover map comparison graphic incomplete posts")).not.toBeInTheDocument();
expect(screen.queryByLabelText("Leftover-map graphic incomplete posts")).not.toBeInTheDocument();
- expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
rerender(
{
);
expect(screen.queryByLabelText("Leftover map comparison graphic incomplete posts")).not.toBeInTheDocument();
expect(screen.queryByLabelText("Leftover-map graphic incomplete posts")).not.toBeInTheDocument();
- expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
});
it("omits leftover-map comparison graphic incomplete items when incomplete item coverage is missing or not usable", () => {
@@ -1128,7 +1211,7 @@ describe("LeftoverMapPlot", () => {
);
expect(screen.queryByLabelText("Leftover map comparison graphic incomplete items")).not.toBeInTheDocument();
expect(screen.queryByLabelText("Leftover-map graphic incomplete items")).not.toBeInTheDocument();
- expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
rerender(
{
);
expect(screen.queryByLabelText("Leftover map comparison graphic incomplete items")).not.toBeInTheDocument();
expect(screen.queryByLabelText("Leftover-map graphic incomplete items")).not.toBeInTheDocument();
- expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
});
it("names leftover-map comparison graphic coverage 0 of M on a rank-0 origin when that persisted used count is a non-negative integer", () => {
@@ -1209,8 +1292,8 @@ describe("LeftoverMapPlot", () => {
expect(screen.queryByLabelText("Leftover-map graphic item coverage")).not.toBeInTheDocument();
expect(screen.queryByLabelText("Leftover-map graphic incomplete posts")).not.toBeInTheDocument();
expect(screen.queryByLabelText("Leftover-map graphic incomplete items")).not.toBeInTheDocument();
- expect(screen.getByText("leftover map comparison axis 1 (0%)")).toBeInTheDocument();
- expect(screen.getByText("leftover map comparison axis 2 (0%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 0.00 (0%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 2 σ 0.00 (0%)")).toBeInTheDocument();
});
it("names leftover-map reconstruction on the comparison graphic with a distinct accessible name", () => {
@@ -1246,7 +1329,7 @@ describe("LeftoverMapPlot", () => {
expect(screen.getByLabelText("Leftover map comparison graphic incomplete items")).toHaveTextContent(
"Leftover map dropped 0 incomplete criteria",
);
- expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
});
it("omits leftover-map comparison graphic reconstruction when R̂ is missing or not usable", () => {
@@ -1280,7 +1363,7 @@ describe("LeftoverMapPlot", () => {
expect(screen.getByLabelText("Leftover map comparison graphic coverage")).toHaveTextContent(
"Leftover map used 2 of 3 scored posts (complete-case)",
);
- expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
});
it("names rank-0 origin reconstruction on the comparison graphic when that persisted value is finite", () => {
@@ -1323,7 +1406,7 @@ describe("LeftoverMapPlot", () => {
expect(screen.getByLabelText("Leftover map comparison graphic coverage")).toHaveTextContent(
"Leftover map used 0 of 3 scored posts (complete-case)",
);
- expect(screen.getByText("leftover map comparison axis 1 (0%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 0.00 (0%)")).toBeInTheDocument();
});
it("names leftover-map explained leftover share on the comparison graphic with a distinct accessible name", () => {
@@ -1359,7 +1442,7 @@ describe("LeftoverMapPlot", () => {
expect(
screen.getByLabelText("leftover map comparison graphic reconstruction R̂ +0.25"),
).toHaveTextContent("R̂ +0.25");
- expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
});
it("omits leftover-map comparison graphic explained leftover share when e is missing or not usable", () => {
@@ -1396,7 +1479,7 @@ describe("LeftoverMapPlot", () => {
expect(screen.getByLabelText("Leftover map comparison graphic coverage")).toHaveTextContent(
"Leftover map used 2 of 3 scored posts (complete-case)",
);
- expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
});
it("names rank-0 origin explained leftover share on the comparison graphic when that persisted value is finite", () => {
@@ -1443,7 +1526,7 @@ describe("LeftoverMapPlot", () => {
expect(screen.getByLabelText("Leftover map comparison graphic coverage")).toHaveTextContent(
"Leftover map used 0 of 3 scored posts (complete-case)",
);
- expect(screen.getByText("leftover map comparison axis 1 (0%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 0.00 (0%)")).toBeInTheDocument();
});
it("names leftover-map unexplained leftover share on the comparison graphic with a distinct accessible name", () => {
@@ -1482,7 +1565,7 @@ describe("LeftoverMapPlot", () => {
expect(
screen.getByLabelText("leftover map comparison graphic reconstruction R̂ +0.25"),
).toHaveTextContent("R̂ +0.25");
- expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
});
it("omits leftover-map comparison graphic unexplained leftover share when s is missing or not usable", () => {
@@ -1522,7 +1605,7 @@ describe("LeftoverMapPlot", () => {
expect(screen.getByLabelText("Leftover map comparison graphic coverage")).toHaveTextContent(
"Leftover map used 2 of 3 scored posts (complete-case)",
);
- expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
});
it("names rank-0 origin unexplained leftover share on the comparison graphic when that persisted value is finite", () => {
@@ -1573,7 +1656,7 @@ describe("LeftoverMapPlot", () => {
expect(screen.getByLabelText("Leftover map comparison graphic coverage")).toHaveTextContent(
"Leftover map used 0 of 3 scored posts (complete-case)",
);
- expect(screen.getByText("leftover map comparison axis 1 (0%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 0.00 (0%)")).toBeInTheDocument();
});
it("names leftover-map cross share on the comparison graphic with a distinct accessible name", () => {
@@ -1615,7 +1698,7 @@ describe("LeftoverMapPlot", () => {
expect(
screen.getByLabelText("leftover map comparison graphic reconstruction R̂ +0.25"),
).toHaveTextContent("R̂ +0.25");
- expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
});
it("omits leftover-map comparison graphic cross share when x is missing or not usable", () => {
@@ -1658,7 +1741,7 @@ describe("LeftoverMapPlot", () => {
expect(screen.getByLabelText("Leftover map comparison graphic coverage")).toHaveTextContent(
"Leftover map used 2 of 3 scored posts (complete-case)",
);
- expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
});
it("names rank-0 origin leftover-map cross share on the comparison graphic when that persisted value is finite", () => {
@@ -1713,7 +1796,7 @@ describe("LeftoverMapPlot", () => {
expect(screen.getByLabelText("Leftover map comparison graphic coverage")).toHaveTextContent(
"Leftover map used 0 of 3 scored posts (complete-case)",
);
- expect(screen.getByText("leftover map comparison axis 1 (0%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 0.00 (0%)")).toBeInTheDocument();
});
it("names leftover-map unexplained leftover on the comparison graphic with a distinct accessible name", () => {
@@ -1758,7 +1841,7 @@ describe("LeftoverMapPlot", () => {
expect(
screen.getByLabelText("leftover map comparison graphic reconstruction R̂ +0.25"),
).toHaveTextContent("R̂ +0.25");
- expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
});
it("omits leftover-map comparison graphic unexplained leftover when U is missing or not usable", () => {
@@ -1804,7 +1887,7 @@ describe("LeftoverMapPlot", () => {
expect(screen.getByLabelText("Leftover map comparison graphic coverage")).toHaveTextContent(
"Leftover map used 2 of 3 scored posts (complete-case)",
);
- expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
});
it("names rank-0 origin leftover-map unexplained leftover on the comparison graphic when that persisted value is finite", () => {
@@ -1863,7 +1946,7 @@ describe("LeftoverMapPlot", () => {
expect(screen.getByLabelText("Leftover map comparison graphic coverage")).toHaveTextContent(
"Leftover map used 0 of 3 scored posts (complete-case)",
);
- expect(screen.getByText("leftover map comparison axis 1 (0%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 0.00 (0%)")).toBeInTheDocument();
});
it("names leftover residual on the comparison graphic with a distinct accessible name", () => {
@@ -1911,7 +1994,7 @@ describe("LeftoverMapPlot", () => {
expect(
screen.getByLabelText("leftover map comparison graphic reconstruction R̂ +0.25"),
).toHaveTextContent("R̂ +0.25");
- expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
});
it("omits leftover-map comparison graphic leftover residual when R is missing or not usable", () => {
@@ -1960,7 +2043,7 @@ describe("LeftoverMapPlot", () => {
expect(screen.getByLabelText("Leftover map comparison graphic coverage")).toHaveTextContent(
"Leftover map used 2 of 3 scored posts (complete-case)",
);
- expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
});
it("names rank-0 origin leftover residual on the comparison graphic when that persisted value is finite", () => {
@@ -2022,7 +2105,7 @@ describe("LeftoverMapPlot", () => {
expect(screen.getByLabelText("Leftover map comparison graphic coverage")).toHaveTextContent(
"Leftover map used 0 of 3 scored posts (complete-case)",
);
- expect(screen.getByText("leftover map comparison axis 1 (0%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 0.00 (0%)")).toBeInTheDocument();
});
it("names leftover observed on the comparison graphic with a distinct accessible name", () => {
@@ -2064,7 +2147,7 @@ describe("LeftoverMapPlot", () => {
expect(
screen.getByLabelText("leftover map comparison graphic reconstruction R̂ +0.25"),
).toHaveTextContent("R̂ +0.25");
- expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
});
it("omits leftover-map comparison graphic leftover observed when Y is missing or not usable", () => {
@@ -2106,7 +2189,7 @@ describe("LeftoverMapPlot", () => {
expect(screen.getByLabelText("Leftover map comparison graphic coverage")).toHaveTextContent(
"Leftover map used 2 of 3 scored posts (complete-case)",
);
- expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
});
it("names rank-0 origin leftover observed on the comparison graphic when that persisted value is finite", () => {
@@ -2163,7 +2246,7 @@ describe("LeftoverMapPlot", () => {
expect(screen.getByLabelText("Leftover map comparison graphic coverage")).toHaveTextContent(
"Leftover map used 0 of 3 scored posts (complete-case)",
);
- expect(screen.getByText("leftover map comparison axis 1 (0%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 0.00 (0%)")).toBeInTheDocument();
});
it("names leftover expected on the comparison graphic with a distinct accessible name", () => {
@@ -2198,7 +2281,7 @@ describe("LeftoverMapPlot", () => {
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();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
});
it("omits leftover-map comparison graphic leftover expected when E is missing or not usable", () => {
@@ -2234,7 +2317,7 @@ describe("LeftoverMapPlot", () => {
screen.getByLabelText("leftover map comparison graphic leftover residual R +0.40"),
).toHaveTextContent("R +0.40");
expect(screen.getByLabelText("leftover map comparison graphic leftover-map distance d 0.12")).toBeInTheDocument();
- expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
});
it("names rank-0 origin leftover expected on the comparison graphic when that persisted value is finite", () => {
@@ -2286,7 +2369,7 @@ describe("LeftoverMapPlot", () => {
expect(
screen.getByLabelText("leftover map comparison graphic leftover residual R 0.00"),
).toHaveTextContent("R 0.00");
- expect(screen.getByText("leftover map comparison axis 1 (0%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 0.00 (0%)")).toBeInTheDocument();
});
it("names leftover-map rank on the comparison graphic with a distinct accessible name", () => {
@@ -2324,7 +2407,7 @@ describe("LeftoverMapPlot", () => {
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();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
});
it("omits leftover-map comparison graphic leftover-map rank when rank is missing or not usable", () => {
@@ -2363,7 +2446,7 @@ describe("LeftoverMapPlot", () => {
screen.getByLabelText("leftover map comparison graphic leftover residual R +0.40"),
).toHaveTextContent("R +0.40");
expect(screen.getByLabelText("leftover map comparison graphic leftover-map distance d 0.12")).toBeInTheDocument();
- expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
});
it("names rank-0 origin leftover-map rank on the comparison graphic when that persisted value is a non-negative integer", () => {
@@ -2418,7 +2501,7 @@ describe("LeftoverMapPlot", () => {
expect(
screen.getByLabelText("leftover map comparison graphic leftover residual R 0.00"),
).toHaveTextContent("R 0.00");
- expect(screen.getByText("leftover map comparison axis 1 (0%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 0.00 (0%)")).toBeInTheDocument();
});
it("names leftover-map distance on the comparison graphic with a distinct accessible name", () => {
@@ -2456,7 +2539,7 @@ describe("LeftoverMapPlot", () => {
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();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
});
it("omits leftover-map comparison graphic leftover-map distance when d is missing or not usable", () => {
@@ -2494,7 +2577,7 @@ describe("LeftoverMapPlot", () => {
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();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
});
it("names rank-0 origin leftover-map distance on the comparison graphic when that persisted value is finite", () => {
@@ -2546,7 +2629,7 @@ describe("LeftoverMapPlot", () => {
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();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 0.00 (0%)")).toBeInTheDocument();
});
it("names leftover-map coordinate ticks on the comparison graphic with a distinct accessible name", () => {
@@ -2588,7 +2671,7 @@ describe("LeftoverMapPlot", () => {
expect(
screen.getAllByLabelText("leftover map comparison graphic leftover-map rank rank 1"),
).toHaveLength(2);
- expect(screen.getByText("leftover map comparison axis 1 (82%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument();
});
it("omits invented leftover-map comparison graphic leftover-map axis ticks that no persisted coordinate occupies", () => {
@@ -2644,7 +2727,7 @@ describe("LeftoverMapPlot", () => {
expect(
screen.getByLabelText("leftover map comparison graphic leftover-map distance d 0.00"),
).toHaveTextContent("d 0.00");
- expect(screen.getByText("leftover map comparison axis 1 (0%)")).toBeInTheDocument();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 0.00 (0%)")).toBeInTheDocument();
});
it("names rank-0 origin leftover-map coordinate ticks on the comparison graphic", () => {
@@ -2700,6 +2783,6 @@ describe("LeftoverMapPlot", () => {
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();
+ expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 0.00 (0%)")).toBeInTheDocument();
});
});
diff --git a/frontend/src/components/LeftoverMapPlot.tsx b/frontend/src/components/LeftoverMapPlot.tsx
index c0636c65c..a93f6eae8 100644
--- a/frontend/src/components/LeftoverMapPlot.tsx
+++ b/frontend/src/components/LeftoverMapPlot.tsx
@@ -27,6 +27,12 @@ import {
LEFTOVER_MAP_COMPARE_PLOT_AXIS_SHARE,
LEFTOVER_MAP_PLOT_AXIS_SHARE,
} from "../leftoverMapPlotAxisShare";
+import {
+ formatLeftoverMapPlotAxisSingular,
+ leftoverSingularForAxis,
+ LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR,
+ LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR_SHARE,
+} from "../leftoverMapPlotAxisSingular";
import {
firstPlottablePairForPost,
layoutLeftoverMapPlot,
@@ -84,10 +90,23 @@ function leftoverMapPlotAxisText(
leftoverShareForAxis(leftoverMapAxes, axisIndex),
);
if (variant === "comparison") {
- if (percent === null) {
+ const singular = formatLeftoverMapPlotAxisSingular(
+ leftoverSingularForAxis(leftoverMapAxes, axisIndex),
+ );
+ if (singular === null && percent === null) {
return t(axisIndex === 1 ? LEFTOVER_MAP_COMPARE_PLOT_AXIS_1 : LEFTOVER_MAP_COMPARE_PLOT_AXIS_2);
}
- return tf(LEFTOVER_MAP_COMPARE_PLOT_AXIS_SHARE, { axis: axisIndex, share: percent });
+ if (singular === null) {
+ return tf(LEFTOVER_MAP_COMPARE_PLOT_AXIS_SHARE, { axis: axisIndex, share: percent });
+ }
+ if (percent === null) {
+ return tf(LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR, { axis: axisIndex, value: singular });
+ }
+ return tf(LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR_SHARE, {
+ axis: axisIndex,
+ value: singular,
+ share: percent,
+ });
}
if (percent === null) {
return t(axisIndex === 1 ? "leftover-map axis 1" : "leftover-map axis 2");
@@ -129,8 +148,10 @@ function leftoverMapPlotAxisText(
* caption when incomplete post coverage is missing or not a usable integer.
* Omit that leftover-map incomplete item caption when incomplete item
* coverage is missing or not a usable integer.
- * Omit that axis badge when share is
- * missing or non-finite and keep the existing leftover-map axis text.
+ * Omit that axis singular-value badge when ``σ_k`` is missing, non-finite,
+ * or negative, independently of leftover-map axis share. Omit that axis badge when share is
+ * missing or non-finite and keep the existing leftover-map axis text,
+ * including any leftover-map comparison graphic leftover-map axis singular value.
* Omit the plot when no pair has four finite leftover-map coordinates.
* ADR 0304 reuses this graphic on the grouping comparison strip from
* already-named leftover-map coordinates. ADR 0305 captions leftover-map axis
@@ -181,6 +202,9 @@ function leftoverMapPlotAxisText(
* labels. ADR 0320 captions leftover-map coordinate ticks on that
* comparison graphic from already-named leftover-map coordinates
* with distinct leftover map comparison graphic leftover-map axis tick
+ * labels. ADR 0321 captions leftover-map singular values on that
+ * comparison graphic from already-named leftover-map axes
+ * with distinct leftover map comparison graphic leftover-map axis σ
* labels.
* Never invent a leftover score.
*/
diff --git a/frontend/src/i18n.test.ts b/frontend/src/i18n.test.ts
index d7ee7ef32..57b911fb0 100644
--- a/frontend/src/i18n.test.ts
+++ b/frontend/src/i18n.test.ts
@@ -105,6 +105,8 @@ describe("i18n", () => {
"Leftover map comparison rank",
"leftover map comparison graphic leftover-map distance {label}",
"leftover map comparison graphic leftover-map axis {axis} tick {value}",
+ "leftover map comparison graphic leftover-map axis {axis} σ {value}",
+ "leftover map comparison graphic leftover-map axis {axis} σ {value} ({share}%)",
"Leftover map comparison coordinates",
"Leftover map comparison graphic",
"Leftover map comparison",
@@ -688,6 +690,43 @@ describe("i18n", () => {
},
);
+ it.each([
+ ["ko", "잔여 지도 비교 그림 축 1 σ 1.84"],
+ ["zh", "残差地图比较图形轴 1 σ 1.84"],
+ ["ja", "残差マップの比較図軸 1 σ 1.84"],
+ ["vi", "trục đồ họa so sánh bản đồ phần dư 1 σ 1.84"],
+ ] as const)(
+ "formats leftover map comparison graphic leftover-map axis singular values in %s",
+ (locale, expected) => {
+ setLocale(locale);
+ expect(
+ tf("leftover map comparison graphic leftover-map axis {axis} σ {value}", {
+ axis: 1,
+ value: "1.84",
+ }),
+ ).toBe(expected);
+ },
+ );
+
+ it.each([
+ ["ko", "잔여 지도 비교 그림 축 1 σ 1.84 (82%)"],
+ ["zh", "残差地图比较图形轴 1 σ 1.84 (82%)"],
+ ["ja", "残差マップの比較図軸 1 σ 1.84 (82%)"],
+ ["vi", "trục đồ họa so sánh bản đồ phần dư 1 σ 1.84 (82%)"],
+ ] as const)(
+ "formats leftover map comparison graphic leftover-map axis singular share in %s",
+ (locale, expected) => {
+ setLocale(locale);
+ expect(
+ tf("leftover map comparison graphic leftover-map axis {axis} σ {value} ({share}%)", {
+ axis: 1,
+ value: "1.84",
+ share: "82",
+ }),
+ ).toBe(expected);
+ },
+ );
+
it.each([
["ko", "잔여 지도 비교 설명 잔여 점유율"],
["zh", "残差地图比较已解释残差份额"],
diff --git a/frontend/src/i18n.ts b/frontend/src/i18n.ts
index e1fa05892..203113342 100644
--- a/frontend/src/i18n.ts
+++ b/frontend/src/i18n.ts
@@ -297,6 +297,9 @@ const TRANSLATIONS: Partial>> = {
"Leftover map comparison rank": "잔여 지도 비교 순위",
"leftover map comparison graphic leftover-map distance {label}": "잔여 지도 비교 그림 거리 {label}",
"leftover map comparison graphic leftover-map axis {axis} tick {value}": "잔여 지도 비교 그림 축 {axis} 눈금 {value}",
+ "leftover map comparison graphic leftover-map axis {axis} σ {value}": "잔여 지도 비교 그림 축 {axis} σ {value}",
+ "leftover map comparison graphic leftover-map axis {axis} σ {value} ({share}%)":
+ "잔여 지도 비교 그림 축 {axis} σ {value} ({share}%)",
"Leftover map comparison coordinates": "잔여 지도 비교 좌표",
"Leftover map comparison graphic": "잔여 지도 비교 그림",
"Leftover map comparison": "잔여 지도 비교",
@@ -940,6 +943,9 @@ const TRANSLATIONS: Partial>> = {
"Leftover map comparison rank": "残差地图比较秩",
"leftover map comparison graphic leftover-map distance {label}": "残差地图比较图形距离 {label}",
"leftover map comparison graphic leftover-map axis {axis} tick {value}": "残差地图比较图形轴 {axis} 刻度 {value}",
+ "leftover map comparison graphic leftover-map axis {axis} σ {value}": "残差地图比较图形轴 {axis} σ {value}",
+ "leftover map comparison graphic leftover-map axis {axis} σ {value} ({share}%)":
+ "残差地图比较图形轴 {axis} σ {value} ({share}%)",
"Leftover map comparison coordinates": "残差地图比较坐标",
"Leftover map comparison graphic": "残差地图比较图形",
"Leftover map comparison": "残差地图比较",
@@ -1604,6 +1610,9 @@ const TRANSLATIONS: Partial>> = {
"Leftover map comparison rank": "残差マップの比較階数",
"leftover map comparison graphic leftover-map distance {label}": "残差マップの比較図距離 {label}",
"leftover map comparison graphic leftover-map axis {axis} tick {value}": "残差マップの比較図軸 {axis} 目盛 {value}",
+ "leftover map comparison graphic leftover-map axis {axis} σ {value}": "残差マップの比較図軸 {axis} σ {value}",
+ "leftover map comparison graphic leftover-map axis {axis} σ {value} ({share}%)":
+ "残差マップの比較図軸 {axis} σ {value} ({share}%)",
"Leftover map comparison coordinates": "残差マップの比較座標",
"Leftover map comparison graphic": "残差マップの比較図",
"Leftover map comparison": "残差マップの比較",
@@ -2247,6 +2256,10 @@ const TRANSLATIONS: Partial>> = {
"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 graphic leftover-map axis {axis} tick {value}": "vạch trục đồ họa so sánh bản đồ phần dư {axis} {value}",
+ "leftover map comparison graphic leftover-map axis {axis} σ {value}":
+ "trục đồ họa so sánh bản đồ phần dư {axis} σ {value}",
+ "leftover map comparison graphic leftover-map axis {axis} σ {value} ({share}%)":
+ "trục đồ họa so sánh bản đồ phần dư {axis} σ {value} ({share}%)",
"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/leftoverMapPlotAxisShare.test.ts b/frontend/src/leftoverMapPlotAxisShare.test.ts
index 6c99dac66..7315be18d 100644
--- a/frontend/src/leftoverMapPlotAxisShare.test.ts
+++ b/frontend/src/leftoverMapPlotAxisShare.test.ts
@@ -7,6 +7,10 @@ import {
LEFTOVER_MAP_COMPARE_PLOT_AXIS_SHARE,
LEFTOVER_MAP_PLOT_AXIS_SHARE,
} from "./leftoverMapPlotAxisShare";
+import {
+ LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR,
+ LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR_SHARE,
+} from "./leftoverMapPlotAxisSingular";
describe("leftoverShareForAxis", () => {
const axes = [
@@ -63,5 +67,9 @@ describe("leftover map comparison axis share labels", () => {
expect(LEFTOVER_MAP_COMPARE_PLOT_AXIS_SHARE).not.toBe(LEFTOVER_MAP_PLOT_AXIS_SHARE);
expect(LEFTOVER_MAP_COMPARE_PLOT_AXIS_1).not.toBe("leftover-map axis 1");
expect(LEFTOVER_MAP_COMPARE_PLOT_AXIS_2).not.toBe("leftover-map axis 2");
+ expect(LEFTOVER_MAP_COMPARE_PLOT_AXIS_SHARE).not.toBe(
+ LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR_SHARE,
+ );
+ expect(LEFTOVER_MAP_COMPARE_PLOT_AXIS_1).not.toBe(LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR);
});
});
diff --git a/frontend/src/leftoverMapPlotAxisSingular.test.ts b/frontend/src/leftoverMapPlotAxisSingular.test.ts
new file mode 100644
index 000000000..77cb55e73
--- /dev/null
+++ b/frontend/src/leftoverMapPlotAxisSingular.test.ts
@@ -0,0 +1,93 @@
+import { describe, expect, it } from "vitest";
+import {
+ formatLeftoverMapPlotAxisSingular,
+ leftoverSingularForAxis,
+ LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR,
+ LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR_SHARE,
+ LEFTOVER_MAP_PLOT_AXIS_SINGULAR,
+ LEFTOVER_MAP_PLOT_AXIS_SINGULAR_SHARE,
+} from "./leftoverMapPlotAxisSingular";
+import { LEFTOVER_MAP_COMPARE_PLOT_AXIS_SHARE } from "./leftoverMapPlotAxisShare";
+import { LEFTOVER_MAP_COMPARE_PLOT_TICK } from "./leftoverMapPlotLayout";
+
+describe("leftoverSingularForAxis", () => {
+ const axes = [
+ { axis_index: 1, leftover_singular_value: 1.84 },
+ { axis_index: 2, leftover_singular_value: 0.86 },
+ ];
+
+ it("reads persisted leftover-map singular values without inventing a leftover score", () => {
+ expect(leftoverSingularForAxis(axes, 1)).toBe(1.84);
+ expect(leftoverSingularForAxis(axes, 2)).toBe(0.86);
+ });
+
+ it("names a rank-0 zero leftover-map singular value", () => {
+ expect(
+ leftoverSingularForAxis(
+ [
+ { axis_index: 1, leftover_singular_value: 0 },
+ { axis_index: 2, leftover_singular_value: 0 },
+ ],
+ 1,
+ ),
+ ).toBe(0);
+ });
+
+ it("omits a leftover-map axis when singular value is missing, non-finite, or negative", () => {
+ expect(leftoverSingularForAxis(undefined, 1)).toBeNull();
+ expect(leftoverSingularForAxis([], 1)).toBeNull();
+ expect(leftoverSingularForAxis([{ axis_index: 1, leftover_singular_value: null }], 1)).toBeNull();
+ expect(
+ leftoverSingularForAxis([{ axis_index: 1, leftover_singular_value: Number.NaN }], 1),
+ ).toBeNull();
+ expect(
+ leftoverSingularForAxis(
+ [{ axis_index: 1, leftover_singular_value: Number.POSITIVE_INFINITY }],
+ 1,
+ ),
+ ).toBeNull();
+ expect(leftoverSingularForAxis([{ axis_index: 1, leftover_singular_value: -0.01 }], 1)).toBeNull();
+ expect(leftoverSingularForAxis(axes, 3)).toBeNull();
+ });
+
+ it("does not invent leftover-map singular values from leftover-map axis share", () => {
+ expect(leftoverSingularForAxis([{ axis_index: 1 }], 1)).toBeNull();
+ });
+});
+
+describe("formatLeftoverMapPlotAxisSingular", () => {
+ it("formats persisted leftover-map singular values without inventing a leftover score", () => {
+ expect(formatLeftoverMapPlotAxisSingular(1.84)).toBe("1.84");
+ expect(formatLeftoverMapPlotAxisSingular(0.86)).toBe("0.86");
+ expect(formatLeftoverMapPlotAxisSingular(0)).toBe("0.00");
+ });
+
+ it("omits leftover-map singular values when the value is missing, non-finite, or negative", () => {
+ expect(formatLeftoverMapPlotAxisSingular(null)).toBeNull();
+ expect(formatLeftoverMapPlotAxisSingular(undefined)).toBeNull();
+ expect(formatLeftoverMapPlotAxisSingular(Number.NaN)).toBeNull();
+ expect(formatLeftoverMapPlotAxisSingular(Number.POSITIVE_INFINITY)).toBeNull();
+ expect(formatLeftoverMapPlotAxisSingular(Number.NEGATIVE_INFINITY)).toBeNull();
+ expect(formatLeftoverMapPlotAxisSingular(-0.01)).toBeNull();
+ });
+});
+
+describe("leftover map comparison graphic leftover-map axis singular labels", () => {
+ it("stays distinct from leftover-map graphic axis singular copy and comparison axis share", () => {
+ expect(LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR).toBe(
+ "leftover map comparison graphic leftover-map axis {axis} σ {value}",
+ );
+ expect(LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR_SHARE).toBe(
+ "leftover map comparison graphic leftover-map axis {axis} σ {value} ({share}%)",
+ );
+ expect(LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR).not.toBe(LEFTOVER_MAP_PLOT_AXIS_SINGULAR);
+ expect(LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR_SHARE).not.toBe(
+ LEFTOVER_MAP_PLOT_AXIS_SINGULAR_SHARE,
+ );
+ expect(LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR_SHARE).not.toBe(
+ LEFTOVER_MAP_COMPARE_PLOT_AXIS_SHARE,
+ );
+ expect(LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR).not.toBe(LEFTOVER_MAP_COMPARE_PLOT_TICK);
+ expect(LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR).not.toBe("leftover axis {axis} σ {value}");
+ });
+});
diff --git a/frontend/src/leftoverMapPlotAxisSingular.ts b/frontend/src/leftoverMapPlotAxisSingular.ts
new file mode 100644
index 000000000..a621fe351
--- /dev/null
+++ b/frontend/src/leftoverMapPlotAxisSingular.ts
@@ -0,0 +1,44 @@
+/** Caption leftover-map plot axes with persisted Gabriel singular values. */
+
+import type { LeftoverMapAxis } from "./api";
+
+export const LEFTOVER_MAP_PLOT_AXIS_SINGULAR = "leftover-map axis {axis} σ {value}";
+
+export const LEFTOVER_MAP_PLOT_AXIS_SINGULAR_SHARE =
+ "leftover-map axis {axis} σ {value} ({share}%)";
+
+export const LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR =
+ "leftover map comparison graphic leftover-map axis {axis} σ {value}";
+
+export const LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR_SHARE =
+ "leftover map comparison graphic leftover-map axis {axis} σ {value} ({share}%)";
+
+export type LeftoverMapPlotAxisSingular = {
+ axis_index: LeftoverMapAxis["axis_index"];
+ leftover_singular_value?: LeftoverMapAxis["leftover_singular_value"] | null;
+};
+
+export function leftoverSingularForAxis(
+ axes: ReadonlyArray | null | undefined,
+ axisIndex: number,
+): number | null {
+ const axis = axes?.find((candidate) => candidate.axis_index === axisIndex);
+ if (
+ axis == null ||
+ axis.leftover_singular_value == null ||
+ !Number.isFinite(axis.leftover_singular_value) ||
+ axis.leftover_singular_value < 0
+ ) {
+ return null;
+ }
+ return axis.leftover_singular_value;
+}
+
+export function formatLeftoverMapPlotAxisSingular(
+ leftoverSingular: number | null | undefined,
+): string | null {
+ if (leftoverSingular == null || !Number.isFinite(leftoverSingular) || leftoverSingular < 0) {
+ return null;
+ }
+ return leftoverSingular.toFixed(2);
+}
diff --git a/frontend/src/leftoverMapPlotLayout.test.ts b/frontend/src/leftoverMapPlotLayout.test.ts
index d3d5481e0..6787cd828 100644
--- a/frontend/src/leftoverMapPlotLayout.test.ts
+++ b/frontend/src/leftoverMapPlotLayout.test.ts
@@ -1366,6 +1366,9 @@ describe("leftover map comparison graphic labels", () => {
expect(LEFTOVER_MAP_COMPARE_PLOT_TICK).not.toBe(
"leftover map comparison axis {axis} ({share}%)",
);
+ expect(LEFTOVER_MAP_COMPARE_PLOT_TICK).not.toBe(
+ "leftover map comparison graphic leftover-map axis {axis} σ {value}",
+ );
expect(LEFTOVER_MAP_COMPARE_PLOT_TICK).not.toBe(
LEFTOVER_MAP_COMPARE_PLOT_SEGMENT_DISTANCE,
);
diff --git a/frontend/src/leftoverMapPlotLayout.ts b/frontend/src/leftoverMapPlotLayout.ts
index 2c86013e5..c0dac3c23 100644
--- a/frontend/src/leftoverMapPlotLayout.ts
+++ b/frontend/src/leftoverMapPlotLayout.ts
@@ -48,7 +48,8 @@
* expected on that graphic (ADR 0317), and grouping comparison leftover-map
* rank on that graphic (ADR 0318), grouping comparison leftover-map
* distance on that graphic (ADR 0319), and grouping comparison leftover-map
- * coordinate ticks on that graphic (ADR 0320) caption the pair list or the grouping comparison
+ * coordinate ticks on that graphic (ADR 0320), and grouping comparison leftover-map
+ * singular values on that graphic (ADR 0321) 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
@@ -78,6 +79,8 @@
* already-named leftover-map distance.
* ADR 0320 captions leftover-map coordinate ticks on that comparison graphic from
* already-named leftover-map coordinates.
+ * ADR 0321 captions leftover-map singular values on that comparison graphic from
+ * already-named leftover-map axes.
*/
import { formatLeftoverMapCoordinatePair } from "./leftoverMapCoordinates";
diff --git a/pyproject.toml b/pyproject.toml
index c1f5188d8..703556def 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "lineageweave"
-version = "2.77.0"
+version = "2.78.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" }