Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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) 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) 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
Expand Down Expand Up @@ -476,6 +476,12 @@ compares leftover pairs can match the pair-row coordinate badge; a missing or
non-finite axis omits that leftover-map comparison coordinates badge and does not
invent coordinates from leftover-map rank, leftover-map distance, leftover-map
reconstruction, or leftover residual. The strip does not gain the leftover-map graphic.
ADR 0303 returns persisted leftover-map coordinates `ξ` / `ζ` on
`GET /api/reports/compare/{period}` leftover pairs so a buyer who
compares leftover pairs can match the pair-row coordinate badge on live
responses; a missing axis stays null and does not invent coordinates from
leftover-map rank, leftover-map distance, leftover-map reconstruction, or
leftover residual. The strip does not gain the leftover-map graphic.
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
Expand Down Expand Up @@ -518,6 +524,8 @@ Grouping comparison leftover-map rank (ADR 0301) captions grouping comparison le
buttons with persisted leftover-map rank.
Grouping comparison leftover-map coordinates (ADR 0302) captions grouping comparison leftover-pair
buttons with persisted leftover-map coordinates `ξ` / `ζ`.
Grouping comparison leftover-map coordinates payload (ADR 0303) returns persisted leftover-map
coordinates `ξ` / `ζ` on `GET /api/reports/compare/{period}` leftover pairs.
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)
Expand Down
7 changes: 5 additions & 2 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,8 @@ ADR 0301 captions grouping comparison leftover-pair buttons with persisted lefto
rank through formatLeftoverMapRank.
ADR 0302 captions grouping comparison leftover-pair buttons with persisted leftover-map
coordinates `ξ` / `ζ` through formatLeftoverMapCoordinates.
ADR 0303 returns persisted leftover-map coordinates `ξ` / `ζ` on
`GET /api/reports/compare/{period}` leftover pairs.
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
Expand Down Expand Up @@ -724,8 +726,9 @@ incomplete item coverage (ADR 0292), leftover-map reconstruction `R̂`
(ADR 0298), leftover observed `Y`
(ADR 0299), leftover expected `E`
(ADR 0300), leftover-map rank
(ADR 0301), and leftover-map coordinates `ξ` / `ζ`
(ADR 0302);
(ADR 0301), leftover-map coordinates `ξ` / `ζ`
(ADR 0302), and leftover-map coordinates on the compare leftover-pair payload
(ADR 0303);
`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
Expand Down
19 changes: 19 additions & 0 deletions CHANGELOG.d/2.60.0-leftover-map-compare-coordinates-payload.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
## 2.60.0 — Leftover-map coordinates on grouping comparison leftover-pair payload

- Return persisted leftover-map coordinates `ξ` / `ζ` on
`GET /api/reports/compare/{period}` leftover pairs (ADR 0303). After
`make seed`, grouping comparison leftover-pair buttons that already
caption formatLeftoverMapCoordinates can match leftover-map coordinates
on the pair row from the live compare payload; click a post marker or a
pair button opens that post. A missing axis stays null and omits that
leftover-map comparison coordinates badge independently of leftover-map
rank, leftover expected `E`, leftover observed `Y`, leftover residual `R`,
leftover-map unexplained leftover `U`, leftover-map cross share `x`,
leftover-map unexplained leftover share `s`, leftover-map explained leftover
share `e`, leftover-map reconstruction `R̂`, leftover-map distance `d`, and
the strip coverage notes. Rank-0 origin cells still return `0.0` on each
axis when those persisted coordinates are stored. Do not invent coordinates
from leftover-map rank, leftover-map distance, or leftover-map reconstruction.
A finite negative leftover is shown, never clamped. The strip does not gain
the leftover-map graphic. Never invent a leftover score. Never invent a
theta. No new columns.
59 changes: 59 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,65 @@ All notable changes to this project are documented here. Format follows

### Added

- Period leftover pairs now return persisted leftover-map coordinates
`ξ` / `ζ` on `GET /api/reports/compare/{period}` leftover pairs
(ADR 0303 / v2.60.0). After `make seed`, closest and farthest leftover
pairs sit above the member list with the Gabriel biplot of already-named
coordinates, leftover-map axis share when finite, axis ticks that match
`ξ (x, y) ζ (x, y)` on the pair row, pair segments that match `d` on the
pair row, pair segments that match `R̂` on the pair row, pair segments
that match `R̂²/R²` on the pair row, pair segments that match `U²/R²` on
the pair row, pair segments that match `2R̂U/R²` on the pair row, pair
segments that match `U` on the pair row, pair segments that match `R` on
the pair row, pair segments that match `Y` on the pair row, pair segments
that match `E` on the pair row, pair segments that match leftover-map
rank on the pair row, a plot caption that matches leftover-map
complete-case coverage above the pair list, a plot caption that matches
leftover-map item complete-case coverage, a plot caption that matches
leftover-map incomplete post coverage, a plot caption that matches
leftover-map incomplete item coverage, a pair-list note that matches
leftover-map post complete-case coverage, a pair-list note that matches
leftover-map item complete-case coverage, a pair-list note that matches
leftover-map incomplete post coverage, a pair-list note that matches
leftover-map incomplete item coverage, a grouping comparison note that
matches leftover-map post complete-case coverage, a grouping comparison
note that matches leftover-map item complete-case coverage, a grouping
comparison note that matches leftover-map incomplete post coverage, a
grouping comparison note that matches leftover-map incomplete item
coverage, grouping comparison leftover-pair buttons that match leftover-map
reconstruction `R̂` on the pair row, grouping comparison leftover-pair
buttons that match leftover-map explained leftover share `e` on the pair
row, grouping comparison leftover-pair buttons that match leftover-map
unexplained leftover share `s` on the pair row, grouping comparison
leftover-pair buttons that match leftover-map cross share `x` on the pair
row, grouping comparison leftover-pair buttons that match leftover-map
unexplained leftover `U` on the pair row, grouping comparison leftover-pair
buttons that match leftover residual `R` on the pair row, grouping
comparison leftover-pair buttons that match leftover observed `Y` on the
pair row, grouping comparison leftover-pair buttons that match leftover
expected `E` on the pair row, grouping comparison leftover-pair buttons
that match leftover-map rank on the pair row, grouping comparison leftover-pair
buttons that match leftover-map coordinates `ξ` / `ζ` on the pair row, and
a live compare payload that carries those persisted leftover-map
coordinates; click a post marker or a pair button opens that post. A
missing axis stays null and omits that leftover-map comparison coordinates
badge and keeps leftover-map rank when that rank is a non-negative integer,
leftover expected `E` when finite, leftover observed `Y` when finite,
leftover residual `R` when finite, leftover-map unexplained leftover `U`
when finite, leftover-map cross share `x` when finite, leftover-map
unexplained leftover share `s` when finite, leftover-map explained leftover
share `e` when finite, leftover-map reconstruction `R̂` when finite,
leftover-map distance `d`, plus the strip coverage notes. Rank-0 origin
cells still return `0.0` on each axis when those persisted coordinates are
stored. Do not invent coordinates from leftover-map rank, leftover-map
distance, leftover expected, leftover observed, leftover residual,
leftover-map reconstruction, leftover-map unexplained leftover, leftover-map
post coverage, leftover-map item coverage, leftover-map incomplete post
coverage, leftover-map incomplete item coverage, or the count of unused
axes. A finite negative leftover is shown, never clamped. The strip does
not gain the leftover-map graphic. Never invent a leftover score or a
theta. No new columns.

- Period leftover pairs now caption grouping comparison leftover-pair
buttons with persisted leftover-map coordinates `ξ` / `ζ` through
formatLeftoverMapCoordinates (ADR 0302 / v2.59.0). After `make seed`,
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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), 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), 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),
Expand Down
24 changes: 23 additions & 1 deletion backend/app/report_ingestion.py
Original file line number Diff line number Diff line change
Expand Up @@ -1052,7 +1052,9 @@ async def fetch_period_comparison(
f"""
select lp.grouping_kind, lp.grouping_key, lp.pair_kind, lp.post_id,
lp.criterion_code, lp.leftover_distance, lp.leftover_residual,
lp.leftover_map_reconstruction,
lp.leftover_map_reconstruction, lp.leftover_map_person_axis_1,
lp.leftover_map_person_axis_2, lp.leftover_map_item_axis_1,
lp.leftover_map_item_axis_2,
p.post_title, p.visibility_code, p.corporate_entity_id,
({_SOURCE_CONTEXT_PRESENT_SQL}) as has_real_source_context
from report_leftover_pair lp
Expand Down Expand Up @@ -1123,6 +1125,26 @@ async def fetch_period_comparison(
if pair["leftover_map_reconstruction"] is None
else float(pair["leftover_map_reconstruction"])
),
"leftover_map_person_axis_1": (
None
if pair["leftover_map_person_axis_1"] is None
else float(pair["leftover_map_person_axis_1"])
),
Comment on lines +1128 to +1132

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Non-finite coordinates break comparisons

When a stored coordinate is NaN or infinite, float forwards it into JSON. The entire comparison request fails instead of omitting coordinates.

Prompt for agents
Make fetch_period_comparison serialize each of the four leftover-map coordinate fields only when its database numeric is finite; return null for missing or non-finite values. The report_leftover_pair coordinate columns are unconstrained PostgreSQL numeric values, which can contain NaN or infinities, while FastAPI's JSON serializer rejects their float forms. Apply the same handling consistently to person axes 1/2 and item axes 1/2, and add coverage for non-finite persisted coordinates without deriving replacement coordinates.
Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

"leftover_map_person_axis_2": (
None
if pair["leftover_map_person_axis_2"] is None
else float(pair["leftover_map_person_axis_2"])
),
"leftover_map_item_axis_1": (
None
if pair["leftover_map_item_axis_1"] is None
else float(pair["leftover_map_item_axis_1"])
),
"leftover_map_item_axis_2": (
None
if pair["leftover_map_item_axis_2"] is None
else float(pair["leftover_map_item_axis_2"])
),
Comment on lines +1128 to +1147

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Redaction preserves new coordinates

Authorization filtering still removes hidden pairs before stripping internal metadata. The four coordinate fields remain in each surviving public pair.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +1128 to +1147

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Partial coordinates fail closed

Each missing axis remains independently null. The existing formatter requires four finite values, so partial coordinates cannot produce a misleading badge.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

"visibility_code": pair["visibility_code"],
"corporate_entity_id": str(pair["corporate_entity_id"]),
"has_real_source_context": bool(pair["has_real_source_context"]),
Expand Down
30 changes: 30 additions & 0 deletions backend/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -5851,6 +5851,36 @@ def test_seed_period_report_surfaces_on_get_reports(client, demo_analyst_token,
or isinstance(pair["leftover_map_reconstruction"], (int, float))
for pair in leftover_thread.get("leftover_pairs", [])
)
assert all(
{
"leftover_map_person_axis_1",
"leftover_map_person_axis_2",
"leftover_map_item_axis_1",
"leftover_map_item_axis_2",
}.issubset(pair)
for pair in leftover_thread.get("leftover_pairs", [])
)
for pair in leftover_thread.get("leftover_pairs", []):
person_axis_1 = pair["leftover_map_person_axis_1"]
person_axis_2 = pair["leftover_map_person_axis_2"]
item_axis_1 = pair["leftover_map_item_axis_1"]
item_axis_2 = pair["leftover_map_item_axis_2"]
axes = (person_axis_1, person_axis_2, item_axis_1, item_axis_2)
if any(axis is None for axis in axes):
assert axes == (None, None, None, None)
continue
for axis in axes:
assert isinstance(axis, (int, float))
assert not math.isnan(axis)
assert not math.isinf(axis)
reconstruction = pair.get("leftover_map_reconstruction")
if reconstruction is not None:
assert reconstruction == pytest.approx(
person_axis_1 * item_axis_1 + person_axis_2 * item_axis_2
)
assert pair["leftover_distance"] == pytest.approx(
math.hypot(person_axis_1 - item_axis_1, person_axis_2 - item_axis_2)
)


def test_seed_period_report_includes_fixture_event_lineage_posts(
Expand Down
Loading
Loading