diff --git a/AGENTS.md b/AGENTS.md index 154addfbc..da1b19520 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -846,6 +846,11 @@ returns a leftover-map origin tick caption independently of leftover-map axis sh `leftover axis {axis} origin tick {value}`. Rank-0 unused axes still name leftover-map origin `0.00`. Share and singular omit independently. Do not invent leftover-map origin from leftover-map axis share or leftover-map singular values `σ_k`. leftoverMapPlotTickAxisBadge stays leftover-map graphic leftover-map axis origin tick keys. leftoverMapComparePlotTickAxisBadge stays leftover-map comparison graphic leftover-map axis origin tick keys. leftoverMapCompareAxisTickBadge stays leftover-map comparison leftover-axis origin tick keys this increment. +ADR 0347 captions leftover-map graphic leftover-map criterion leftover-map origin leftover-map item coordinates with leftover-map origin when leftoverMapPlotCriterionBadge +returns a leftover-map origin leftover-map item coordinate caption independently of leftover-map person coordinates. Distinct accessible name +`leftover-map criterion {label} at leftover-map origin ζ {item}`. Rank-0 unused axes still name leftover-map origin `(0.00, 0.00)`. +Do not invent leftover-map origin from leftover-map person coordinates `ξ`. leftoverMapComparePlotCriterionBadge stays leftover-map comparison graphic leftover-map +criterion leftover-map item coordinate keys. leftoverMapPlotPostBadge stays leftover-map graphic leftover-map post leftover-map person coordinate keys 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 @@ -1027,6 +1032,8 @@ Leftover-map comparison leftover-axis origin ticks independently of leftover-map (ADR 0345) captions leftover-map comparison leftover-axis origin ticks when leftoverMapCompareAxisTickBadge returns a leftover-map origin tick caption. Leftover-map leftover-axis origin ticks independently of leftover-map axis share and leftover-map singular values (ADR 0346) captions leftover-map leftover-axis origin ticks when leftoverMapAxisTickBadge returns a leftover-map origin tick caption. +Leftover-map graphic leftover-map criterion leftover-map origin leftover-map item coordinates independently of leftover-map person coordinates +(ADR 0347) captions leftover-map graphic leftover-map criterion leftover-map origin leftover-map item coordinates when leftoverMapPlotCriterionBadge returns a leftover-map origin 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 9a6d0a627..40609cbe2 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -817,6 +817,8 @@ ADR 0345 captions leftover-map comparison leftover-axis origin ticks when leftov returns a leftover-map origin tick caption independently of leftover-map axis share and leftover-map singular values. ADR 0346 captions leftover-map leftover-axis origin ticks when leftoverMapAxisTickBadge returns a leftover-map origin tick caption independently of leftover-map axis share and leftover-map singular values. +ADR 0347 captions leftover-map graphic leftover-map criterion leftover-map origin leftover-map item coordinates when leftoverMapPlotCriterionBadge +returns a leftover-map origin leftover-map item coordinate caption independently of leftover-map person coordinates. 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 diff --git a/CHANGELOG.d/2.104.0-leftover-map-plot-criterion-origin-badge.md b/CHANGELOG.d/2.104.0-leftover-map-plot-criterion-origin-badge.md new file mode 100644 index 000000000..b4cf014f2 --- /dev/null +++ b/CHANGELOG.d/2.104.0-leftover-map-plot-criterion-origin-badge.md @@ -0,0 +1,12 @@ +## 2.104.0 — Leftover-map origin on leftover-map graphic leftover-map criterion leftover-map item coordinates independently of leftover-map person coordinates + +- Caption leftover-map graphic leftover-map criterion leftover-map origin leftover-map item coordinates through leftoverMapPlotCriterionBadge + independently of leftover-map person coordinates (ADR 0347). After `make seed`, leftover-map graphic leftover-map + criterion leftover-map origin leftover-map item coordinates name leftover-map origin when leftoverMapPlotCoordinatePairIsOrigin returns true. Distinct accessible name + `leftover-map criterion {label} at leftover-map origin ζ {item}`. Rank-0 unused axes still name leftover-map origin `(0.00, 0.00)`. + Non-origin leftover-map graphic leftover-map criterion leftover-map item coordinates stay + `leftover-map criterion {label} at ζ {item}`. leftoverMapComparePlotCriterionBadge stays leftover-map comparison graphic leftover-map + criterion leftover-map item coordinate keys. leftoverMapPlotPostBadge stays leftover-map graphic leftover-map post leftover-map + person coordinate keys this increment. Do not invent leftover-map origin from leftover-map person coordinates `ξ`. + Do not mix #877. 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 6d8896f3e..aa651f107 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,16 @@ All notable changes to this project are documented here. Format follows ### Added +- Period leftover pairs now caption leftover-map graphic leftover-map criterion leftover-map origin leftover-map item coordinates + through leftoverMapPlotCriterionBadge independently of leftover-map person coordinates (ADR 0347 / v2.104.0). After `make seed`, leftover-map graphic leftover-map + criterion leftover-map origin leftover-map item coordinates name leftover-map origin when leftoverMapPlotCoordinatePairIsOrigin returns true. Distinct accessible name + `leftover-map criterion {label} at leftover-map origin ζ {item}`. Rank-0 unused axes still name leftover-map origin `(0.00, 0.00)`. + Non-origin leftover-map graphic leftover-map criterion leftover-map item coordinates stay + `leftover-map criterion {label} at ζ {item}`. leftoverMapComparePlotCriterionBadge stays leftover-map comparison graphic leftover-map + criterion leftover-map item coordinate keys. leftoverMapPlotPostBadge stays leftover-map graphic leftover-map post leftover-map + person coordinate keys this increment. Do not invent leftover-map origin from leftover-map person coordinates `ξ`. + Do not mix #877. 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-map leftover-axis origin ticks through leftoverMapAxisTickBadge independently of leftover-map axis share and leftover-map singular values (ADR 0346 / v2.103.0). After `make seed`, leftover-map leftover-axis origin ticks name leftover-map origin when leftoverMapPlotTickIsOrigin returns true. Distinct accessible name diff --git a/CLAUDE.md b/CLAUDE.md index 4c09ad523..6b92d1ddf 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 / 0335 / 0336 / 0337 / 0338 / 0339 / 0340 / 0341 / 0342 / 0343 / 0344 / 0345 / 0346), 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 / 0336 / 0337 / 0338 / 0339 / 0340 / 0341 / 0342 / 0343 / 0344 / 0345 / 0346 / 0347), 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/0335-leftover-map-plot-criterion-coordinates.md b/docs/adr/0335-leftover-map-plot-criterion-coordinates.md index 61398dceb..2c22443b1 100644 --- a/docs/adr/0335-leftover-map-plot-criterion-coordinates.md +++ b/docs/adr/0335-leftover-map-plot-criterion-coordinates.md @@ -4,7 +4,9 @@ **Date:** 2026-08-31 **Amended by:** [ADR 0336](0336-leftover-map-compare-plot-criterion-coordinates.md) -(leftover-map item coordinates on leftover-map comparison graphic leftover-map criterion markers) +(leftover-map item coordinates on leftover-map comparison graphic leftover-map criterion markers); +[ADR 0347](0347-leftover-map-plot-criterion-origin-badge.md) +(leftover-map origin on leftover-map graphic leftover-map criterion leftover-map item coordinates independently of leftover-map person coordinates) Amends leftover-map graphic display of persisted coordinates ([ADR 0268](0268-leftover-map-graphic-display.md)), leftover-map diff --git a/docs/adr/0346-leftover-map-axis-tick-origin-badge.md b/docs/adr/0346-leftover-map-axis-tick-origin-badge.md index 931b4d15d..19aa222e2 100644 --- a/docs/adr/0346-leftover-map-axis-tick-origin-badge.md +++ b/docs/adr/0346-leftover-map-axis-tick-origin-badge.md @@ -83,7 +83,9 @@ axis share and leftover-map singular values comparison graphic leftover-map axis origin ticks independently of leftover-map axis share and leftover-map singular values ([ADR 0344](0344-leftover-map-compare-plot-tick-origin-badge.md)). Independent of leftover-map graphic leftover-map axis origin ticks independently of leftover-map axis share and leftover-map singular values -([ADR 0343](0343-leftover-map-plot-tick-origin-badge.md)). Independent of leftover-axis +([ADR 0343](0343-leftover-map-plot-tick-origin-badge.md)). Independent of leftover-map +graphic leftover-map criterion leftover-map origin leftover-map item coordinates independently of leftover-map +person coordinates ([ADR 0347](0347-leftover-map-plot-criterion-origin-badge.md)). Independent of leftover-axis ticks leftover-map axis share independently of leftover-map singular values ([ADR 0334](0334-leftover-map-axis-tick-share-badge.md)). Independent of leftover-axis ticks leftover-map singular values independently of leftover-map diff --git a/docs/adr/0347-leftover-map-plot-criterion-origin-badge.md b/docs/adr/0347-leftover-map-plot-criterion-origin-badge.md new file mode 100644 index 000000000..f43151aa2 --- /dev/null +++ b/docs/adr/0347-leftover-map-plot-criterion-origin-badge.md @@ -0,0 +1,90 @@ +# ADR 0347 — Name leftover-map origin on leftover-map graphic leftover-map criterion leftover-map item coordinates independently of leftover-map person coordinates + +**Decision status:** Accepted +**Date:** 2026-08-31 + +Amends leftover-map item coordinates on leftover-map graphic leftover-map criterion markers independently of leftover-map post ξ markers +([ADR 0335](0335-leftover-map-plot-criterion-coordinates.md)). Independent of leftover-map leftover-axis origin ticks independently of leftover-map axis share and leftover-map singular values +([ADR 0346](0346-leftover-map-axis-tick-origin-badge.md)). Independent of leftover-map comparison leftover-axis origin ticks independently of leftover-map axis share and leftover-map singular values +([ADR 0345](0345-leftover-map-compare-axis-tick-origin-badge.md)). Independent of leftover-map comparison graphic leftover-map axis origin ticks independently of leftover-map axis share and leftover-map singular values +([ADR 0344](0344-leftover-map-compare-plot-tick-origin-badge.md)). Independent of leftover-map graphic leftover-map axis origin ticks independently of leftover-map axis share and leftover-map singular values +([ADR 0343](0343-leftover-map-plot-tick-origin-badge.md)). Independent of leftover-map leftover-axis origin ticks on the competing origin-tick stack (do not mix #877). + +## Context + +ADR 0335 already names leftover-map graphic leftover-map criterion leftover-map item coordinates +`leftover-map criterion {label} at ζ {item}`. Rank-0 unused axes still persist leftover-map +origin `(0.00, 0.00)` (`formatSignedLeftoverValue(0)` emits no plus). Origin leftover-map +item coordinates still interpolate leftover-map origin only through leftover-map criterion leftover-map +item coordinate keys. A missing or non-finite leftover-map item coordinate pair omits independently +of leftover-map person coordinates `ξ`. A finite negative leftover is shown, never clamped. +Do not invent leftover-map origin from leftover-map person coordinates `ξ`. leftoverMapComparePlotCriterionBadge stays +`leftover map comparison graphic leftover-map criterion {label} at ζ {item}` +this increment. leftoverMapPlotPostBadge stays +`Open leftover-map post {title} at ξ {person}` +this increment. + +This increment names leftover-map graphic leftover-map criterion leftover-map origin leftover-map item +coordinates as leftoverMapPlotCriterionBadge. Leftover-map graphic leftover-map criterion leftover-map origin leftover-map +item coordinates stay +`leftover-map criterion {label} at leftover-map origin ζ {item}` +when leftoverMapPlotCoordinatePairIsOrigin returns true, so they stay distinct from leftover-map +graphic leftover-map criterion leftover-map item coordinates +`leftover-map criterion {label} at ζ {item}`, +leftover-map comparison graphic leftover-map criterion leftover-map item coordinates +`leftover map comparison graphic leftover-map criterion {label} at ζ {item}`, +and leftover-map graphic leftover-map post leftover-map person coordinates +`Open leftover-map post {title} at ξ {person}`. +It does not add columns. Do not invent a leftover score. Do not invent a theta. + +This protected increment uses **0347** so it does not collide with leftover-map leftover-axis +origin ticks independently of leftover-map axis share and leftover-map singular values +(0346) or leftover-map leftover-axis origin ticks (#877). + +## Decision + +On leftover-map graphic leftover-map criterion markers, caption leftover-map origin +when leftoverMapPlotCoordinatePairIsOrigin returns true. Rank-0 unused axes still name leftover-map +origin `(0.00, 0.00)`. Non-origin leftover-map item coordinates stay leftover-map criterion leftover-map +item coordinate keys. leftoverMapComparePlotCriterionBadge, leftoverMapPlotPostBadge, +leftoverMapListCriterionBadge, leftoverMapCompareListCriterionBadge, leftoverMapPlotTickAxisBadge, +leftoverMapComparePlotTickAxisBadge, leftoverMapCompareAxisTickBadge, and leftoverMapAxisTickBadge +do not change leftover-map origin naming this increment. + +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 leftover-map origin leftover-map item +coordinates name leftover-map origin independently of leftover-map person coordinates. Rank-0 unused +axes still name leftover-map origin `(0.00, 0.00)`. leftoverMapComparePlotCriterionBadge stays leftover-map +comparison graphic leftover-map criterion leftover-map item coordinate keys. leftoverMapPlotPostBadge +stays leftover-map graphic leftover-map post leftover-map person coordinate keys. leftover-map graphic leftover-map +criterion leftover-map item coordinates independently of leftover-map post ξ markers +(ADR 0335) remain. + +## Related + +Independent of leftover-map leftover-axis origin ticks independently of leftover-map +axis share and leftover-map singular values +([ADR 0346](0346-leftover-map-axis-tick-origin-badge.md)). Independent of leftover-map +item coordinates on leftover-map graphic leftover-map criterion markers independently of leftover-map +post ξ markers ([ADR 0335](0335-leftover-map-plot-criterion-coordinates.md)). Independent of leftover-map +graphic leftover-map axis origin ticks independently of leftover-map axis share and leftover-map singular values +([ADR 0343](0343-leftover-map-plot-tick-origin-badge.md)). Independent of leftover-map +comparison graphic leftover-map criterion leftover-map item coordinates independently of leftover-map +post ξ markers ([ADR 0336](0336-leftover-map-compare-plot-criterion-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 401b1b5ac..ec465adcf 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,5 +1,15 @@ # Product & Technical Gap Baseline +> Exact-head loop overlay: 2026-08-31 19:35 KST. Protected `main` is +> `cb187cadee5fb6c46d8a944815ccc154a1e028d1`. Writes work. Do not +> self-approve. #889 leftover-map leftover-axis origin ticks independently of leftover-map +> axis share and leftover-map singular values (v2.103.0 / ADR 0346) is +> `4bfb490`, stacked on #887 @ `7637fc8`. Independent APPROVE is missing (Devin COMMENTED, +> not APPROVE). Next buyer increment on this cycle: leftover-map graphic leftover-map criterion leftover-map origin leftover-map +> item coordinates independently of leftover-map person coordinates as leftoverMapPlotCriterionBadge (ADR 0347 / v2.104.0) delivered locally on +> `feat/leftover-map-plot-criterion-origin-badge-v21040`. Distinct accessible name +> `leftover-map criterion {label} at leftover-map origin ζ {item}`. Rank-0 unused axes still name leftover-map origin `(0.00, 0.00)`. leftoverMapComparePlotCriterionBadge stays leftover-map comparison graphic leftover-map criterion leftover-map item coordinate keys. leftoverMapPlotPostBadge stays leftover-map graphic leftover-map post leftover-map person coordinate keys. Do not invent leftover-map origin from leftover-map person coordinates `ξ`. Do not mix #877. Stack onto #889. 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. + > Exact-head loop overlay: 2026-08-31 19:32 KST. Protected `main` is > `cb187cadee5fb6c46d8a944815ccc154a1e028d1`. Writes work. Do not > self-approve. #887 leftover-map comparison leftover-axis origin ticks independently of leftover-map diff --git a/frontend/package.json b/frontend/package.json index 9aed0741c..8401b2758 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "frontend", "private": true, - "version": "2.103.0", + "version": "2.104.0", "type": "module", "scripts": { "dev": "vite", diff --git a/frontend/src/components/LeftoverMapPlot.test.tsx b/frontend/src/components/LeftoverMapPlot.test.tsx index ddde84b74..01c021b5f 100644 --- a/frontend/src/components/LeftoverMapPlot.test.tsx +++ b/frontend/src/components/LeftoverMapPlot.test.tsx @@ -172,7 +172,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.getByLabelText("leftover-map criterion sales-lead at leftover-map origin ζ (0.00, 0.00)")).toBeInTheDocument(); + expect(screen.queryByLabelText("leftover-map criterion sales-lead at ζ (0.00, 0.00)")).not.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(); @@ -1008,6 +1009,9 @@ describe("LeftoverMapPlot", () => { ).not.toBeInTheDocument(); expect(screen.queryByLabelText("Criterion ζ sales-lead")).not.toBeInTheDocument(); expect(screen.queryByLabelText("leftover-map criterion sales-lead at ζ (0.00, 0.00)")).not.toBeInTheDocument(); + expect( + screen.queryByLabelText("leftover-map criterion sales-lead at leftover-map origin ζ (0.00, 0.00)"), + ).not.toBeInTheDocument(); }); it("keeps leftover map comparison axis text when share is missing or non-finite", () => { diff --git a/frontend/src/components/LeftoverMapPlot.tsx b/frontend/src/components/LeftoverMapPlot.tsx index fd6aea44a..96ae0e2a2 100644 --- a/frontend/src/components/LeftoverMapPlot.tsx +++ b/frontend/src/components/LeftoverMapPlot.tsx @@ -165,7 +165,9 @@ function leftoverMapPlotPostText( * 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. Caption leftover-map comparison graphic leftover-map + * leftover-map item coordinate caption. Caption leftover-map origin on leftover-map graphic leftover-map + * criterion leftover-map item coordinates independently of leftover-map person coordinates when leftoverMapPlotCoordinatePairIsOrigin + * returns true. Caption leftover-map comparison graphic leftover-map * criterion markers with persisted leftover-map item coordinates ``ζ_{1:2}`` * when leftoverMapComparePlotCriterionBadge returns a usable leftover-map comparison * graphic leftover-map criterion leftover-map item coordinate caption. Caption leftover-map @@ -293,6 +295,9 @@ function leftoverMapPlotPostText( * ADR 0346 fail-closes leftover-map leftover-axis origin ticks through * leftoverMapAxisTickBadge independently of leftover-map axis share and leftover-map * singular values. + * ADR 0347 fail-closes leftover-map graphic leftover-map criterion leftover-map origin leftover-map + * item coordinates through leftoverMapPlotCriterionBadge independently of leftover-map + * person coordinates. * Never invent a leftover score. */ export function LeftoverMapPlot({ diff --git a/frontend/src/i18n.test.ts b/frontend/src/i18n.test.ts index 2484dcda5..f60beb5f1 100644 --- a/frontend/src/i18n.test.ts +++ b/frontend/src/i18n.test.ts @@ -77,6 +77,7 @@ describe("i18n", () => { "Post ξ", "Criterion ζ", "leftover-map criterion {label} at ζ {item}", + "leftover-map criterion {label} at leftover-map origin ζ {item}", "leftover map comparison graphic leftover-map criterion {label} at ζ {item}", "leftover-map axis 1", "leftover-map axis 2", @@ -469,6 +470,24 @@ describe("i18n", () => { ).toBe(expected); }); + it.each([ + ["ko", "잔여 지도 원점 기준 sales-lead (ζ (0.00, 0.00))"], + ["zh", "残差图原点准则 sales-lead(ζ (0.00, 0.00))"], + ["ja", "残差マップの原点基準 sales-lead(ζ (0.00, 0.00))"], + ["vi", "tiêu chí gốc bản đồ phần dư sales-lead tại ζ (0.00, 0.00)"], + ] as const)( + "formats leftover-map graphic leftover-map criterion leftover-map origin ζ in %s", + (locale, expected) => { + setLocale(locale); + expect( + tf("leftover-map criterion {label} at leftover-map origin ζ {item}", { + label: "sales-lead", + item: "(0.00, 0.00)", + }), + ).toBe(expected); + }, + ); + it.each([ ["ko", "잔여 지도 비교 그림 기준 sales-lead (ζ (+0.50, −0.02))"], ["zh", "残差地图比较图形准则 sales-lead(ζ (+0.50, −0.02))"], diff --git a/frontend/src/i18n.ts b/frontend/src/i18n.ts index cfb8a4160..bce2f3e63 100644 --- a/frontend/src/i18n.ts +++ b/frontend/src/i18n.ts @@ -694,6 +694,8 @@ const TRANSLATIONS: Partial>> = { "Post ξ": "글 ξ", "Criterion ζ": "기준 ζ", "leftover-map criterion {label} at ζ {item}": "잔여 지도 기준 {label} (ζ {item})", + "leftover-map criterion {label} at leftover-map origin ζ {item}": + "잔여 지도 원점 기준 {label} (ζ {item})", "leftover map comparison graphic leftover-map criterion {label} at ζ {item}": "잔여 지도 비교 그림 기준 {label} (ζ {item})", "Open leftover-map post {title}": "잔여 지도 글 {title} 열기", @@ -1412,6 +1414,8 @@ const TRANSLATIONS: Partial>> = { "Post ξ": "帖子 ξ", "Criterion ζ": "准则 ζ", "leftover-map criterion {label} at ζ {item}": "残差图准则 {label}(ζ {item})", + "leftover-map criterion {label} at leftover-map origin ζ {item}": + "残差图原点准则 {label}(ζ {item})", "leftover map comparison graphic leftover-map criterion {label} at ζ {item}": "残差地图比较图形准则 {label}(ζ {item})", "Open leftover-map post {title}": "打开残差图帖子 {title}", @@ -2134,6 +2138,8 @@ const TRANSLATIONS: Partial>> = { "Post ξ": "投稿 ξ", "Criterion ζ": "基準 ζ", "leftover-map criterion {label} at ζ {item}": "残差マップの基準 {label}(ζ {item})", + "leftover-map criterion {label} at leftover-map origin ζ {item}": + "残差マップの原点基準 {label}(ζ {item})", "leftover map comparison graphic leftover-map criterion {label} at ζ {item}": "残差マップの比較図基準 {label}(ζ {item})", "Open leftover-map post {title}": "残差マップの投稿 {title} を開く", @@ -2860,6 +2866,8 @@ const TRANSLATIONS: Partial>> = { "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 criterion {label} at leftover-map origin ζ {item}": + "tiêu chí gốc bản đồ phần dư {label} tại ζ {item}", "leftover map comparison graphic leftover-map criterion {label} at ζ {item}": "tiêu chí đồ họa so sánh bản đồ phần dư {label} tại ζ {item}", "Open leftover-map post {title}": "Mở bài viết bản đồ phần dư {title}", diff --git a/frontend/src/leftoverMapAxisBadge.ts b/frontend/src/leftoverMapAxisBadge.ts index 76f74bdf2..a54f5fe04 100644 --- a/frontend/src/leftoverMapAxisBadge.ts +++ b/frontend/src/leftoverMapAxisBadge.ts @@ -30,6 +30,8 @@ * leftoverMapCompareAxisTickBadge, not this helper. * ADR 0346 names leftover-map leftover-axis origin ticks as leftoverMapAxisTickBadge * independently of leftover-map axis share and leftover-map singular values. + * ADR 0347 names leftover-map origin on leftover-map graphic leftover-map criterion leftover-map + * item coordinates as leftoverMapPlotCriterionBadge, not this helper. */ import type { LeftoverMapAxis } from "./api"; diff --git a/frontend/src/leftoverMapCoordinates.test.ts b/frontend/src/leftoverMapCoordinates.test.ts index f1a28c569..88e10f5d8 100644 --- a/frontend/src/leftoverMapCoordinates.test.ts +++ b/frontend/src/leftoverMapCoordinates.test.ts @@ -7,6 +7,7 @@ import { LEFTOVER_MAP_COMPARE_PLOT_CRITERION, LEFTOVER_MAP_COMPARE_PLOT_POST_ACTION, LEFTOVER_MAP_PLOT_CRITERION, + LEFTOVER_MAP_PLOT_CRITERION_ORIGIN, LEFTOVER_MAP_PLOT_POST_ACTION, } from "./leftoverMapPlotLayout"; import { @@ -16,6 +17,7 @@ import { leftoverMapCompareListCriterionBadge, leftoverMapListCriterionBadge, leftoverMapListPostBadge, + leftoverMapPlotCoordinatePairIsOrigin, LEFTOVER_MAP_COMPARE_COORDINATES_LABEL, LEFTOVER_MAP_COMPARE_LIST_POST_ACTION, LEFTOVER_MAP_COMPARE_LIST_CRITERION, @@ -62,6 +64,25 @@ describe("formatLeftoverMapCoordinatePair", () => { }); }); +describe("leftoverMapPlotCoordinatePairIsOrigin", () => { + it("names leftover-map origin independently of leftover-map person coordinates", () => { + expect(leftoverMapPlotCoordinatePairIsOrigin("(0.00, 0.00)")).toBe(true); + expect(leftoverMapPlotCoordinatePairIsOrigin("(+0.50, \u22120.02)")).toBe(false); + expect(leftoverMapPlotCoordinatePairIsOrigin("(+0.00, 0.00)")).toBe(false); + expect(leftoverMapPlotCoordinatePairIsOrigin("(0.00, +0.00)")).toBe(false); + expect(leftoverMapPlotCoordinatePairIsOrigin("0.00")).toBe(false); + expect(formatLeftoverMapCoordinatePair(0, 0)).toBe("(0.00, 0.00)"); + expect(leftoverMapPlotCriterionBadge("sales-lead", 0, 0)?.key).toBe(LEFTOVER_MAP_PLOT_CRITERION_ORIGIN); + expect(leftoverMapComparePlotCriterionBadge("sales-lead", 0, 0)?.key).not.toBe( + LEFTOVER_MAP_PLOT_CRITERION_ORIGIN, + ); + expect(leftoverMapPlotPostBadge("Public post", 0, 0)?.key).not.toBe(LEFTOVER_MAP_PLOT_CRITERION_ORIGIN); + expect(leftoverMapListCriterionBadge("sales-lead", 0, 0)?.key).not.toBe( + LEFTOVER_MAP_PLOT_CRITERION_ORIGIN, + ); + }); +}); + describe("leftoverMapListPostBadge", () => { it("names persisted leftover-map person coordinates without inventing a leftover score", () => { expect(leftoverMapListPostBadge("Public post", 0.5, 0.1)).toEqual({ @@ -151,6 +172,7 @@ describe("leftoverMapListCriterionBadge", () => { "leftover pair leftover-map criterion {label} at ζ {item}", ); expect(LEFTOVER_MAP_LIST_CRITERION).not.toBe(LEFTOVER_MAP_PLOT_CRITERION); + expect(LEFTOVER_MAP_LIST_CRITERION).not.toBe(LEFTOVER_MAP_PLOT_CRITERION_ORIGIN); expect(LEFTOVER_MAP_LIST_CRITERION).not.toBe(LEFTOVER_MAP_COMPARE_PLOT_CRITERION); expect(LEFTOVER_MAP_LIST_CRITERION).not.toBe(LEFTOVER_MAP_LIST_POST_ACTION); expect(LEFTOVER_MAP_LIST_CRITERION).not.toBe("Criterion ζ {label}"); @@ -264,6 +286,7 @@ describe("leftoverMapCompareListCriterionBadge", () => { ); expect(LEFTOVER_MAP_COMPARE_LIST_CRITERION).not.toBe(LEFTOVER_MAP_LIST_CRITERION); expect(LEFTOVER_MAP_COMPARE_LIST_CRITERION).not.toBe(LEFTOVER_MAP_PLOT_CRITERION); + expect(LEFTOVER_MAP_COMPARE_LIST_CRITERION).not.toBe(LEFTOVER_MAP_PLOT_CRITERION_ORIGIN); expect(LEFTOVER_MAP_COMPARE_LIST_CRITERION).not.toBe(LEFTOVER_MAP_COMPARE_PLOT_CRITERION); expect(LEFTOVER_MAP_COMPARE_LIST_CRITERION).not.toBe(LEFTOVER_MAP_COMPARE_LIST_POST_ACTION); expect(leftoverMapCompareListCriterionBadge("sales-lead", 0.5, -0.02)?.key).not.toBe( diff --git a/frontend/src/leftoverMapCoordinates.ts b/frontend/src/leftoverMapCoordinates.ts index f505ad67e..99de1f500 100644 --- a/frontend/src/leftoverMapCoordinates.ts +++ b/frontend/src/leftoverMapCoordinates.ts @@ -1,4 +1,9 @@ -/** Two-axis leftover-map coordinates ``ξ_{1:2}`` and ``ζ_{1:2}``. */ +/** Two-axis leftover-map coordinates ``ξ_{1:2}`` and ``ζ_{1:2}``. + * ADR 0347 names leftover-map origin on leftover-map graphic leftover-map + * criterion leftover-map item coordinates as leftoverMapPlotCriterionBadge + * independently of leftover-map person coordinates. leftoverMapListCriterionBadge + * stays leftover-map pair leftover-map criterion leftover-map item coordinate keys. + */ import { formatSignedLeftoverValue } from "./leftoverMapUnexplained"; @@ -48,6 +53,16 @@ export function formatLeftoverMapCoordinatePair( return `(${first}, ${second})`; } +/** True when the formatted leftover-map coordinate pair is leftover-map origin + * `(formatSignedLeftoverValue(0), formatSignedLeftoverValue(0))`. Rank-0 unused + * axes still name leftover-map origin `(0.00, 0.00)`. Do not invent leftover-map + * origin from leftover-map person coordinates ξ. + */ +export function leftoverMapPlotCoordinatePairIsOrigin(pairLabel: string): boolean { + const origin = formatLeftoverMapCoordinatePair(0, 0); + return origin !== null && pairLabel === origin; +} + export function formatLeftoverMapCoordinates( personAxis1: number | null | undefined, personAxis2: number | null | undefined, @@ -75,7 +90,10 @@ export function leftoverMapListPostBadge( return { key: LEFTOVER_MAP_LIST_POST_ACTION, values: { title, person } }; } -/** ADR 0340 leftover-map pair leftover-map criterion leftover-map item coordinates ζ. */ +/** ADR 0340 leftover-map pair leftover-map criterion leftover-map item coordinates ζ. + * ADR 0347 names leftover-map origin on leftover-map graphic leftover-map criterion + * leftover-map item coordinates as leftoverMapPlotCriterionBadge, not this helper. + */ export function leftoverMapListCriterionBadge( label: string, axis1: number | null | undefined, diff --git a/frontend/src/leftoverMapPlotAxisSingular.ts b/frontend/src/leftoverMapPlotAxisSingular.ts index 344bbdea7..f5ff73070 100644 --- a/frontend/src/leftoverMapPlotAxisSingular.ts +++ b/frontend/src/leftoverMapPlotAxisSingular.ts @@ -40,6 +40,9 @@ * leftover-map singular values. * ADR 0346 names leftover-map leftover-axis origin ticks as leftoverMapAxisTickBadge * independently of leftover-map axis share and leftover-map singular values. + * ADR 0347 names leftover-map origin on leftover-map graphic leftover-map criterion leftover-map + * item coordinates as leftoverMapPlotCriterionBadge independently of leftover-map person + * coordinates, not leftoverMapPlotTickAxisBadge. */ import type { LeftoverMapAxis } from "./api"; diff --git a/frontend/src/leftoverMapPlotLayout.test.ts b/frontend/src/leftoverMapPlotLayout.test.ts index d440003dd..a3b761cb6 100644 --- a/frontend/src/leftoverMapPlotLayout.test.ts +++ b/frontend/src/leftoverMapPlotLayout.test.ts @@ -24,6 +24,7 @@ import { LEFTOVER_MAP_COMPARE_PLOT_TICK, LEFTOVER_MAP_COMPARE_PLOT_SVG, LEFTOVER_MAP_PLOT_CRITERION, + LEFTOVER_MAP_PLOT_CRITERION_ORIGIN, LEFTOVER_MAP_COMPARE_PLOT_CRITERION, LEFTOVER_MAP_PLOT_POST_ACTION, LEFTOVER_MAP_PLOT_POST_ACTION_OMITTED, @@ -1224,11 +1225,14 @@ describe("leftoverMapPlotCriterionBadge", () => { }); }); - it("names rank-0 origin leftover-map item coordinates as ζ (0.00, 0.00)", () => { + it("names rank-0 leftover-map origin leftover-map item coordinates independently of leftover-map person coordinates", () => { expect(leftoverMapPlotCriterionBadge("sales-lead", 0, 0)).toEqual({ - key: LEFTOVER_MAP_PLOT_CRITERION, + key: LEFTOVER_MAP_PLOT_CRITERION_ORIGIN, values: { label: "sales-lead", item: "(0.00, 0.00)" }, }); + expect(leftoverMapPlotCriterionBadge("sales-lead", 0, 0)?.key).not.toBe(LEFTOVER_MAP_PLOT_CRITERION); + expect(leftoverMapPlotCriterionBadge("sales-lead", 0, 0)?.key).not.toBe(LEFTOVER_MAP_COMPARE_PLOT_CRITERION); + expect(leftoverMapPlotPostBadge("Public post", 0, 0)?.key).not.toBe(LEFTOVER_MAP_PLOT_CRITERION_ORIGIN); }); it("omits leftover-map item coordinates when ζ is missing or non-finite", () => { @@ -1240,6 +1244,11 @@ describe("leftoverMapPlotCriterionBadge", () => { 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_ORIGIN).toBe( + "leftover-map criterion {label} at leftover-map origin ζ {item}", + ); + expect(LEFTOVER_MAP_PLOT_CRITERION_ORIGIN).not.toBe(LEFTOVER_MAP_PLOT_CRITERION); + expect(LEFTOVER_MAP_PLOT_CRITERION_ORIGIN).not.toBe(LEFTOVER_MAP_COMPARE_PLOT_CRITERION); 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 ζ"); @@ -1273,6 +1282,9 @@ describe("leftoverMapComparePlotCriterionBadge", () => { key: LEFTOVER_MAP_COMPARE_PLOT_CRITERION, values: { label: "sales-lead", item: "(0.00, 0.00)" }, }); + expect(leftoverMapComparePlotCriterionBadge("sales-lead", 0, 0)?.key).not.toBe( + LEFTOVER_MAP_PLOT_CRITERION_ORIGIN, + ); }); it("omits leftover-map item coordinates when ζ is missing or non-finite", () => { @@ -1287,6 +1299,7 @@ describe("leftoverMapComparePlotCriterionBadge", () => { "leftover map comparison graphic leftover-map criterion {label} at ζ {item}", ); expect(LEFTOVER_MAP_COMPARE_PLOT_CRITERION).not.toBe(LEFTOVER_MAP_PLOT_CRITERION); + expect(LEFTOVER_MAP_COMPARE_PLOT_CRITERION).not.toBe(LEFTOVER_MAP_PLOT_CRITERION_ORIGIN); expect(LEFTOVER_MAP_COMPARE_PLOT_CRITERION).not.toBe(LEFTOVER_MAP_PLOT_POST_ACTION); expect(LEFTOVER_MAP_COMPARE_PLOT_CRITERION).not.toBe("Criterion ζ {label}"); expect(LEFTOVER_MAP_COMPARE_PLOT_CRITERION).not.toBe("Criterion ζ"); diff --git a/frontend/src/leftoverMapPlotLayout.ts b/frontend/src/leftoverMapPlotLayout.ts index 3acd106c4..3cb819dff 100644 --- a/frontend/src/leftoverMapPlotLayout.ts +++ b/frontend/src/leftoverMapPlotLayout.ts @@ -159,9 +159,13 @@ * ADR 0346 fail-closes leftover-map leftover-axis origin ticks through * leftoverMapAxisTickBadge independently of leftover-map axis share and leftover-map * singular values, not leftover-map comparison leftover-axis ticks. + * ADR 0347 fail-closes leftover-map graphic leftover-map criterion leftover-map origin + * leftover-map item coordinates through leftoverMapPlotCriterionBadge independently of leftover-map + * person coordinates ξ, not leftover-map comparison graphic leftover-map criterion leftover-map + * item coordinates. */ -import { formatLeftoverMapCoordinatePair } from "./leftoverMapCoordinates"; +import { formatLeftoverMapCoordinatePair, leftoverMapPlotCoordinatePairIsOrigin } from "./leftoverMapCoordinates"; import { formatLeftoverMapCrossShare } from "./leftoverMapCrossShare"; import { formatLeftoverMapExplainedShare } from "./leftoverMapExplainedShare"; import { formatLeftoverMapRank } from "./leftoverMapRank"; @@ -197,6 +201,9 @@ export const LEFTOVER_MAP_COMPARE_PLOT_POST_ACTION = export const LEFTOVER_MAP_PLOT_CRITERION = "leftover-map criterion {label} at ζ {item}"; +export const LEFTOVER_MAP_PLOT_CRITERION_ORIGIN = + "leftover-map criterion {label} at leftover-map origin ζ {item}"; + export const LEFTOVER_MAP_COMPARE_PLOT_CRITERION = "leftover map comparison graphic leftover-map criterion {label} at ζ {item}"; @@ -219,7 +226,11 @@ export function leftoverMapPlotCriterionBadge( if (item === null) { return null; } - return { key: LEFTOVER_MAP_PLOT_CRITERION, values: { label, item } }; + const origin = leftoverMapPlotCoordinatePairIsOrigin(item); + return { + key: origin ? LEFTOVER_MAP_PLOT_CRITERION_ORIGIN : LEFTOVER_MAP_PLOT_CRITERION, + values: { label, item }, + }; } export function leftoverMapComparePlotCriterionBadge( diff --git a/pyproject.toml b/pyproject.toml index 8af048443..f82235b76 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "lineageweave" -version = "2.103.0" +version = "2.104.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" }