Skip to content

feat: name leftover-map explained share on leftover pairs (v2.12.28) - #539

Closed
seonghobae wants to merge 15 commits into
mainfrom
feat/leftover-map-explained-share-v21228
Closed

feat: name leftover-map explained share on leftover pairs (v2.12.28)#539
seonghobae wants to merge 15 commits into
mainfrom
feat/leftover-map-explained-share-v21228

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Buyer next action

After make seed, leftover post–criterion pairs sit above the member list with explained leftover share R̂²/R̃² next to leftover-map distance d. Click the pair to open that post. The share badge is omitted when the pair has no complete-case leftover map (fallback rows do not invent a share). Never invent leftover score or theta.

A leftover residual R is not the leftover the two leftover-map axes reconstruct. Explained leftover share names e = R̂_c² / R̃² of centered leftover R̃ = R − center after two-axis reconstruction R̂_c = ξ_{1:2} · ζ_{1:2}. Using raw R in the denominator leaves the grand mean inside the named leftover, so a fully reconstructed rank-1 cell would look only partly explained whenever center ≠ 0. This PR centers first. Per-cell e is not 1 − s: truncated two-axis reconstruction keeps a cross term 2 R̂_c U_c. R̂_c and U_c stay internal and are not persisted.

A 0/0 origin cell (R̃ = 0 and R̂_c = 0) stores e = 0, including the origin cell of a rank-1 map. A reconstructed nonzero rank-1 cell stores e = 1 even when mean(R) ≠ 0.

Scope (this PR only)

  • ADR 0184 leftover-map explained leftover share
  • migration 0184 nullable leftover_map_explained_share on leftover pair rows
  • persist/fetch/seed leftover_map_explained_share when complete-case ξ, ζ exist (e = R̂_c² / R̃²; unused axes pad with 0; hidden SVD axes after the second are dropped)
  • frontend R̂²/R̃² badge + named next action; i18n en/ko/zh/ja/vi
  • rank-1 nonzero cell share is 1 even when mean(R) ≠ 0; rank-3 synthetic residual proves e ≠ R, ≠ leftover_distance, and e + s ≠ 1 (cross term); leftover_distance stays full-rank Euclidean
  • rank-0 maps store e = 0; fallback omits share
  • do not persist leftover_map_unexplained_share, leftover_map_unexplained, or leftover_map_reconstruction
  • tsc: optional AdminPanel accessToken (login screen has no token) and drop unused oidcReturnUrl import so leftover UI typechecks
  • release 2.12.28

Independent of leftover stacks already in review

Do not mix into:

Merge contract


Open in Devin Review

Summary by CodeRabbit

  • 새 기능

    • 잔여 쌍에 잔여 지도 설명 비율과 거리를 함께 표시합니다.
    • 유효한 설명 비율이 있는 경우 관련 기준 문항을 클릭해 바로 열 수 있습니다.
    • 한국어·중국어·일본어·베트남어 안내 문구를 지원합니다.
    • API가 잔여 지도 설명 비율을 제공합니다.
  • 개선 사항

    • 설명 비율이 없거나 유효하지 않으면 기존 가까운 쌍·먼 쌍 안내를 유지합니다.
    • 잔여 쌍 정보 저장 및 조회를 안정화했습니다.
    • 버전을 2.12.28로 업데이트했습니다.

Persist explained leftover share e = R̂_c² / R̃² of centered leftover
on leftover post–criterion pairs (ADR 0184). Two-axis reconstruction
R̂_c stays internal. A reconstructed rank-1 cell stores share 1 even
when mean(R) ≠ 0. A 0/0 origin cell stores 0. Fallback omits the share.
Do not persist leftover-map unexplained leftover share s or reconstruction R̂.
@coderabbitai

coderabbitai Bot commented Aug 23, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

Next included review available in 40 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: cdbb5e3d-7b3d-4b57-84f5-9bf93cdb6d18

📥 Commits

Reviewing files that changed from the base of the PR and between b15d0ee and e4dffe6.

📒 Files selected for processing (26)
  • AGENTS.md
  • ARCHITECTURE.md
  • CHANGELOG.d/2.12.28-leftover-map-explained-share.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/0185-leftover-map-explained-share.md
  • frontend/src/App.test.tsx
  • frontend/src/api.ts
  • frontend/src/components/AdminPanel.tsx
  • frontend/src/components/LeftoverPairList.tsx
  • frontend/src/i18n.test.ts
  • frontend/src/i18n.ts
  • frontend/src/leftoverMapExplainedShare.test.ts
  • frontend/src/leftoverMapExplainedShare.ts
  • lineageweave/leftover_pairs.py
  • migrations/0185_report_leftover_map_explained_share.sql
  • migrations/rollback/0185_report_leftover_map_explained_share.sql
  • scripts/seed_demo_data.py
  • tests/test_leftover_pairs.py
  • tests/test_period_report.py
  • tests/test_schema.py
