diff --git a/AGENTS.md b/AGENTS.md index 533d78922..cea602044 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -746,6 +746,15 @@ Share and singular value omit independently. Rank-0 unused axes still name lefto leftover-axis tick leftover-map axis share `0%`. Do not invent leftover-map axis share from leftover-map singular values. Do not invent leftover-map singular values from leftover-map axis share. +ADR 0335 captions leftover-map graphic leftover-map criterion markers with persisted leftover-map +item coordinates when leftoverMapPlotCriterionBadge returns a usable leftover-map criterion leftover-map +item coordinate caption. Distinct accessible name +`leftover-map criterion {label} at ζ {item}`. +A missing or non-finite leftover-map item coordinate pair omits that leftover-map criterion leftover-map +item coordinate caption and keeps `Criterion ζ {label}`. Rank-0 unused axes still name leftover-map +item coordinates `(0.00, 0.00)`. Do not invent leftover-map item coordinates from leftover-map post +`ξ`. Do not invent leftover-map post `ξ` from leftover-map item coordinates. Leftover-map comparison graphic leftover-map +criterion markers never name leftover-map item coordinates this increment. 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 @@ -887,6 +896,10 @@ Leftover-axis tick leftover-map axis share independently of leftover-map singula (ADR 0334) captions leftover-axis ticks with persisted leftover-map axis share when leftoverMapAxisTickBadge returns a usable leftover-axis tick leftover-map axis share caption. +Leftover-map graphic leftover-map criterion leftover-map item coordinates independently of leftover-map post ξ markers +(ADR 0335) captions leftover-map graphic leftover-map criterion markers with persisted leftover-map +item coordinates when leftoverMapPlotCriterionBadge returns a usable leftover-map criterion leftover-map +item coordinate 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 4a47ed48a..40ac65f0a 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -785,6 +785,9 @@ axis share caption independently of leftover-map singular values. ADR 0334 captions leftover-axis ticks with persisted leftover-map axis share when leftoverMapAxisTickBadge returns a usable leftover-axis tick leftover-map axis share caption independently of leftover-map singular values. +ADR 0335 captions leftover-map graphic leftover-map criterion markers with persisted leftover-map +item coordinates when leftoverMapPlotCriterionBadge returns a usable leftover-map criterion leftover-map +item coordinate caption independently of leftover-map post ξ markers. 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 @@ -849,7 +852,8 @@ comparison graphic leftover-map axis leftover-map singular values as leftoverMap (ADR 0331), leftover-map graphic leftover-map axis tick leftover-map axis share independently of leftover-map singular values (ADR 0332), leftover-map comparison leftover-axis tick leftover-map axis share independently of leftover-map singular values (ADR 0333), leftover-axis tick leftover-map axis share independently of leftover-map singular values -(ADR 0334); +(ADR 0334), leftover-map graphic leftover-map criterion leftover-map item coordinates independently of leftover-map post ξ markers +(ADR 0335); `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.92.0-leftover-map-plot-criterion-coordinates.md b/CHANGELOG.d/2.92.0-leftover-map-plot-criterion-coordinates.md new file mode 100644 index 000000000..c839a3f3b --- /dev/null +++ b/CHANGELOG.d/2.92.0-leftover-map-plot-criterion-coordinates.md @@ -0,0 +1,22 @@ +## 2.92.0 — Leftover-map item coordinates on leftover-map graphic leftover-map criterion markers independently of leftover-map post ξ markers + +- Caption leftover-map graphic leftover-map criterion markers with persisted leftover-map + item coordinates through leftoverMapPlotCriterionBadge independently of leftover-map + post ξ markers (ADR 0335). After `make seed`, leftover-map graphic leftover-map + criterion markers name persisted leftover-map item coordinates when leftoverMapPlotCriterionBadge + returns a usable leftover-map criterion leftover-map item coordinate caption; click a leftover pair + or a leftover-map post marker opens that post. A missing or + non-finite leftover-map item coordinate pair omits that leftover-map criterion leftover-map + item coordinate caption and keeps `Criterion ζ {label}`. Rank-0 unused + axes still name leftover-map item coordinates `(0.00, 0.00)`. Leftover-map graphic leftover-map + criterion markers stay + `leftover-map criterion {label} at ζ {item}` + when leftover-map item coordinates are finite so they stay distinct from leftover-map post markers + `Open leftover-map post {title} at ξ {person}` and from leftover-map comparison graphic leftover-map + criterion markers `Criterion ζ {label}`. Do not invent leftover-map + item coordinates from leftover-map post `ξ`. Do not invent leftover-map post `ξ` from leftover-map + item coordinates. This increment does not change leftover-map comparison graphic leftover-map + criterion markers, leftover-axis ticks, leftover-map graphic leftover-map axis ticks, + leftover-map comparison leftover-axis ticks, or leftover-map comparison graphic leftover-map axis ticks. + 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 51ea0cf1f..9cc7fe51b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,27 @@ All notable changes to this project are documented here. Format follows ### Added +- Period leftover pairs now caption leftover-map graphic leftover-map + criterion markers with persisted leftover-map item coordinates through leftoverMapPlotCriterionBadge + independently of leftover-map post ξ markers (ADR 0335 / v2.92.0). After `make seed`, + leftover-map graphic leftover-map criterion markers name persisted leftover-map + item coordinates when leftoverMapPlotCriterionBadge returns a usable leftover-map criterion + leftover-map item coordinate caption; click a leftover pair or a leftover-map post marker + opens that post. A missing or non-finite leftover-map item coordinate pair omits that leftover-map + criterion leftover-map item coordinate caption and keeps + `Criterion ζ {label}`. + Rank-0 unused axes still name leftover-map item coordinates `(0.00, 0.00)`. Leftover-map graphic leftover-map + criterion markers stay + `leftover-map criterion {label} at ζ {item}` + when leftover-map item coordinates are finite so they stay distinct from leftover-map post markers + `Open leftover-map post {title} at ξ {person}` and from leftover-map comparison graphic leftover-map + criterion markers `Criterion ζ {label}`. Do not invent leftover-map + item coordinates from leftover-map post `ξ`. Do not invent leftover-map post `ξ` from leftover-map + item coordinates. This increment does not change leftover-map comparison graphic leftover-map + criterion markers, leftover-axis ticks, leftover-map graphic leftover-map axis ticks, + leftover-map comparison leftover-axis ticks, or leftover-map comparison graphic leftover-map axis ticks. 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 ticks with persisted leftover-map axis share through leftoverMapAxisTickBadge independently of leftover-map singular values (ADR 0334 / v2.91.0). After `make seed`, diff --git a/CLAUDE.md b/CLAUDE.md index d724a8e92..399d7ef1f 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 / 0326 / 0327 / 0328 / 0329 / 0330 / 0331 / 0332 / 0333 / 0334), 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 / 0327 / 0328 / 0329 / 0330 / 0331 / 0332 / 0333 / 0334 / 0335), 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/0267-leftover-map-coordinates.md b/docs/adr/0267-leftover-map-coordinates.md index 60e64ae66..8fd8ade16 100644 --- a/docs/adr/0267-leftover-map-coordinates.md +++ b/docs/adr/0267-leftover-map-coordinates.md @@ -6,7 +6,9 @@ **Amended by:** [ADR 0268](0268-leftover-map-graphic-display.md) (leftover-map graphic display); [ADR 0270](0270-leftover-map-coordinate-ticks.md) -(leftover-map coordinate ticks) +(leftover-map coordinate ticks); +[ADR 0335](0335-leftover-map-plot-criterion-coordinates.md) +(leftover-map item coordinates on leftover-map graphic leftover-map criterion markers) Amends [ADR 0048](0048-persist-lsirm-leftover-pairs.md), [ADR 0049](0049-leftover-pair-report-ui.md), and diff --git a/docs/adr/0268-leftover-map-graphic-display.md b/docs/adr/0268-leftover-map-graphic-display.md index f61bf8c40..373a44d29 100644 --- a/docs/adr/0268-leftover-map-graphic-display.md +++ b/docs/adr/0268-leftover-map-graphic-display.md @@ -28,7 +28,9 @@ [ADR 0280](0280-leftover-map-segment-rank.md) (leftover-map rank on pair segments); [ADR 0304](0304-leftover-map-compare-graphic.md) -(leftover-map graphic display on the grouping comparison strip) +(leftover-map graphic display on the grouping comparison strip); +[ADR 0335](0335-leftover-map-plot-criterion-coordinates.md) +(leftover-map item coordinates on leftover-map graphic leftover-map criterion markers) Amends [ADR 0049](0049-leftover-pair-report-ui.md) and [ADR 0267](0267-leftover-map-coordinates.md). Independent of leftover-map diff --git a/docs/adr/0334-leftover-map-axis-tick-share-badge.md b/docs/adr/0334-leftover-map-axis-tick-share-badge.md index 3ac6326ff..b69431754 100644 --- a/docs/adr/0334-leftover-map-axis-tick-share-badge.md +++ b/docs/adr/0334-leftover-map-axis-tick-share-badge.md @@ -117,7 +117,9 @@ tick leftover-map singular values independently of leftover-map axis share ([ADR 0330](0330-leftover-map-axis-tick-badge.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 -axis share persistence ([ADR 0148](0148-leftover-map-axis-share.md)). +axis share persistence ([ADR 0148](0148-leftover-map-axis-share.md)). Independent of leftover-map +graphic leftover-map criterion leftover-map item coordinates independently of leftover-map post ξ markers +([ADR 0335](0335-leftover-map-plot-criterion-coordinates.md)). ## References diff --git a/docs/adr/0335-leftover-map-plot-criterion-coordinates.md b/docs/adr/0335-leftover-map-plot-criterion-coordinates.md new file mode 100644 index 000000000..547d6b5c8 --- /dev/null +++ b/docs/adr/0335-leftover-map-plot-criterion-coordinates.md @@ -0,0 +1,119 @@ +# ADR 0335 — Name leftover-map item coordinates on leftover-map graphic leftover-map criterion markers independently of leftover-map post ξ markers + +**Decision status:** Accepted +**Date:** 2026-08-31 + +Amends leftover-map graphic display of persisted coordinates +([ADR 0268](0268-leftover-map-graphic-display.md)), leftover-map +coordinates ([ADR 0267](0267-leftover-map-coordinates.md)). Independent of leftover-axis +tick leftover-map axis share independently of leftover-map singular values +([ADR 0334](0334-leftover-map-axis-tick-share-badge.md)). Independent of leftover-map +comparison leftover-axis tick leftover-map axis share independently of leftover-map +singular values ([ADR 0333](0333-leftover-map-compare-axis-tick-share-badge.md)). Independent of leftover-map +graphic leftover-map axis tick leftover-map axis share independently of leftover-map +singular values ([ADR 0332](0332-leftover-map-plot-tick-share-badge.md)). Independent of leftover-map +comparison graphic leftover-map axis tick leftover-map axis share independently of leftover-map +singular values ([ADR 0331](0331-leftover-map-compare-plot-tick-share-badge.md)). + +## Context + +ADR 0267 already persists two-axis Gabriel person coordinates +`ξ_{1:2}` and item coordinates `ζ_{1:2}` on leftover pair rows so +`R̂ = ξ_{1:2} · ζ_{1:2}` and `d = ‖ξ_{1:2} − ζ_{1:2}‖` stay +auditable. ADR 0268 already draws leftover-map graphic leftover-map +post markers at persisted `ξ` and leftover-map graphic leftover-map +criterion markers at persisted `ζ`. Post markers already name +`Open leftover-map post {title} at ξ {person}`. Those leftover-map +graphic leftover-map criterion markers still read only +`Criterion ζ {label}`, so a buyer who reads leftover-map graphic leftover-map +criterion markers can treat leftover-map location as leftover-map post +`ξ` without a next action on leftover-map item coordinates. A missing or +non-finite leftover-map item coordinate pair is not a leftover score and +must omit independently of leftover-map post `ξ` markers. Rank-0 unused +axes still persist leftover-map item coordinates `(0.00, 0.00)`. A finite +negative leftover is shown, never clamped. Do not invent leftover-map +item coordinates from leftover-map post `ξ`. Do not invent leftover-map +post `ξ` from leftover-map item coordinates. Leftover-map comparison graphic leftover-map +criterion markers stay `Criterion ζ {label}` this increment. + +This increment names leftover-map graphic leftover-map criterion markers leftover-map +item coordinates as leftoverMapPlotCriterionBadge, matching leftover-map +graphic leftover-map post `ξ` markers. Leftover-map graphic leftover-map +criterion markers stay +`leftover-map criterion {label} at ζ {item}` +when leftover-map item coordinates are finite, so they stay distinct from leftover-map +post markers `Open leftover-map post {title} at ξ {person}` and from leftover-map +comparison graphic leftover-map criterion markers `Criterion ζ {label}`. +It does not add columns. Do not invent a leftover score. Do not invent a theta. + +This protected increment uses **0335** so it does not collide with leftover-axis +tick leftover-map axis share independently of leftover-map singular values +(0334), leftover-map comparison leftover-axis tick leftover-map axis share independently of leftover-map singular values +(0333), leftover-map graphic leftover-map axis tick leftover-map axis share independently of leftover-map singular values +(0332), leftover-map comparison graphic leftover-map axis tick leftover-map axis share independently of leftover-map singular values +(0331), leftover-map graphic display (0268), leftover-map coordinates (0267), +or the dashboard stacks. + +## Decision + +On leftover-map graphic leftover-map criterion markers, caption leftover-map +item coordinates `ζ_{1:2}` when leftoverMapPlotCriterionBadge +returns a usable leftover-map criterion leftover-map item coordinate caption. +A missing or non-finite leftover-map item coordinate pair omits that leftover-map +criterion leftover-map item coordinate caption and keeps +`Criterion ζ {label}`. Rank-0 unused axes still name leftover-map +item coordinates `(0.00, 0.00)`. Click a leftover pair or a leftover-map +post marker to open that post. Criterion markers are not post buttons. + +Leftover-map graphic leftover-map criterion leftover-map item coordinates omit +independently of leftover-map post `ξ` markers. This increment does not +change leftover-map comparison graphic leftover-map criterion markers, +leftover-axis ticks, leftover-map graphic leftover-map axis ticks, leftover-map +comparison leftover-axis ticks, or leftover-map comparison graphic leftover-map +axis ticks. 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`, leftover-map graphic leftover-map criterion markers name persisted +leftover-map item coordinates when leftoverMapPlotCriterionBadge returns a usable +leftover-map criterion leftover-map item coordinate caption; click a leftover pair +or a leftover-map post marker opens that post. Hidden posts stay hidden. Rank-0 unused +axes still name leftover-map graphic leftover-map criterion leftover-map item coordinates +`(0.00, 0.00)`. Leftover-map comparison graphic leftover-map criterion markers stay +`Criterion ζ {label}`. Leftover-axis tick leftover-map axis share independently of leftover-map +singular values (ADR 0334), leftover-map comparison leftover-axis tick leftover-map axis share independently of leftover-map +singular values (ADR 0333), leftover-map graphic leftover-map axis tick leftover-map axis share independently of leftover-map +singular values (ADR 0332), leftover-map comparison graphic leftover-map axis tick leftover-map axis share independently of leftover-map +singular values (ADR 0331), leftover-map graphic display (ADR 0268), and leftover-map +coordinates (ADR 0267) remain. + +## Related + +Independent of leftover-axis tick leftover-map axis share independently of leftover-map +singular values +([ADR 0334](0334-leftover-map-axis-tick-share-badge.md)). Independent of leftover-map +comparison leftover-axis tick leftover-map axis share independently of leftover-map +singular values +([ADR 0333](0333-leftover-map-compare-axis-tick-share-badge.md)). Independent of leftover-map +graphic leftover-map axis tick leftover-map axis share independently of leftover-map singular values +([ADR 0332](0332-leftover-map-plot-tick-share-badge.md)). Independent of leftover-map +comparison graphic leftover-map axis tick leftover-map axis share independently of leftover-map singular values +([ADR 0331](0331-leftover-map-compare-plot-tick-share-badge.md)). Independent of leftover-map +graphic display ([ADR 0268](0268-leftover-map-graphic-display.md)). Independent of leftover-map +coordinates ([ADR 0267](0267-leftover-map-coordinates.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 ae69b9f92..c0d9f509d 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,5 +1,25 @@ # Product & Technical Gap Baseline +> Exact-head loop overlay: 2026-08-31 16:00 KST. Protected `main` is +> `cb187cadee5fb6c46d8a944815ccc154a1e028d1`. Writes work. Do not +> self-approve. #875 leftover-map axis share on leftover-axis ticks independently of leftover-map +> singular values (v2.91.0 / ADR 0334) is +> `d19f1fd`, stacked on #874 @ `ba58c21`. Independent APPROVE is missing (Devin COMMENTED, +> not APPROVE; trailing blank line resolved). Next buyer increment on this cycle: leftover-map graphic leftover-map +> criterion markers naming persisted leftover-map item coordinates independently of leftover-map +> post ξ markers (ADR 0335 / v2.92.0) delivered locally on +> `feat/leftover-map-plot-criterion-coordinates-v2920`. Caption persisted leftover-map +> item coordinates on leftover-map graphic leftover-map criterion markers when leftoverMapPlotCriterionBadge +> returns a usable leftover-map criterion leftover-map item coordinate caption. Distinct accessible name +> `leftover-map criterion {label} at ζ {item}`. +> Rank-0 unused axes still name leftover-map item coordinates `(0.00, 0.00)`. A missing or +> non-finite leftover-map item coordinate pair omits independently of leftover-map post `ξ`. +> Leftover-map comparison graphic leftover-map criterion markers never name leftover-map item coordinates this +> increment. Do not invent leftover-map item coordinates from leftover-map post `ξ`. Do not invent leftover-map +> post `ξ` from leftover-map item coordinates. Do not persist leftover-map inner product, cosine, or length. Stack onto #875. +> 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 15:40 KST. Protected `main` is > `cb187cadee5fb6c46d8a944815ccc154a1e028d1`. Writes work. Do not > self-approve. #874 leftover-map axis share on leftover-map comparison leftover-axis diff --git a/docs/storybook-inventory.md b/docs/storybook-inventory.md index 7b486636a..2af4d32b4 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, pair-segment `2R̂U/R²` to leftover-map cross share, pair-segment `U` to leftover-map unexplained leftover, pair-segment `R` to leftover residual, pair-segment `Y` to leftover observed, pair-segment `E` to leftover expected, and pair-segment leftover-map rank, then click a post marker to open that post. Leftover-map axes name persisted leftover-map singular values `σ_k` and leftover-map axis share when finite. The plot names leftover-map complete-case coverage, leftover-map item complete-case coverage, leftover-map incomplete post coverage, and leftover-map incomplete item coverage when persisted. The comparison variant names leftover-map complete-case coverage under `Leftover map comparison graphic coverage` and leftover-map item complete-case coverage under `Leftover map comparison graphic item coverage` and leftover-map incomplete post coverage under `Leftover map comparison graphic incomplete posts` and leftover-map incomplete item coverage under `Leftover map comparison graphic incomplete items`. `ClosestAndFarthest`, `RankZeroOrigin`, `MissingCoordinates`, `MissingAxisShare`, `Comparison`, `ComparisonMissingCoverage`, `ComparisonMissingItemCoverage`, `ComparisonMissingIncompletePosts`, and `ComparisonMissingIncompleteItems` cover two-pair maps, rank-0 origin with 0% share, a `0` tick, `d 0.00`, `R̂ 0.00`, `R̂²/R² 0.00`, `U²/R² 0.00`, `2R̂U/R² 0.00`, `U 0.00`, `R 0.00`, `Y 0.00`, `E 0.00`, and `rank 0`, omitted plots, missing share that keeps leftover-map axis `σ` without share, grouping comparison leftover-map graphic coverage that matches leftover map used N of M scored posts, omitted comparison graphic coverage when leftoverMapCoverageCounts fail-closes, grouping comparison leftover-map graphic item coverage that matches leftover map used N of M scored criteria, omitted comparison graphic item coverage when leftoverMapItemCoverageCounts fail-closes, grouping comparison leftover-map graphic incomplete posts that matches leftover map dropped N incomplete posts, omitted comparison graphic incomplete posts when leftoverMapIncompletePostCount fail-closes, grouping comparison leftover-map graphic incomplete items that matches leftover map dropped N incomplete criteria, and omitted comparison graphic incomplete items when leftoverMapIncompleteItemCount fail-closes. The plot does not invent a leftover score. | `LeftoverMapPlot`, `leftoverMapPlotLayout`, `leftoverMapPlotAxisShare`, `--color-primary`, `--color-palette-blue-mid` | -| `Reports/LeftoverPairList` | Read closest/farthest leftover pairs with named `R`, `Y`/`E`, rank, `U`, `s`, `e`, `x`, `R̂`, `ξ`/`ζ`, and `d`, then open that post. The leftover-map graphic display sits above the pair buttons when coordinates are finite, leftover-map axes name persisted leftover-map singular values and leftover-map axis share, leftover-map axis ticks name persisted coordinates, leftover-axis ticks name persisted leftover-map singular values and leftover-map axis share independently under `leftover axis {axis} tick {value} σ {singular} {share}%`, pair segments name persisted leftover-map distance, pair segments name persisted leftover-map reconstruction, pair segments name persisted leftover-map explained leftover share, pair segments name persisted leftover-map unexplained leftover share, pair segments name persisted leftover-map cross share, pair segments name persisted leftover-map unexplained leftover, pair segments name persisted leftover residual, pair segments name persisted leftover observed, pair segments name persisted leftover expected, and pair segments name persisted leftover-map rank. The pair-list note names leftover-map complete-case coverage only when leftoverMapCoverageCounts returns usable complete-case integers, leftover-map item complete-case coverage, leftover-map incomplete post coverage, and leftover-map incomplete item coverage when persisted. The grouping comparison strip names leftover-map complete-case coverage, leftover-map item complete-case coverage, leftover-map incomplete post coverage, leftover-map incomplete item coverage, leftover-axis report badges with persisted leftover-map singular values under `leftover map comparison leftover axis {axis} σ {value}`, and leftover-axis ticks with persisted leftover-map singular values and leftover-map axis share under `leftover map comparison leftover axis {axis} tick {value} σ {singular} {share}%` independently of leftover-map singular values with distinct comparison labels when leftoverMapCoverageCounts / leftoverMapItemCoverageCounts / leftoverMapIncompletePostCount / leftoverMapIncompleteItemCount / leftoverMapCompareAxisBadge / leftoverMapCompareAxisTickBadge return usable values. | `LeftoverPairList`, `LeftoverMapPlot`, `ticket-list`, `post-badge` | +| `Reports/LeftoverMapPlot` | Read the leftover-map graphic display of persisted `ξ` (posts) and `ζ` (criteria), match leftover-map graphic leftover-map criterion markers to `leftover-map criterion {label} at ζ {item}`, match axis ticks to those coordinates, pair-segment `d` to leftover-map distance, pair-segment `R̂` to leftover-map reconstruction, pair-segment `R̂²/R²` to leftover-map explained leftover share, pair-segment `U²/R²` to leftover-map unexplained leftover share, pair-segment `2R̂U/R²` to leftover-map cross share, pair-segment `U` to leftover-map unexplained leftover, pair-segment `R` to leftover residual, pair-segment `Y` to leftover observed, pair-segment `E` to leftover expected, and pair-segment leftover-map rank, then click a post marker to open that post. Leftover-map axes name persisted leftover-map singular values `σ_k` and leftover-map axis share when finite. The plot names leftover-map complete-case coverage, leftover-map item complete-case coverage, leftover-map incomplete post coverage, and leftover-map incomplete item coverage when persisted. The comparison variant names leftover-map complete-case coverage under `Leftover map comparison graphic coverage` and leftover-map item complete-case coverage under `Leftover map comparison graphic item coverage` and leftover-map incomplete post coverage under `Leftover map comparison graphic incomplete posts` and leftover-map incomplete item coverage under `Leftover map comparison graphic incomplete items` and leftover-map comparison graphic leftover-map criterion markers under `Criterion ζ {label}`. `ClosestAndFarthest`, `RankZeroOrigin`, `MissingCoordinates`, `MissingAxisShare`, `Comparison`, `ComparisonMissingCoverage`, `ComparisonMissingItemCoverage`, `ComparisonMissingIncompletePosts`, and `ComparisonMissingIncompleteItems` cover two-pair maps, rank-0 origin with 0% share, a `0` tick, `d 0.00`, `R̂ 0.00`, `R̂²/R² 0.00`, `U²/R² 0.00`, `2R̂U/R² 0.00`, `U 0.00`, `R 0.00`, `Y 0.00`, `E 0.00`, and `rank 0`, omitted plots, missing share that keeps leftover-map axis `σ` without share, grouping comparison leftover-map graphic coverage that matches leftover map used N of M scored posts, omitted comparison graphic coverage when leftoverMapCoverageCounts fail-closes, grouping comparison leftover-map graphic item coverage that matches leftover map used N of M scored criteria, omitted comparison graphic item coverage when leftoverMapItemCoverageCounts fail-closes, grouping comparison leftover-map graphic incomplete posts that matches leftover map dropped N incomplete posts, omitted comparison graphic incomplete posts when leftoverMapIncompletePostCount fail-closes, grouping comparison leftover-map graphic incomplete items that matches leftover map dropped N incomplete criteria, and omitted comparison graphic incomplete items when leftoverMapIncompleteItemCount fail-closes. The plot does not invent a leftover score. | `LeftoverMapPlot`, `leftoverMapPlotLayout`, `leftoverMapPlotAxisShare`, `--color-primary`, `--color-palette-blue-mid` | +| `Reports/LeftoverPairList` | Read closest/farthest leftover pairs with named `R`, `Y`/`E`, rank, `U`, `s`, `e`, `x`, `R̂`, `ξ`/`ζ`, and `d`, then open that post. The leftover-map graphic display sits above the pair buttons when coordinates are finite, leftover-map axes name persisted leftover-map singular values and leftover-map axis share, leftover-map axis ticks name persisted coordinates, leftover-map graphic leftover-map criterion markers name persisted leftover-map item coordinates under `leftover-map criterion {label} at ζ {item}`, leftover-axis ticks name persisted leftover-map singular values and leftover-map axis share independently under `leftover axis {axis} tick {value} σ {singular} {share}%`, pair segments name persisted leftover-map distance, pair segments name persisted leftover-map reconstruction, pair segments name persisted leftover-map explained leftover share, pair segments name persisted leftover-map unexplained leftover share, pair segments name persisted leftover-map cross share, pair segments name persisted leftover-map unexplained leftover, pair segments name persisted leftover residual, pair segments name persisted leftover observed, pair segments name persisted leftover expected, and pair segments name persisted leftover-map rank. The pair-list note names leftover-map complete-case coverage only when leftoverMapCoverageCounts returns usable complete-case integers, leftover-map item complete-case coverage, leftover-map incomplete post coverage, and leftover-map incomplete item coverage when persisted. The grouping comparison strip names leftover-map complete-case coverage, leftover-map item complete-case coverage, leftover-map incomplete post coverage, leftover-map incomplete item coverage, leftover-axis report badges with persisted leftover-map singular values under `leftover map comparison leftover axis {axis} σ {value}`, leftover-axis ticks with persisted leftover-map singular values and leftover-map axis share under `leftover map comparison leftover axis {axis} tick {value} σ {singular} {share}%` independently of leftover-map singular values, and leftover-map comparison graphic leftover-map criterion markers under `Criterion ζ {label}` with distinct comparison labels when leftoverMapCoverageCounts / leftoverMapItemCoverageCounts / leftoverMapIncompletePostCount / leftoverMapIncompleteItemCount / leftoverMapCompareAxisBadge / leftoverMapCompareAxisTickBadge return usable values. | `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 d49feffeb..59bdbe0f1 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "frontend", "private": true, - "version": "2.91.0", + "version": "2.92.0", "type": "module", "scripts": { "dev": "vite", diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx index 9899209aa..04e76ed01 100644 --- a/frontend/src/App.test.tsx +++ b/frontend/src/App.test.tsx @@ -4211,6 +4211,15 @@ describe("App, authenticated", () => { expect(await screen.findByLabelText("Leftover pairs")).toBeInTheDocument(); expect(screen.getByLabelText("Leftover-map graphic display")).toBeInTheDocument(); expect(screen.getByLabelText("Leftover map comparison graphic")).toBeInTheDocument(); + expect(screen.getByLabelText("leftover-map criterion sales-lead at ζ (+0.50, −0.02)")).toBeInTheDocument(); + expect( + within(screen.getByLabelText("Grouping comparison")).getByLabelText("Criterion ζ sales-lead"), + ).toBeInTheDocument(); + expect( + within(screen.getByLabelText("Grouping comparison")).queryByLabelText( + "leftover-map criterion sales-lead at ζ (+0.50, −0.02)", + ), + ).not.toBeInTheDocument(); expect(screen.getByText("leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument(); expect(screen.getByText("leftover-map axis 2 σ 0.86 (18%)")).toBeInTheDocument(); expect(screen.getByLabelText("leftover-map axis 1 tick +0.50 σ 1.84 82%")).toBeInTheDocument(); diff --git a/frontend/src/components/LeftoverMapPlot.test.tsx b/frontend/src/components/LeftoverMapPlot.test.tsx index f1479f382..9eb4d1704 100644 --- a/frontend/src/components/LeftoverMapPlot.test.tsx +++ b/frontend/src/components/LeftoverMapPlot.test.tsx @@ -66,6 +66,9 @@ describe("LeftoverMapPlot", () => { ).toBeInTheDocument(); expect(screen.getByText("Post ξ")).toBeInTheDocument(); expect(screen.getByText("Criterion ζ")).toBeInTheDocument(); + expect(screen.getByLabelText("leftover-map criterion sales-lead at ζ (+0.50, −0.02)")).toBeInTheDocument(); + expect(screen.getByLabelText("leftover-map criterion negative at ζ (−0.70, −0.40)")).toBeInTheDocument(); + expect(screen.queryByLabelText("Criterion ζ sales-lead")).not.toBeInTheDocument(); expect(screen.getByText("leftover-map axis 1")).toBeInTheDocument(); expect(screen.getByText("leftover-map axis 2")).toBeInTheDocument(); expect(screen.getByLabelText("leftover-map axis 1 tick +0.50")).toBeInTheDocument(); @@ -164,6 +167,8 @@ describe("LeftoverMapPlot", () => { expect( screen.getByRole("button", { name: "Open leftover-map post Public post at ξ (0.00, 0.00)" }), ).toBeInTheDocument(); + expect(screen.getByLabelText("leftover-map criterion sales-lead at ζ (0.00, 0.00)")).toBeInTheDocument(); + expect(screen.queryByLabelText("Criterion ζ sales-lead")).not.toBeInTheDocument(); expect(screen.getByText("leftover-map axis 1 σ 0.00 (0%)")).toBeInTheDocument(); expect(screen.getByText("leftover-map axis 2 σ 0.00 (0%)")).toBeInTheDocument(); expect(screen.getAllByLabelText("leftover-map axis 1 tick 0.00 σ 0.00 0%").length).toBeGreaterThan(0); @@ -921,6 +926,14 @@ describe("LeftoverMapPlot", () => { ).toBeInTheDocument(); expect(screen.getByText("leftover map comparison graphic leftover-map axis 1 σ 1.84 (82%)")).toBeInTheDocument(); expect(screen.getByText("leftover map comparison graphic leftover-map axis 2 σ 0.86 (18%)")).toBeInTheDocument(); + expect(screen.getByLabelText("Criterion ζ sales-lead")).toBeInTheDocument(); + expect(screen.getByLabelText("Criterion ζ negative")).toBeInTheDocument(); + expect( + screen.queryByLabelText("leftover-map criterion sales-lead at ζ (+0.50, −0.02)"), + ).not.toBeInTheDocument(); + expect( + screen.queryByLabelText("leftover-map criterion negative at ζ (−0.70, −0.40)"), + ).not.toBeInTheDocument(); expect(screen.queryByText("leftover-map axis 1 σ 1.84 (82%)")).not.toBeInTheDocument(); expect(screen.queryByText("leftover-map axis 2 σ 0.86 (18%)")).not.toBeInTheDocument(); expect(screen.queryByText("leftover-map axis 1 (82%)")).not.toBeInTheDocument(); diff --git a/frontend/src/components/LeftoverMapPlot.tsx b/frontend/src/components/LeftoverMapPlot.tsx index b00235cae..04cffa5fc 100644 --- a/frontend/src/components/LeftoverMapPlot.tsx +++ b/frontend/src/components/LeftoverMapPlot.tsx @@ -34,6 +34,7 @@ import { import { firstPlottablePairForPost, layoutLeftoverMapPlot, + leftoverMapPlotCriterionBadge, LEFTOVER_MAP_COMPARE_PLOT_CAPTION, LEFTOVER_MAP_COMPARE_PLOT_LABEL, LEFTOVER_MAP_COMPARE_PLOT_SVG, @@ -119,11 +120,29 @@ function leftoverMapPlotTickText( return tf(badge.key, badge.values); } +function leftoverMapPlotCriterionText( + marker: { label: string; axis1: number; axis2: number }, + variant: LeftoverMapPlotVariant, +): string { + if (variant === "comparison") { + return `${t("Criterion ζ")} ${marker.label}`; + } + const badge = leftoverMapPlotCriterionBadge(marker.label, marker.axis1, marker.axis2); + if (badge === null) { + return `${t("Criterion ζ")} ${marker.label}`; + } + return tf(badge.key, badge.values); +} + /** * Gabriel leftover-map graphic display of persisted ``ξ_{1:2}`` / ``ζ_{1:2}``. * * Person markers are posts; item markers are leftover criteria. Click a - * post marker to open that post. Caption leftover-map axes with persisted + * post marker to open that post. Caption leftover-map graphic leftover-map + * criterion markers with persisted leftover-map item coordinates ``ζ_{1:2}`` + * when leftoverMapPlotCriterionBadge returns a usable leftover-map criterion + * leftover-map item coordinate caption. Leftover-map comparison graphic leftover-map + * criterion markers stay ``Criterion ζ {label}`` this increment. Caption leftover-map axes with persisted * leftover-map singular values ``σ_k`` and Gabriel inertia share when finite, * including rank-0 zero-share axes. * Axis ticks name persisted leftover-map coordinates so ξ / ζ on the @@ -547,7 +566,7 @@ export function LeftoverMapPlot({ ))} {layout.items.map((marker) => ( - + {marker.label} diff --git a/frontend/src/components/LeftoverPairList.test.tsx b/frontend/src/components/LeftoverPairList.test.tsx index 6972dd29b..1e995db5d 100644 --- a/frontend/src/components/LeftoverPairList.test.tsx +++ b/frontend/src/components/LeftoverPairList.test.tsx @@ -167,6 +167,8 @@ describe("LeftoverPairList", () => { name: "Open leftover-map post Public post at ξ (+0.50, +0.10)", }), ).toBeInTheDocument(); + expect(screen.getByLabelText("leftover-map criterion sales-lead at ζ (+0.50, −0.02)")).toBeInTheDocument(); + expect(screen.queryByLabelText("Criterion ζ sales-lead")).not.toBeInTheDocument(); }); it("opens the named post from a leftover-map graphic display marker", async () => { diff --git a/frontend/src/i18n.test.ts b/frontend/src/i18n.test.ts index c3dccda8c..df4a3bb2a 100644 --- a/frontend/src/i18n.test.ts +++ b/frontend/src/i18n.test.ts @@ -68,6 +68,7 @@ describe("i18n", () => { "Leftover map", "Post ξ", "Criterion ζ", + "leftover-map criterion {label} at ζ {item}", "leftover-map axis 1", "leftover-map axis 2", "leftover-map axis {axis} ({share}%)", @@ -430,6 +431,21 @@ describe("i18n", () => { ).toBe(expected); }); + it.each([ + ["ko", "잔여 지도 기준 sales-lead (ζ (+0.50, −0.02))"], + ["zh", "残差图准则 sales-lead(ζ (+0.50, −0.02))"], + ["ja", "残差マップの基準 sales-lead(ζ (+0.50, −0.02))"], + ["vi", "tiêu chí bản đồ phần dư sales-lead tại ζ (+0.50, −0.02)"], + ] as const)("formats leftover-map graphic leftover-map criterion ζ in %s", (locale, expected) => { + setLocale(locale); + expect( + tf("leftover-map criterion {label} at ζ {item}", { + label: "sales-lead", + item: "(+0.50, −0.02)", + }), + ).toBe(expected); + }); + it.each([ ["ko", "잔여 지도 그림 포함 범위"], ["zh", "残差图图形覆盖范围"], diff --git a/frontend/src/i18n.ts b/frontend/src/i18n.ts index d9849eafd..e2e296df3 100644 --- a/frontend/src/i18n.ts +++ b/frontend/src/i18n.ts @@ -663,6 +663,7 @@ const TRANSLATIONS: Partial>> = { "Leftover map": "잔여 지도", "Post ξ": "글 ξ", "Criterion ζ": "기준 ζ", + "leftover-map criterion {label} at ζ {item}": "잔여 지도 기준 {label} (ζ {item})", "leftover-map axis 1": "잔여 지도 축 1", "leftover-map axis 2": "잔여 지도 축 2", "leftover-map axis {axis} ({share}%)": "잔여 지도 축 {axis} ({share}%)", @@ -1338,6 +1339,7 @@ const TRANSLATIONS: Partial>> = { "Leftover map": "残差图", "Post ξ": "帖子 ξ", "Criterion ζ": "准则 ζ", + "leftover-map criterion {label} at ζ {item}": "残差图准则 {label}(ζ {item})", "leftover-map axis 1": "残差图轴 1", "leftover-map axis 2": "残差图轴 2", "leftover-map axis {axis} ({share}%)": "残差图轴 {axis} ({share}%)", @@ -2017,6 +2019,7 @@ const TRANSLATIONS: Partial>> = { "Leftover map": "残差マップ", "Post ξ": "投稿 ξ", "Criterion ζ": "基準 ζ", + "leftover-map criterion {label} at ζ {item}": "残差マップの基準 {label}(ζ {item})", "leftover-map axis 1": "残差マップ軸 1", "leftover-map axis 2": "残差マップ軸 2", "leftover-map axis {axis} ({share}%)": "残差マップ軸 {axis} ({share}%)", @@ -2700,6 +2703,7 @@ const TRANSLATIONS: Partial>> = { "Leftover map": "Bản đồ phần dư", "Post ξ": "Bài viết ξ", "Criterion ζ": "Tiêu chí ζ", + "leftover-map criterion {label} at ζ {item}": "tiêu chí bản đồ phần dư {label} tại ζ {item}", "leftover-map axis 1": "trục bản đồ phần dư 1", "leftover-map axis 2": "trục bản đồ phần dư 2", "leftover-map axis {axis} ({share}%)": "trục bản đồ phần dư {axis} ({share}%)", diff --git a/frontend/src/leftoverMapPlotLayout.test.ts b/frontend/src/leftoverMapPlotLayout.test.ts index 6b55e3d07..0b8905c6c 100644 --- a/frontend/src/leftoverMapPlotLayout.test.ts +++ b/frontend/src/leftoverMapPlotLayout.test.ts @@ -5,6 +5,7 @@ import { formatLeftoverMapDistance, hasLeftoverMapPlotCoordinates, layoutLeftoverMapPlot, + leftoverMapPlotCriterionBadge, LEFTOVER_MAP_COMPARE_PLOT_CAPTION, LEFTOVER_MAP_COMPARE_PLOT_LABEL, LEFTOVER_MAP_COMPARE_PLOT_SEGMENT_RECONSTRUCTION, @@ -19,6 +20,8 @@ import { LEFTOVER_MAP_COMPARE_PLOT_SEGMENT_DISTANCE, LEFTOVER_MAP_COMPARE_PLOT_TICK, LEFTOVER_MAP_COMPARE_PLOT_SVG, + LEFTOVER_MAP_PLOT_CRITERION, + LEFTOVER_MAP_PLOT_POST_ACTION, LEFTOVER_MAP_PLOT_TICK, PLOT_HEIGHT, PLOT_PADDING, @@ -1202,6 +1205,46 @@ describe("formatLeftoverMapDistance", () => { }); }); +describe("leftoverMapPlotCriterionBadge", () => { + it("names persisted leftover-map item coordinates without inventing a leftover score", () => { + expect(leftoverMapPlotCriterionBadge("sales-lead", 0.5, -0.02)).toEqual({ + key: LEFTOVER_MAP_PLOT_CRITERION, + values: { label: "sales-lead", item: "(+0.50, \u22120.02)" }, + }); + expect(leftoverMapPlotCriterionBadge("negative", -0.7, -0.4)).toEqual({ + key: LEFTOVER_MAP_PLOT_CRITERION, + values: { label: "negative", item: "(\u22120.70, \u22120.40)" }, + }); + }); + + it("names rank-0 origin leftover-map item coordinates as ζ (0.00, 0.00)", () => { + expect(leftoverMapPlotCriterionBadge("sales-lead", 0, 0)).toEqual({ + key: LEFTOVER_MAP_PLOT_CRITERION, + values: { label: "sales-lead", item: "(0.00, 0.00)" }, + }); + }); + + it("omits leftover-map item coordinates when ζ is missing or non-finite", () => { + expect(leftoverMapPlotCriterionBadge("sales-lead", null, -0.02)).toBeNull(); + expect(leftoverMapPlotCriterionBadge("sales-lead", 0.5, undefined)).toBeNull(); + expect(leftoverMapPlotCriterionBadge("sales-lead", Number.NaN, -0.02)).toBeNull(); + expect(leftoverMapPlotCriterionBadge("sales-lead", 0.5, Number.POSITIVE_INFINITY)).toBeNull(); + }); + + it("stays distinct from leftover-map post ξ markers and leftover-map comparison graphic leftover-map criterion markers", () => { + expect(LEFTOVER_MAP_PLOT_CRITERION).toBe("leftover-map criterion {label} at ζ {item}"); + expect(LEFTOVER_MAP_PLOT_CRITERION).not.toBe(LEFTOVER_MAP_PLOT_POST_ACTION); + expect(LEFTOVER_MAP_PLOT_CRITERION).not.toBe("Criterion ζ {label}"); + expect(LEFTOVER_MAP_PLOT_CRITERION).not.toBe("Criterion ζ"); + expect(LEFTOVER_MAP_PLOT_CRITERION).not.toBe( + "leftover map comparison graphic leftover-map criterion {label} at ζ {item}", + ); + expect(leftoverMapPlotCriterionBadge("sales-lead", 0.5, -0.02)?.key).not.toBe( + LEFTOVER_MAP_PLOT_POST_ACTION, + ); + }); +}); + describe("firstPlottablePairForPost", () => { it("returns the first leftover pair whose coordinates can open that post", () => { const closest = pair(); diff --git a/frontend/src/leftoverMapPlotLayout.ts b/frontend/src/leftoverMapPlotLayout.ts index 521525cf4..2c09021c2 100644 --- a/frontend/src/leftoverMapPlotLayout.ts +++ b/frontend/src/leftoverMapPlotLayout.ts @@ -115,6 +115,10 @@ * ADR 0334 fail-closes leftover-map leftover-axis ticks leftover-map * axis share through leftoverMapAxisTickBadge independently of leftover-map * singular values, not this graphic. + * ADR 0335 fail-closes leftover-map graphic leftover-map criterion markers + * leftover-map item coordinates ζ through leftoverMapPlotCriterionBadge + * independently of leftover-map post ξ markers, not leftover-map comparison + * graphic leftover-map criterion markers. */ import { formatLeftoverMapCoordinatePair } from "./leftoverMapCoordinates"; @@ -144,6 +148,26 @@ export const LEFTOVER_MAP_COMPARE_PLOT_SVG = "Leftover map comparison"; export const LEFTOVER_MAP_PLOT_POST_ACTION = "Open leftover-map post {title} at ξ {person}"; +export const LEFTOVER_MAP_PLOT_CRITERION = + "leftover-map criterion {label} at ζ {item}"; + +export type LeftoverMapPlotCriterionBadge = { + key: string; + values: { label: string; item: string }; +}; + +export function leftoverMapPlotCriterionBadge( + label: string, + axis1: number | null | undefined, + axis2: number | null | undefined, +): LeftoverMapPlotCriterionBadge | null { + const item = formatLeftoverMapCoordinatePair(axis1, axis2); + if (item === null) { + return null; + } + return { key: LEFTOVER_MAP_PLOT_CRITERION, values: { label, item } }; +} + export const LEFTOVER_MAP_PLOT_TICK = "leftover-map axis {axis} tick {value}"; diff --git a/pyproject.toml b/pyproject.toml index ff27fbf8a..c03740504 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "lineageweave" -version = "2.91.0" +version = "2.92.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" }