Skip to content

feat: persist leftover interaction-map coordinates (v2.12.19) - #579

Open
seonghobae wants to merge 4 commits into
mainfrom
feat/persist-leftover-interaction-map-v21219
Open

feat: persist leftover interaction-map coordinates (v2.12.19)#579
seonghobae wants to merge 4 commits into
mainfrom
feat/persist-leftover-interaction-map-v21219

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Period reports now persist complete-case leftover interaction-map coordinates ξ / ζ after IRT main effects and render a 2D Jeon / Gabriel map above leftover pairs (ADR 0121 / 0126). Click a post node or a leftover-pair criterion node to open that post.

This restacks the unique 2D-map increment from #481 onto current main@b4911f8 as v2.12.19. Closest/farthest leftover pairs already live on main. Do not mix into #74/#92. #96 stays closed.

Buyer next action

After seed, the leftover interaction map sits above leftover pairs. Click a post node or a highlighted leftover-pair criterion to open that post.

Constraints

  • Rank-0 and rank-1 maps pad unused axes with zero. Do not invent a second component.
  • Hidden posts stay hidden (same ABAC gate as leftover pairs).
  • Never invent a leftover score or a theta.
  • Synthetic fixtures only.
  • Migration 0172_report_leftover_interaction_map.sql is four-digit replayed (ADR 0166).

Tests

  • leftover + SQL contract + migration replay: 39 passed
  • frontend LeftoverInteractionMap + i18n + App: 131 passed

Independent review required. Never self-approve. Squash-merge only with independent APPROVE + exact-head required success. Do not wait on Checks.


Open in Devin Review

After IRT main effects, persist complete-case ξ/ζ leftover-map
coordinates and render the 2D Jeon/Gabriel map above leftover
pairs (ADR 0121 / 0126). Click a post node or leftover-pair
criterion to open that post. Rank-0/1 maps pad unused axes
with zero. Hidden posts stay hidden. Never invent a leftover
score or a theta.
@coderabbitai

coderabbitai Bot commented Aug 24, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 37 minutes.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b6c7e930-9263-477a-ac89-1a81ac70224d

📥 Commits

Reviewing files that changed from the base of the PR and between fcd7cfd and 57b6ae8.

📒 Files selected for processing (36)
  • AGENTS.md
  • ARCHITECTURE.md
  • CHANGELOG.d/2.12.17-leftover-map-coverage.md
  • CHANGELOG.d/2.12.19-leftover-interaction-map.md
  • CHANGELOG.md
  • CLAUDE.md
  • backend/app/main.py
  • backend/app/report_ingestion.py
  • backend/tests/test_api.py
  • docs/adr/0048-persist-lsirm-leftover-pairs.md
  • docs/adr/0049-leftover-pair-report-ui.md
  • docs/adr/0121-persist-leftover-interaction-map.md
  • docs/adr/0126-leftover-map-criterion-node.md
  • docs/adr/0182-leftover-map-unexplained.md
  • docs/adr/0183-leftover-map-complete-case-coverage.md
  • docs/storybook-inventory.md
  • frontend/src/App.css
  • frontend/src/App.test.tsx
  • frontend/src/App.tsx
  • frontend/src/LeftoverInteractionMap.stories.tsx
  • frontend/src/LeftoverInteractionMap.test.tsx
  • frontend/src/LeftoverInteractionMap.tsx
  • frontend/src/api.ts
  • frontend/src/i18n.test.ts
  • frontend/src/i18n.ts
  • lineageweave/leftover_pairs.py
  • lineageweave/period_report.py
  • migrations/0168_report_leftover_map_coverage.sql
  • migrations/0172_report_leftover_interaction_map.sql
  • migrations/rollback/0172_report_leftover_interaction_map.sql
  • scripts/seed_demo_data.py
  • tests/test_leftover_pairs.py
  • tests/test_migration_replay.py
  • tests/test_period_report.py
  • tests/test_schema.py
  • tests/test_static_sql_review_contracts.py

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copy link
Copy Markdown
Contributor Author

Requesting independent review on exact head 8640199. Closest/farthest leftover pairs already live on main; this increment only persists leftover-map ξ/ζ and renders the 2D map. Hidden posts stay hidden. Never invent leftover score/theta. Never self-approve. Squash-merge only with independent APPROVE + exact-head required success. Do not wait on Checks.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Devin Review found 3 potential issues.

Open in Devin Review

