Skip to content

feat: name leftover-map reconstruction on leftover pairs (v2.12.30) - #564

Open
seonghobae wants to merge 6 commits into
mainfrom
feat/leftover-map-reconstruction-v21230
Open

feat: name leftover-map reconstruction on leftover pairs (v2.12.30)#564
seonghobae wants to merge 6 commits into
mainfrom
feat/leftover-map-reconstruction-v21230

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Buyer next action

After make seed, leftover post–criterion pairs sit above the member list with leftover-map reconstruction next to leftover-map distance d. Click the pair to open that post. The reconstruction badge is omitted when the pair has no complete-case leftover map (fallback rows do not invent a reconstruction). A signed reconstruction is shown, never clamped. Never invent leftover score or theta.

A leftover residual R is not the leftover the two leftover-map axes reconstruct. Gabriel (1971) reconstructs a centered matrix as the inner product of person and item coordinates. Two leftover-map axes pad unused axes with zero and drop hidden SVD axes after the second, so reconstruction R̂_c = ξ_{1:2} · ζ_{1:2} recovers centered leftover R̃ = R − center, not raw residual R and not leftover-map distance d. Rank-0 origin maps store R̂ = 0. A rank-1 cell stores exact centered leftover. A rank-3+ cell stores truncated reconstruction, which is not R and not d.

Scope (this PR only)

  • ADR 0186 leftover-map reconstruction
  • migration 0186 nullable leftover_map_reconstruction on leftover pair rows (no nonnegative CHECK)
  • persist/fetch/seed leftover_map_reconstruction when complete-case ξ, ζ exist (R̂_c = ξ_{1:2} · ζ_{1:2}; unused axes pad with 0; hidden SVD axes after the second are dropped)
  • frontend badge + named reconstruction next action; i18n en/ko/zh/ja/vi
  • rank-1 cell reconstruction equals centered leftover; rank-4 synthetic residual proves R̂ ≠ R, ≠ leftover_distance, and full-rank inner product; leftover_distance stays two-axis Euclidean
  • rank-0 maps store R̂ = 0; fallback omits reconstruction; negative finite reconstruction is stored
  • do not persist leftover_map_explained_share, leftover_map_unexplained_share, leftover_map_unexplained, leftover_map_cross_share, or leftover-map coordinates
  • release 2.12.30

Independent of leftover stacks already in review

Do not mix into:

Independent exact-head APPROVE required. Do not self-approve. Squash-merge only with independent APPROVE + exact-head required success.

Verification

  • uv run --with pytest --with numpy pytest tests/test_leftover_pairs.py — 13 passed
  • frontend leftover formatters, LeftoverPairList, i18n, and App.test leftover report surface — 133 passed

Open in Devin Review

Persist two-axis Gabriel reconstruction R̂ of centered leftover on
closest and farthest leftover pairs so buyers can read reconstructed
leftover next to distance d, then open that post.
@coderabbitai

coderabbitai Bot commented Aug 24, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 16 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: d202d22e-9080-4e32-8d8e-50bb1c7390aa

📥 Commits

Reviewing files that changed from the base of the PR and between b5c5620 and 62d3e12.

📒 Files selected for processing (27)
  • AGENTS.md
  • ARCHITECTURE.md
  • CHANGELOG.d/2.12.30-leftover-map-reconstruction.md
  • CHANGELOG.md
  • CLAUDE.md
  • backend/app/report_ingestion.py
  • backend/tests/test_api.py
  • docs/adr/0003-fast-mlsirm-report-integration.md
  • docs/adr/0048-persist-lsirm-leftover-pairs.md
  • docs/adr/0049-leftover-pair-report-ui.md
  • docs/adr/0186-leftover-map-reconstruction.md
  • frontend/src/App.test.tsx
  • frontend/src/api.ts
  • frontend/src/components/LeftoverPairList.stories.tsx
  • frontend/src/components/LeftoverPairList.test.tsx
  • frontend/src/components/LeftoverPairList.tsx
  • frontend/src/i18n.test.ts
  • frontend/src/i18n.ts
  • frontend/src/leftoverMapReconstruction.test.ts
  • frontend/src/leftoverMapReconstruction.ts
  • lineageweave/leftover_pairs.py
  • migrations/0186_report_leftover_map_reconstruction.sql
  • migrations/rollback/0186_report_leftover_map_reconstruction.sql
  • scripts/seed_demo_data.py
  • tests/test_leftover_pairs.py
  • tests/test_period_report.py
  • tests/test_schema.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.

@seonghobae
seonghobae enabled auto-merge (squash) August 24, 2026 05:21

Copy link
Copy Markdown
Contributor Author

Cycle 2026-08-24: pushed exact head ac5de72 as independent leftover-map reconstruction (ADR 0186, v2.12.30) onto main. Copilot review requested. Auto-merge armed squash; still blocked on independent exact-head APPROVE. Do not self-approve. Do not mix into #481/#485/#535/#537/#539/#563 leftover stacks.

Local verification: leftover pair unit tests 13 passed; frontend leftover formatters + LeftoverPairList + i18n + App leftover surface 133 passed. Synthetic fixtures only.

@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 tests/test_leftover_pairs.py
Comment thread frontend/src/components/LeftoverPairList.tsx
Comment on lines +155 to +167
def _leftover_map_reconstruction(
person_xy: np.ndarray, item_xy: np.ndarray
) -> float | None:
"""Return two-axis reconstruction ``R̂_c = ξ_{1:2} · ζ_{1:2}`` when finite.

Rank-0 origin coordinates store ``0.0``. A non-finite inner product
is omitted rather than invented. Negative finite reconstruction is
stored; do not clamp or take an absolute value.
"""
reconstruction = float(np.dot(person_xy, item_xy))
if np.isfinite(reconstruction):
return reconstruction
return None

