diff --git a/AGENTS.md b/AGENTS.md
index 75791e501..f5f687a98 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) 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) 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
@@ -379,6 +379,12 @@ every scored criterion entering the map; a missing, non-integer, or negative
dropped count, or a dropped count that contradicts usable item complete-case
integers, omits that leftover-map incomplete item note and does not invent
dropped criteria from scored minus used or from plotted criterion marker count.
+ADR 0288 fail-closes leftover-map post complete-case coverage on the pair list
+through leftoverMapCoverageCounts so a used-greater-than-scored, negative, or
+non-integer payload cannot caption a contradictory `used N of M scored posts`
+note; a missing, non-integer, negative-used, non-positive-scored, or
+used-greater-than-scored coverage omits that leftover-map coverage note and
+does not invent post coverage from plotted marker count.
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
@@ -391,7 +397,9 @@ residual SVD axes 1 and 2 and persists to `report_leftover_map_axis`.
Rank-0 residuals emit two zero-share axes; the shares are report-level
and are not a leftover score. Complete-case coverage (ADR 0168) persists to
`report_leftover_map_coverage` and captions the pair list and the leftover-map
-graphic with how many scored posts entered the map. Item complete-case coverage
+graphic with how many scored posts entered the map. Pair-list post complete-case
+coverage (ADR 0288) fail-closes that pair-list note through leftoverMapCoverageCounts.
+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)
captions the pair list with how many scored criteria entered the map. Incomplete post coverage (ADR 0283) captions the leftover-map
diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md
index aab40280e..d741206c1 100644
--- a/ARCHITECTURE.md
+++ b/ARCHITECTURE.md
@@ -637,7 +637,7 @@ information at the group's mean θ (Lord, 1980 max-info CAT). Rankings
persist to `report_item_information`. After those IRT main effects,
residual SVD leftover pairs on two Gabriel axes (Jeon et al., 2021;
ADR 0017 / 0048 / 0049 / 0119 / 0148 / 0158 / 0162 / 0163 / 0164 / 0168 /
-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) persist to `report_leftover_pair` with signed residual `R`,
+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) persist to `report_leftover_pair` with signed residual `R`,
observed `Y`, expected `E[Y|θ, item]`, full leftover-map rank, unexplained
leftover, ADR 0201 reconstruction evidence, ADR 0185 cross-share evidence,
ADR 0233 unexplained leftover share `s`, ADR 0266 explained leftover
@@ -666,7 +666,8 @@ captions the leftover-map graphic display with persisted leftover-map incomplete
item coverage. ADR 0285 captions the leftover pair list with persisted leftover-map
item complete-case coverage. ADR 0286 captions the leftover pair list with persisted leftover-map
incomplete post coverage. ADR 0287 captions the leftover pair list with persisted leftover-map
-incomplete item coverage. Click a post marker or a pair button
+incomplete item coverage. ADR 0288 fail-closes leftover-map post complete-case coverage
+on the leftover pair list through leftoverMapCoverageCounts. 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
(Gabriel inertia of residual SVD axes 1 and 2; ADR 0148) persists to
diff --git a/CHANGELOG.d/2.45.0-leftover-map-list-post-coverage-helper.md b/CHANGELOG.d/2.45.0-leftover-map-list-post-coverage-helper.md
new file mode 100644
index 000000000..c0436456d
--- /dev/null
+++ b/CHANGELOG.d/2.45.0-leftover-map-list-post-coverage-helper.md
@@ -0,0 +1,31 @@
+## 2.45.0 — Leftover-map post complete-case coverage fail-closed on the pair list
+
+- Fail-close leftover-map post complete-case coverage on the leftover pair
+ list through leftoverMapCoverageCounts (ADR 0288). 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, 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, and a pair-list
+ note that matches leftover-map incomplete item coverage; 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 coverage omits
+ that leftover-map coverage note. Coverage `0 of M` is shown when that
+ persisted used count is a non-negative integer and scored is a positive
+ integer. Do not invent post coverage from plotted marker count,
+ leftover-map distance, leftover-map rank, leftover-map item 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 6079ba373..71bf70876 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,37 @@ All notable changes to this project are documented here. Format follows
### Added
+- Period leftover pairs now fail-close leftover-map post complete-case
+ coverage on the leftover pair list through leftoverMapCoverageCounts
+ (ADR 0288 / v2.45.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, 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, and a pair-list note
+ that matches leftover-map incomplete item coverage; 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 coverage omits that
+ leftover-map coverage note. Coverage `0 of M` is shown when that
+ persisted used count is a non-negative integer and scored is a positive
+ integer. Do not invent post coverage from plotted marker count,
+ leftover-map distance, leftover-map rank, leftover-map item coverage,
+ leftover-map incomplete post coverage, leftover-map incomplete item
+ coverage, or the count of unused axes. Never invent a leftover score or
+ a theta. No new columns.
+
- Period leftover pairs now caption the leftover pair list with persisted
leftover-map incomplete item coverage (ADR 0287 / v2.44.0). After
`make seed`, closest and farthest leftover pairs sit above the member
diff --git a/CLAUDE.md b/CLAUDE.md
index 347626b38..889f61d82 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), 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), 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/0288-leftover-map-list-post-coverage-helper.md b/docs/adr/0288-leftover-map-list-post-coverage-helper.md
new file mode 100644
index 000000000..425a973a0
--- /dev/null
+++ b/docs/adr/0288-leftover-map-list-post-coverage-helper.md
@@ -0,0 +1,197 @@
+# ADR 0288 — Fail-close leftover-map post complete-case coverage on the pair list
+
+**Decision status:** Proposed
+**Date:** 2026-08-30
+
+Amends [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
+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-map item
+complete-case coverage on the graphic display
+([ADR 0282](0282-leftover-map-plot-item-coverage.md)), leftover-map complete-case
+coverage on the graphic display
+([ADR 0281](0281-leftover-map-plot-coverage.md)), leftover-map rank on pair
+segments ([ADR 0280](0280-leftover-map-segment-rank.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 coordinate ticks ([ADR 0270](0270-leftover-map-coordinate-ticks.md)),
+leftover-map axis share on the graphic display
+([ADR 0269](0269-leftover-map-axis-share-plot.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 explained leftover share persistence
+([ADR 0266](0266-leftover-map-explained-share.md)), leftover-map
+unexplained leftover share persistence
+([ADR 0233](0233-leftover-map-unexplained-share.md)), leftover-map
+reconstruction persistence ([ADR 0201](0201-leftover-map-reconstruction.md)),
+leftover-map cross share persistence
+([ADR 0185](0185-leftover-map-cross-share.md)), leftover-map unexplained leftover
+persistence ([ADR 0182](0182-leftover-map-unexplained.md)), leftover-map rank
+persistence ([ADR 0164](0164-leftover-map-rank.md)), and leftover-map axis
+share persistence ([ADR 0148](0148-leftover-map-axis-share.md)).
+
+## Context
+
+ADR 0168 already persists `map_post_count` / `scored_post_count` on
+`report_leftover_map_coverage` and captions the pair list with post
+complete-case coverage. ADR 0281 already fail-closes that same coverage on
+the leftover-map graphic display through leftoverMapCoverageCounts. The
+pair-list note still interpolates raw `map_post_count` / `scored_post_count`
+whenever `scored_post_count > 0`, so a used-greater-than-scored, negative,
+or non-integer payload still captions a contradictory `used N of M scored
+posts (complete-case)` note. Incomplete rows are dropped from Gabriel
+factorization; a contradictory pair-list census lets a buyer treat those N
+posts as the scored census even when the integers cannot be a complete-case
+count.
+
+This increment fail-closes leftover-map post complete-case coverage on the
+pair-list note through leftoverMapCoverageCounts. It does not add columns.
+It does not recompute post coverage from plotted marker count, leftover-map
+distance, or leftover-map rank. It does not persist leftover-map inner
+product, cosine, or length as separate columns. It does not land Post
+quality on the leftover criterion. Leftover-map distance stays two-axis
+Euclidean. 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 **0288** so it does not collide with
+leftover-map incomplete item coverage on the pair list (0287), leftover-map
+incomplete post coverage on the pair list (0286), leftover-map item
+complete-case coverage on the pair list (0285), leftover-map incomplete
+item coverage on the graphic display (0284), leftover-map incomplete post
+coverage on the graphic display (0283), leftover-map item complete-case
+coverage on the graphic display (0282), leftover-map complete-case coverage
+on the graphic display (0281), leftover-map rank on pair segments (0280),
+leftover expected on pair segments (0279), leftover observed on pair
+segments (0278), leftover residual on pair segments (0277), leftover-map
+unexplained leftover on pair segments (0276), leftover-map cross share on
+pair segments (0275), leftover-map unexplained leftover share on pair
+segments (0274), leftover-map explained leftover share on pair segments
+(0273), leftover-map reconstruction on pair segments (0272), leftover-map
+distance on pair segments (0271), leftover-map coordinate ticks (0270),
+leftover-map axis share on the graphic display (0269), leftover-map graphic
+display (0268), leftover-map coordinates (0267 / migration 0245), leftover-map
+explained leftover share persistence (0266 / migration 0244), leftover-map
+unexplained leftover share persistence (0233 / migration 0233), leftover-map
+reconstruction persistence (0201 / migration 0206), leftover-map cross share
+persistence (0185), leftover-map unexplained leftover persistence (0182),
+leftover residual disclosure (0162), leftover observed `Y` / expected `E`
+persistence (0163), leftover-map rank persistence (0164), leftover coverage
+persistence (0168), two-axis leftover-map distance persistence, leftover-map
+axis share persistence (0148), leftover interaction-map persistence,
+occupational construct catalog search (0265), or the dashboard stacks.
+
+## Decision
+
+On the leftover pair list, caption persisted leftover-map post complete-case
+coverage as `Leftover map used {used} of {scored} scored posts (complete-case)`
+only when leftoverMapCoverageCounts returns usable complete-case integers
+from persisted `map_post_count` / `scored_post_count`. 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 coverage note
+and keeps the pair-list item coverage note, the pair-list incomplete post
+note, the pair-list incomplete item note, and any leftover-map distance,
+reconstruction, explained leftover share, unexplained leftover share,
+leftover-map cross share, unexplained leftover, leftover residual, leftover
+observed, leftover expected, leftover-map rank, leftover-map post coverage,
+leftover-map item coverage, leftover-map incomplete post, or leftover-map
+incomplete item caption on the graphic. Coverage `0 of M` is shown when
+that persisted used count is a non-negative integer and scored is a
+positive integer. Do not invent post coverage from plotted marker count,
+leftover-map distance, leftover-map rank, leftover-map item coverage,
+leftover-map incomplete post coverage, leftover-map incomplete item
+coverage, or the count of unused axes. Click a pair button to open that
+post. The grouping comparison strip (ADR 0149) stays on its reduced leftover
+payload and does not gain this leftover-map coverage caption.
+
+Do not add SQL. 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`, closest and farthest leftover pairs sit above the member
+list with the leftover-map graphic display of persisted `ξ` and `ζ`,
+leftover-map axes name persisted Gabriel inertia share when finite,
+leftover-map axis ticks name the same coordinates shown on the pair row,
+pair segments name persisted leftover-map distance `d`, persisted leftover-map
+reconstruction `R̂`, persisted leftover-map explained leftover share `e`,
+persisted leftover-map unexplained leftover share `s`, persisted leftover-map
+cross share `x`, persisted leftover-map unexplained leftover `U`, persisted
+leftover residual `R`, persisted leftover observed `Y`, persisted leftover
+expected `E`, persisted leftover-map rank, the plot names persisted leftover-map
+complete-case coverage, the plot names persisted leftover-map item
+complete-case coverage, the plot names persisted leftover-map incomplete
+post coverage, the plot names persisted leftover-map incomplete item
+coverage, the pair list names persisted leftover-map post complete-case
+coverage only when leftoverMapCoverageCounts returns usable integers, the
+pair list names persisted leftover-map item complete-case coverage, the pair
+list names persisted leftover-map incomplete post coverage, and the pair list
+names persisted leftover-map incomplete item coverage; click a post marker
+or a pair button opens that post.
+Hidden posts stay hidden. Rank-0 unused axes still plot at the origin and still
+name post coverage on the pair list when that coverage is persisted as usable
+complete-case integers.
+
+## Related
+
+Independent of leftover interaction-map persistence, leftover-criterion
+evaluation landing, leftover residual disclosure, leftover-map
+complete-case coverage persistence, leftover-map axis share persistence,
+leftover pairs on the grouping comparison strip, two-axis leftover-map
+distance persistence, leftover-map rank persistence, leftover-map inner
+product, leftover-map cosine, leftover-map length, leftover-map
+reconstruction persistence, leftover-map unexplained leftover persistence,
+leftover-map cross share persistence, leftover-map unexplained leftover
+share persistence, leftover-map explained leftover share persistence,
+leftover-map coordinate persistence, leftover-map graphic display,
+leftover-map axis share on the graphic display, leftover-map coordinate
+ticks, leftover-map distance on pair segments, leftover-map reconstruction
+on pair segments, leftover-map explained leftover share on pair segments,
+leftover-map unexplained leftover share on pair segments, leftover-map
+cross share on pair segments, leftover-map unexplained leftover on pair
+segments, leftover residual on pair segments, leftover observed on pair
+segments, leftover expected on pair segments, leftover-map rank on pair
+segments, leftover-map complete-case coverage on the graphic display,
+leftover-map item complete-case coverage on the graphic display,
+leftover-map incomplete post coverage on the graphic display,
+leftover-map incomplete item coverage on the graphic display,
+leftover-map item complete-case coverage on the pair list, leftover-map
+incomplete post coverage on the pair list, and leftover-map incomplete
+item coverage on the pair list.
+
+## References
+
+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
+
+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. Gabriel
+reconstruction of the leftover cell is the two-axis inner product
+`R̂ = ξ_{1:2} · ζ_{1:2}`. Incomplete rows are dropped from the
+complete-case residual rectangle; pair-list post coverage names how many
+scored posts entered that factorization only when leftoverMapCoverageCounts
+returns usable complete-case integers.)
diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md
index 6eaf49e5b..6159c7240 100644
--- a/docs/product-technical-gap-baseline.md
+++ b/docs/product-technical-gap-baseline.md
@@ -1,5 +1,11 @@
# Product & Technical Gap Baseline
+> #819 current-parent reconstruction: v2.45 pair-list post coverage fail-close
+> is being rebuilt from exact #818 `bc971a402ef9faecb2f0b4ffd743092f4779d76b`.
+> Preserve only feature delta `a2c965511d26923bd878ec56d655fb8a0183c4d7`;
+> historical convergence is evidence only. ADR 0288 remains Proposed while Draft,
+> and package/frontend/runtime release identity must converge at 2.45.0 before promotion.
+
> Exact-head loop overlay: 2026-08-30 22:18 KST. Protected `main` is
> `cb187cadee5fb6c46d8a944815ccc154a1e028d1` after unauthorized squash
> of leftover-map coordinates (v2.24.0 / #782). Revert #808
diff --git a/docs/storybook-inventory.md b/docs/storybook-inventory.md
index 12ea76430..f0aa61428 100644
--- a/docs/storybook-inventory.md
+++ b/docs/storybook-inventory.md
@@ -6,7 +6,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. `ClosestAndFarthest`, `RankZeroOrigin`, `MissingCoordinates`, and `MissingAxisShare` 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, and missing share that keeps existing leftover-map axis text. 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, leftover-map item complete-case coverage, leftover-map incomplete post coverage, and leftover-map incomplete item coverage when persisted. | `LeftoverPairList`, `LeftoverMapPlot`, `ticket-list`, `post-badge` |
+| `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. | `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` |
| `Post/Recorded perspectives` | Read the imported primary and every evidence-connected additional Voice with its recorded truth state instead of flattening them into one compound category. `CombinedEvidence`, `RejectedEvidence`, and `NarrowViewport` cover desktop, rejected-evidence, and narrow layouts. | `VoicePerspectiveList`, `ticket-list`, `post-meta` |
diff --git a/frontend/package.json b/frontend/package.json
index 4850829ac..a1c5ca160 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,7 +1,7 @@
{
"name": "frontend",
"private": true,
- "version": "2.44.0",
+ "version": "2.45.0",
"type": "module",
"scripts": {
"dev": "vite",
diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx
index 60859037b..70a4ad8c6 100644
--- a/frontend/src/App.test.tsx
+++ b/frontend/src/App.test.tsx
@@ -4240,6 +4240,9 @@ describe("App, authenticated", () => {
render(
- {tf("Leftover map used {used} of {scored} scored posts (complete-case)", { - used: report.leftover_map_coverage.map_post_count, - scored: report.leftover_map_coverage.scored_post_count, - })} + {coverageCounts !== null ? ( +
+ {tf(LEFTOVER_MAP_PLOT_COVERAGE, coverageCounts)}
- )} + ) : 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 94e489e40..cdee52429 100644 --- a/frontend/src/components/LeftoverPairList.tsx +++ b/frontend/src/components/LeftoverPairList.tsx @@ -79,7 +79,9 @@ export type LeftoverPairListProps = { * incomplete item coverage on the graphic. ADR 0285 names persisted leftover-map * item complete-case coverage on the pair-list note. ADR 0286 names persisted leftover-map * incomplete post coverage on the pair-list note. ADR 0287 names persisted leftover-map - * incomplete item coverage on the pair-list note. Every badge still + * incomplete item coverage on the pair-list note. ADR 0288 fail-closes pair-list + * leftover-map post complete-case coverage through leftoverMapCoverageCounts so + * used-greater-than-scored, negative, or non-integer counts omit that note. Every badge still * renders together before opening the named post. */ export function LeftoverPairList({ diff --git a/frontend/src/leftoverMapCoverage.test.ts b/frontend/src/leftoverMapCoverage.test.ts index 1f05b14f0..1d5540955 100644 --- a/frontend/src/leftoverMapCoverage.test.ts +++ b/frontend/src/leftoverMapCoverage.test.ts @@ -5,9 +5,11 @@ import { leftoverMapIncompleteItemCount, leftoverMapIncompletePostCount, leftoverMapItemCoverageCounts, + LEFTOVER_MAP_LIST_COVERAGE_LABEL, LEFTOVER_MAP_LIST_INCOMPLETE_ITEM_LABEL, LEFTOVER_MAP_LIST_INCOMPLETE_POST_LABEL, LEFTOVER_MAP_LIST_ITEM_COVERAGE_LABEL, + LEFTOVER_MAP_PLOT_COVERAGE_LABEL, LEFTOVER_MAP_PLOT_INCOMPLETE_ITEM_LABEL, LEFTOVER_MAP_PLOT_INCOMPLETE_POST_LABEL, LEFTOVER_MAP_PLOT_ITEM_COVERAGE_LABEL, @@ -62,6 +64,12 @@ describe("leftoverMapCoverageCounts", () => { scored: 2, }); }); + + it("keeps the pair-list coverage label distinct from the graphic coverage label", () => { + expect(LEFTOVER_MAP_LIST_COVERAGE_LABEL).toBe("Leftover map coverage"); + expect(LEFTOVER_MAP_PLOT_COVERAGE_LABEL).toBe("Leftover-map graphic coverage"); + expect(LEFTOVER_MAP_LIST_COVERAGE_LABEL).not.toBe(LEFTOVER_MAP_PLOT_COVERAGE_LABEL); + }); }); describe("leftoverMapItemCoverageCounts", () => { diff --git a/frontend/src/leftoverMapCoverage.ts b/frontend/src/leftoverMapCoverage.ts index eaf57e8ad..0c4554441 100644 --- a/frontend/src/leftoverMapCoverage.ts +++ b/frontend/src/leftoverMapCoverage.ts @@ -1,9 +1,11 @@ -/** 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). */ +/** 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). */ import type { LeftoverMapCoverage } from "./api"; export const LEFTOVER_MAP_PLOT_COVERAGE_LABEL = "Leftover-map graphic coverage"; +export const LEFTOVER_MAP_LIST_COVERAGE_LABEL = "Leftover map coverage"; + export const LEFTOVER_MAP_PLOT_COVERAGE = "Leftover map used {used} of {scored} scored posts (complete-case)"; diff --git a/frontend/src/leftoverMapPlotLayout.ts b/frontend/src/leftoverMapPlotLayout.ts index 8414cf2d1..05360efc9 100644 --- a/frontend/src/leftoverMapPlotLayout.ts +++ b/frontend/src/leftoverMapPlotLayout.ts @@ -12,10 +12,11 @@ * rank (ADR 0280). The plot names persisted leftover-map complete-case * coverage (ADR 0281), leftover-map item complete-case coverage * (ADR 0282), leftover-map incomplete post coverage (ADR 0283), and - * leftover-map incomplete item coverage (ADR 0284). Pair-list item - * complete-case coverage (ADR 0285), pair-list incomplete post - * coverage (ADR 0286), and pair-list incomplete item coverage - * (ADR 0287) caption the pair list, not this graphic layout. + * leftover-map incomplete item coverage (ADR 0284). Pair-list post + * complete-case coverage fail-closed through leftoverMapCoverageCounts + * (ADR 0288), pair-list item complete-case coverage (ADR 0285), pair-list + * incomplete post coverage (ADR 0286), and pair-list incomplete item + * coverage (ADR 0287) caption the pair list, not this graphic layout. */ import { formatLeftoverMapCoordinatePair } from "./leftoverMapCoordinates"; diff --git a/lineageweave/__init__.py b/lineageweave/__init__.py index 93a7733f1..1fca0e0a5 100644 --- a/lineageweave/__init__.py +++ b/lineageweave/__init__.py @@ -130,4 +130,4 @@ "serialize_lineage_analysis_result", ] -__version__ = "2.44.0" +__version__ = "2.45.0" diff --git a/pyproject.toml b/pyproject.toml index c0182fb90..df990f86f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "lineageweave" -version = "2.44.0" +version = "2.45.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/tests/test_adr_0288_governance.py b/tests/test_adr_0288_governance.py new file mode 100644 index 000000000..fd2aad542 --- /dev/null +++ b/tests/test_adr_0288_governance.py @@ -0,0 +1,13 @@ +"""Governance regression for the draft ADR 0288 decision state.""" + +from pathlib import Path + + +ADR_PATH = Path(__file__).parents[1] / "docs/adr/0288-leftover-map-list-post-coverage-helper.md" + + +def test_draft_adr_0288_remains_proposed() -> None: + """Keep the unmerged decision proposed until independent acceptance exists.""" + text = ADR_PATH.read_text(encoding="utf-8") + assert "**Decision status:** Proposed" in text + assert "**Decision status:** Accepted" not in text