Comment thread backend/app/main.py
Comment on lines +2388 to +2392
leftover_map_persons = [
{key: value for key, value in person.items() if key != "has_real_source_context"}
for person in leftover_map_persons
]
leftover_map_items = list(report.get("leftover_map_items", []))

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: Leftover-map criterion nodes are not ABAC filtered, but cannot leak

In read_period_reports, leftover_map_persons are ABAC/demo filtered while leftover_map_items pass through unfiltered. This is safe: items carry only criterion_code and coordinates, and a criterion node opens a post only through leftoverPairForCriterion over the already-filtered leftover_pairs. A hidden post's pair is removed, leaving its criterion non-interactive. Consistent with ADR 0121, which gates only persons.

Open in Devin Review

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

Comment on lines +463 to +494
for person in report.leftover_map_persons:
await conn.execute(
"""
insert into report_leftover_map_person (
grouping_kind, grouping_key, period_code, rubric_version,
post_id, axis_one, axis_two
) values ($1,$2,$3,$4,$5,$6,$7)
""",
grouping_kind,
grouping_key,
period_code,
RUBRIC_VERSION,
person.post_id,
person.axis_one,
person.axis_two,
)
for item in report.leftover_map_items:
await conn.execute(
"""
insert into report_leftover_map_item (
grouping_kind, grouping_key, period_code, rubric_version,
criterion_code, axis_one, axis_two
) values ($1,$2,$3,$4,$5,$6,$7)
""",
grouping_kind,
grouping_key,
period_code,
RUBRIC_VERSION,
item.criterion_code,
item.axis_one,
item.axis_two,
)

@devin-ai-integration devin-ai-integration Bot Aug 24, 2026

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: Map-row FKs depend on in-transaction insert order

report_leftover_map_person references report_member_score and report_leftover_map_item references report_item_information. Both persist paths insert member scores and item information before the map rows in one transaction, so immediate FK checks pass. Map persons/items are always subsets of those rows (same fit post_ids; selected_items ranks every bank item), so the constraints hold across free-calibrate, FIPC, and shared-metric reports.

Open in Devin Review

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

Comment thread lineageweave/leftover_pairs.py Outdated
@opencode-agent
opencode-agent Bot disabled auto-merge August 24, 2026 11:12
@seonghobae
seonghobae enabled auto-merge August 24, 2026 11:49
…-interaction-map-v21219

# Conflicts:
#	AGENTS.md
#	ARCHITECTURE.md
#	CHANGELOG.md
#	CLAUDE.md
#	backend/app/main.py
#	backend/app/report_ingestion.py
#	backend/tests/test_api.py
#	frontend/src/App.test.tsx
#	frontend/src/App.tsx
#	frontend/src/api.ts
#	lineageweave/leftover_pairs.py
#	lineageweave/period_report.py
#	scripts/seed_demo_data.py
#	tests/test_leftover_pairs.py
#	tests/test_migration_replay.py
#	tests/test_period_report.py
#	tests/test_schema.py
@opencode-agent
opencode-agent Bot disabled auto-merge August 24, 2026 16:51

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Devin Review found 2 new potential issues.

Open in Devin Review

Comment thread lineageweave/period_report.py
@@ -0,0 +1,9 @@
## 2.12.19 — Persist leftover interaction-map coordinates

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: Version naming inconsistency in changelog fragment

package.json/pyproject.toml and CHANGELOG.md ship 2.12.20, but the PR title and the CHANGELOG.d fragment (filename and its ## 2.12.19 header) say 2.12.19. Documentation-only, no functional impact.

Open in Devin Review

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

@seonghobae
seonghobae enabled auto-merge August 24, 2026 17:03
@github-actions
github-actions Bot disabled auto-merge August 24, 2026 17:29
@seonghobae
seonghobae enabled auto-merge August 24, 2026 17:37
@opencode-agent
opencode-agent Bot disabled auto-merge August 24, 2026 17:59
…wave 2 conflict resolution)

# Conflicts:
#	AGENTS.md
#	ARCHITECTURE.md
#	CHANGELOG.md
#	CLAUDE.md
#	backend/tests/test_api.py
#	frontend/package.json
#	lineageweave/leftover_pairs.py
#	pyproject.toml
#	scripts/seed_demo_data.py
#	tests/test_leftover_pairs.py
#	tests/test_period_report.py
#	tests/test_schema.py
#	uv.lock
@seonghobae
seonghobae enabled auto-merge August 24, 2026 18:40

Copy link
Copy Markdown
Contributor Author