📝 Walkthrough

Walkthrough

잔여 쌍 계산이 centered leftover 기반 설명 공유율 e를 생성하도록 변경되었습니다. 공유율은 마이그레이션을 통해 저장되고 API와 다국어 UI에서 거리 및 기준 문항과 함께 표시됩니다.

Changes

잔여 맵 설명 공유

Layer / File(s) Summary
설명 공유율 계산 및 검증
lineageweave/leftover_pairs.py, tests/test_leftover_pairs.py, tests/test_period_report.py, docs/adr/*
2축 Gabriel 재구성에서 centered leftover 설명 공유율을 계산합니다. rank-0, fallback, 결측 셀, 비유한 값과 2축 패딩 동작을 검증합니다.
스키마·저장·API 연결
migrations/*, backend/app/report_ingestion.py, scripts/seed_demo_data.py, docker/postgres-init/migrate.sh, backend/tests/test_api.py, tests/test_schema.py, tests/test_migration_replay.py
leftover_map_explained_share nullable 컬럼과 음수 방지 제약을 추가합니다. 시드 저장, 보고서 조회, API 직렬화 및 마이그레이션 테스트를 갱신합니다.
UI 표시 및 릴리스 반영
frontend/src/App.tsx, frontend/src/api.ts, frontend/src/leftoverMapExplainedShare.ts, frontend/src/i18n.ts, frontend/src/*test*, frontend/src/components/AdminPanel.tsx, CHANGELOG*, AGENTS.md, ARCHITECTURE.md, CLAUDE.md, pyproject.toml, frontend/package.json
유효한 공유율을 R̂²/R̃² 형식으로 표시하고, 누락 시 기존 안내를 유지합니다. 잔여 쌍 라벨과 안내를 한국어·중국어·일본어·베트남어로 추가하고 버전을 2.12.28로 변경합니다.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: 🟡 Moderate · up to b15d0

The PR adds persisted explained-share values and new badges, but valid small rank-1 cells can display 0% and very large inputs can produce invalid values, leading to incorrect user-facing explanations. Merge should wait for the calculation fix and regression coverage.

Sequence Diagram(s)

sequenceDiagram
  participant Seed as seed_demo_data.py
  participant Report as persist_period_report
  participant Database as report_leftover_pair
  participant API as fetch_period_reports
  participant Browser as App.tsx

  Seed->>Report: leftover pair 및 explained share 전달
  Report->>Database: leftover_map_explained_share 저장
  Database-->>API: 저장된 leftover pair 조회
  API-->>Browser: leftover_map_explained_share 포함 응답
  Browser->>Browser: 공유율·거리·criterion 표시
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 leftover pair에 leftover-map explained share를 명명하고 추가하는 주요 변경 사항을 정확하고 간결하게 요약합니다.
Docstring Coverage ✅ Passed Docstring check was indeterminate for this PR — some files could not be analyzed in time. Not blocking.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/leftover-map-explained-share-v21228

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.

devin-ai-integration[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

Squaring before the 1e-12 comparison made the effective singular
threshold sqrt(1e-12) = 1e-6, collapsing small-but-valid rank-1 cells
to share 0, and could overflow large finite inputs to inf. Compare
absolute values first, compute the ratio once, and persist only a
finite, non-negative result. Adds regression tests for both edges
(devin review thread PRRT_kwDOT22WIM6bi4hz).
devin-ai-integration[bot]

This comment was marked as resolved.

… share

- floor the explained share on absolute magnitudes so a small-but-valid
  rank-1 cell keeps its share and large finite inputs cannot overflow to
  inf; add regression tests for both edges
- show the centered-reconstruction subscript (R-hat_c squared over
  R-tilde squared) in the share badge so UI notation matches the ADR
  definition; update badge tests
- build the pair aria-label from the localized kind label so screen
  readers stop reading raw closest/farthest enums, mirroring visible text
- smooth Korean next-action copy ({value}만큼, 주효과 이후 가장 가까운/먼
  기준) and update i18n expectations
- align ADR 0049's screen-reader contract with the criterion-bearing
  label this increment ships

devin review threads on PR #539.
devin-ai-integration[bot]

This comment was marked as resolved.

Resolves 23 conflicts against a main that had moved well past this
branch's base, including several already-landed leftover-map
amendments (ADR 0119/0162/0163/0164) this branch predated.

Key resolutions:
- lineageweave/leftover_pairs.py: combined ADR 0184's explained-share
  computation with the already-landed observed/expected/rank
  tracking -- LeftoverPair now carries all of it. Both
  _candidate_row and _pair_from_candidate needed their signatures
  widened to a 7-element candidate row.
- tests/test_leftover_pairs.py: two tests (rank-three explained-share,
  rank-four map-vs-full distance) shared identical 4x4 matrix setup by
  coincidence but tested different things -- split into two complete,
  independent test functions instead of forcing one merge. Found and
  fixed a real pre-existing bug in the rank-three test along the way:
  it asserted leftover_distance equals the *full*-rank Gabriel
  distance, which directly contradicts the already-established (and
  now doubly-tested) 2-axis-map behavior documented in the module's
  own docstring.
- frontend/src/App.tsx: took main's <LeftoverPairList> component
  (already established during a separate merge) over this branch's
  now-superseded inline <ul> rendering; extended LeftoverPairList
  itself with the explained-share tier so the feature isn't lost.
- backend/app/report_ingestion.py, scripts/seed_demo_data.py: both
  insert/select statements needed the full column set (residual,
  observed/expected, rank, explained share) merged together.
- 9 doc files (AGENTS.md, ARCHITECTURE.md, CLAUDE.md, ADR 0048/0049,
  CHANGELOG.md, migrate.sh): additive concatenation of amendment
  descriptions, matching the fixed-lower-bound migrate.sh pattern
  already established elsewhere.
- Fixed two pre-existing (unconflicted, untouched by either side)
  App.test.tsx assertions that predated the LeftoverPairList
  component swap and checked a stale aria-label word order.

Verified: tests/ (789 passed, 11 skipped), backend/tests/ (130
passed, 5 skipped -- docker-stack-gated), frontend (234 passed), tsc
clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NpWw9SnPBaemFZmW3fdTVM
devin-ai-integration[bot]

This comment was marked as resolved.

@seonghobae
seonghobae enabled auto-merge August 24, 2026 14:54
@github-actions
github-actions Bot disabled auto-merge August 24, 2026 15:07
# 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
@seonghobae
seonghobae enabled auto-merge August 24, 2026 16:13
@opencode-agent
opencode-agent Bot disabled auto-merge August 24, 2026 16:50
@seonghobae
seonghobae enabled auto-merge August 24, 2026 17:04
@opencode-agent
opencode-agent Bot disabled auto-merge August 24, 2026 17:58
# 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
#	frontend/src/i18n.test.ts
#	frontend/src/i18n.ts
#	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:46
github-code-quality[bot]

This comment was marked as resolved.

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

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.

devin-ai-integration[bot]

This comment was marked as resolved.

The identical redefinition at the bottom of the file silently shadowed
the first, so pytest collected it once but code-quality flagged the
dead assignment. Review follow-up on this PR's thread.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VENX71RtEntaUq6nkAWZho
@seonghobae

Copy link
Copy Markdown
Contributor Author

Addressed in the pushed commit: the identical redefinition of test_pad_map_axes_truncates_hidden_svd_components is removed (it shadowed the first definition). On the U-vs-e note: intentional per the ADR — U is the raw-residual unexplained leftover while e is the centered leftover the map plots; the docstrings state each. File suite 23/23 locally.

devin-ai-integration[bot]

This comment was marked as resolved.

seonghobae and others added 2 commits August 25, 2026 08:12
# Conflicts:
#	AGENTS.md
#	CHANGELOG.md
#	lineageweave/leftover_pairs.py
#	tests/test_leftover_pairs.py
The branch's ADR 0184 collided with main's
0184-ontology-provenance-explorer after the main merge; the
explained-share ADR and every reference to it (AGENTS, ARCHITECTURE,
CHANGELOG + fragment, module and component docstrings, tests) now use
0185. Also updates the sparse-map test to the ADR 0168 contract merged
on main: no complete-case rectangle names no pairs at all, so the
old omit-share fallback assertion is replaced by the empty-pairs
contract. hygiene+leftover+schema suites 42/42.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VENX71RtEntaUq6nkAWZho
devin-ai-integration[bot]

This comment was marked as resolved.

The prior renumbering (ADR 0184 -> 0185) only touched the ADR file
and left the migration/rollback pair, several cross-references, and
one broken relative link (ADR 0049) still pointing at 0184. It also
blind-replaced 0184->0185 in AGENTS.md/ARCHITECTURE.md/CHANGELOG.md
without distinguishing the unrelated ontology-provenance-explorer
ADR, which still legitimately owns 0184 -- those got reverted back.

Migration and rollback files renamed 0184 -> 0185 to match the ADR
number (matches the codebase's established one-number-per-slice
convention), with every test/script path reference updated.
@github-actions
github-actions Bot disabled auto-merge August 24, 2026 23:37
@seonghobae
seonghobae enabled auto-merge (squash) August 24, 2026 23:48
devin-ai-integration[bot]

This comment was marked as resolved.

@github-actions
github-actions Bot disabled auto-merge August 25, 2026 00:12
@seonghobae

Copy link
Copy Markdown
Contributor Author

Thread dispositions: the badge's compact R̂c²/R̃² is the UI-width form of the docs' e = R̂_c² / R̃² — same quantity, subscript flattened for badge width; AGENTS.md and the tests carry the canonical form. The floor-guard note confirms intended behavior. Resolving both.

@seonghobae
seonghobae enabled auto-merge (squash) August 25, 2026 01:07
@github-actions
github-actions Bot disabled auto-merge August 25, 2026 01:37
devin-ai-integration[bot]

This comment was marked as resolved.

# Conflicts:
#	AGENTS.md
#	ARCHITECTURE.md
#	docs/adr/0049-leftover-pair-report-ui.md
@seonghobae
seonghobae enabled auto-merge August 25, 2026 01:57
The 7-element tuple passed only because the negative-rank guard raised
before _pair_from_candidate read row[7]; the row now carries all 8
elements so the test exercises the guard, not an IndexError shield.
Review follow-up on this PR's thread.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VENX71RtEntaUq6nkAWZho
@seonghobae

Copy link
Copy Markdown
Contributor Author

Both threads addressed: the negative-rank test now passes a full 8-element candidate row (pushed), so it exercises the guard instead of surviving by short-circuit; and the comparison strip's reduced payload is the established contract — rank, observed/expected, and unexplained are likewise report-panel-only, with the strip carrying distance+residual and the full detail one click away on the named post. Resolving.

@opencode-agent
opencode-agent Bot disabled auto-merge August 25, 2026 03:40
@seonghobae

Copy link
Copy Markdown
Contributor Author

Closed because protected main now normatively rejects this per-cell share alias. ADR 0003 defines the auditable raw-residual identity through U = R − R̂ and x = 2 R̂U/R², and explicitly says not to persist explained share e or unexplained share s. Keeping this branch open would conflict with the accepted exact-main measurement contract.

@seonghobae seonghobae closed this Aug 25, 2026
seonghobae added a commit that referenced this pull request Aug 25, 2026
…588)

* feat: name leftover-map reconstruction on leftover pairs (v2.12.31)

Persist two-axis Gabriel reconstruction R̂ = ξ_{1:2} · ζ_{1:2} on
period leftover pairs so landed unexplained leftover U = R − R̂ stays
auditable as U + R̂ = R (ADR 0183). Reconstruction is the same internal
two-axis inner product already used for U; do not substitute the
centered R̃ reconstruction claimed by leftover stack #564.

After make seed, closest and farthest leftover pairs sit above the
member list with signed R̂ next to leftover-map distance d; click opens
that post. Missing or non-finite reconstruction omits the badge rather
than inventing a leftover score. Signed reconstruction is stored, never
clamped. Complete-case coverage (ADR 0168) stays independent.

Independent of leftover stacks #485, #518 (landed), #521, #537, #539,
#563, #564, and #579.

* fix(adr): allocate reconstruction decision 0201

* fix: restore R̂-persistence docs and finish ADR 0183→0201 renumbering

The prior merge of origin/main into this branch (91d8e4f) resolved the
AGENTS.md/ARCHITECTURE.md/CLAUDE.md conflicts by dropping this PR's own
leftover-map reconstruction documentation:

- AGENTS.md reverted to "Two-axis reconstruction R̂ is not persisted",
  contradicting the shipped migration/ADR 0201 that persists it, and
  dropped ADR 0201 from the governing-ADR list.
- ARCHITECTURE.md kept a redundant "0183 / 0201" pair (0183 is this
  repo's real, unrelated ADR 0183 "GNB four Korean chrome"; the stale
  0183 leftover-map reference should have been renumbered to 0201, not
  kept alongside it).
- CLAUDE.md's "Where the rest lives" pointer never got the ADR 0201
  cross-reference added.

Also finishes the ADR-number renumbering the PR's own history had
started (docs/adr/0201-leftover-map-reconstruction.md is the actual
ADR; ADR 0183 already belongs to a different, already-landed decision
on main): fixes remaining stale "ADR 0183" citations in
docs/adr/0003, the 2.12.31 CHANGELOG.d fragment, and the migration
0183 SQL header comment, all of which should cite ADR 0201.

docs/adr/0049's own conflict resolution (0158 + 0201 amendments) was
already correct and is unchanged.

* docs: reconcile ADR 0182 reconstruction context

* test(leftover): cover reconstruction candidate contract

* fix(leftover): prove rank-zero reconstruction identity

---------

Co-authored-by: seonghobae <seonghobae@users.noreply.github.com>
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