diff --git a/AGENTS.md b/AGENTS.md index ae33e2e06..825fe408d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -273,7 +273,7 @@ stops startup instead of leaving a healthy-looking partial schema, and application code must not compensate for a missing table. Period leftover pairs (ADR 0017 / 0018 / 0048 / 0049 / 0119 / 0158 / 0162 / -0163 / 0164 / 0182 / 0185 / 0201 / 0233 / 0266 / 0267 / 0268 / 0269 / 0270 / 0271 / 0272 / 0273 / 0274 / 0275 / 0276 / 0277 / 0278 / 0279 / 0280 / 0281 / 0282 / 0283 / 0284 / 0285 / 0286 / 0287 / 0288 / 0289 / 0290 / 0291 / 0292 / 0293 / 0294 / 0295 / 0296 / 0297 / 0298 / 0299 / 0300 / 0301 / 0302 / 0303 / 0304 / 0305 / 0306 / 0307 / 0308 / 0309 / 0310 / 0311 / 0312 / 0313 / 0314 / 0315 / 0316 / 0317 / 0318 / 0319 / 0320 / 0321 / 0322 / 0323 / 0324 / 0325) are computed in `lineageweave/leftover_pairs.py` from the +0163 / 0164 / 0182 / 0185 / 0201 / 0233 / 0266 / 0267 / 0268 / 0269 / 0270 / 0271 / 0272 / 0273 / 0274 / 0275 / 0276 / 0277 / 0278 / 0279 / 0280 / 0281 / 0282 / 0283 / 0284 / 0285 / 0286 / 0287 / 0288 / 0289 / 0290 / 0291 / 0292 / 0293 / 0294 / 0295 / 0296 / 0297 / 0298 / 0299 / 0300 / 0301 / 0302 / 0303 / 0304 / 0305 / 0306 / 0307 / 0308 / 0309 / 0310 / 0311 / 0312 / 0313 / 0314 / 0315 / 0316 / 0317 / 0318 / 0319 / 0320 / 0321 / 0322 / 0323 / 0324 / 0325 / 0326) 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 @@ -668,6 +668,14 @@ returns a usable leftover-axis caption. Distinct accessible name Rank-0 unused axes still name leftover-axis `σ 0.00`. Do not invent leftover-map singular values from leftover-map axis share. Do not invent leftover-map axis share from leftover-map singular values. +ADR 0326 captions leftover-map comparison graphic leftover-map axes with persisted leftover-map +singular values `σ_k` when leftoverMapComparePlotAxisBadge returns a usable leftover-map +axis caption. Distinct accessible name +`leftover map comparison graphic leftover-map axis {axis} σ {value}`. Share and +singular value omit independently. Rank-0 unused axes still name leftover-map +comparison graphic leftover-map axis `σ 0.00`. Do not invent leftover-map +singular values from leftover-map axis share. Do not invent leftover-map axis +share from leftover-map singular values. 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 @@ -778,6 +786,9 @@ returns a usable leftover-map axis caption. Leftover-axis report badge leftover-map singular values independently of leftover-map axis share (ADR 0325) captions leftover-axis report badges with persisted leftover-map singular values `σ_k` when leftoverMapAxisBadge returns a usable leftover-axis caption. +Leftover-map comparison graphic leftover-map axis leftover-map singular values as leftoverMapComparePlotAxisBadge +(ADR 0326) captions leftover-map comparison graphic leftover-map axes with persisted leftover-map +singular values `σ_k` when leftoverMapComparePlotAxisBadge returns a usable leftover-map axis caption. Item complete-case coverage (ADR 0282) captions the leftover-map graphic with how many scored criteria entered the map. Item complete-case coverage on the pair list (ADR 0285) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index ba4108f8a..869131453 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -758,6 +758,9 @@ ADR 0324 captions leftover-map graphic-display axes with persisted leftover-map singular values `σ_k`. ADR 0325 captions leftover-axis report badges with persisted leftover-map singular values `σ_k` independently of leftover-map axis share. +ADR 0326 captions leftover-map comparison graphic leftover-map axes with persisted leftover-map +singular values `σ_k` when leftoverMapComparePlotAxisBadge returns a usable leftover-map +axis caption. 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 @@ -812,7 +815,9 @@ graphic (ADR 0321), leftover-map singular values on leftover-axis report badges (ADR 0322), leftover-map singular values on leftover-axis report badges on the grouping comparison strip (ADR 0323), leftover-map singular values on leftover-map graphic-display axes (ADR 0324), leftover-map singular values on leftover-axis -report badges independently of leftover-map axis share (ADR 0325); +report badges independently of leftover-map axis share (ADR 0325), leftover-map +comparison graphic leftover-map axis leftover-map singular values as leftoverMapComparePlotAxisBadge +(ADR 0326); `POST .../rebuild` scores every grouping kind (post_admin). `make seed` folds A-100/B-200 Event Lineage fixtures (and the Riverbend calendar post) that already have constructed IRT cells into the same shared diff --git a/CHANGELOG.d/2.83.0-leftover-map-compare-plot-axis-badge.md b/CHANGELOG.d/2.83.0-leftover-map-compare-plot-axis-badge.md new file mode 100644 index 000000000..7b715eb17 --- /dev/null +++ b/CHANGELOG.d/2.83.0-leftover-map-compare-plot-axis-badge.md @@ -0,0 +1,24 @@ +## 2.83.0 — Leftover-map comparison graphic leftover-map axis leftover-map singular values as leftoverMapComparePlotAxisBadge + +- Caption leftover-map comparison graphic leftover-map axes with persisted + leftover-map singular values `σ_k` through leftoverMapComparePlotAxisBadge + (ADR 0326). After `make seed`, grouping comparison leftover-map graphic + leftover-map axes name persisted leftover-map singular values when + leftoverMapComparePlotAxisBadge returns a usable leftover-map axis caption + even when leftover-map axis share is omitted; click a leftover pair opens + that post. A missing or non-finite leftover-map axis share omits that share + caption and keeps `leftover map comparison graphic leftover-map axis {k} σ {value}`. + A missing, non-finite, or negative singular value omits that `σ` badge and + keeps `leftover map comparison axis {k} ({share}%)`. Rank-0 unused axes still + name `σ 0.00`. Leftover-map comparison graphic leftover-map axes stay + `leftover map comparison graphic leftover-map axis {k} σ {value}` when share + is omitted so they stay distinct from leftover-axis + `leftover axis {k} σ {value}`, from hyphen `leftover-map axis {k} σ {value}`, + and from comparison leftover-axis + `leftover map comparison leftover axis {k} σ {value}`. Do not invent `σ_k` + from leftover-map axis share. Do not invent leftover-map axis share from + `σ_k`. This increment does not change leftover-map singular values on leftover-map + graphic-display axes, leftover-axis report badges, or leftover-axis report + badges on the grouping comparison strip. A finite negative leftover is shown, + never clamped. Never invent a leftover score. Never invent a theta. No new + columns. diff --git a/CHANGELOG.md b/CHANGELOG.md index c88b008df..e516a9baa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,29 @@ All notable changes to this project are documented here. Format follows ### Added +- Period leftover pairs now caption leftover-map comparison graphic leftover-map + axes with persisted leftover-map singular values `σ_k` through + leftoverMapComparePlotAxisBadge (ADR 0326 / v2.83.0). After `make seed`, + grouping comparison leftover-map graphic leftover-map axes name persisted + leftover-map singular values when leftoverMapComparePlotAxisBadge returns a + usable leftover-map axis caption even when leftover-map axis share is omitted; + click a leftover pair opens that post. A missing or non-finite leftover-map + axis share omits that share caption and keeps + `leftover map comparison graphic leftover-map axis {k} σ {value}`. A missing, + non-finite, or negative singular value omits that `σ` badge and keeps + `leftover map comparison axis {k} ({share}%)`. Rank-0 unused axes still name + `σ 0.00`. Leftover-map comparison graphic leftover-map axes stay + `leftover map comparison graphic leftover-map axis {k} σ {value}` when share + is omitted so they stay distinct from leftover-axis + `leftover axis {k} σ {value}`, from hyphen `leftover-map axis {k} σ {value}`, + and from comparison leftover-axis + `leftover map comparison leftover axis {k} σ {value}`. Do not invent `σ_k` + from leftover-map axis share. Do not invent leftover-map axis share from + `σ_k`. This increment does not change leftover-map singular values on leftover-map + graphic-display axes, leftover-axis report badges, or leftover-axis report + badges on the grouping comparison strip. A finite negative leftover is shown, + never clamped. Never invent a leftover score or a theta. No new columns. + - Period leftover pairs now caption leftover-axis report badges with persisted leftover-map singular values `σ_k` independently of leftover-map axis share (ADR 0325 / v2.82.0). After `make seed`, leftover-axis report badges name diff --git a/CLAUDE.md b/CLAUDE.md index 9de8440ab..4b9edef76 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -49,7 +49,7 @@ cutoff. Global Ask optional `knowledge_cutoff` uses the same cover Create/start endpoint rules (ADR 0017 / 0021), tie-vs-miss similarity (ADR 0026), R&R catalog ids (ADR 0019 / 0027), leftover pairs -(ADR 0048–0164 / 0182 / 0185 / 0201 / 0233 / 0266 / 0267 / 0268 / 0269 / 0270 / 0271 / 0272 / 0273 / 0274 / 0275 / 0276 / 0277 / 0278 / 0279 / 0280 / 0281 / 0282 / 0283 / 0284 / 0285 / 0286 / 0287 / 0288 / 0289 / 0290 / 0291 / 0292 / 0293 / 0294 / 0295 / 0296 / 0297 / 0298 / 0299 / 0300 / 0301 / 0302 / 0303 / 0304 / 0305 / 0306 / 0307 / 0308 / 0309 / 0310 / 0311 / 0312 / 0313 / 0314 / 0315 / 0316 / 0317 / 0318 / 0319 / 0320 / 0321 / 0322 / 0323 / 0324 / 0325), occupational construct catalog search +(ADR 0048–0164 / 0182 / 0185 / 0201 / 0233 / 0266 / 0267 / 0268 / 0269 / 0270 / 0271 / 0272 / 0273 / 0274 / 0275 / 0276 / 0277 / 0278 / 0279 / 0280 / 0281 / 0282 / 0283 / 0284 / 0285 / 0286 / 0287 / 0288 / 0289 / 0290 / 0291 / 0292 / 0293 / 0294 / 0295 / 0296 / 0297 / 0298 / 0299 / 0300 / 0301 / 0302 / 0303 / 0304 / 0305 / 0306 / 0307 / 0308 / 0309 / 0310 / 0311 / 0312 / 0313 / 0314 / 0315 / 0316 / 0317 / 0318 / 0319 / 0320 / 0321 / 0322 / 0323 / 0324 / 0325 / 0326), 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/0148-leftover-map-axis-share.md b/docs/adr/0148-leftover-map-axis-share.md index b2eebef3d..ca4f28f95 100644 --- a/docs/adr/0148-leftover-map-axis-share.md +++ b/docs/adr/0148-leftover-map-axis-share.md @@ -11,7 +11,9 @@ [ADR 0324](0324-leftover-map-plot-axis-singular.md) (leftover-map singular values on leftover-map graphic-display axes); [ADR 0325](0325-leftover-map-axis-singular-only.md) -(leftover-map singular values on leftover-axis report badges independently of leftover-map axis share) +(leftover-map singular values on leftover-axis report badges independently of leftover-map axis share); +[ADR 0326](0326-leftover-map-compare-plot-axis-badge.md) +(leftover-map comparison graphic leftover-map axis leftover-map singular values as leftoverMapComparePlotAxisBadge) ## Context diff --git a/docs/adr/0321-leftover-map-compare-plot-singular.md b/docs/adr/0321-leftover-map-compare-plot-singular.md index 0d386b4d0..fa604fc98 100644 --- a/docs/adr/0321-leftover-map-compare-plot-singular.md +++ b/docs/adr/0321-leftover-map-compare-plot-singular.md @@ -100,7 +100,9 @@ leftover-map axis share is `σ_k² / Σ_j σ_j²`. ## Related Independent of leftover-map singular values on leftover-axis report badges -([ADR 0322](0322-leftover-map-axis-singular.md)). +([ADR 0322](0322-leftover-map-axis-singular.md)). Independent of leftover-map +comparison graphic leftover-map axis leftover-map singular values as leftoverMapComparePlotAxisBadge +([ADR 0326](0326-leftover-map-compare-plot-axis-badge.md)). ## References diff --git a/docs/adr/0322-leftover-map-axis-singular.md b/docs/adr/0322-leftover-map-axis-singular.md index aac40500a..d4288dd63 100644 --- a/docs/adr/0322-leftover-map-axis-singular.md +++ b/docs/adr/0322-leftover-map-axis-singular.md @@ -88,7 +88,9 @@ not caption leftover-map singular values on leftover-map graphic-display axes ([ADR 0324](0324-leftover-map-plot-axis-singular.md)). This increment does not caption leftover-map singular values on leftover-axis report badges independently of leftover-map axis share -([ADR 0325](0325-leftover-map-axis-singular-only.md)). +([ADR 0325](0325-leftover-map-axis-singular-only.md)). This increment does not +caption leftover-map comparison graphic leftover-map axes through leftoverMapComparePlotAxisBadge +([ADR 0326](0326-leftover-map-compare-plot-axis-badge.md)). ## References diff --git a/docs/adr/0323-leftover-map-compare-axis-singular.md b/docs/adr/0323-leftover-map-compare-axis-singular.md index ebe2a5260..899776b0b 100644 --- a/docs/adr/0323-leftover-map-compare-axis-singular.md +++ b/docs/adr/0323-leftover-map-compare-axis-singular.md @@ -107,7 +107,9 @@ Independent of leftover-map singular values on leftover-map graphic-display axes ([ADR 0324](0324-leftover-map-plot-axis-singular.md)). Independent of leftover-map singular values on leftover-axis report badges independently of leftover-map axis share -([ADR 0325](0325-leftover-map-axis-singular-only.md)). +([ADR 0325](0325-leftover-map-axis-singular-only.md)). Independent of leftover-map +comparison graphic leftover-map axis leftover-map singular values as leftoverMapComparePlotAxisBadge +([ADR 0326](0326-leftover-map-compare-plot-axis-badge.md)). ## References diff --git a/docs/adr/0324-leftover-map-plot-axis-singular.md b/docs/adr/0324-leftover-map-plot-axis-singular.md index bb175246f..c4a33b2ea 100644 --- a/docs/adr/0324-leftover-map-plot-axis-singular.md +++ b/docs/adr/0324-leftover-map-plot-axis-singular.md @@ -115,7 +115,9 @@ strip ([ADR 0323](0323-leftover-map-compare-axis-singular.md)). Independent of leftover-map singular values on the grouping comparison leftover-map graphic ([ADR 0321](0321-leftover-map-compare-plot-singular.md)). Independent of leftover-map singular values on leftover-axis report badges independently of leftover-map axis -share ([ADR 0325](0325-leftover-map-axis-singular-only.md)). +share ([ADR 0325](0325-leftover-map-axis-singular-only.md)). Independent of leftover-map +comparison graphic leftover-map axis leftover-map singular values as leftoverMapComparePlotAxisBadge +([ADR 0326](0326-leftover-map-compare-plot-axis-badge.md)). ## References diff --git a/docs/adr/0325-leftover-map-axis-singular-only.md b/docs/adr/0325-leftover-map-axis-singular-only.md index b11a4526a..fb4bfeb03 100644 --- a/docs/adr/0325-leftover-map-axis-singular-only.md +++ b/docs/adr/0325-leftover-map-axis-singular-only.md @@ -104,7 +104,9 @@ leftover-map singular values on leftover-axis report badges on the grouping comparison strip ([ADR 0323](0323-leftover-map-compare-axis-singular.md)). Independent of leftover-map singular values on leftover-axis report badges that still require leftover-map axis share in the combined caption -([ADR 0322](0322-leftover-map-axis-singular.md)). +([ADR 0322](0322-leftover-map-axis-singular.md)). Independent of leftover-map +comparison graphic leftover-map axis leftover-map singular values as leftoverMapComparePlotAxisBadge +([ADR 0326](0326-leftover-map-compare-plot-axis-badge.md)). ## References diff --git a/docs/adr/0326-leftover-map-compare-plot-axis-badge.md b/docs/adr/0326-leftover-map-compare-plot-axis-badge.md new file mode 100644 index 000000000..ccd02ce89 --- /dev/null +++ b/docs/adr/0326-leftover-map-compare-plot-axis-badge.md @@ -0,0 +1,132 @@ +# ADR 0326 — Name leftover-map comparison graphic leftover-map axis leftover-map singular values as leftoverMapComparePlotAxisBadge + +**Decision status:** Accepted +**Date:** 2026-08-31 + +Amends leftover-map singular values on the grouping comparison leftover-map +graphic ([ADR 0321](0321-leftover-map-compare-plot-singular.md)), leftover-map +axis share on that comparison graphic +([ADR 0305](0305-leftover-map-compare-plot-axis-share.md)), leftover-map axis +share persistence ([ADR 0148](0148-leftover-map-axis-share.md)). Independent of +leftover-map singular values on leftover-map graphic-display axes +([ADR 0324](0324-leftover-map-plot-axis-singular.md)), leftover-map singular +values on leftover-axis report badges independently of leftover-map axis share +([ADR 0325](0325-leftover-map-axis-singular-only.md)), leftover-map singular +values on leftover-axis report badges on the grouping comparison strip +([ADR 0323](0323-leftover-map-compare-axis-singular.md)), leftover-map singular +values on leftover-axis report badges +([ADR 0322](0322-leftover-map-axis-singular.md)). + +## Context + +ADR 0148 already persists leftover-map singular values `σ_k` and leftover-map +axis share `σ_k² / Σ_j σ_j²`. ADR 0321 already captions leftover-map singular +values on the grouping comparison leftover-map graphic with +`leftover map comparison graphic leftover-map axis {k} σ {value}` when `σ_k` +is finite. Those comparison graphic leftover-map axes still inline σ and share +in leftoverMapPlotAxisText instead of fail-closing through a named helper. +leftoverMapPlotAxisBadge (ADR 0324), leftoverMapCompareAxisBadge (ADR 0323), +and leftoverMapAxisBadge (ADR 0325) already fail-close leftover-map singular +values through named helpers. Pair-list leftover-map coverage fail-closes +through leftoverMapCoverageCounts (ADR 0288). An inlined comparison graphic +leftover-map axis can invent leftover-map inner product, cosine, or length, +or couple `σ_k` to leftover-map axis share. A missing, non-finite, or negative +singular value is not a leftover score and must omit independently of leftover-map +axis share. Rank-0 unused axes still persist `σ_k = 0`. A finite negative leftover +is shown, never clamped. Do not invent `σ_k` from leftover-map axis share. Do not +invent leftover-map axis share from `σ_k`. + +This increment names leftover-map comparison graphic leftover-map axis leftover-map +singular values as leftoverMapComparePlotAxisBadge, matching leftoverMapPlotAxisBadge, +leftoverMapCompareAxisBadge, and leftoverMapAxisBadge. Comparison copy stays +`leftover map comparison graphic leftover-map axis {k} σ {value}` when share is +omitted so it stays distinct from leftover-axis `leftover axis {k} σ {value}` +(ADR 0325), from hyphen `leftover-map axis {k} σ {value}` (ADR 0324), and from +comparison leftover-axis `leftover map comparison leftover axis {k} σ {value}` +(ADR 0323). It does not add columns. Do not invent a leftover score. Do not invent +a theta. + +This protected increment uses **0326** so it does not collide with leftover-map +singular values on leftover-axis report badges independently of leftover-map axis +share (0325), leftover-map singular values on leftover-map graphic-display axes +(0324), leftover-map singular values on leftover-axis report badges on the grouping +comparison strip (0323), leftover-map singular values on leftover-axis report badges +(0322), leftover-map singular values on the grouping comparison leftover-map graphic +(0321), leftover-map axis share persistence (0148), or the dashboard stacks. + +## Decision + +On the grouping comparison leftover-map graphic, caption leftover-map axis `k` +with persisted leftover-map singular value `σ_k` when leftoverMapComparePlotAxisBadge +returns a usable leftover-map axis caption. Share and singular value omit +independently through that helper: no share and no `σ_k` returns null and the +graphic keeps `leftover map comparison axis {k}`; share only is +`leftover map comparison axis {k} ({share}%)`; `σ_k` only is +`leftover map comparison graphic leftover-map axis {k} σ {value}`; both is +`leftover map comparison graphic leftover-map axis {k} σ {value} ({share}%)`. +A missing or non-finite leftover-map axis share omits that share caption and +does not invent leftover-map axis share from `σ_k`. A missing, non-finite, or +negative singular value omits that `σ` badge and keeps a usable leftover-map +comparison axis share caption. Rank-0 unused axes still name `σ 0.00`. Click a +post marker to open that post. Criterion markers are not post buttons. + +Leftover-map comparison graphic leftover-map singular values omit independently +of leftover-map graphic-display leftover-map axis singular values, leftover-axis +report badge leftover-map singular values, and leftover-map comparison leftover-axis +singular values. A missing leftover-map axis share omits that leftover-map +comparison graphic leftover-map axis share caption and keeps a usable leftover-map +comparison graphic leftover-map axis `σ` caption, leftover-map graphic leftover-map +axis `σ` caption, leftover-axis `σ` caption, leftover-map comparison leftover-axis +`σ` caption, leftover-map graphic leftover-map axis ticks, leftover-map distance +caption, leftover-map rank caption, leftover expected `E`, leftover observed `Y`, +leftover residual `R`, leftover-map unexplained leftover `U`, leftover-map +reconstruction `R̂`, and leftover-map graphic coverage notes. + +This increment does not change leftover-map singular values on leftover-map +graphic-display axes. Those leftover-map graphic axes stay +`leftover-map axis {axis} σ {value} ({share}%)` (ADR 0324). This increment does +not change leftover-map singular values on leftover-axis report badges +(ADR 0325). This increment does not change leftover-map singular values on +leftover-axis report badges on the grouping comparison strip (ADR 0323). This +increment does not persist leftover-map inner product, cosine, or length. + +Do not add SQL. Do not edit shipped migrations. Do not invent a leftover +score. Do not invent a theta. + +## Consequences + +After `make seed`, grouping comparison leftover-map graphic leftover-map axes +name persisted leftover-map singular values when leftoverMapComparePlotAxisBadge +returns a usable leftover-map axis caption even when leftover-map axis share is +omitted; click a leftover pair opens that post. Hidden posts stay hidden. Rank-0 +unused axes still name leftover-map comparison graphic leftover-map axis `σ 0.00`. +Leftover-map graphic-display leftover-map singular values (ADR 0324), leftover-axis +report badge leftover-map singular values independently of leftover-map axis share +(ADR 0325), and grouping comparison leftover-axis report badge leftover-map +singular values (ADR 0323) remain. + +## Related + +Independent of leftover-map singular values on leftover-map graphic-display +axes ([ADR 0324](0324-leftover-map-plot-axis-singular.md)). Independent of +leftover-map singular values on leftover-axis report badges independently of +leftover-map axis share ([ADR 0325](0325-leftover-map-axis-singular-only.md)). +Independent of leftover-map singular values on leftover-axis report badges on +the grouping comparison strip ([ADR 0323](0323-leftover-map-compare-axis-singular.md)). +Independent of leftover-map singular values on leftover-axis report badges +([ADR 0322](0322-leftover-map-axis-singular.md)). Independent of leftover-map +singular values on the grouping comparison leftover-map graphic that still +inline σ and share ([ADR 0321](0321-leftover-map-compare-plot-singular.md)). + +## 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.) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 5efa4eb84..c52f1b12a 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,5 +1,27 @@ # Product & Technical Gap Baseline +> Exact-head loop overlay: 2026-08-31 12:05 KST. Protected `main` is +> `cb187cadee5fb6c46d8a944815ccc154a1e028d1`. Writes work. Do not +> self-approve. #866 leftover-map singular values on leftover-axis report badges +> independently of leftover-map axis share (v2.82.0 / ADR 0325) is `593b8d8`, +> stacked on #865 @ `a3613ac`. Independent APPROVE is missing. Next buyer +> increment on this cycle: leftover-map comparison graphic leftover-map axis +> leftover-map singular values as leftoverMapComparePlotAxisBadge +> (ADR 0326 / v2.83.0) delivered locally on +> `feat/leftover-map-compare-plot-axis-badge-v2830`. Caption persisted leftover-map +> singular values `σ_k` on leftover-map comparison graphic leftover-map axes when +> leftoverMapComparePlotAxisBadge returns a usable leftover-map axis caption. +> Distinct accessible name `leftover map comparison graphic leftover-map axis {axis} σ {value}`. +> Rank-0 unused axes still name `σ 0.00`. Share and singular value omit +> independently. Do not invent `σ_k` from leftover-map axis share. Do not invent +> leftover-map axis share from `σ_k`. Do not persist leftover-map inner product, +> cosine, or length. Do not change leftover-map singular values on leftover-map +> graphic-display axes, leftover-axis report badges, or leftover-axis report +> badges on the grouping comparison strip this increment. Stack onto #866. Leave +> open for independent review. Do not squash-merge. Do not self-approve. Issues +> #79 and #87 stay open. Do not merge #808 without independent APPROVE. Never +> self-approve. + > Exact-head loop overlay: 2026-08-31 11:25 KST. Protected `main` is > `cb187cadee5fb6c46d8a944815ccc154a1e028d1`. Writes work. Do not > self-approve. #865 leftover-map singular values on leftover-map graphic-display diff --git a/frontend/package.json b/frontend/package.json index 1f6fe1636..ca2960c70 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "frontend", "private": true, - "version": "2.82.0", + "version": "2.83.0", "type": "module", "scripts": { "dev": "vite", diff --git a/frontend/src/components/LeftoverMapPlot.tsx b/frontend/src/components/LeftoverMapPlot.tsx index cad1f961d..3fda6999f 100644 --- a/frontend/src/components/LeftoverMapPlot.tsx +++ b/frontend/src/components/LeftoverMapPlot.tsx @@ -20,18 +20,14 @@ import { LEFTOVER_MAP_PLOT_ITEM_COVERAGE_LABEL, } from "../leftoverMapCoverage"; import { - formatLeftoverMapPlotAxisShare, leftoverShareForAxis, LEFTOVER_MAP_COMPARE_PLOT_AXIS_1, LEFTOVER_MAP_COMPARE_PLOT_AXIS_2, - LEFTOVER_MAP_COMPARE_PLOT_AXIS_SHARE, } from "../leftoverMapPlotAxisShare"; import { - formatLeftoverMapPlotAxisSingular, + leftoverMapComparePlotAxisBadge, leftoverMapPlotAxisBadge, leftoverSingularForAxis, - LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR, - LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR_SHARE, } from "../leftoverMapPlotAxisSingular"; import { firstPlottablePairForPost, @@ -89,22 +85,11 @@ function leftoverMapPlotAxisText( const leftoverShare = leftoverShareForAxis(leftoverMapAxes, axisIndex); const leftoverSingular = leftoverSingularForAxis(leftoverMapAxes, axisIndex); if (variant === "comparison") { - const percent = formatLeftoverMapPlotAxisShare(leftoverShare); - const singular = formatLeftoverMapPlotAxisSingular(leftoverSingular); - if (singular === null && percent === null) { + const badge = leftoverMapComparePlotAxisBadge(axisIndex, leftoverSingular, leftoverShare); + if (badge === null) { return t(axisIndex === 1 ? LEFTOVER_MAP_COMPARE_PLOT_AXIS_1 : LEFTOVER_MAP_COMPARE_PLOT_AXIS_2); } - if (singular === null && percent !== null) { - return tf(LEFTOVER_MAP_COMPARE_PLOT_AXIS_SHARE, { axis: axisIndex, share: percent }); - } - if (singular !== null && percent === null) { - return tf(LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR, { axis: axisIndex, value: singular }); - } - return tf(LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR_SHARE, { - axis: axisIndex, - value: singular as string, - share: percent as string, - }); + return tf(badge.key, badge.values); } const badge = leftoverMapPlotAxisBadge(axisIndex, leftoverSingular, leftoverShare); if (badge === null) { @@ -210,6 +195,8 @@ function leftoverMapPlotAxisText( * report badges on the grouping comparison strip with persisted leftover-map * singular values, not this graphic. ADR 0324 captions leftover-map * graphic-display axes with persisted leftover-map singular values. + * ADR 0326 fail-closes leftover-map comparison graphic leftover-map axis leftover-map + * singular values through leftoverMapComparePlotAxisBadge. * Never invent a leftover score. */ export function LeftoverMapPlot({ diff --git a/frontend/src/leftoverMapAxisBadge.ts b/frontend/src/leftoverMapAxisBadge.ts index a6d767964..d33e9ac24 100644 --- a/frontend/src/leftoverMapAxisBadge.ts +++ b/frontend/src/leftoverMapAxisBadge.ts @@ -4,6 +4,8 @@ * ADR 0323 captions leftover-axis report badges on the grouping comparison strip * with a distinct leftover map comparison leftover axis name, not this helper. * ADR 0324 captions leftover-map graphic-display axes, not this helper. + * ADR 0326 captions leftover-map comparison graphic leftover-map axes as + * leftoverMapComparePlotAxisBadge, not this helper. */ import type { LeftoverMapAxis } from "./api"; diff --git a/frontend/src/leftoverMapPlotAxisSingular.test.ts b/frontend/src/leftoverMapPlotAxisSingular.test.ts index 3f4056c52..acd29fb9b 100644 --- a/frontend/src/leftoverMapPlotAxisSingular.test.ts +++ b/frontend/src/leftoverMapPlotAxisSingular.test.ts @@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest"; import { formatLeftoverMapPlotAxisSingular, leftoverMapCompareAxisBadge, + leftoverMapComparePlotAxisBadge, leftoverMapPlotAxisBadge, leftoverSingularForAxis, LEFTOVER_MAP_COMPARE_AXIS_CAPTION, @@ -228,3 +229,78 @@ describe("leftover-map graphic-display axis singular badges", () => { expect(LEFTOVER_MAP_PLOT_AXIS_SINGULAR_SHARE).not.toBe(LEFTOVER_MAP_PLOT_AXIS_SHARE); }); }); + +describe("leftover-map comparison graphic leftover-map axis singular badges", () => { + it("names persisted leftover-map singular values on leftover-map comparison graphic leftover-map axes", () => { + expect(leftoverMapComparePlotAxisBadge(1, 1.84, 0.82)).toEqual({ + key: LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR_SHARE, + values: { axis: 1, value: "1.84", share: "82" }, + }); + expect(leftoverMapComparePlotAxisBadge(2, 0.86, 0.18)).toEqual({ + key: LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR_SHARE, + values: { axis: 2, value: "0.86", share: "18" }, + }); + }); + + it("names rank-0 zero leftover-map singular values on leftover-map comparison graphic leftover-map axes", () => { + expect(leftoverMapComparePlotAxisBadge(1, 0, 0)).toEqual({ + key: LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR_SHARE, + values: { axis: 1, value: "0.00", share: "0" }, + }); + }); + + it("omits leftover-map singular values independently of leftover-map axis share", () => { + expect(leftoverMapComparePlotAxisBadge(1, Number.NaN, 0.82)).toEqual({ + key: LEFTOVER_MAP_COMPARE_PLOT_AXIS_SHARE, + values: { axis: 1, share: "82" }, + }); + expect(leftoverMapComparePlotAxisBadge(2, -0.01, 0.18)).toEqual({ + key: LEFTOVER_MAP_COMPARE_PLOT_AXIS_SHARE, + values: { axis: 2, share: "18" }, + }); + expect(leftoverMapComparePlotAxisBadge(1, 1.84, Number.NaN)).toEqual({ + key: LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR, + values: { axis: 1, value: "1.84" }, + }); + expect(leftoverMapComparePlotAxisBadge(1, null, null)).toBeNull(); + }); + + it("does not invent leftover-map singular values from leftover-map axis share", () => { + expect(leftoverMapComparePlotAxisBadge(1, undefined, 0.82)?.key).toBe( + LEFTOVER_MAP_COMPARE_PLOT_AXIS_SHARE, + ); + expect(leftoverMapComparePlotAxisBadge(1, undefined, 0.82)?.values.value).toBeUndefined(); + }); + + it("does not invent leftover-map axis share from leftover-map singular values", () => { + expect(leftoverMapComparePlotAxisBadge(1, 1.84, undefined)?.key).toBe( + LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR, + ); + expect(leftoverMapComparePlotAxisBadge(1, 1.84, undefined)?.values.share).toBeUndefined(); + }); + + it("stays distinct from leftover-axis, leftover-map graphic, and comparison leftover-axis copy", () => { + expect(leftoverMapComparePlotAxisBadge(1, 1.84, 0.82)?.key).not.toBe( + leftoverMapPlotAxisBadge(1, 1.84, 0.82)?.key, + ); + expect(leftoverMapComparePlotAxisBadge(1, 1.84, 0.82)?.key).not.toBe( + leftoverMapCompareAxisBadge(1, 1.84, 0.82)?.key, + ); + expect(leftoverMapComparePlotAxisBadge(1, 1.84, null)?.key).not.toBe( + leftoverMapPlotAxisBadge(1, 1.84, null)?.key, + ); + expect(leftoverMapComparePlotAxisBadge(1, 1.84, null)?.key).not.toBe( + leftoverMapCompareAxisBadge(1, 1.84, null)?.key, + ); + expect(leftoverMapComparePlotAxisBadge(1, 1.84, null)?.key).not.toBe( + LEFTOVER_MAP_AXIS_BADGE_SINGULAR_ONLY, + ); + expect(leftoverMapComparePlotAxisBadge(1, 1.84, 0.82)?.key).not.toBe( + LEFTOVER_MAP_AXIS_BADGE_SINGULAR, + ); + expect(leftoverMapComparePlotAxisBadge(1, 1.84, null)?.key).not.toBe(LEFTOVER_MAP_COMPARE_PLOT_TICK); + expect(leftoverMapComparePlotAxisBadge(1, 1.84, 0.82)?.key).toBe( + LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR_SHARE, + ); + }); +}); diff --git a/frontend/src/leftoverMapPlotAxisSingular.ts b/frontend/src/leftoverMapPlotAxisSingular.ts index 8d0ab36d9..4e8b8def5 100644 --- a/frontend/src/leftoverMapPlotAxisSingular.ts +++ b/frontend/src/leftoverMapPlotAxisSingular.ts @@ -1,8 +1,16 @@ -/** Caption leftover-map plot axes with persisted Gabriel singular values (ADR 0324). */ +/** Caption leftover-map plot axes with persisted Gabriel singular values. + * ADR 0324 names leftover-map graphic-display leftover-map axis leftover-map + * singular values as leftoverMapPlotAxisBadge. + * ADR 0326 names leftover-map comparison graphic leftover-map axis leftover-map + * singular values as leftoverMapComparePlotAxisBadge. + * ADR 0323 captions leftover-axis report badges on the grouping comparison strip + * as leftoverMapCompareAxisBadge, not leftoverMapComparePlotAxisBadge. + */ import type { LeftoverMapAxis } from "./api"; import { formatLeftoverMapPlotAxisShare, + LEFTOVER_MAP_COMPARE_PLOT_AXIS_SHARE, LEFTOVER_MAP_PLOT_AXIS_SHARE, } from "./leftoverMapPlotAxisShare"; @@ -109,3 +117,28 @@ export function leftoverMapCompareAxisBadge( values: { axis: axisIndex, value: singular as string, share: percent as string }, }; } + +export function leftoverMapComparePlotAxisBadge( + axisIndex: number, + leftoverSingular: number | null | undefined, + leftoverShare: number | null | undefined, +): LeftoverMapCompareAxisBadge | null { + const singular = formatLeftoverMapPlotAxisSingular(leftoverSingular); + const percent = formatLeftoverMapPlotAxisShare(leftoverShare); + if (singular === null && percent === null) { + return null; + } + if (singular === null && percent !== null) { + return { key: LEFTOVER_MAP_COMPARE_PLOT_AXIS_SHARE, values: { axis: axisIndex, share: percent } }; + } + if (singular !== null && percent === null) { + return { + key: LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR, + values: { axis: axisIndex, value: singular }, + }; + } + return { + key: LEFTOVER_MAP_COMPARE_PLOT_AXIS_SINGULAR_SHARE, + values: { axis: axisIndex, value: singular as string, share: percent as string }, + }; +} diff --git a/frontend/src/leftoverMapPlotLayout.ts b/frontend/src/leftoverMapPlotLayout.ts index df6cb0caa..845f07c6c 100644 --- a/frontend/src/leftoverMapPlotLayout.ts +++ b/frontend/src/leftoverMapPlotLayout.ts @@ -89,6 +89,8 @@ * with persisted leftover-map singular values, not this graphic. * ADR 0324 captions leftover-map graphic-display axes with persisted leftover-map * singular values `σ_k`. + * ADR 0326 fail-closes leftover-map comparison graphic leftover-map axis leftover-map + * singular values through leftoverMapComparePlotAxisBadge. */ import { formatLeftoverMapCoordinatePair } from "./leftoverMapCoordinates"; diff --git a/pyproject.toml b/pyproject.toml index ab9a1f9af..88797a9cd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "lineageweave" -version = "2.82.0" +version = "2.83.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" }