Cycle 2026-08-25T04:01 KST: leftover interaction-map coordinates remain independent of leftover-share/reconstruction stacks. Independent exact-head APPROVE required. This identity will not self-approve. Squash-merge only with independent APPROVE + exact-head required success.

Copy link
Copy Markdown
Contributor Author

Cycle comment: leftover-map coordinates (#579) still waits for independent APPROVE + exact-head required success. Do not self-approve. Recutting leftover-map length onto protected main as independent v2.12.31 / ADR 0187 (0183–0186 remain claimed by open leftover PRs). Never mix reconstruction/share/cosine/inner-product/coordinates into that recut.

@opencode-agent
opencode-agent Bot disabled auto-merge August 24, 2026 19:26

Copy link
Copy Markdown
Contributor Author

Cycle comment: leftover increment still waits for independent APPROVE + exact-head required success. Author must not self-approve. Do not squash-merge without that APPROVE. Recut leftover-map length onto protected main as independent v2.12.31 / ADR 0187 (0183–0186 claimed by open leftover share/reconstruction PRs). Do not mix leftover stacks. Issues #79 and #87 stay open.

# Conflicts:
#	AGENTS.md
#	ARCHITECTURE.md
#	backend/app/report_ingestion.py
#	backend/tests/test_api.py
#	frontend/src/App.test.tsx
#	frontend/src/App.tsx
#	frontend/src/i18n.test.ts
#	lineageweave/leftover_pairs.py
#	lineageweave/period_report.py
#	scripts/seed_demo_data.py
#	tests/test_leftover_pairs.py
#	tests/test_schema.py

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Devin Review found 2 new potential issues.

Open in Devin Review

Comment on lines 232 to +248
)
)
if not candidates:
# ADR 0168: without a complete-case Gabriel map there is no
# ADR 0183: without a complete-case Gabriel map there is no
# leftover pair to name. The report carries coverage counts
# instead of a center-distance stand-in pair.
return (), ()
return LeftoverInteractionMap(pairs=(), persons=persons, items=items, axes=axes)
closest = min(candidates, key=lambda row: (row[0], row[1], row[2]))
farthest = max(candidates, key=lambda row: (row[0], row[1], row[2]))
pairs = (
_pair_from_candidate(PAIR_KIND_CLOSEST, closest, leftover_map_rank),
_pair_from_candidate(PAIR_KIND_FARTHEST, farthest, leftover_map_rank),
return LeftoverInteractionMap(
pairs=(
_pair_from_candidate(PAIR_KIND_CLOSEST, closest, leftover_map_rank),
_pair_from_candidate(PAIR_KIND_FARTHEST, farthest, leftover_map_rank),
),
persons=persons,
items=items,
axes=axes,

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: Map coordinates and pair distances share one basis

leftover_map_from_residual emits person/item coordinates from the same padded two-axis arrays used for the closest/farthest pair distances, so persisted node positions and pair distances stay mutually consistent and hidden higher SVD components cannot shift a visible pair off the map. Confirmed by test_rank_three_pair_distances_match_the_persisted_two_axis_map.

(Refers to this code)

Open in Devin Review

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

Comment on lines +465 to +496
for person in report.leftover_map_persons:
await conn.execute(
"""
insert into report_leftover_map_person (
grouping_kind, grouping_key, period_code, rubric_version,
post_id, axis_one, axis_two
) values ($1,$2,$3,$4,$5,$6,$7)
""",
grouping_kind,
grouping_key,
period_code,
RUBRIC_VERSION,
person.post_id,
person.axis_one,
person.axis_two,
)
for item in report.leftover_map_items:
await conn.execute(
"""
insert into report_leftover_map_item (
grouping_kind, grouping_key, period_code, rubric_version,
criterion_code, axis_one, axis_two
) values ($1,$2,$3,$4,$5,$6,$7)
""",
grouping_kind,
grouping_key,
period_code,
RUBRIC_VERSION,
item.criterion_code,
item.axis_one,
item.axis_two,
)

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: Map rows rely on period-score cascade for cleanup

persist_period_report adds no explicit delete for the new map tables; it relies on the on delete cascade FK to report_period_score, which it deletes first (same pattern as pairs/axes/coverage). Insert order satisfies the composite FKs (members before map persons, item_information before map items), so rebuild stays idempotent.

Open in Devin Review

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

@seonghobae
seonghobae enabled auto-merge August 24, 2026 22:56
@github-actions
github-actions Bot disabled auto-merge August 24, 2026 23:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant