From 47797643dc5c3071a7bbe3970ab563755113aa5b Mon Sep 17 00:00:00 2001
From: seonghobae
Date: Sun, 30 Aug 2026 20:14:38 +0000
Subject: [PATCH] feat(reports): leftover-map item coverage on grouping
comparison graphic (v2.64.0)
Caption leftover-map item complete-case coverage on the grouping comparison leftover-map graphic from already-named leftover_map_coverage (ADR 0307). Distinct accessible name Leftover map comparison graphic item coverage. Omit incomplete notes on that comparison plot. Never invent a leftover score or a theta.
---
AGENTS.md | 20 +-
ARCHITECTURE.md | 12 +-
...leftover-map-compare-plot-item-coverage.md | 25 ++
CHANGELOG.md | 72 +++++
CLAUDE.md | 2 +-
.../0282-leftover-map-plot-item-coverage.md | 3 +
...0290-leftover-map-compare-item-coverage.md | 3 +
docs/adr/0304-leftover-map-compare-graphic.md | 4 +-
...0306-leftover-map-compare-plot-coverage.md | 3 +
...leftover-map-compare-plot-item-coverage.md | 254 ++++++++++++++++++
docs/product-technical-gap-baseline.md | 19 ++
docs/storybook-inventory.md | 2 +-
frontend/package.json | 2 +-
frontend/src/App.test.tsx | 18 ++
.../components/LeftoverMapPlot.stories.tsx | 14 +
.../src/components/LeftoverMapPlot.test.tsx | 65 +++++
frontend/src/components/LeftoverMapPlot.tsx | 17 +-
frontend/src/components/LeftoverPairList.tsx | 4 +-
frontend/src/i18n.test.ts | 11 +
frontend/src/i18n.ts | 4 +
frontend/src/leftoverMapCoverage.test.ts | 11 +
frontend/src/leftoverMapCoverage.ts | 5 +-
frontend/src/leftoverMapPlotLayout.ts | 10 +-
pyproject.toml | 2 +-
uv.lock | 2 +-
25 files changed, 561 insertions(+), 23 deletions(-)
create mode 100644 CHANGELOG.d/2.64.0-leftover-map-compare-plot-item-coverage.md
create mode 100644 docs/adr/0307-leftover-map-compare-plot-item-coverage.md
diff --git a/AGENTS.md b/AGENTS.md
index ef3a9a1eb..c947ebc89 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -273,7 +273,7 @@ stops startup instead of leaving a healthy-looking partial schema, and
application code must not compensate for a missing table.
Period leftover pairs (ADR 0017 / 0018 / 0048 / 0049 / 0119 / 0158 / 0162 /
-0163 / 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) are computed in `lineageweave/leftover_pairs.py` from the
+0163 / 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) are computed in `lineageweave/leftover_pairs.py` from the
residual after a real GRM/GPCM score, never invented. Distances are
Euclidean on the two-dimensional Gabriel leftover map; missing cells stay
out of the factorization. Closest and farthest post–criterion pairs
@@ -503,8 +503,18 @@ Do not invent leftover-map coverage from plotted marker count, leftover pair
count, leftover-map rank, leftover-map distance, leftover-map axis share,
leftover-map reconstruction, leftover residual, leftover-map item coverage,
leftover-map incomplete post coverage, leftover-map incomplete item coverage,
-or the count of unused axes. This increment does not caption leftover-map item
-coverage or leftover-map incomplete coverage on the comparison graphic.
+or the count of unused axes. ADR 0307 captions leftover-map item complete-case
+coverage on that grouping comparison leftover-map graphic when leftoverMapItemCoverageCounts
+returns usable complete-case integers; a missing, non-integer, negative-used,
+non-positive-scored, or used-greater-than-scored item coverage omits that leftover-map
+comparison graphic item coverage caption and keeps leftover-map comparison graphic
+coverage when leftoverMapCoverageCounts returns usable complete-case integers.
+Do not invent leftover-map item coverage from plotted criterion marker count,
+leftover pair count, leftover-map rank, leftover-map distance, leftover-map
+axis share, leftover-map reconstruction, leftover residual, leftover-map post
+coverage, leftover-map incomplete post coverage, leftover-map incomplete item
+coverage, or the count of unused axes. This increment does not caption leftover-map
+incomplete coverage on the comparison graphic.
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
@@ -557,6 +567,10 @@ comparison leftover-map graphic with persisted leftover-map axis share.
Grouping comparison leftover-map complete-case coverage (ADR 0306) captions that
grouping comparison leftover-map graphic with persisted leftover-map complete-case
coverage when leftoverMapCoverageCounts returns usable complete-case integers.
+Grouping comparison leftover-map item complete-case coverage (ADR 0307) captions
+that grouping comparison leftover-map graphic with persisted leftover-map item
+complete-case coverage when leftoverMapItemCoverageCounts returns usable
+complete-case integers.
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 6dbd73d35..d641ce5c7 100644
--- a/ARCHITECTURE.md
+++ b/ARCHITECTURE.md
@@ -706,8 +706,11 @@ on that grouping comparison leftover-map graphic when the persisted share
is finite.
ADR 0306 captions leftover-map complete-case coverage on that grouping
comparison leftover-map graphic when leftoverMapCoverageCounts returns usable
-complete-case integers and does not caption leftover-map item coverage or
-leftover-map incomplete coverage on that comparison plot.
+complete-case integers.
+ADR 0307 captions leftover-map item complete-case coverage on that grouping
+comparison leftover-map graphic when leftoverMapItemCoverageCounts returns usable
+complete-case integers and does not caption leftover-map incomplete coverage
+on that comparison plot.
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
@@ -741,8 +744,9 @@ incomplete item coverage (ADR 0292), leftover-map reconstruction `R̂`
(ADR 0302), leftover-map coordinates on the compare leftover-pair payload
(ADR 0303), leftover-map graphic display on the grouping comparison strip
(ADR 0304), leftover-map axis share on the grouping comparison leftover-map
-graphic (ADR 0305), and leftover-map complete-case coverage on the grouping
-comparison leftover-map graphic (ADR 0306);
+graphic (ADR 0305), leftover-map complete-case coverage on the grouping
+comparison leftover-map graphic (ADR 0306), and leftover-map item complete-case
+coverage on the grouping comparison leftover-map graphic (ADR 0307);
`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.64.0-leftover-map-compare-plot-item-coverage.md b/CHANGELOG.d/2.64.0-leftover-map-compare-plot-item-coverage.md
new file mode 100644
index 000000000..61cd4c119
--- /dev/null
+++ b/CHANGELOG.d/2.64.0-leftover-map-compare-plot-item-coverage.md
@@ -0,0 +1,25 @@
+## 2.64.0 — Leftover-map item complete-case coverage on grouping comparison leftover-map graphic
+
+- Caption leftover-map item complete-case coverage on the grouping comparison
+ leftover-map graphic (ADR 0307). After `make seed`, closest and farthest
+ leftover pairs sit above the member list with the Gabriel biplot of
+ already-named coordinates, leftover-map axis share when finite, leftover-map
+ complete-case coverage when leftoverMapCoverageCounts returns usable
+ complete-case integers, and a plot caption that matches leftover-map item
+ complete-case coverage on the grouping comparison leftover-map graphic; click
+ a post marker or a pair button opens that post. A missing, non-integer,
+ negative-used, non-positive-scored, or used-greater-than-scored item coverage
+ omits that leftover-map comparison graphic item coverage caption and keeps
+ leftover-map comparison graphic coverage when leftoverMapCoverageCounts
+ returns usable complete-case integers. Coverage `0 of M` is shown when that
+ persisted used count is a non-negative integer. Comparison copy uses
+ `Leftover map comparison graphic item coverage` so it stays distinct from
+ hyphen `Leftover-map graphic item coverage` and from strip
+ `Leftover map comparison item coverage`. This increment does not caption
+ leftover-map incomplete post coverage or leftover-map incomplete item coverage
+ on the comparison graphic. Do not invent item coverage from plotted criterion
+ marker count, leftover pair count, leftover-map rank, leftover-map distance,
+ leftover-map axis share, leftover-map reconstruction, leftover-map post
+ coverage, leftover-map incomplete post coverage, leftover-map incomplete item
+ coverage, or the count of unused axes. Never invent a leftover score. Never
+ invent a theta. No new columns.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 60549a04c..2414863d0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,78 @@ All notable changes to this project are documented here. Format follows
### Added
+- Period leftover pairs now name leftover-map item complete-case coverage on the
+ grouping comparison leftover-map graphic (ADR 0307 / v2.64.0). After
+ `make seed`, closest and farthest leftover pairs sit above the member list
+ with the Gabriel biplot of already-named coordinates, leftover-map axis share
+ when finite, leftover-map axis share on the grouping comparison leftover-map
+ graphic when finite, axis ticks that match `ξ (x, y) ζ (x, y)` on the pair
+ row, pair segments that match `d` on the pair row, pair segments that match
+ `R̂` on the pair row, pair segments that match `R̂²/R²` on the pair row,
+ pair segments that match `U²/R²` on the pair row, pair segments that match
+ `2R̂U/R²` on the pair row, pair segments that match `U` on the pair row,
+ pair segments that match `R` on the pair row, pair segments that match `Y`
+ on the pair row, pair segments that match `E` on the pair row, pair segments
+ that match leftover-map rank on the pair row, a plot caption that matches
+ leftover-map complete-case coverage above the pair list, a plot caption that
+ matches leftover-map item complete-case coverage, a plot caption that matches
+ leftover-map incomplete post coverage, a plot caption that matches leftover-map
+ incomplete item coverage, a pair-list note that matches leftover-map post
+ complete-case coverage, a pair-list note that matches leftover-map item
+ complete-case coverage, a pair-list note that matches leftover-map incomplete
+ post coverage, a pair-list note that matches leftover-map incomplete item
+ coverage, a grouping comparison note that matches leftover-map post
+ complete-case coverage, a grouping comparison note that matches leftover-map
+ item complete-case coverage, a grouping comparison note that matches leftover-map
+ incomplete post coverage, a grouping comparison note that matches leftover-map
+ incomplete item coverage, grouping comparison leftover-pair buttons that match
+ leftover-map reconstruction `R̂` on the pair row, grouping comparison leftover-pair
+ buttons that match leftover-map explained leftover share `e` on the pair row,
+ grouping comparison leftover-pair buttons that match leftover-map unexplained
+ leftover share `s` on the pair row, grouping comparison leftover-pair buttons
+ that match leftover-map cross share `x` on the pair row, grouping comparison
+ leftover-pair buttons that match leftover-map unexplained leftover `U` on the
+ pair row, grouping comparison leftover-pair buttons that match leftover residual
+ `R` on the pair row, grouping comparison leftover-pair buttons that match leftover
+ observed `Y` on the pair row, grouping comparison leftover-pair buttons that match
+ leftover expected `E` on the pair row, grouping comparison leftover-pair buttons
+ that match leftover-map rank on the pair row, grouping comparison leftover-pair
+ buttons that match leftover-map coordinates `ξ` / `ζ` on the pair row, a live
+ compare payload that carries those persisted leftover-map coordinates, the
+ grouping comparison leftover-map graphic of those already-named coordinates when
+ four leftover-map axes are finite, leftover-map axis share on that grouping
+ comparison leftover-map graphic when the persisted share is finite, leftover-map
+ complete-case coverage on that grouping comparison leftover-map graphic when
+ leftoverMapCoverageCounts returns usable complete-case integers, and leftover-map
+ item complete-case coverage on that grouping comparison leftover-map graphic when
+ leftoverMapItemCoverageCounts returns usable complete-case integers; click a post
+ marker or a pair button opens that post. A missing, non-integer, negative-used,
+ non-positive-scored, or used-greater-than-scored item coverage omits that leftover-map
+ comparison graphic item coverage caption and keeps leftover-map comparison graphic
+ coverage when leftoverMapCoverageCounts returns usable complete-case integers,
+ leftover map comparison axis share when finite, leftover map comparison axis text,
+ leftover-map rank when that rank is a non-negative integer, leftover expected `E`
+ when finite, leftover observed `Y` when finite, leftover residual `R` when finite,
+ leftover-map unexplained leftover `U` when finite, leftover-map cross share `x`
+ when finite, leftover-map unexplained leftover share `s` when finite, leftover-map
+ explained leftover share `e` when finite, leftover-map reconstruction `R̂` when
+ finite, leftover-map distance `d`, plus the strip coverage notes. Coverage `0 of M`
+ is shown when that persisted used count is a non-negative integer. Rank-0 origin
+ cells still plot at `(0, 0)` and still name item coverage when that item coverage
+ is persisted. Comparison copy uses `Leftover map comparison graphic item coverage`
+ so it stays distinct from hyphen `Leftover-map graphic item coverage` and from
+ strip `Leftover map comparison item coverage`. Post coverage and item coverage omit
+ independently. This increment does not caption leftover-map incomplete post coverage
+ or leftover-map incomplete item coverage on the comparison graphic. Do not invent
+ leftover-map item coverage from plotted criterion marker count, leftover pair count,
+ leftover-map rank, leftover-map distance, leftover-map axis share, leftover expected,
+ leftover observed, leftover residual, leftover-map reconstruction, leftover-map
+ unexplained leftover, leftover-map post coverage, leftover-map incomplete post
+ coverage, leftover-map incomplete item coverage, or the count of unused axes. A
+ finite negative leftover is shown, never clamped. Omit the comparison graphic
+ when no leftover pair has four finite leftover-map coordinates. Never invent
+ a leftover score or a theta. No new columns.
+
- Period leftover pairs now name leftover-map complete-case coverage on the
grouping comparison leftover-map graphic (ADR 0306 / v2.63.0). After
`make seed`, closest and farthest leftover pairs sit above the member list
diff --git a/CLAUDE.md b/CLAUDE.md
index 03e1db9a3..8b70d517f 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), 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), 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/0282-leftover-map-plot-item-coverage.md b/docs/adr/0282-leftover-map-plot-item-coverage.md
index 48affb306..880b01a74 100644
--- a/docs/adr/0282-leftover-map-plot-item-coverage.md
+++ b/docs/adr/0282-leftover-map-plot-item-coverage.md
@@ -3,6 +3,9 @@
**Decision status:** Accepted
**Date:** 2026-08-30
+**Amended by:** [ADR 0307](0307-leftover-map-compare-plot-item-coverage.md)
+(leftover-map item complete-case coverage on the grouping comparison leftover-map graphic)
+
Amends [ADR 0268](0268-leftover-map-graphic-display.md),
[ADR 0049](0049-leftover-pair-report-ui.md), and leftover-map complete-case
coverage ([ADR 0168](0168-leftover-map-complete-case-coverage.md)). Independent of
diff --git a/docs/adr/0290-leftover-map-compare-item-coverage.md b/docs/adr/0290-leftover-map-compare-item-coverage.md
index 96537b0ce..0a8900688 100644
--- a/docs/adr/0290-leftover-map-compare-item-coverage.md
+++ b/docs/adr/0290-leftover-map-compare-item-coverage.md
@@ -3,6 +3,9 @@
**Decision status:** Accepted
**Date:** 2026-08-30
+**Amended by:** [ADR 0307](0307-leftover-map-compare-plot-item-coverage.md)
+(leftover-map item complete-case coverage on the grouping comparison leftover-map graphic)
+
Amends leftover pairs on the grouping comparison strip
([ADR 0149](0149-leftover-pairs-on-comparison-strip.md)), leftover-map
complete-case coverage ([ADR 0168](0168-leftover-map-complete-case-coverage.md)),
diff --git a/docs/adr/0304-leftover-map-compare-graphic.md b/docs/adr/0304-leftover-map-compare-graphic.md
index bff105cf4..656a65c26 100644
--- a/docs/adr/0304-leftover-map-compare-graphic.md
+++ b/docs/adr/0304-leftover-map-compare-graphic.md
@@ -6,7 +6,9 @@
**Amended by:** [ADR 0305](0305-leftover-map-compare-plot-axis-share.md)
(leftover-map axis share on the grouping comparison leftover-map graphic),
[ADR 0306](0306-leftover-map-compare-plot-coverage.md)
-(leftover-map complete-case coverage on the grouping comparison leftover-map graphic)
+(leftover-map complete-case coverage on the grouping comparison leftover-map graphic),
+[ADR 0307](0307-leftover-map-compare-plot-item-coverage.md)
+(leftover-map item complete-case coverage on the grouping comparison leftover-map graphic)
Amends leftover pairs on the grouping comparison strip
([ADR 0149](0149-leftover-pairs-on-comparison-strip.md)), leftover-map
diff --git a/docs/adr/0306-leftover-map-compare-plot-coverage.md b/docs/adr/0306-leftover-map-compare-plot-coverage.md
index 97009bd32..37fd8b3e8 100644
--- a/docs/adr/0306-leftover-map-compare-plot-coverage.md
+++ b/docs/adr/0306-leftover-map-compare-plot-coverage.md
@@ -3,6 +3,9 @@
**Decision status:** Accepted
**Date:** 2026-08-31
+**Amended by:** [ADR 0307](0307-leftover-map-compare-plot-item-coverage.md)
+(leftover-map item complete-case coverage on the grouping comparison leftover-map graphic)
+
Amends leftover-map complete-case coverage on the graphic display
([ADR 0281](0281-leftover-map-plot-coverage.md)), leftover-map graphic
display on the grouping comparison strip
diff --git a/docs/adr/0307-leftover-map-compare-plot-item-coverage.md b/docs/adr/0307-leftover-map-compare-plot-item-coverage.md
new file mode 100644
index 000000000..2fe73036b
--- /dev/null
+++ b/docs/adr/0307-leftover-map-compare-plot-item-coverage.md
@@ -0,0 +1,254 @@
+# ADR 0307 — Name leftover-map item complete-case coverage on the grouping comparison leftover-map graphic
+
+**Decision status:** Accepted
+**Date:** 2026-08-31
+
+Amends leftover-map item complete-case coverage on the graphic display
+([ADR 0282](0282-leftover-map-plot-item-coverage.md)), leftover-map item
+complete-case coverage on the grouping comparison strip
+([ADR 0290](0290-leftover-map-compare-item-coverage.md)), leftover-map
+complete-case coverage on the grouping comparison leftover-map graphic
+([ADR 0306](0306-leftover-map-compare-plot-coverage.md)), leftover-map graphic
+display on the grouping comparison strip
+([ADR 0304](0304-leftover-map-compare-graphic.md)), leftover-map axis share
+on the grouping comparison leftover-map graphic
+([ADR 0305](0305-leftover-map-compare-plot-axis-share.md)), leftover-map
+complete-case coverage persistence
+([ADR 0168](0168-leftover-map-complete-case-coverage.md)), leftover pairs on
+the grouping comparison strip
+([ADR 0149](0149-leftover-pairs-on-comparison-strip.md)), leftover-map
+coordinates on the compare leftover-pair payload
+([ADR 0303](0303-leftover-map-compare-coordinates-payload.md)), leftover-map
+coordinates on grouping comparison strip pair rows
+([ADR 0302](0302-leftover-map-compare-coordinates.md)), leftover-map
+rank on grouping comparison strip pair rows
+([ADR 0301](0301-leftover-map-compare-rank.md)), leftover expected on grouping
+comparison strip pair rows
+([ADR 0300](0300-leftover-map-compare-expected.md)), leftover observed on
+grouping comparison strip pair rows
+([ADR 0299](0299-leftover-map-compare-observed.md)), leftover residual
+on grouping comparison strip pair rows
+([ADR 0298](0298-leftover-map-compare-residual.md)), leftover-map unexplained leftover
+on grouping comparison strip pair rows
+([ADR 0297](0297-leftover-map-compare-unexplained.md)), leftover-map cross share
+on grouping comparison strip pair rows
+([ADR 0296](0296-leftover-map-compare-cross-share.md)), leftover-map unexplained
+leftover share on grouping comparison strip pair rows
+([ADR 0295](0295-leftover-map-compare-unexplained-share.md)), leftover-map
+explained leftover share on grouping comparison strip pair rows
+([ADR 0294](0294-leftover-map-compare-explained-share.md)), leftover-map
+reconstruction on grouping comparison strip pair rows
+([ADR 0293](0293-leftover-map-compare-reconstruction.md)), leftover-map
+incomplete item coverage on the grouping comparison strip
+([ADR 0292](0292-leftover-map-compare-incomplete-item.md)), leftover-map
+incomplete post coverage on the grouping comparison strip
+([ADR 0291](0291-leftover-map-compare-incomplete-post.md)), leftover-map
+complete-case coverage on the grouping comparison strip
+([ADR 0289](0289-leftover-map-compare-coverage.md)), leftover residual
+disclosure ([ADR 0162](0162-leftover-residual-disclosure.md)), leftover
+observed `Y` / expected `E` ([ADR 0163](0163-leftover-observed-expected.md)), leftover-map unexplained leftover persistence ([ADR 0182](0182-leftover-map-unexplained.md)),
+leftover-map reconstruction persistence
+([ADR 0201](0201-leftover-map-reconstruction.md)), leftover-map rank
+([ADR 0164](0164-leftover-map-rank.md)), leftover-map rank on pair segments
+([ADR 0280](0280-leftover-map-segment-rank.md)), leftover-map coordinate ticks
+([ADR 0270](0270-leftover-map-coordinate-ticks.md)), leftover-map graphic display
+([ADR 0268](0268-leftover-map-graphic-display.md)), leftover-map axis share on
+the graphic display ([ADR 0269](0269-leftover-map-axis-share-plot.md)), leftover-map
+complete-case coverage on the graphic display
+([ADR 0281](0281-leftover-map-plot-coverage.md)), and leftover-map coordinates
+([ADR 0267](0267-leftover-map-coordinates.md)). Independent of leftover-map
+post complete-case coverage fail-closed on the pair list
+([ADR 0288](0288-leftover-map-list-post-coverage-helper.md)), leftover-map
+incomplete item coverage on the pair list
+([ADR 0287](0287-leftover-map-list-incomplete-item.md)), leftover-map incomplete
+post coverage on the pair list
+([ADR 0286](0286-leftover-map-list-incomplete-post.md)), leftover-map item
+complete-case coverage on the pair list
+([ADR 0285](0285-leftover-map-list-item-coverage.md)), leftover-map incomplete
+item coverage on the graphic display
+([ADR 0284](0284-leftover-map-plot-incomplete-item.md)), leftover-map incomplete
+post coverage on the graphic display
+([ADR 0283](0283-leftover-map-plot-incomplete.md)), leftover expected on pair
+segments ([ADR 0279](0279-leftover-map-segment-expected.md)), leftover observed
+on pair segments ([ADR 0278](0278-leftover-map-segment-observed.md)), leftover
+residual on pair segments ([ADR 0277](0277-leftover-map-segment-residual.md)),
+leftover-map unexplained leftover on pair segments
+([ADR 0276](0276-leftover-map-segment-unexplained-leftover.md)), leftover-map
+cross share on pair segments ([ADR 0275](0275-leftover-map-segment-cross-share.md)),
+leftover-map unexplained leftover share on pair segments
+([ADR 0274](0274-leftover-map-segment-unexplained-share.md)), leftover-map
+explained leftover share on pair segments
+([ADR 0273](0273-leftover-map-segment-explained-share.md)), leftover-map
+reconstruction on pair segments
+([ADR 0272](0272-leftover-map-segment-reconstruction.md)), leftover-map
+distance on pair segments ([ADR 0271](0271-leftover-map-segment-distance.md)),
+leftover-map cross share persistence ([ADR 0185](0185-leftover-map-cross-share.md)), leftover-map
+unexplained leftover share persistence
+([ADR 0233](0233-leftover-map-unexplained-share.md)), leftover-map explained leftover
+share persistence ([ADR 0266](0266-leftover-map-explained-share.md)), leftover-map
+incomplete post coverage on the grouping comparison leftover-map graphic, and leftover-map
+incomplete item coverage on the grouping comparison leftover-map graphic.
+
+## Context
+
+ADR 0168 already persists `map_item_count` / `scored_item_count` on
+`report_leftover_map_coverage`. ADR 0282 already captions the period-report
+leftover-map graphic with `Leftover map used N of M scored criteria
+(complete-case)` under accessible name `Leftover-map graphic item coverage`.
+ADR 0290 already captions the grouping comparison strip with that same body
+under accessible name `Leftover map comparison item coverage`. ADR 0304
+already draws the leftover-map graphic of persisted `ξ_{1:2}` / `ζ_{1:2}`
+above grouping comparison leftover-pair buttons. ADR 0306 already captions
+leftover-map complete-case coverage on that graphic. The comparison graphic
+still omits leftover-map item coverage, so a buyer who reads two criterion
+diamonds can treat those markers as the scored-criterion census even after
+the strip note names `2 of 2`. Incomplete columns are dropped from Gabriel
+factorization; hiding item coverage on the comparison graphic lets a sparse
+criterion with one missing post vanish without a next action.
+
+This increment captions leftover-map item complete-case coverage on the
+grouping comparison leftover-map graphic from already-named
+`leftover_map_coverage`. Comparison copy uses the accessible name
+`Leftover map comparison graphic item coverage` so it stays distinct from
+hyphen `Leftover-map graphic item coverage` on the period-report graphic
+and from strip `Leftover map comparison item coverage`. It does not add
+columns. It does not recompute leftover-map item coverage from leftover-map
+rank, leftover-map distance, leftover expected, leftover observed, leftover
+residual, leftover-map reconstruction, leftover-map unexplained leftover,
+leftover-map axis share, leftover-map post coverage, leftover-map incomplete
+post coverage, leftover-map incomplete item coverage, plotted criterion
+marker count, leftover pair count, or the count of unused axes. It does not
+persist leftover-map inner product, cosine, or length as separate columns.
+Do not invent a leftover score. Do not invent a theta.
+
+The dashboard stack already used neighbouring leftover facts under other
+numbers. This protected increment uses **0307** so it does not collide with
+leftover-map complete-case coverage on the grouping comparison leftover-map
+graphic (0306), leftover-map axis share on the grouping comparison leftover-map
+graphic (0305), leftover-map graphic display on the grouping comparison strip
+(0304), leftover-map coordinates on the compare leftover-pair payload (0303),
+leftover-map coordinates on grouping comparison strip pair rows (0302),
+leftover-map rank on grouping comparison strip pair rows (0301), leftover-map
+item complete-case coverage on the graphic display (0282), leftover-map item
+complete-case coverage on the grouping comparison strip (0290), leftover-map
+graphic display (0268), leftover-map coordinates (0267), or the dashboard
+stacks.
+
+## Decision
+
+On the grouping comparison leftover-map graphic, caption persisted leftover-map
+item complete-case coverage as `Leftover map used N of M scored criteria
+(complete-case)`, using the same `map_item_count` / `scored_item_count`
+integers the strip note already shows through leftoverMapItemCoverageCounts.
+Use the distinct accessible name `Leftover map comparison graphic item coverage`
+so the graphic caption is not the strip note (`Leftover map comparison item
+coverage`) and is not the period-report graphic caption (`Leftover-map graphic
+item coverage`). A missing coverage row, a non-integer count, a negative used
+count, a non-positive scored count, or used greater than scored omits that
+leftover-map comparison graphic item coverage caption and keeps leftover-map
+comparison graphic coverage when leftoverMapCoverageCounts returns usable
+complete-case integers, leftover map comparison axis share when finite,
+leftover map comparison axis text, leftover-map rank when that rank is a
+non-negative integer, leftover expected `E` when finite, leftover observed `Y`
+when finite, leftover residual `R` when finite, leftover-map unexplained leftover
+`U` when finite, leftover-map cross share `x` when finite, leftover-map
+unexplained leftover share `s` when finite, leftover-map explained leftover
+share `e` when finite, leftover-map reconstruction `R̂` when finite,
+leftover-map distance `d`, plus the strip coverage notes. Coverage `0 of M` is
+shown when that persisted used count is a non-negative integer and scored is a
+positive integer. Rank-0 origin cells still name item coverage when that item
+coverage is persisted. Do not invent item coverage from plotted criterion
+marker count, leftover pair count, leftover-map rank, leftover-map distance,
+leftover-map axis share, leftover expected, leftover observed, leftover
+residual, leftover-map reconstruction, leftover-map unexplained leftover,
+leftover-map post coverage, leftover-map incomplete post coverage, leftover-map
+incomplete item coverage, or the count of unused axes. Click a post marker to
+open that post.
+
+Post coverage and item coverage omit independently. A used-greater-than-scored
+post count omits leftover-map comparison graphic coverage and keeps a usable
+item caption. A used-greater-than-scored item count omits leftover-map
+comparison graphic item coverage and keeps a usable post caption.
+
+This increment does not caption leftover-map incomplete post coverage or
+leftover-map incomplete item coverage on the comparison graphic. Those notes
+already sit on the strip through ADR 0291–0292. A finite negative leftover on
+neighbouring fields is shown, never clamped.
+
+Do not add SQL migrations. Do not edit shipped migrations. Do not persist inner
+product, cosine, or length as separate columns. 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
+item complete-case coverage on that graphic when leftoverMapItemCoverageCounts
+returns usable complete-case integers. Rank-0 unused axes still plot at
+the origin and still name item coverage when that item coverage is persisted.
+Click a post marker or a pair button opens that post. Hidden posts stay hidden.
+When `Y`, `E`, and `R` are finite, `Y − E = R`. When `R`, `R̂`, and `U`
+are finite, `U + R̂ = R`. When `R`, `R̂`, `U`, `x`, `s`, and `e` are
+finite, `e + s + x = 1`. When coordinates, reconstruction, and distance
+are finite, `R̂ = ξ · ζ` and `d = ‖ξ − ζ‖`.
+
+## Related
+
+Independent of leftover interaction-map persistence, leftover-criterion
+evaluation landing, leftover residual disclosure, leftover-map
+complete-case coverage persistence, leftover pairs on the grouping comparison
+strip, leftover-map complete-case coverage on the grouping comparison strip,
+leftover-map item complete-case coverage on the grouping comparison strip,
+leftover-map incomplete post coverage on the grouping comparison strip,
+leftover-map incomplete item coverage on the grouping comparison strip,
+leftover-map reconstruction on grouping comparison strip pair rows,
+leftover-map explained leftover share on grouping comparison strip pair rows,
+leftover-map unexplained leftover share on grouping comparison strip pair rows,
+leftover-map cross share on grouping comparison strip pair rows,
+leftover-map unexplained leftover on grouping comparison strip pair rows,
+leftover residual on grouping comparison strip pair rows, leftover observed
+on grouping comparison strip pair rows, leftover expected on grouping
+comparison strip pair rows, leftover-map rank on grouping comparison strip
+pair rows, leftover-map coordinates on grouping comparison strip pair rows,
+leftover-map coordinates on the compare leftover-pair payload, leftover-map
+inner product, leftover-map cosine, leftover-map length, leftover residual
+on pair segments, leftover observed on pair segments, leftover expected on
+pair segments, leftover-map rank on pair segments, leftover-map unexplained
+leftover on pair segments, leftover-map unexplained leftover persistence,
+leftover-map cross share on pair segments, leftover-map cross share
+persistence, leftover-map unexplained leftover share on pair segments,
+leftover-map unexplained leftover share persistence, leftover-map explained
+leftover share on pair segments, leftover-map explained leftover share
+persistence, leftover-map reconstruction on pair segments, leftover-map
+reconstruction persistence, leftover-map item complete-case coverage on the
+graphic display, leftover-map item complete-case coverage on the pair list,
+leftover-map incomplete post coverage on the graphic display, leftover-map
+incomplete post coverage on the pair list, leftover-map incomplete item
+coverage on the graphic display, leftover-map incomplete item coverage on
+the pair list, leftover-map post complete-case coverage fail-closed on the
+pair list, leftover-map rank persistence, leftover-map coordinate
+persistence, leftover-map coordinate ticks, leftover-map complete-case
+coverage on the graphic display, leftover-map complete-case coverage on the
+grouping comparison leftover-map graphic, leftover-map axis share on the
+grouping comparison leftover-map graphic, leftover-map incomplete post
+coverage on the grouping comparison leftover-map graphic, and leftover-map
+incomplete item coverage 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
+(LSIRM interaction `−γ‖ξ_j − ζ_i‖` after main effects
+`α_j − β_i`; typically `p = 2` for the interaction map. Incomplete columns
+are dropped from the complete-case residual rectangle; item coverage names how
+many scored criteria entered that factorization. Grouping comparison leftover-map
+item complete-case coverage captions those persisted used/scored criterion counts
+on the grouping comparison leftover-map graphic only when leftoverMapItemCoverageCounts
+returns usable complete-case integers. Rank-0 unused axes still name item coverage
+when that item coverage is stored.)
+
+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 06757c23d..4a9b57e14 100644
--- a/docs/product-technical-gap-baseline.md
+++ b/docs/product-technical-gap-baseline.md
@@ -1,5 +1,24 @@
# Product & Technical Gap Baseline
+> Exact-head loop overlay: 2026-08-31 05:02 KST. Protected `main` is
+> `cb187cadee5fb6c46d8a944815ccc154a1e028d1`. Writes work. Do not
+> self-approve. #845 leftover-map coverage on the grouping comparison leftover-map
+> graphic (v2.63.0 / ADR 0306) is `7c026df`, stacked on #844 @ `95538f9`.
+> Next buyer increment on this cycle: leftover-map item complete-case coverage on
+> the grouping comparison leftover-map graphic (ADR 0307 / v2.64.0) delivered
+> locally on `feat/leftover-map-compare-plot-item-coverage-v2640`. Caption leftover
+> map used N of M scored criteria (complete-case) on that comparison graphic from
+> already-named leftover_map_coverage. Distinct accessible name `Leftover map
+> comparison graphic item coverage`. Omit when leftoverMapItemCoverageCounts
+> fail-closes. Do not caption leftover-map incomplete coverage on that comparison
+> graphic this increment. Do not invent leftover-map item coverage from plotted
+> criterion marker count, leftover pair count, leftover-map rank, leftover-map
+> distance, leftover-map axis share, leftover-map reconstruction, leftover-map
+> post coverage, leftover-map incomplete post coverage, leftover-map incomplete
+> item coverage, or the count of unused axes. Stack onto #845. Leave open for
+> independent review. Do not squash-merge. Issues #79 and #87 stay open. #96 is
+> already closed. Do not merge #808 without independent APPROVE.
+
> Exact-head loop overlay: 2026-08-31 04:23 KST. Protected `main` is
> `cb187cadee5fb6c46d8a944815ccc154a1e028d1`. Writes work. Do not
> self-approve. #844 leftover-map axis share on the grouping comparison leftover-map
diff --git a/docs/storybook-inventory.md b/docs/storybook-inventory.md
index dc41941d6..1d99ff72c 100644
--- a/docs/storybook-inventory.md
+++ b/docs/storybook-inventory.md
@@ -5,7 +5,7 @@ operator-facing control you can click before changing product CSS.
| Story | Operator next action | Token / module |
|---|---|---|
-| `Reports/LeftoverMapPlot` | Read the leftover-map graphic display of persisted `ξ` (posts) and `ζ` (criteria), match axis ticks to those coordinates, pair-segment `d` to leftover-map distance, pair-segment `R̂` to leftover-map reconstruction, pair-segment `R̂²/R²` to leftover-map explained leftover share, pair-segment `U²/R²` to leftover-map unexplained leftover share, pair-segment `2R̂U/R²` to leftover-map cross share, pair-segment `U` to leftover-map unexplained leftover, pair-segment `R` to leftover residual, pair-segment `Y` to leftover observed, pair-segment `E` to leftover expected, and pair-segment leftover-map rank, then click a post marker to open that post. Leftover-map axes name persisted leftover-map axis share when finite. The plot names leftover-map complete-case coverage, leftover-map item complete-case coverage, leftover-map incomplete post coverage, and leftover-map incomplete item coverage when persisted. The comparison variant names leftover-map complete-case coverage under `Leftover map comparison graphic coverage` and omits leftover-map item coverage and leftover-map incomplete coverage on that comparison plot. `ClosestAndFarthest`, `RankZeroOrigin`, `MissingCoordinates`, `MissingAxisShare`, `Comparison`, and `ComparisonMissingCoverage` cover two-pair maps, rank-0 origin with 0% share, a `0` tick, `d 0.00`, `R̂ 0.00`, `R̂²/R² 0.00`, `U²/R² 0.00`, `2R̂U/R² 0.00`, `U 0.00`, `R 0.00`, `Y 0.00`, `E 0.00`, and `rank 0`, omitted plots, missing share that keeps existing leftover-map axis text, grouping comparison leftover-map graphic coverage that matches leftover map used N of M scored posts, and omitted comparison graphic coverage when leftoverMapCoverageCounts fail-closes. The plot does not invent a leftover score. | `LeftoverMapPlot`, `leftoverMapPlotLayout`, `leftoverMapPlotAxisShare`, `--color-primary`, `--color-palette-blue-mid` |
+| `Reports/LeftoverMapPlot` | Read the leftover-map graphic display of persisted `ξ` (posts) and `ζ` (criteria), match axis ticks to those coordinates, pair-segment `d` to leftover-map distance, pair-segment `R̂` to leftover-map reconstruction, pair-segment `R̂²/R²` to leftover-map explained leftover share, pair-segment `U²/R²` to leftover-map unexplained leftover share, pair-segment `2R̂U/R²` to leftover-map cross share, pair-segment `U` to leftover-map unexplained leftover, pair-segment `R` to leftover residual, pair-segment `Y` to leftover observed, pair-segment `E` to leftover expected, and pair-segment leftover-map rank, then click a post marker to open that post. Leftover-map axes name persisted leftover-map axis share when finite. The plot names leftover-map complete-case coverage, leftover-map item complete-case coverage, leftover-map incomplete post coverage, and leftover-map incomplete item coverage when persisted. The comparison variant names leftover-map complete-case coverage under `Leftover map comparison graphic coverage` and leftover-map item complete-case coverage under `Leftover map comparison graphic item coverage` and omits leftover-map incomplete coverage on that comparison plot. `ClosestAndFarthest`, `RankZeroOrigin`, `MissingCoordinates`, `MissingAxisShare`, `Comparison`, `ComparisonMissingCoverage`, and `ComparisonMissingItemCoverage` cover two-pair maps, rank-0 origin with 0% share, a `0` tick, `d 0.00`, `R̂ 0.00`, `R̂²/R² 0.00`, `U²/R² 0.00`, `2R̂U/R² 0.00`, `U 0.00`, `R 0.00`, `Y 0.00`, `E 0.00`, and `rank 0`, omitted plots, missing share that keeps existing leftover-map axis text, grouping comparison leftover-map graphic coverage that matches leftover map used N of M scored posts, omitted comparison graphic coverage when leftoverMapCoverageCounts fail-closes, grouping comparison leftover-map graphic item coverage that matches leftover map used N of M scored criteria, and omitted comparison graphic item coverage when leftoverMapItemCoverageCounts fail-closes. The plot does not invent a leftover score. | `LeftoverMapPlot`, `leftoverMapPlotLayout`, `leftoverMapPlotAxisShare`, `--color-primary`, `--color-palette-blue-mid` |
| `Reports/LeftoverPairList` | Read closest/farthest leftover pairs with named `R`, `Y`/`E`, rank, `U`, `s`, `e`, `x`, `R̂`, `ξ`/`ζ`, and `d`, then open that post. The leftover-map graphic display sits above the pair buttons when coordinates are finite, leftover-map axes name persisted leftover-map axis share, leftover-map axis ticks name persisted coordinates, pair segments name persisted leftover-map distance, pair segments name persisted leftover-map reconstruction, pair segments name persisted leftover-map explained leftover share, pair segments name persisted leftover-map unexplained leftover share, pair segments name persisted leftover-map cross share, pair segments name persisted leftover-map unexplained leftover, pair segments name persisted leftover residual, pair segments name persisted leftover observed, pair segments name persisted leftover expected, and pair segments name persisted leftover-map rank. The pair-list note names leftover-map complete-case coverage only when leftoverMapCoverageCounts returns usable complete-case integers, leftover-map item complete-case coverage, leftover-map incomplete post coverage, and leftover-map incomplete item coverage when persisted. The grouping comparison strip names leftover-map complete-case coverage, leftover-map item complete-case coverage, leftover-map incomplete post coverage, and leftover-map incomplete item coverage with distinct comparison labels when leftoverMapCoverageCounts / leftoverMapItemCoverageCounts / leftoverMapIncompletePostCount / leftoverMapIncompleteItemCount return usable integers. | `LeftoverPairList`, `LeftoverMapPlot`, `ticket-list`, `post-badge` |
| `Workspace/OperationsDashboard` | Compare Event and post counts, inspect external-information coverage, then open the cited source behind a claim, handover, or repeat-issue fact. `EvidenceReady`, `NarrowViewport`, `AnalysisPendingAndMissingEvidence`, `AnalysisFailed`, and `LoadError` cover populated, mobile, unavailable-evidence, analysis-pending, retryable failure, and transport-error states. | `--color-dashboard-*`, `OperationsDashboard` |
| `Post/SimilarVocPanel` | Compare ontology/semantic similar VOC and prior action evidence, then open the source; unavailable states show no fabricated TEPP theta or weight. | `SimilarVocPanel.css`, `SimilarVocPanel` |
diff --git a/frontend/package.json b/frontend/package.json
index 3c312155a..d88962467 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,7 +1,7 @@
{
"name": "frontend",
"private": true,
- "version": "2.63.0",
+ "version": "2.64.0",
"type": "module",
"scripts": {
"dev": "vite",
diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx
index e3fb40521..a5bbc5732 100644
--- a/frontend/src/App.test.tsx
+++ b/frontend/src/App.test.tsx
@@ -4222,6 +4222,9 @@ describe("App, authenticated", () => {
expect(screen.getByLabelText("Leftover map comparison graphic coverage")).toHaveTextContent(
"Leftover map used 2 of 3 scored posts (complete-case)",
);
+ expect(screen.getByLabelText("Leftover map comparison graphic item coverage")).toHaveTextContent(
+ "Leftover map used 2 of 2 scored criteria (complete-case)",
+ );
expect(screen.getByLabelText("Leftover-map graphic item coverage")).toHaveTextContent(
"Leftover map used 2 of 2 scored criteria (complete-case)",
);
@@ -4360,6 +4363,21 @@ describe("App, authenticated", () => {
"Leftover-map graphic coverage",
),
).not.toBeInTheDocument();
+ expect(
+ within(screen.getByLabelText("Grouping comparison")).getByLabelText(
+ "Leftover map comparison graphic item coverage",
+ ),
+ ).toHaveTextContent("Leftover map used 2 of 2 scored criteria (complete-case)");
+ expect(
+ within(screen.getByLabelText("Grouping comparison")).getAllByLabelText(
+ "Leftover map comparison graphic item coverage",
+ ),
+ ).toHaveLength(1);
+ expect(
+ within(screen.getByLabelText("Grouping comparison")).queryByLabelText(
+ "Leftover-map graphic item coverage",
+ ),
+ ).not.toBeInTheDocument();
expect(
within(screen.getByLabelText("Grouping comparison")).queryByLabelText("Leftover map item coverage"),
).not.toBeInTheDocument();
diff --git a/frontend/src/components/LeftoverMapPlot.stories.tsx b/frontend/src/components/LeftoverMapPlot.stories.tsx
index 7d2b4fe20..b95b08449 100644
--- a/frontend/src/components/LeftoverMapPlot.stories.tsx
+++ b/frontend/src/components/LeftoverMapPlot.stories.tsx
@@ -150,3 +150,17 @@ export const ComparisonMissingCoverage: Story = {
leftoverMapCoverage: undefined,
},
};
+
+export const ComparisonMissingItemCoverage: Story = {
+ args: {
+ variant: "comparison",
+ leftoverMapCoverage: {
+ map_post_count: 2,
+ scored_post_count: 3,
+ map_item_count: 3,
+ scored_item_count: 2,
+ incomplete_post_count: 1,
+ incomplete_item_count: 0,
+ },
+ },
+};
diff --git a/frontend/src/components/LeftoverMapPlot.test.tsx b/frontend/src/components/LeftoverMapPlot.test.tsx
index 93e3b9955..7f93b07b4 100644
--- a/frontend/src/components/LeftoverMapPlot.test.tsx
+++ b/frontend/src/components/LeftoverMapPlot.test.tsx
@@ -918,9 +918,13 @@ describe("LeftoverMapPlot", () => {
expect(screen.getByLabelText("Leftover map comparison graphic coverage")).toHaveTextContent(
"Leftover map used 2 of 3 scored posts (complete-case)",
);
+ expect(screen.getByLabelText("Leftover map comparison graphic item coverage")).toHaveTextContent(
+ "Leftover map used 2 of 2 scored criteria (complete-case)",
+ );
expect(screen.queryByLabelText("Leftover-map graphic coverage")).not.toBeInTheDocument();
expect(screen.queryByLabelText("Leftover map comparison coverage")).not.toBeInTheDocument();
expect(screen.queryByLabelText("Leftover-map graphic item coverage")).not.toBeInTheDocument();
+ expect(screen.queryByLabelText("Leftover map comparison 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 (82%)")).toBeInTheDocument();
@@ -964,10 +968,68 @@ describe("LeftoverMapPlot", () => {
/>,
);
expect(screen.queryByLabelText("Leftover map comparison graphic coverage")).not.toBeInTheDocument();
+ expect(screen.getByLabelText("Leftover map comparison graphic item coverage")).toHaveTextContent(
+ "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();
});
+ it("omits leftover-map comparison graphic item coverage when item coverage is missing or not usable", () => {
+ const { rerender } = render(
+ ,
+ );
+ expect(screen.getByLabelText("Leftover map comparison graphic coverage")).toHaveTextContent(
+ "Leftover map used 2 of 3 scored posts (complete-case)",
+ );
+ 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();
+ rerender(
+ ,
+ );
+ expect(screen.getByLabelText("Leftover map comparison graphic coverage")).toHaveTextContent(
+ "Leftover map used 2 of 3 scored posts (complete-case)",
+ );
+ 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();
+ });
+
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", () => {
render(
{
expect(screen.getByLabelText("Leftover map comparison graphic coverage")).toHaveTextContent(
"Leftover map used 0 of 3 scored posts (complete-case)",
);
+ expect(screen.getByLabelText("Leftover map comparison graphic item coverage")).toHaveTextContent(
+ "Leftover map used 0 of 2 scored criteria (complete-case)",
+ );
expect(screen.queryByLabelText("Leftover-map graphic coverage")).not.toBeInTheDocument();
expect(screen.queryByLabelText("Leftover-map graphic item coverage")).not.toBeInTheDocument();
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 6c0a82d26..7adfcdb92 100644
--- a/frontend/src/components/LeftoverMapPlot.tsx
+++ b/frontend/src/components/LeftoverMapPlot.tsx
@@ -7,6 +7,7 @@ import {
leftoverMapIncompletePostCount,
leftoverMapItemCoverageCounts,
LEFTOVER_MAP_COMPARE_PLOT_COVERAGE_LABEL,
+ LEFTOVER_MAP_COMPARE_PLOT_ITEM_COVERAGE_LABEL,
LEFTOVER_MAP_PLOT_COVERAGE,
LEFTOVER_MAP_PLOT_COVERAGE_LABEL,
LEFTOVER_MAP_PLOT_INCOMPLETE_ITEM,
@@ -124,8 +125,12 @@ function leftoverMapPlotAxisText(
* with distinct leftover map comparison axis labels. ADR 0306 captions leftover-map
* complete-case coverage on that comparison graphic from already-named
* leftover-map coverage with distinct leftover map comparison graphic coverage
- * labels and does not caption leftover-map item coverage or leftover-map
- * incomplete coverage on that comparison plot.
+ * labels and does not caption leftover-map incomplete coverage on that
+ * comparison plot. ADR 0307 captions leftover-map item complete-case
+ * coverage on that comparison graphic from already-named leftover-map
+ * coverage with distinct leftover map comparison graphic item coverage
+ * labels and does not caption leftover-map incomplete coverage on that
+ * comparison plot.
* Never invent a leftover score.
*/
export function LeftoverMapPlot({
@@ -173,11 +178,15 @@ export function LeftoverMapPlot({
{tf(LEFTOVER_MAP_PLOT_COVERAGE, coverageCounts)}
) : null}
- {variant !== "comparison" && itemCoverageCounts !== null ? (
+ {itemCoverageCounts !== null ? (
{tf(LEFTOVER_MAP_PLOT_ITEM_COVERAGE, itemCoverageCounts)}
diff --git a/frontend/src/components/LeftoverPairList.tsx b/frontend/src/components/LeftoverPairList.tsx
index 75978848f..9b4bf6654 100644
--- a/frontend/src/components/LeftoverPairList.tsx
+++ b/frontend/src/components/LeftoverPairList.tsx
@@ -109,7 +109,9 @@ export type LeftoverPairListProps = {
* this pair list. ADR 0305 captions leftover-map axis share on that
* grouping comparison leftover-map graphic, not this pair list. ADR 0306
* captions leftover-map complete-case coverage on that grouping comparison
- * leftover-map graphic, not this pair list. Every badge still
+ * leftover-map graphic, not this pair list. ADR 0307 captions leftover-map
+ * item complete-case coverage 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 4cd9b7494..77a574f1e 100644
--- a/frontend/src/i18n.test.ts
+++ b/frontend/src/i18n.test.ts
@@ -79,6 +79,7 @@ describe("i18n", () => {
"Leftover-map graphic coverage",
"Leftover map comparison coverage",
"Leftover map comparison graphic coverage",
+ "Leftover map comparison graphic item coverage",
"Leftover map comparison item coverage",
"Leftover map comparison incomplete posts",
"Leftover map comparison incomplete items",
@@ -421,6 +422,16 @@ describe("i18n", () => {
expect(t("Leftover map comparison graphic coverage")).toBe(expected);
});
+ it.each([
+ ["ko", "잔여 지도 비교 그림 기준 포함 범위"],
+ ["zh", "残差地图比较图形准则覆盖范围"],
+ ["ja", "残差マップの比較図基準対象範囲"],
+ ["vi", "Phạm vi tiêu chí đồ họa so sánh bản đồ phần dư"],
+ ] as const)("formats leftover map comparison graphic item coverage label in %s", (locale, expected) => {
+ setLocale(locale);
+ expect(t("Leftover map comparison graphic item coverage")).toBe(expected);
+ });
+
it.each([
["ko", "잔여 지도 비교 기준 포함 범위"],
["zh", "残差地图比较准则覆盖范围"],
diff --git a/frontend/src/i18n.ts b/frontend/src/i18n.ts
index 27baa3d25..0845da8e0 100644
--- a/frontend/src/i18n.ts
+++ b/frontend/src/i18n.ts
@@ -270,6 +270,7 @@ const TRANSLATIONS: Partial>> = {
"Leftover map coverage": "잔여 지도 포함 범위",
"Leftover map comparison coverage": "잔여 지도 비교 포함 범위",
"Leftover map comparison graphic coverage": "잔여 지도 비교 그림 포함 범위",
+ "Leftover map comparison graphic item coverage": "잔여 지도 비교 그림 기준 포함 범위",
"Leftover map comparison item coverage": "잔여 지도 비교 기준 포함 범위",
"Leftover map comparison incomplete posts": "잔여 지도 비교 불완전 글",
"Leftover map comparison incomplete items": "잔여 지도 비교 불완전 기준",
@@ -898,6 +899,7 @@ const TRANSLATIONS: Partial>> = {
"Leftover map coverage": "残差地图覆盖范围",
"Leftover map comparison coverage": "残差地图比较覆盖范围",
"Leftover map comparison graphic coverage": "残差地图比较图形覆盖范围",
+ "Leftover map comparison graphic item coverage": "残差地图比较图形准则覆盖范围",
"Leftover map comparison item coverage": "残差地图比较准则覆盖范围",
"Leftover map comparison incomplete posts": "残差地图比较不完整帖文",
"Leftover map comparison incomplete items": "残差地图比较不完整准则",
@@ -1547,6 +1549,7 @@ const TRANSLATIONS: Partial>> = {
"Leftover map coverage": "残差マップの対象範囲",
"Leftover map comparison coverage": "残差マップの比較対象範囲",
"Leftover map comparison graphic coverage": "残差マップの比較図対象範囲",
+ "Leftover map comparison graphic item coverage": "残差マップの比較図基準対象範囲",
"Leftover map comparison item coverage": "残差マップの比較基準対象範囲",
"Leftover map comparison incomplete posts": "残差マップの比較不完全投稿",
"Leftover map comparison incomplete items": "残差マップの比較不完全基準",
@@ -2175,6 +2178,7 @@ const TRANSLATIONS: Partial>> = {
"Leftover map coverage": "Phạm vi bản đồ phần dư",
"Leftover map comparison coverage": "Phạm vi so sánh bản đồ phần dư",
"Leftover map comparison graphic coverage": "Phạm vi đồ họa so sánh bản đồ phần dư",
+ "Leftover map comparison graphic item coverage": "Phạm vi tiêu chí đồ họa so sánh bản đồ phần dư",
"Leftover map comparison item coverage": "Phạm vi so sánh tiêu chí bản đồ phần dư",
"Leftover map comparison incomplete posts": "Bài không đầy đủ so sánh trên bản đồ phần dư",
"Leftover map comparison incomplete items": "Tiêu chí không đầy đủ so sánh trên bản đồ phần dư",
diff --git a/frontend/src/leftoverMapCoverage.test.ts b/frontend/src/leftoverMapCoverage.test.ts
index 72fd9fdbf..7e2812323 100644
--- a/frontend/src/leftoverMapCoverage.test.ts
+++ b/frontend/src/leftoverMapCoverage.test.ts
@@ -10,6 +10,7 @@ import {
LEFTOVER_MAP_COMPARE_INCOMPLETE_POST_LABEL,
LEFTOVER_MAP_COMPARE_INCOMPLETE_ITEM_LABEL,
LEFTOVER_MAP_COMPARE_PLOT_COVERAGE_LABEL,
+ LEFTOVER_MAP_COMPARE_PLOT_ITEM_COVERAGE_LABEL,
LEFTOVER_MAP_LIST_COVERAGE_LABEL,
LEFTOVER_MAP_LIST_INCOMPLETE_ITEM_LABEL,
LEFTOVER_MAP_LIST_INCOMPLETE_POST_LABEL,
@@ -138,6 +139,16 @@ describe("leftoverMapItemCoverageCounts", () => {
expect(LEFTOVER_MAP_COMPARE_ITEM_COVERAGE_LABEL).not.toBe(LEFTOVER_MAP_LIST_ITEM_COVERAGE_LABEL);
expect(LEFTOVER_MAP_COMPARE_ITEM_COVERAGE_LABEL).not.toBe(LEFTOVER_MAP_PLOT_ITEM_COVERAGE_LABEL);
});
+
+ it("keeps the grouping comparison graphic item coverage label distinct from the pair-list, graphic, strip, and comparison graphic coverage labels", () => {
+ expect(LEFTOVER_MAP_COMPARE_PLOT_ITEM_COVERAGE_LABEL).toBe(
+ "Leftover map comparison graphic item coverage",
+ );
+ expect(LEFTOVER_MAP_COMPARE_PLOT_ITEM_COVERAGE_LABEL).not.toBe(LEFTOVER_MAP_LIST_ITEM_COVERAGE_LABEL);
+ expect(LEFTOVER_MAP_COMPARE_PLOT_ITEM_COVERAGE_LABEL).not.toBe(LEFTOVER_MAP_PLOT_ITEM_COVERAGE_LABEL);
+ expect(LEFTOVER_MAP_COMPARE_PLOT_ITEM_COVERAGE_LABEL).not.toBe(LEFTOVER_MAP_COMPARE_ITEM_COVERAGE_LABEL);
+ expect(LEFTOVER_MAP_COMPARE_PLOT_ITEM_COVERAGE_LABEL).not.toBe(LEFTOVER_MAP_COMPARE_PLOT_COVERAGE_LABEL);
+ });
});
describe("leftoverMapIncompletePostCount", () => {
diff --git a/frontend/src/leftoverMapCoverage.ts b/frontend/src/leftoverMapCoverage.ts
index 9f9366662..b66000b64 100644
--- a/frontend/src/leftoverMapCoverage.ts
+++ b/frontend/src/leftoverMapCoverage.ts
@@ -1,4 +1,4 @@
-/** Leftover-map complete-case coverage after IRT main effects (ADR 0168 / ADR 0281 / ADR 0282 / ADR 0283 / ADR 0284 / ADR 0285 / ADR 0286 / ADR 0287 / ADR 0288 / ADR 0289 / ADR 0290 / ADR 0291 / ADR 0292 / ADR 0306). */
+/** Leftover-map complete-case coverage after IRT main effects (ADR 0168 / ADR 0281 / ADR 0282 / ADR 0283 / ADR 0284 / ADR 0285 / ADR 0286 / ADR 0287 / ADR 0288 / ADR 0289 / ADR 0290 / ADR 0291 / ADR 0292 / ADR 0306 / ADR 0307). */
import type { LeftoverMapCoverage } from "./api";
@@ -11,6 +11,9 @@ export const LEFTOVER_MAP_COMPARE_COVERAGE_LABEL = "Leftover map comparison cove
export const LEFTOVER_MAP_COMPARE_PLOT_COVERAGE_LABEL =
"Leftover map comparison graphic coverage";
+export const LEFTOVER_MAP_COMPARE_PLOT_ITEM_COVERAGE_LABEL =
+ "Leftover map comparison graphic item coverage";
+
export const LEFTOVER_MAP_COMPARE_ITEM_COVERAGE_LABEL = "Leftover map comparison item coverage";
export const LEFTOVER_MAP_COMPARE_INCOMPLETE_POST_LABEL = "Leftover map comparison incomplete posts";
diff --git a/frontend/src/leftoverMapPlotLayout.ts b/frontend/src/leftoverMapPlotLayout.ts
index 5705428be..ab41b1acc 100644
--- a/frontend/src/leftoverMapPlotLayout.ts
+++ b/frontend/src/leftoverMapPlotLayout.ts
@@ -33,14 +33,16 @@
* (ADR 0302), grouping comparison leftover-map coordinates payload
* (ADR 0303), grouping comparison leftover-map graphic display
* (ADR 0304), grouping comparison leftover-map axis share on that
- * graphic (ADR 0305), and grouping comparison leftover-map complete-case
- * coverage on that graphic (ADR 0306) caption the pair list or the grouping comparison
+ * graphic (ADR 0305), grouping comparison leftover-map complete-case
+ * coverage on that graphic (ADR 0306), and grouping comparison leftover-map
+ * item complete-case coverage on that graphic (ADR 0307) 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
* complete-case coverage on that comparison graphic from already-named leftover-map
- * coverage and does not caption leftover-map item coverage or leftover-map
- * incomplete coverage on that comparison plot.
+ * coverage. ADR 0307 captions leftover-map item complete-case coverage on that
+ * comparison graphic from already-named leftover-map coverage and does not caption
+ * leftover-map incomplete coverage on that comparison plot.
*/
import { formatLeftoverMapCoordinatePair } from "./leftoverMapCoordinates";
diff --git a/pyproject.toml b/pyproject.toml
index f1c5adf9e..41b9517da 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "lineageweave"
-version = "2.63.0"
+version = "2.64.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 872aba222..e5dab9aac 100644
--- a/uv.lock
+++ b/uv.lock
@@ -685,7 +685,7 @@ wheels = [
[[package]]
name = "lineageweave"
-version = "2.63.0"
+version = "2.64.0"
source = { editable = "." }
dependencies = [
{ name = "certifi" },