diff --git a/AGENTS.md b/AGENTS.md
index 019f0e89c..306c433b3 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) 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) 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
@@ -317,7 +317,11 @@ the pair-row `U²/R²` badge matches the graphic; a missing or non-finite
segments with persisted leftover-map cross share `x` so
the pair-row `2R̂U/R²` badge matches the graphic; a missing or non-finite
`x` omits that leftover-map cross share caption and does not invent
-`x` from `R̂`, `U`, and `R` or from plotted coordinates. When `R`, `R̂`, `U`, `x`,
+`x` from `R̂`, `U`, and `R` or from plotted coordinates. ADR 0276 captions leftover-map pair
+segments with persisted leftover-map unexplained leftover `U` so
+the pair-row `U` badge matches the graphic; a missing or non-finite
+`U` omits that unexplained leftover caption and does not invent
+`U` from `R` and `R̂` or from plotted coordinates. When `R`, `R̂`, `U`, `x`,
`s`, and `e` are finite, `e + s + x = 1`. When coordinates,
reconstruction, and distance are finite, `R̂ = ξ · ζ` and
`d = ‖ξ − ζ‖`. The pairs sit above the member
diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md
index e1e86008d..cfd68b96d 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) persist to `report_leftover_pair` with signed residual `R`,
+0182 / 0185 / 0201 / 0233 / 0266 / 0267 / 0268 / 0269 / 0270 / 0271 / 0272 / 0273 / 0274 / 0275 / 0276) 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
@@ -653,7 +653,8 @@ captions leftover-map pair segments with persisted leftover-map
explained leftover share `e`. ADR 0274 captions leftover-map pair
segments with persisted leftover-map unexplained leftover share `s`.
ADR 0275 captions leftover-map pair segments with persisted leftover-map
-cross share `x`. Click a post marker or a pair button
+cross share `x`. ADR 0276 captions leftover-map pair segments with persisted leftover-map
+unexplained leftover `U`. 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.33.0-leftover-map-segment-unexplained-leftover.md b/CHANGELOG.d/2.33.0-leftover-map-segment-unexplained-leftover.md
new file mode 100644
index 000000000..8d0bc4a91
--- /dev/null
+++ b/CHANGELOG.d/2.33.0-leftover-map-segment-unexplained-leftover.md
@@ -0,0 +1,17 @@
+## 2.33.0 — Leftover-map unexplained leftover on graphic-display pair segments
+
+- Caption leftover-map graphic-display pair segments with persisted
+ leftover-map unexplained leftover `U = R − R̂` (ADR 0276). 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, and
+ pair segments that match `U` on the pair row; click a post marker or
+ a pair button opens that post. A missing or non-finite `U` omits that
+ unexplained leftover caption. A finite negative leftover is shown;
+ do not clamp to nonnegative. Do not invent `U` from `R` and `R̂` or
+ from plotted coordinates. Never invent a leftover score. Never invent
+ a theta. No new columns.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 944e3a14c..1afc6d53c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,23 @@ All notable changes to this project are documented here. Format follows
### Added
+- Period leftover pairs now caption leftover-map graphic-display pair
+ segments with persisted leftover-map unexplained leftover
+ `U = R − R̂` (ADR 0276 / v2.33.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, and pair
+ segments that match `U` on the pair row; click a post marker or a
+ pair button opens that post. A missing or non-finite `U` omits that
+ unexplained leftover caption. A finite negative leftover is shown;
+ do not clamp to nonnegative. Do not invent `U` from `R` and `R̂` or
+ from plotted coordinates. Never invent a leftover score or a theta.
+ No new columns.
+
- Period leftover pairs now caption leftover-map graphic-display pair
segments with persisted leftover-map cross share
`x = 2 R̂ U / R²` (ADR 0275 / v2.32.0). After `make seed`, closest and
diff --git a/CLAUDE.md b/CLAUDE.md
index 107079ed7..56cc3bcda 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), occupational construct catalog search
+(ADR 0048–0164 / 0182 / 0185 / 0201 / 0233 / 0266 / 0267 / 0268 / 0269 / 0270 / 0271 / 0272 / 0273 / 0274 / 0275 / 0276), 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/0048-persist-lsirm-leftover-pairs.md b/docs/adr/0048-persist-lsirm-leftover-pairs.md
index f94e7d097..74e871ea3 100644
--- a/docs/adr/0048-persist-lsirm-leftover-pairs.md
+++ b/docs/adr/0048-persist-lsirm-leftover-pairs.md
@@ -18,7 +18,8 @@
[ADR 0272](0272-leftover-map-segment-reconstruction.md) (leftover-map reconstruction on pair segments);
[ADR 0273](0273-leftover-map-segment-explained-share.md) (leftover-map explained leftover share on pair segments);
[ADR 0274](0274-leftover-map-segment-unexplained-share.md) (leftover-map unexplained leftover share on pair segments);
-[ADR 0275](0275-leftover-map-segment-cross-share.md) (leftover-map cross share on pair segments)
+[ADR 0275](0275-leftover-map-segment-cross-share.md) (leftover-map cross share on pair segments);
+[ADR 0276](0276-leftover-map-segment-unexplained-leftover.md) (leftover-map unexplained leftover on pair segments)
## Context
@@ -84,7 +85,9 @@ leftover-map pair segments with persisted leftover-map explained leftover
share `e`; it adds no columns. ADR 0274 captions leftover-map pair
segments with persisted leftover-map unexplained leftover share `s`; it
adds no columns. ADR 0275 captions leftover-map pair segments with
-persisted leftover-map cross share `x`; it adds no columns.
+persisted leftover-map cross share `x`; it adds no columns. ADR 0276
+captions leftover-map pair segments with persisted leftover-map
+unexplained leftover `U`; it adds no columns.
Cascade the rows with `report_period_score`. A leftover post must
also be a `report_member_score` row, and the leftover criterion
diff --git a/docs/adr/0049-leftover-pair-report-ui.md b/docs/adr/0049-leftover-pair-report-ui.md
index b3ae6fea1..fd856219c 100644
--- a/docs/adr/0049-leftover-pair-report-ui.md
+++ b/docs/adr/0049-leftover-pair-report-ui.md
@@ -19,7 +19,8 @@
[ADR 0272](0272-leftover-map-segment-reconstruction.md) (leftover-map reconstruction on pair segments);
[ADR 0273](0273-leftover-map-segment-explained-share.md) (leftover-map explained leftover share on pair segments);
[ADR 0274](0274-leftover-map-segment-unexplained-share.md) (leftover-map unexplained leftover share on pair segments);
-[ADR 0275](0275-leftover-map-segment-cross-share.md) (leftover-map cross share on pair segments)
+[ADR 0275](0275-leftover-map-segment-cross-share.md) (leftover-map cross share on pair segments);
+[ADR 0276](0276-leftover-map-segment-unexplained-leftover.md) (leftover-map unexplained leftover on pair segments)
## Context
@@ -51,7 +52,8 @@ distance `d` (ADR 0271). Pair segments name persisted leftover-map
reconstruction `R̂` (ADR 0272). Pair segments name persisted leftover-map
explained leftover share `e` (ADR 0273). Pair segments name persisted leftover-map
unexplained leftover share `s` (ADR 0274). Pair segments name persisted leftover-map
-cross share `x` (ADR 0275). The pair renders every available finite measurement.
+cross share `x` (ADR 0275). Pair segments name persisted leftover-map
+unexplained leftover `U` (ADR 0276). The pair renders every available finite measurement.
The next action uses the first available value in the priority below; no
amendment hides another badge, rank 0
explicitly names no leftover structure, and unexplained leftover names
@@ -92,6 +94,8 @@ Leftover-map unexplained leftover share on pair segments is
[ADR 0274](0274-leftover-map-segment-unexplained-share.md).
Leftover-map cross share on pair segments is
[ADR 0275](0275-leftover-map-segment-cross-share.md).
+Leftover-map unexplained leftover on pair segments is
+[ADR 0276](0276-leftover-map-segment-unexplained-leftover.md).
After `make seed`, closest and farthest leftover pairs sit above the
member list. Click a pair to open that post with the leftover
diff --git a/docs/adr/0182-leftover-map-unexplained.md b/docs/adr/0182-leftover-map-unexplained.md
index 13ab5a573..1e96d8f81 100644
--- a/docs/adr/0182-leftover-map-unexplained.md
+++ b/docs/adr/0182-leftover-map-unexplained.md
@@ -4,7 +4,9 @@
**Date:** 2026-08-24
**Amended by:** [ADR 0201](0201-leftover-map-reconstruction.md)
-(two-axis reconstruction R̂)
+(two-axis reconstruction R̂);
+[ADR 0276](0276-leftover-map-segment-unexplained-leftover.md)
+(leftover-map unexplained leftover on graphic-display pair segments)
Amends [ADR 0048](0048-persist-lsirm-leftover-pairs.md) and
[ADR 0049](0049-leftover-pair-report-ui.md).
@@ -73,7 +75,9 @@ score. Do not invent a theta.
`GET /api/reports/{grouping}/{period}` returns
`leftover_map_unexplained`. After `make seed`, closest and farthest
leftover pairs sit above the member list with named `U` next to `d`;
-click opens that post. Hidden posts stay hidden.
+click opens that post. Hidden posts stay hidden. ADR 0276
+captions leftover-map graphic-display pair segments with the same
+persisted leftover-map unexplained leftover; it adds no columns.
## Related
diff --git a/docs/adr/0268-leftover-map-graphic-display.md b/docs/adr/0268-leftover-map-graphic-display.md
index c11c16c7d..674f1de06 100644
--- a/docs/adr/0268-leftover-map-graphic-display.md
+++ b/docs/adr/0268-leftover-map-graphic-display.md
@@ -16,7 +16,9 @@
[ADR 0274](0274-leftover-map-segment-unexplained-share.md)
(leftover-map unexplained leftover share on pair segments);
[ADR 0275](0275-leftover-map-segment-cross-share.md)
-(leftover-map cross share on pair segments)
+(leftover-map cross share on pair segments);
+[ADR 0276](0276-leftover-map-segment-unexplained-leftover.md)
+(leftover-map unexplained leftover on pair segments)
Amends [ADR 0049](0049-leftover-pair-report-ui.md) and
[ADR 0267](0267-leftover-map-coordinates.md). Independent of leftover-map
@@ -95,7 +97,8 @@ persisted leftover-map distance `d` (ADR 0271). Pair segments name
persisted leftover-map reconstruction `R̂` (ADR 0272). Pair segments name
persisted leftover-map explained leftover share `e` (ADR 0273). Pair segments name
persisted leftover-map unexplained leftover share `s` (ADR 0274). Pair segments name
-persisted leftover-map cross share `x` (ADR 0275). When coordinates, reconstruction, and
+persisted leftover-map cross share `x` (ADR 0275). Pair segments name
+persisted leftover-map unexplained leftover `U` (ADR 0276). When coordinates, reconstruction, and
distance are all finite, `R̂ = ξ_{1:2} · ζ_{1:2}` and
`d = ‖ξ_{1:2} − ζ_{1:2}‖` remain the same identities already
persisted by ADR 0267.
diff --git a/docs/adr/0275-leftover-map-segment-cross-share.md b/docs/adr/0275-leftover-map-segment-cross-share.md
index c5e062c43..c80b19fb6 100644
--- a/docs/adr/0275-leftover-map-segment-cross-share.md
+++ b/docs/adr/0275-leftover-map-segment-cross-share.md
@@ -2,6 +2,8 @@
**Decision status:** Accepted
**Date:** 2026-08-29
+**Amended by:** [ADR 0276](0276-leftover-map-segment-unexplained-leftover.md)
+(leftover-map unexplained leftover on pair segments)
Amends [ADR 0268](0268-leftover-map-graphic-display.md),
[ADR 0049](0049-leftover-pair-report-ui.md), and leftover-map cross share
diff --git a/docs/adr/0276-leftover-map-segment-unexplained-leftover.md b/docs/adr/0276-leftover-map-segment-unexplained-leftover.md
new file mode 100644
index 000000000..79ee88b01
--- /dev/null
+++ b/docs/adr/0276-leftover-map-segment-unexplained-leftover.md
@@ -0,0 +1,147 @@
+# ADR 0276 — Name leftover-map unexplained leftover on graphic-display pair segments
+
+**Decision status:** Accepted
+**Date:** 2026-08-30
+
+Amends [ADR 0268](0268-leftover-map-graphic-display.md),
+[ADR 0049](0049-leftover-pair-report-ui.md), and leftover-map unexplained
+leftover persistence ([ADR 0182](0182-leftover-map-unexplained.md)). Independent of
+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-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)), and leftover-map axis share
+persistence ([ADR 0148](0148-leftover-map-axis-share.md)).
+
+## Context
+
+ADR 0182 already persists unexplained leftover `U = R − R̂` after
+two-axis Gabriel reconstruction. ADR 0275 already names persisted
+leftover-map cross share `x` on the leftover-map graphic-display pair
+segment. The segment still has no unexplained leftover label, so a
+buyer who reads `U +0.05` on the pair row cannot match that signed
+leftover to the graphic pair. Hiding `U` on the segment lets leftover
+residual `R`, leftover-map reconstruction `R̂`, leftover-map explained
+leftover share `e`, leftover-map unexplained leftover share `s`, or
+leftover-map cross share `x` be read as the leftover the truncated map
+cannot reconstruct even after `e`, `s`, and `x` are named on the
+segment. When `R`, `R̂`, and `U` are finite, `U + R̂ = R`; the graphic
+must name the same persisted `U` the pair row already shows.
+
+This increment names leftover-map graphic-display pair segments with
+persisted leftover-map unexplained leftover. It does not add columns.
+It does not recompute `U` from `R` and `R̂` or from plotted coordinates.
+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 **0276** so it does not
+collide with 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, leftover observed `Y` / expected `E`, leftover-map
+rank, two-axis leftover-map distance persistence, leftover coverage,
+leftover-map axis share persistence (0148), leftover interaction-map
+persistence, occupational construct catalog search (0265), or the
+dashboard stacks.
+
+## Decision
+
+On the leftover-map graphic display, caption each closest or farthest
+pair segment with the same persisted leftover-map unexplained leftover
+formatter as the pair-row `U` badge. A missing or non-finite `U` omits
+that unexplained leftover caption and keeps the connecting line and any
+leftover-map distance, reconstruction, explained leftover share,
+unexplained leftover share, or leftover-map cross share caption. Rank-0
+origin cells still name `U 0.00` when that persisted leftover is finite.
+A finite negative leftover is shown; do not clamp to nonnegative. Do not
+invent `U` from `R` and `R̂` or from plotted coordinates. Click a post
+marker to open that post. Criterion markers are not post buttons. The
+grouping comparison strip (ADR 0149) stays on its reduced leftover
+payload and does not gain these unexplained leftover captions.
+
+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`, and persisted leftover-map
+unexplained leftover `U`; click a post marker or a pair button opens that
+post. Hidden posts stay hidden. Rank-0 unused axes still plot at the
+origin, still name zero leftover-map axis share with a `0` tick, still
+name `d 0.00` when that distance is persisted, still name `R̂ 0.00`
+when that reconstruction is persisted, still name `R̂²/R² 0.00` when
+that explained leftover share is persisted, still name `U²/R² 0.00`
+when that unexplained leftover share is persisted, still name
+`2R̂U/R² 0.00` when that leftover-map cross share is persisted, and
+still name `U 0.00` when that unexplained leftover is persisted. When
+`R`, `R̂`, and `U` are all finite, `U + R̂ = R` remains the same identity
+already persisted by ADR 0182 and ADR 0201. When `R`, `R̂`, `U`, `x`,
+`s`, and `e` are all finite, `e + s + x = 1` remains the same identity
+already persisted by ADR 0185, ADR 0233, and ADR 0266.
+
+## Related
+
+Independent of leftover interaction-map persistence, leftover-criterion
+evaluation landing, leftover residual disclosure, leftover observed
+`Y` / expected `E`, leftover-map complete-case coverage, leftover-map
+axis share persistence, leftover pairs on the grouping comparison
+strip, two-axis leftover-map distance persistence, leftover-map rank,
+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, and leftover-map cross share on pair segments.
+
+## 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}`. Unexplained leftover is the signed remainder
+`U = R − R̂` after that two-axis reconstruction.)
diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md
index c6b291c2e..10ffd80ea 100644
--- a/docs/product-technical-gap-baseline.md
+++ b/docs/product-technical-gap-baseline.md
@@ -1,5 +1,38 @@
# Product & Technical Gap Baseline
+> Exact-head loop overlay: 2026-08-30 02:09 KST. Protected `main` is
+> `fc13acaa20adca11968238e398d4aafcf62b6cee` (v2.23.0 leftover-map
+> explained leftover share). GitHub writes work (comment/close/create-PR).
+> Token still has empty `X-OAuth-Scopes`; repo permission is ADMIN.
+> Open leftover stack still lacks independent APPROVE. Do not self-approve.
+> #782 leftover-map coordinates through pair-segment distance
+> (v2.24.0–v2.28.0 / ADR 0267–0271) is `9bdd3e4d`. #802 explained
+> leftover share on pair segments (v2.30.0 / ADR 0273, includes v2.29
+> reconstruction) is `79ec22f0`. #803 unexplained leftover share on pair
+> segments (v2.31.0 / ADR 0274) is `089a1571`. #804 leftover-map cross
+> share on pair segments (v2.32.0 / ADR 0275) is `c513002b`. Leave
+> #782/#802/#803/#804 open for independent review. Do not squash-merge
+> stacked leftover PRs onto an unprotected leftover base. Strix on #782
+> failed closed at `Run Strix (quick)`; do not weaken fail-closed on
+> `Vulnerabilities [1-9]`. Org Strix `ModelBehaviorError` classifier is
+> already on ContextualWisdomLab/.github. Copilot review is not
+> independent APPROVE. Issues #79 and #87 stay open.
+>
+> Next buyer increment on this cycle: leftover-map unexplained leftover
+> `U` on graphic-display pair segments (ADR 0276 / v2.33.0) delivered
+> locally on `feat/leftover-map-segment-unexplained-leftover-v2330`.
+> Caption each closest/farthest segment with persisted leftover-map
+> unexplained leftover so the pair-row `U` badge matches the graphic
+> and `U + R̂ = R` is graphic-auditable. UI-only; no new columns.
+> Missing/non-finite `U` omits that unexplained leftover caption. A
+> finite negative leftover is shown; do not clamp to nonnegative. Do not
+> invent `U` from `R` and `R̂` or from plotted coordinates. Do not invent
+> leftover scores. Stack onto leftover branch
+> `feat/leftover-map-segment-cross-share-v2320` / #804; leave the PR open
+> for independent review. Do not squash-merge onto the leftover base.
+> Do not persist leftover-map inner product, cosine, or length as
+> separate columns.
+
> Exact-head loop overlay: 2026-08-29 23:10 KST. Protected `main` is
> `fc13acaa20adca11968238e398d4aafcf62b6cee` (v2.23.0 leftover-map
> explained leftover share, #775). Open ready PRs still lack independent
diff --git a/docs/storybook-inventory.md b/docs/storybook-inventory.md
index d63417657..35671b57d 100644
--- a/docs/storybook-inventory.md
+++ b/docs/storybook-inventory.md
@@ -5,8 +5,8 @@ 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, and pair-segment `2R̂U/R²` to leftover-map cross share, then click a post marker to open that post. Leftover-map axes name persisted leftover-map axis share when finite. `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`, and `2R̂U/R² 0.00`, 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, and pair segments name persisted leftover-map cross share. | `LeftoverPairList`, `LeftoverMapPlot`, `ticket-list`, `post-badge` |
+| `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, and pair-segment `U` to leftover-map unexplained leftover, then click a post marker to open that post. Leftover-map axes name persisted leftover-map axis share when finite. `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`, and `U 0.00`, 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, and pair segments name persisted leftover-map unexplained leftover. | `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 fbd3aeb86..465f0dda4 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,7 +1,7 @@
{
"name": "frontend",
"private": true,
- "version": "2.32.0",
+ "version": "2.33.0",
"type": "module",
"scripts": {
"dev": "vite",
diff --git a/frontend/src/components/LeftoverMapPlot.stories.tsx b/frontend/src/components/LeftoverMapPlot.stories.tsx
index 915ff4223..d79587245 100644
--- a/frontend/src/components/LeftoverMapPlot.stories.tsx
+++ b/frontend/src/components/LeftoverMapPlot.stories.tsx
@@ -84,6 +84,7 @@ export const RankZeroOrigin: Story = {
leftover_map_explained_share: 0,
leftover_map_unexplained_share: 0,
leftover_map_cross_share: 0,
+ leftover_map_unexplained: 0,
leftover_map_person_axis_1: 0,
leftover_map_person_axis_2: 0,
leftover_map_item_axis_1: 0,
diff --git a/frontend/src/components/LeftoverMapPlot.test.tsx b/frontend/src/components/LeftoverMapPlot.test.tsx
index 82efd959f..931ee1ed1 100644
--- a/frontend/src/components/LeftoverMapPlot.test.tsx
+++ b/frontend/src/components/LeftoverMapPlot.test.tsx
@@ -16,6 +16,7 @@ const PAIRS: LeftoverPair[] = [
leftover_map_explained_share: 0.76,
leftover_map_unexplained_share: 0.02,
leftover_map_cross_share: 0.12,
+ leftover_map_unexplained: 0.05,
leftover_map_person_axis_1: 0.5,
leftover_map_person_axis_2: 0.1,
leftover_map_item_axis_1: 0.5,
@@ -32,6 +33,7 @@ const PAIRS: LeftoverPair[] = [
leftover_map_explained_share: 0.6,
leftover_map_unexplained_share: 0.05,
leftover_map_cross_share: -0.24,
+ leftover_map_unexplained: -0.25,
leftover_map_person_axis_1: 0.9,
leftover_map_person_axis_2: 0.8,
leftover_map_item_axis_1: -0.7,
@@ -53,7 +55,7 @@ describe("LeftoverMapPlot", () => {
expect(screen.getByLabelText("Leftover-map graphic display")).toBeInTheDocument();
expect(
screen.getByText(
- "Leftover map after IRT main effects. Axis ticks name persisted leftover-map coordinates. Pair segments name leftover-map distance d, leftover-map reconstruction R̂, leftover-map explained leftover share e, leftover-map unexplained leftover share s, and leftover-map cross share x. Click a post marker to open that post. The plot does not invent a leftover score.",
+ "Leftover map after IRT main effects. Axis ticks name persisted leftover-map coordinates. Pair segments name leftover-map distance d, leftover-map reconstruction R̂, leftover-map explained leftover share e, leftover-map unexplained leftover share s, leftover-map cross share x, and leftover-map unexplained leftover U. Click a post marker to open that post. The plot does not invent a leftover score.",
),
).toBeInTheDocument();
expect(screen.getByText("Post ξ")).toBeInTheDocument();
@@ -73,6 +75,8 @@ describe("LeftoverMapPlot", () => {
expect(screen.getByLabelText("leftover-map unexplained leftover share U²/R² 0.05")).toBeInTheDocument();
expect(screen.getByLabelText("leftover-map cross share 2R̂U/R² 0.12")).toBeInTheDocument();
expect(screen.getByLabelText("leftover-map cross share 2R̂U/R² -0.24")).toBeInTheDocument();
+ expect(screen.getByLabelText("leftover-map unexplained leftover U +0.05")).toBeInTheDocument();
+ expect(screen.getByLabelText("leftover-map unexplained leftover U −0.25")).toBeInTheDocument();
const postMarker = screen.getByRole("button", {
name: "Open leftover-map post Public post at ξ (+0.50, +0.10)",
@@ -123,6 +127,7 @@ describe("LeftoverMapPlot", () => {
leftover_map_explained_share: 0,
leftover_map_unexplained_share: 0,
leftover_map_cross_share: 0,
+ leftover_map_unexplained: 0,
leftover_map_person_axis_1: 0,
leftover_map_person_axis_2: 0,
leftover_map_item_axis_1: 0,
@@ -149,6 +154,7 @@ describe("LeftoverMapPlot", () => {
expect(screen.getByLabelText("leftover-map explained leftover share R̂²/R² 0.00")).toBeInTheDocument();
expect(screen.getByLabelText("leftover-map unexplained leftover share U²/R² 0.00")).toBeInTheDocument();
expect(screen.getByLabelText("leftover-map cross share 2R̂U/R² 0.00")).toBeInTheDocument();
+ expect(screen.getByLabelText("leftover-map unexplained leftover U 0.00")).toBeInTheDocument();
});
it("captions leftover-map axes with persisted leftover-map axis share", () => {
@@ -321,4 +327,35 @@ describe("LeftoverMapPlot", () => {
expect(screen.getByLabelText("leftover-map unexplained leftover share U²/R² 0.02")).toBeInTheDocument();
expect(screen.getByLabelText("leftover-map explained leftover share R̂²/R² 0.76")).toBeInTheDocument();
});
+
+ it("omits leftover-map unexplained leftover on a pair segment when U is missing", () => {
+ render(
+ ,
+ );
+ expect(screen.queryByLabelText(/^leftover-map unexplained leftover U/)).not.toBeInTheDocument();
+ expect(screen.getByLabelText("leftover-map cross share 2R̂U/R² 0.12")).toBeInTheDocument();
+ expect(screen.getByLabelText("leftover-map unexplained leftover share U²/R² 0.02")).toBeInTheDocument();
+ });
});
diff --git a/frontend/src/components/LeftoverMapPlot.tsx b/frontend/src/components/LeftoverMapPlot.tsx
index 0f4de1959..8593e56ec 100644
--- a/frontend/src/components/LeftoverMapPlot.tsx
+++ b/frontend/src/components/LeftoverMapPlot.tsx
@@ -15,6 +15,7 @@ import {
LEFTOVER_MAP_PLOT_SEGMENT_DISTANCE,
LEFTOVER_MAP_PLOT_SEGMENT_EXPLAINED_SHARE,
LEFTOVER_MAP_PLOT_SEGMENT_RECONSTRUCTION,
+ LEFTOVER_MAP_PLOT_SEGMENT_UNEXPLAINED,
LEFTOVER_MAP_PLOT_SEGMENT_UNEXPLAINED_SHARE,
LEFTOVER_MAP_PLOT_TICK,
} from "../leftoverMapPlotLayout";
@@ -54,14 +55,15 @@ function leftoverMapPlotAxisText(
* pair row match the plot. Pair segments name persisted leftover-map
* distance ``d``, leftover-map reconstruction ``R̂``, leftover-map
* explained leftover share ``e``, leftover-map unexplained leftover
- * share ``s``, and leftover-map cross share ``x`` so the pair-row
- * badges match the graphic.
+ * share ``s``, leftover-map cross share ``x``, and leftover-map
+ * unexplained leftover ``U`` so the pair-row badges match the graphic.
* Omit that distance caption when ``d`` is missing or non-finite. Omit
* that reconstruction caption when ``R̂`` is missing or non-finite. Omit
* that explained leftover share caption when ``e`` is missing or
* non-finite. Omit that unexplained leftover share caption when ``s`` is
* missing or non-finite. Omit that leftover-map cross share caption when
- * ``x`` is missing or non-finite. Omit that axis badge when share is
+ * ``x`` is missing or non-finite. Omit that unexplained leftover caption
+ * when ``U`` is missing or non-finite. Omit that axis badge when share is
* missing or non-finite and keep the existing leftover-map axis text.
* Omit the plot when no pair has four finite leftover-map coordinates.
* Never invent a leftover score.
@@ -215,6 +217,19 @@ export function LeftoverMapPlot({
{segment.crossShareLabel}
) : null}
+ {segment.unexplainedLeftoverLabel !== null ? (
+
+ {segment.unexplainedLeftoverLabel}
+
+ ) : null}
))}
{layout.items.map((marker) => (
diff --git a/frontend/src/components/LeftoverPairList.tsx b/frontend/src/components/LeftoverPairList.tsx
index ae7fce7c8..327c00e9a 100644
--- a/frontend/src/components/LeftoverPairList.tsx
+++ b/frontend/src/components/LeftoverPairList.tsx
@@ -66,7 +66,8 @@ export type LeftoverPairListProps = {
* explained leftover share ``e`` on those pair segments. ADR 0274 names
* persisted leftover-map unexplained leftover share ``s`` on those pair
* segments. ADR 0275 names persisted leftover-map cross share ``x`` on
- * those pair segments. Every badge still
+ * those pair segments. ADR 0276 names persisted leftover-map unexplained
+ * leftover ``U`` on those pair segments. 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 eade0358e..c64df0090 100644
--- a/frontend/src/i18n.test.ts
+++ b/frontend/src/i18n.test.ts
@@ -71,7 +71,8 @@ describe("i18n", () => {
"leftover-map explained leftover share {label}",
"leftover-map unexplained leftover share {label}",
"leftover-map cross share {label}",
- "Leftover map after IRT main effects. Axis ticks name persisted leftover-map coordinates. Pair segments name leftover-map distance d, leftover-map reconstruction R̂, leftover-map explained leftover share e, leftover-map unexplained leftover share s, and leftover-map cross share x. Click a post marker to open that post. The plot does not invent a leftover score.",
+ "leftover-map unexplained leftover {label}",
+ "Leftover map after IRT main effects. Axis ticks name persisted leftover-map coordinates. Pair segments name leftover-map distance d, leftover-map reconstruction R̂, leftover-map explained leftover share e, leftover-map unexplained leftover share s, leftover-map cross share x, and leftover-map unexplained leftover U. Click a post marker to open that post. The plot does not invent a leftover score.",
"Open leftover-map post {title} at ξ {person}",
"Read observed Y {observed} and expected E {expected} after IRT main effects, then open this post.",
"Leftover map has no leftover structure after IRT main effects. Open this post.",
@@ -335,22 +336,22 @@ describe("i18n", () => {
it.each([
[
"ko",
- "IRT 주효과 이후 잔여 지도입니다. 축 눈금은 저장된 잔여 지도 좌표입니다. 쌍 선분은 잔여 지도 거리 d, 잔여 지도 재구성 R̂, 잔여 지도 설명 잔여 점유율 e, 잔여 지도 미설명 잔여 점유율 s, 잔여 지도 교차 점유율 x입니다. 글 표식을 눌러 그 글을 여세요. 이 그림은 잔여 점수를 만들어내지 않습니다.",
+ "IRT 주효과 이후 잔여 지도입니다. 축 눈금은 저장된 잔여 지도 좌표입니다. 쌍 선분은 잔여 지도 거리 d, 잔여 지도 재구성 R̂, 잔여 지도 설명 잔여 점유율 e, 잔여 지도 미설명 잔여 점유율 s, 잔여 지도 교차 점유율 x, 잔여 지도 미설명 잔여 U입니다. 글 표식을 눌러 그 글을 여세요. 이 그림은 잔여 점수를 만들어내지 않습니다.",
],
- ["zh", "IRT 主效应后的残差图。轴刻度标出已保存的残差图坐标。配对线段标出残差图距离 d、残差图重建 R̂、残差图已解释残差份额 e、残差图未解释残差份额 s 与残差图交叉份额 x。点击帖子标记打开该帖子。此图不会虚构残差分数。"],
+ ["zh", "IRT 主效应后的残差图。轴刻度标出已保存的残差图坐标。配对线段标出残差图距离 d、残差图重建 R̂、残差图已解释残差份额 e、残差图未解释残差份额 s、残差图交叉份额 x 与残差图未解释残差 U。点击帖子标记打开该帖子。此图不会虚构残差分数。"],
[
"ja",
- "IRT主効果後の残差マップです。軸目盛は保存済みの残差マップ座標です。ペア線分は残差マップ距離 d、残差マップ再構成 R̂、残差マップ説明済み残差割合 e、残差マップ未説明残差割合 s、残差マップ交差割合 x です。投稿マーカーをクリックしてその投稿を開いてください。この図は残差スコアを作りません。",
+ "IRT主効果後の残差マップです。軸目盛は保存済みの残差マップ座標です。ペア線分は残差マップ距離 d、残差マップ再構成 R̂、残差マップ説明済み残差割合 e、残差マップ未説明残差割合 s、残差マップ交差割合 x、残差マップ未説明残差 U です。投稿マーカーをクリックしてその投稿を開いてください。この図は残差スコアを作りません。",
],
[
"vi",
- "Bản đồ phần dư sau hiệu ứng chính IRT. Vạch trục ghi tọa độ bản đồ phần dư đã lưu. Đoạn cặp ghi khoảng cách bản đồ phần dư d, tái dựng bản đồ phần dư R̂, phần dư giải thích e, phần dư chưa giải thích s và phần giao x. Nhấn dấu bài viết để mở bài đó. Hình này không tạo ra điểm phần dư.",
+ "Bản đồ phần dư sau hiệu ứng chính IRT. Vạch trục ghi tọa độ bản đồ phần dư đã lưu. Đoạn cặp ghi khoảng cách bản đồ phần dư d, tái dựng bản đồ phần dư R̂, phần dư giải thích e, phần dư chưa giải thích s, phần giao x và phần dư chưa giải thích U. Nhấn dấu bài viết để mở bài đó. Hình này không tạo ra điểm phần dư.",
],
] as const)("formats leftover-map graphic display caption in %s", (locale, expected) => {
setLocale(locale);
expect(
t(
- "Leftover map after IRT main effects. Axis ticks name persisted leftover-map coordinates. Pair segments name leftover-map distance d, leftover-map reconstruction R̂, leftover-map explained leftover share e, leftover-map unexplained leftover share s, and leftover-map cross share x. Click a post marker to open that post. The plot does not invent a leftover score.",
+ "Leftover map after IRT main effects. Axis ticks name persisted leftover-map coordinates. Pair segments name leftover-map distance d, leftover-map reconstruction R̂, leftover-map explained leftover share e, leftover-map unexplained leftover share s, leftover-map cross share x, and leftover-map unexplained leftover U. Click a post marker to open that post. The plot does not invent a leftover score.",
),
).toBe(expected);
});
@@ -419,6 +420,16 @@ describe("i18n", () => {
expect(tf("leftover-map cross share {label}", { label: "2R̂U/R² 0.12" })).toBe(expected);
});
+ it.each([
+ ["ko", "잔여 지도 미설명 잔여 U +0.05"],
+ ["zh", "残差图未解释残差 U +0.05"],
+ ["ja", "残差マップ未説明残差 U +0.05"],
+ ["vi", "phần dư chưa giải thích U +0.05"],
+ ] as const)("formats leftover-map segment unexplained leftover in %s", (locale, expected) => {
+ setLocale(locale);
+ expect(tf("leftover-map unexplained leftover {label}", { label: "U +0.05" })).toBe(expected);
+ });
+
it.each([
["ko", "잔여 지도 축 1 (82%)"],
["zh", "残差图轴 1 (82%)"],
diff --git a/frontend/src/i18n.ts b/frontend/src/i18n.ts
index a16a3b7a7..50d6aad4f 100644
--- a/frontend/src/i18n.ts
+++ b/frontend/src/i18n.ts
@@ -596,8 +596,9 @@ const TRANSLATIONS: Partial>> = {
"leftover-map explained leftover share {label}": "잔여 지도 설명 잔여 점유율 {label}",
"leftover-map unexplained leftover share {label}": "잔여 지도 미설명 잔여 점유율 {label}",
"leftover-map cross share {label}": "잔여 지도 교차 점유율 {label}",
- "Leftover map after IRT main effects. Axis ticks name persisted leftover-map coordinates. Pair segments name leftover-map distance d, leftover-map reconstruction R̂, leftover-map explained leftover share e, leftover-map unexplained leftover share s, and leftover-map cross share x. Click a post marker to open that post. The plot does not invent a leftover score.":
- "IRT 주효과 이후 잔여 지도입니다. 축 눈금은 저장된 잔여 지도 좌표입니다. 쌍 선분은 잔여 지도 거리 d, 잔여 지도 재구성 R̂, 잔여 지도 설명 잔여 점유율 e, 잔여 지도 미설명 잔여 점유율 s, 잔여 지도 교차 점유율 x입니다. 글 표식을 눌러 그 글을 여세요. 이 그림은 잔여 점수를 만들어내지 않습니다.",
+ "leftover-map unexplained leftover {label}": "잔여 지도 미설명 잔여 {label}",
+ "Leftover map after IRT main effects. Axis ticks name persisted leftover-map coordinates. Pair segments name leftover-map distance d, leftover-map reconstruction R̂, leftover-map explained leftover share e, leftover-map unexplained leftover share s, leftover-map cross share x, and leftover-map unexplained leftover U. Click a post marker to open that post. The plot does not invent a leftover score.":
+ "IRT 주효과 이후 잔여 지도입니다. 축 눈금은 저장된 잔여 지도 좌표입니다. 쌍 선분은 잔여 지도 거리 d, 잔여 지도 재구성 R̂, 잔여 지도 설명 잔여 점유율 e, 잔여 지도 미설명 잔여 점유율 s, 잔여 지도 교차 점유율 x, 잔여 지도 미설명 잔여 U입니다. 글 표식을 눌러 그 글을 여세요. 이 그림은 잔여 점수를 만들어내지 않습니다.",
"Open leftover-map post {title} at ξ {person}":
"잔여 지도 글 {title} 열기 (ξ {person})",
"Read observed Y {observed} and expected E {expected} after IRT main effects, then open this post.":
@@ -1180,8 +1181,9 @@ const TRANSLATIONS: Partial>> = {
"leftover-map explained leftover share {label}": "残差图已解释残差份额 {label}",
"leftover-map unexplained leftover share {label}": "残差图未解释残差份额 {label}",
"leftover-map cross share {label}": "残差图交叉份额 {label}",
- "Leftover map after IRT main effects. Axis ticks name persisted leftover-map coordinates. Pair segments name leftover-map distance d, leftover-map reconstruction R̂, leftover-map explained leftover share e, leftover-map unexplained leftover share s, and leftover-map cross share x. Click a post marker to open that post. The plot does not invent a leftover score.":
- "IRT 主效应后的残差图。轴刻度标出已保存的残差图坐标。配对线段标出残差图距离 d、残差图重建 R̂、残差图已解释残差份额 e、残差图未解释残差份额 s 与残差图交叉份额 x。点击帖子标记打开该帖子。此图不会虚构残差分数。",
+ "leftover-map unexplained leftover {label}": "残差图未解释残差 {label}",
+ "Leftover map after IRT main effects. Axis ticks name persisted leftover-map coordinates. Pair segments name leftover-map distance d, leftover-map reconstruction R̂, leftover-map explained leftover share e, leftover-map unexplained leftover share s, leftover-map cross share x, and leftover-map unexplained leftover U. Click a post marker to open that post. The plot does not invent a leftover score.":
+ "IRT 主效应后的残差图。轴刻度标出已保存的残差图坐标。配对线段标出残差图距离 d、残差图重建 R̂、残差图已解释残差份额 e、残差图未解释残差份额 s、残差图交叉份额 x 与残差图未解释残差 U。点击帖子标记打开该帖子。此图不会虚构残差分数。",
"Open leftover-map post {title} at ξ {person}":
"打开残差图帖子 {title}(ξ {person})",
"Read observed Y {observed} and expected E {expected} after IRT main effects, then open this post.":
@@ -1768,8 +1770,9 @@ const TRANSLATIONS: Partial>> = {
"leftover-map explained leftover share {label}": "残差マップ説明済み残差割合 {label}",
"leftover-map unexplained leftover share {label}": "残差マップ未説明残差割合 {label}",
"leftover-map cross share {label}": "残差マップ交差割合 {label}",
- "Leftover map after IRT main effects. Axis ticks name persisted leftover-map coordinates. Pair segments name leftover-map distance d, leftover-map reconstruction R̂, leftover-map explained leftover share e, leftover-map unexplained leftover share s, and leftover-map cross share x. Click a post marker to open that post. The plot does not invent a leftover score.":
- "IRT主効果後の残差マップです。軸目盛は保存済みの残差マップ座標です。ペア線分は残差マップ距離 d、残差マップ再構成 R̂、残差マップ説明済み残差割合 e、残差マップ未説明残差割合 s、残差マップ交差割合 x です。投稿マーカーをクリックしてその投稿を開いてください。この図は残差スコアを作りません。",
+ "leftover-map unexplained leftover {label}": "残差マップ未説明残差 {label}",
+ "Leftover map after IRT main effects. Axis ticks name persisted leftover-map coordinates. Pair segments name leftover-map distance d, leftover-map reconstruction R̂, leftover-map explained leftover share e, leftover-map unexplained leftover share s, leftover-map cross share x, and leftover-map unexplained leftover U. Click a post marker to open that post. The plot does not invent a leftover score.":
+ "IRT主効果後の残差マップです。軸目盛は保存済みの残差マップ座標です。ペア線分は残差マップ距離 d、残差マップ再構成 R̂、残差マップ説明済み残差割合 e、残差マップ未説明残差割合 s、残差マップ交差割合 x、残差マップ未説明残差 U です。投稿マーカーをクリックしてその投稿を開いてください。この図は残差スコアを作りません。",
"Open leftover-map post {title} at ξ {person}":
"残差マップの投稿 {title} を開く(ξ {person})",
"Read observed Y {observed} and expected E {expected} after IRT main effects, then open this post.":
@@ -2356,8 +2359,9 @@ const TRANSLATIONS: Partial>> = {
"leftover-map explained leftover share {label}": "phần dư giải thích bản đồ phần dư {label}",
"leftover-map unexplained leftover share {label}": "phần dư chưa giải thích bản đồ phần dư {label}",
"leftover-map cross share {label}": "phần giao bản đồ phần dư {label}",
- "Leftover map after IRT main effects. Axis ticks name persisted leftover-map coordinates. Pair segments name leftover-map distance d, leftover-map reconstruction R̂, leftover-map explained leftover share e, leftover-map unexplained leftover share s, and leftover-map cross share x. Click a post marker to open that post. The plot does not invent a leftover score.":
- "Bản đồ phần dư sau hiệu ứng chính IRT. Vạch trục ghi tọa độ bản đồ phần dư đã lưu. Đoạn cặp ghi khoảng cách bản đồ phần dư d, tái dựng bản đồ phần dư R̂, phần dư giải thích e, phần dư chưa giải thích s và phần giao x. Nhấn dấu bài viết để mở bài đó. Hình này không tạo ra điểm phần dư.",
+ "leftover-map unexplained leftover {label}": "phần dư chưa giải thích {label}",
+ "Leftover map after IRT main effects. Axis ticks name persisted leftover-map coordinates. Pair segments name leftover-map distance d, leftover-map reconstruction R̂, leftover-map explained leftover share e, leftover-map unexplained leftover share s, leftover-map cross share x, and leftover-map unexplained leftover U. Click a post marker to open that post. The plot does not invent a leftover score.":
+ "Bản đồ phần dư sau hiệu ứng chính IRT. Vạch trục ghi tọa độ bản đồ phần dư đã lưu. Đoạn cặp ghi khoảng cách bản đồ phần dư d, tái dựng bản đồ phần dư R̂, phần dư giải thích e, phần dư chưa giải thích s, phần giao x và phần dư chưa giải thích U. Nhấn dấu bài viết để mở bài đó. Hình này không tạo ra điểm phần dư.",
"Open leftover-map post {title} at ξ {person}":
"Mở bài viết bản đồ phần dư {title} tại ξ {person}",
"Read observed Y {observed} and expected E {expected} after IRT main effects, then open this post.":
diff --git a/frontend/src/leftoverMapPlotLayout.test.ts b/frontend/src/leftoverMapPlotLayout.test.ts
index 8d6e79224..eda3b0d88 100644
--- a/frontend/src/leftoverMapPlotLayout.test.ts
+++ b/frontend/src/leftoverMapPlotLayout.test.ts
@@ -27,6 +27,7 @@ function pair(
leftover_map_explained_share: 0.76,
leftover_map_unexplained_share: 0.02,
leftover_map_cross_share: 0.12,
+ leftover_map_unexplained: 0.05,
...overrides,
};
}
@@ -616,11 +617,113 @@ describe("layoutLeftoverMapPlot", () => {
leftover_map_explained_share: 0,
leftover_map_unexplained_share: 0,
leftover_map_cross_share: 0,
+ leftover_map_unexplained: 0,
}),
],
criterionLabel,
);
expect(layout?.segments[0]?.crossShareLabel).toBe("2R\u0302U/R\u00b2 0.00");
+ expect(layout?.segments[0]?.unexplainedLeftoverLabel).toBe("U 0.00");
+ expect(layout?.segments[0]?.unexplainedShareLabel).toBe("U\u00b2/R\u00b2 0.00");
+ expect(layout?.segments[0]?.explainedShareLabel).toBe("R\u0302\u00b2/R\u00b2 0.00");
+ expect(layout?.segments[0]?.reconstructionLabel).toBe("R\u0302 0.00");
+ expect(layout?.segments[0]?.distanceLabel).toBe("d 0.00");
+ });
+
+ it("names persisted leftover-map unexplained leftover on pair segments without inventing a leftover score", () => {
+ const layout = layoutLeftoverMapPlot(
+ [
+ pair(),
+ pair({
+ pair_kind: "farthest",
+ post_id: "post-demo-spec",
+ criterion_code: "negative_sentiment",
+ leftover_map_person_axis_1: 0.9,
+ leftover_map_person_axis_2: 0.8,
+ leftover_map_item_axis_1: -0.7,
+ leftover_map_item_axis_2: -0.4,
+ leftover_distance: 1.84,
+ leftover_map_reconstruction: -0.95,
+ leftover_map_explained_share: 0.6,
+ leftover_map_unexplained_share: 0.05,
+ leftover_map_cross_share: -0.24,
+ leftover_map_unexplained: -0.25,
+ }),
+ ],
+ criterionLabel,
+ );
+ expect(layout?.segments.map((segment) => segment.unexplainedLeftoverLabel)).toEqual([
+ "U +0.05",
+ "U \u22120.25",
+ ]);
+ expect(layout?.segments[0]?.unexplainedLeftoverX).toBeCloseTo(layout?.segments[0]?.labelX ?? 0, 5);
+ expect(layout?.segments[0]?.unexplainedLeftoverY).toBeGreaterThan(
+ layout?.segments[0]?.crossShareY ?? 0,
+ );
+ });
+
+ it("omits a leftover-map unexplained leftover caption when U is missing or non-finite", () => {
+ const layout = layoutLeftoverMapPlot(
+ [
+ pair({ leftover_map_unexplained: null }),
+ pair({
+ pair_kind: "farthest",
+ leftover_map_unexplained: Number.NaN,
+ leftover_map_item_axis_1: -0.7,
+ leftover_map_item_axis_2: -0.4,
+ criterion_code: "negative_sentiment",
+ }),
+ ],
+ criterionLabel,
+ );
+ expect(layout?.segments.map((segment) => segment.unexplainedLeftoverLabel)).toEqual([null, null]);
+ expect(layout?.segments.map((segment) => segment.crossShareLabel)).toEqual([
+ "2R\u0302U/R\u00b2 0.12",
+ "2R\u0302U/R\u00b2 0.12",
+ ]);
+ });
+
+ it("does not invent leftover-map unexplained leftover from reconstruction or residual", () => {
+ const layout = layoutLeftoverMapPlot(
+ [
+ pair({
+ leftover_map_person_axis_1: 1,
+ leftover_map_person_axis_2: 0,
+ leftover_map_item_axis_1: 1,
+ leftover_map_item_axis_2: 0,
+ leftover_map_reconstruction: 1,
+ leftover_map_explained_share: 0.76,
+ leftover_map_unexplained_share: 0.02,
+ leftover_map_cross_share: 0.12,
+ leftover_map_unexplained: 0.05,
+ }),
+ ],
+ criterionLabel,
+ );
+ expect(layout?.segments[0]?.unexplainedLeftoverLabel).toBe("U +0.05");
+ expect(layout?.segments[0]?.unexplainedLeftoverLabel).not.toBe("U +0.15");
+ });
+
+ it("names rank-0 origin unexplained leftover U 0.00 when that persisted value is finite", () => {
+ const layout = layoutLeftoverMapPlot(
+ [
+ pair({
+ leftover_map_person_axis_1: 0,
+ leftover_map_person_axis_2: 0,
+ leftover_map_item_axis_1: 0,
+ leftover_map_item_axis_2: 0,
+ leftover_distance: 0,
+ leftover_map_reconstruction: 0,
+ leftover_map_explained_share: 0,
+ leftover_map_unexplained_share: 0,
+ leftover_map_cross_share: 0,
+ leftover_map_unexplained: 0,
+ }),
+ ],
+ criterionLabel,
+ );
+ expect(layout?.segments[0]?.unexplainedLeftoverLabel).toBe("U 0.00");
+ expect(layout?.segments[0]?.crossShareLabel).toBe("2R\u0302U/R\u00b2 0.00");
expect(layout?.segments[0]?.unexplainedShareLabel).toBe("U\u00b2/R\u00b2 0.00");
expect(layout?.segments[0]?.explainedShareLabel).toBe("R\u0302\u00b2/R\u00b2 0.00");
expect(layout?.segments[0]?.reconstructionLabel).toBe("R\u0302 0.00");
diff --git a/frontend/src/leftoverMapPlotLayout.ts b/frontend/src/leftoverMapPlotLayout.ts
index 215d3a7dc..94162258d 100644
--- a/frontend/src/leftoverMapPlotLayout.ts
+++ b/frontend/src/leftoverMapPlotLayout.ts
@@ -4,20 +4,24 @@
* Pair segments name persisted leftover-map distance ``d`` (ADR 0271),
* persisted leftover-map reconstruction ``R̂`` (ADR 0272), persisted
* leftover-map explained leftover share ``e`` (ADR 0273), persisted
- * leftover-map unexplained leftover share ``s`` (ADR 0274), and persisted
- * leftover-map cross share ``x`` (ADR 0275).
+ * leftover-map unexplained leftover share ``s`` (ADR 0274), persisted
+ * leftover-map cross share ``x`` (ADR 0275), and persisted leftover-map
+ * unexplained leftover ``U`` (ADR 0276).
*/
import { formatLeftoverMapCoordinatePair } from "./leftoverMapCoordinates";
import { formatLeftoverMapCrossShare } from "./leftoverMapCrossShare";
import { formatLeftoverMapExplainedShare } from "./leftoverMapExplainedShare";
import { formatLeftoverMapReconstruction } from "./leftoverMapReconstruction";
+import {
+ formatLeftoverMapUnexplained,
+ formatSignedLeftoverValue,
+} from "./leftoverMapUnexplained";
import { formatLeftoverMapUnexplainedShare } from "./leftoverMapUnexplainedShare";
-import { formatSignedLeftoverValue } from "./leftoverMapUnexplained";
import type { LeftoverPair } from "./api";
export const LEFTOVER_MAP_PLOT_CAPTION =
- "Leftover map after IRT main effects. Axis ticks name persisted leftover-map coordinates. Pair segments name leftover-map distance d, leftover-map reconstruction R̂, leftover-map explained leftover share e, leftover-map unexplained leftover share s, and leftover-map cross share x. Click a post marker to open that post. The plot does not invent a leftover score.";
+ "Leftover map after IRT main effects. Axis ticks name persisted leftover-map coordinates. Pair segments name leftover-map distance d, leftover-map reconstruction R̂, leftover-map explained leftover share e, leftover-map unexplained leftover share s, leftover-map cross share x, and leftover-map unexplained leftover U. Click a post marker to open that post. The plot does not invent a leftover score.";
export const LEFTOVER_MAP_PLOT_POST_ACTION =
"Open leftover-map post {title} at ξ {person}";
@@ -40,6 +44,9 @@ export const LEFTOVER_MAP_PLOT_SEGMENT_UNEXPLAINED_SHARE =
export const LEFTOVER_MAP_PLOT_SEGMENT_CROSS_SHARE =
"leftover-map cross share {label}";
+export const LEFTOVER_MAP_PLOT_SEGMENT_UNEXPLAINED =
+ "leftover-map unexplained leftover {label}";
+
export const PLOT_WIDTH = 480;
export const PLOT_HEIGHT = 320;
export const PLOT_PADDING = 40;
@@ -59,6 +66,7 @@ export type LeftoverMapPlottablePair = {
leftover_map_explained_share?: number | null;
leftover_map_unexplained_share?: number | null;
leftover_map_cross_share?: number | null;
+ leftover_map_unexplained?: number | null;
leftover_map_person_axis_1?: number | null;
leftover_map_person_axis_2?: number | null;
leftover_map_item_axis_1?: number | null;
@@ -88,6 +96,7 @@ export type LeftoverMapPlotSegment = {
explainedShareLabel: string | null;
unexplainedShareLabel: string | null;
crossShareLabel: string | null;
+ unexplainedLeftoverLabel: string | null;
labelX: number;
labelY: number;
reconstructionX: number;
@@ -98,6 +107,8 @@ export type LeftoverMapPlotSegment = {
unexplainedShareY: number;
crossShareX: number;
crossShareY: number;
+ unexplainedLeftoverX: number;
+ unexplainedLeftoverY: number;
};
export type LeftoverMapPlotTick = {
@@ -325,6 +336,9 @@ export function layoutLeftoverMapPlot(
pair.leftover_map_unexplained_share,
);
const crossShareLabel = formatLeftoverMapCrossShare(pair.leftover_map_cross_share);
+ const unexplainedLeftoverLabel = formatLeftoverMapUnexplained(
+ pair.leftover_map_unexplained,
+ );
const labelPosition = leftoverMapSegmentLabelPosition(
personPos.x,
personPos.y,
@@ -352,6 +366,14 @@ export function layoutLeftoverMapPlot(
(explainedShareLabel !== null ? 1 : 0) +
(unexplainedShareLabel !== null ? 1 : 0),
);
+ const unexplainedLeftoverY = leftoverMapStackedCaptionY(
+ labelPosition.labelY,
+ (distanceLabel !== null ? 1 : 0) +
+ (reconstructionLabel !== null ? 1 : 0) +
+ (explainedShareLabel !== null ? 1 : 0) +
+ (unexplainedShareLabel !== null ? 1 : 0) +
+ (crossShareLabel !== null ? 1 : 0),
+ );
segments.push({
pairKind: pair.pair_kind === "farthest" ? "farthest" : "closest",
postId: pair.post_id,
@@ -365,6 +387,7 @@ export function layoutLeftoverMapPlot(
explainedShareLabel,
unexplainedShareLabel,
crossShareLabel,
+ unexplainedLeftoverLabel,
reconstructionX: labelPosition.labelX,
reconstructionY,
explainedShareX: labelPosition.labelX,
@@ -373,6 +396,8 @@ export function layoutLeftoverMapPlot(
unexplainedShareY,
crossShareX: labelPosition.labelX,
crossShareY,
+ unexplainedLeftoverX: labelPosition.labelX,
+ unexplainedLeftoverY,
...labelPosition,
});
}
diff --git a/pyproject.toml b/pyproject.toml
index e9de742c7..dfc9a04e1 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "lineageweave"
-version = "2.32.0"
+version = "2.33.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 24dddc5f9..ee8b86fda 100644
--- a/uv.lock
+++ b/uv.lock
@@ -685,7 +685,7 @@ wheels = [
[[package]]
name = "lineageweave"
-version = "2.32.0"
+version = "2.33.0"
source = { editable = "." }
dependencies = [
{ name = "certifi" },