@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: Rank-0 maps store R̂=0, fallback stores None

A rank-0 residual still yields zero coordinate arrays (not None), so the complete-case branch runs and _leftover_map_reconstruction returns 0.0, matching ADR 0186 and test_leftover_pairs.py. Only the no-complete-case fallback path passes None.

Open in Devin Review

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

@opencode-agent
opencode-agent Bot disabled auto-merge August 24, 2026 05:42
@seonghobae
seonghobae enabled auto-merge (squash) August 24, 2026 08:03
@opencode-agent
opencode-agent Bot disabled auto-merge August 24, 2026 08:42
@seonghobae
seonghobae enabled auto-merge August 24, 2026 09:12

Copy link
Copy Markdown
Contributor Author

Leftover-map persist+2D UI restack is now #579 (v2.12.19, ADR 0121/0126) on main@b4911f8. Reconstruction naming on leftover pairs stays a later increment after that persist lands. Do not mix into #74/#92. Independent review only — never self-approve.

@github-actions
github-actions Bot disabled auto-merge August 24, 2026 10:55
@seonghobae
seonghobae enabled auto-merge August 24, 2026 11:50
# Conflicts:
#	AGENTS.md
#	ARCHITECTURE.md
#	CHANGELOG.md
#	CLAUDE.md
#	backend/tests/test_api.py
#	docs/adr/0003-fast-mlsirm-report-integration.md
#	frontend/package.json
#	lineageweave/leftover_pairs.py
#	pyproject.toml
#	tests/test_leftover_pairs.py
#	tests/test_period_report.py
#	tests/test_schema.py
#	uv.lock
@github-actions
github-actions Bot disabled auto-merge August 24, 2026 15:53
@seonghobae
seonghobae enabled auto-merge August 24, 2026 15:55
@opencode-agent
opencode-agent Bot disabled auto-merge August 24, 2026 16:51
@seonghobae
seonghobae enabled auto-merge August 24, 2026 17:04
@opencode-agent
opencode-agent Bot disabled auto-merge August 24, 2026 17:58
…onstruction-v21230

# Conflicts:
#	AGENTS.md
#	ARCHITECTURE.md
#	CHANGELOG.md
#	CLAUDE.md
#	backend/app/report_ingestion.py
#	backend/tests/test_api.py
#	docs/adr/0003-fast-mlsirm-report-integration.md
#	docs/adr/0048-persist-lsirm-leftover-pairs.md
#	docs/adr/0049-leftover-pair-report-ui.md
#	frontend/package.json
#	frontend/src/App.test.tsx
#	frontend/src/api.ts
#	frontend/src/components/LeftoverPairList.tsx
#	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

@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 1 new potential issue.

Open in Devin Review

Comment on lines +70 to +73
} else if (reconstructionBadge !== null) {
nextAction = tf(LEFTOVER_RECONSTRUCTION_ACTION, {
reconstruction: reconstructionBadge.replace(/^R̂\s+/, ""),
});

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: Reconstruction next-action text unreachable for real payloads

The reconstruction branch in LeftoverPairList sits below the unexplained branch. Backend code sets leftover_map_unexplained (U = R − R̂) whenever reconstruction is finite, so real payloads always take the unexplained branch and LEFTOVER_RECONSTRUCTION_ACTION renders only for synthetic fixtures where reconstruction is set but unexplained is null. The badge still renders independently, so this is display-text-only, not a defect.

Open in Devin Review

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

@seonghobae
seonghobae enabled auto-merge August 24, 2026 18:45
@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.

Copy link
Copy Markdown
Contributor Author

Cycle 2026-08-25T07:05 KST: #564 stays independent. It must not mix with leftover stacks #485 / #518 / #521 / #537 / #539 / #563 / #579.

Landed ADR 0182 already defines unexplained leftover as U = R − R̂ with the same two-axis inner product used for leftover-map distance. That identity only holds when persisted reconstruction is that internal , not a separately centered .

This cycle therefore opens a fresh main-based persist of leftover-map reconstruction so U + R̂ = R remains auditable. Do not squash-merge #564 onto that work. Independent exact-head APPROVE required. Author will not self-approve.

# Conflicts:
#	AGENTS.md
#	ARCHITECTURE.md
#	frontend/package.json
#	lineageweave/leftover_pairs.py
#	pyproject.toml
#	tests/test_leftover_pairs.py
#	uv.lock

Copy link
Copy Markdown
Contributor Author

Independent leftover stack — do not mix. This cycle implements uncentered leftover-map reconstruction R̂ = ξ_{1:2} · ζ_{1:2} on current main (ADR 0183 / v2.12.31) so landed U + R̂ = R stays auditable. #564 remains the centered-R̃ reconstruction (ADR 0186 / v2.12.30) and is not rebased, amended, or squash-merged into this increment. Do not substitute centered R̃ for the reconstruction used to form unexplained leftover U (ADR 0182).

Copy link
Copy Markdown
Contributor Author

Independent leftover stack — do not mix.

Uncentered leftover-map reconstruction persist is now #588 (ADR 0183 / v2.12.31) on current main so landed U + R̂ = R stays auditable. #564 remains the centered- reconstruction (ADR 0186 / v2.12.30) and is not rebased, amended, or squash-merged into that increment.

@seonghobae
seonghobae enabled auto-merge August 24, 2026 22:46
@github-actions
github-actions Bot disabled auto-merge August 24, 2026 22:56
@seonghobae
seonghobae enabled auto-merge August 24, 2026 22:57
@opencode-agent
opencode-agent Bot disabled auto-merge August 24, 2026 23:38
@seonghobae
seonghobae enabled auto-merge August 25, 2026 00:22
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