diff --git a/apps/api/agents/heir_share_analyzer/agent.py b/apps/api/agents/heir_share_analyzer/agent.py index a397880..0452d4a 100644 --- a/apps/api/agents/heir_share_analyzer/agent.py +++ b/apps/api/agents/heir_share_analyzer/agent.py @@ -336,8 +336,7 @@ def run(payload: AgentInput) -> AgentOutput: state["asked_slot"] = None state["missing_fields"] = [] state["last_result"] = result.model_dump(mode="json") - # 전문가 전달용 요약은 last_result 안에도 있지만, compose/프론트가 법률 - # 계산 전체를 열지 않고 바로 꺼낼 수 있도록 별도 키로 한 번 더 제공한다. + # compose와 프론트가 계산 전체를 열지 않고 전달용 요약을 읽게 한다. state["expert_handoff"] = result.expert_handoff.model_dump(mode="json") return AgentOutput( diff --git a/apps/api/agents/heir_share_analyzer/calculator.py b/apps/api/agents/heir_share_analyzer/calculator.py index 755f41e..86321b3 100644 --- a/apps/api/agents/heir_share_analyzer/calculator.py +++ b/apps/api/agents/heir_share_analyzer/calculator.py @@ -1,9 +1,4 @@ -"""법정상속분과 기본 유류분을 계산하는 결정론적 엔진. - -법정상속인 선택·법정상속분 계산은 공용 모듈(family_graph.heirs)에 위임한다 — -tax_calculator/heir_navigator 와 같은 규칙을 쓰기 위해서다. 이 파일은 유류분 -쪽 계산(기초액·유류분율·예정취득액 비교·전문가 핸드오프 요약)만 담당한다. -""" +"""공용 상속인 분류를 이용해 법정상속분과 기본 유류분을 계산한다.""" from __future__ import annotations diff --git a/apps/api/agents/heir_share_analyzer/models.py b/apps/api/agents/heir_share_analyzer/models.py index c5cb50f..386520a 100644 --- a/apps/api/agents/heir_share_analyzer/models.py +++ b/apps/api/agents/heir_share_analyzer/models.py @@ -4,7 +4,7 @@ from datetime import date from enum import Enum -from typing import Literal, Optional +from typing import Optional from pydantic import BaseModel, Field, field_validator @@ -99,13 +99,3 @@ class HeirShareResult(BaseModel): warnings: list[str] legal_sources: list[str] expert_handoff: ExpertHandoffSummary - - -Relation = Literal["spouse", "child", "parent", "grandchild", "sibling", "grandparent"] - - -class FamilyMember(BaseModel): - name: str = Field(min_length=1) - relation: Relation - alive: bool = True - minor: bool = False diff --git a/apps/api/agents/heir_share_analyzer/rules.py b/apps/api/agents/heir_share_analyzer/rules.py index 4bfdb4a..1ec470f 100644 --- a/apps/api/agents/heir_share_analyzer/rules.py +++ b/apps/api/agents/heir_share_analyzer/rules.py @@ -10,14 +10,6 @@ RULE_VERSION = "civil_act_2026-03-17" RULE_EFFECTIVE_FROM = date(2026, 3, 17) -LEGAL_SOURCES = [ - "민법 제1009조(법정상속분)", - "민법 제1112조(유류분의 권리자와 유류분)", - "민법 제1113조(유류분의 산정)", - "민법 제1114조(산입될 증여)", - "민법 제1115조(유류분의 보전)", -] - LEGAL_SOURCE_URLS = [ "https://www.law.go.kr/lsLinkCommonInfo.do?chrClsCd=010202&lsJoLnkSeq=1030472287", "https://www.law.go.kr/lsLinkCommonInfo.do?lsJoLnkSeq=1031182201", diff --git a/apps/api/agents/tax_calculator/PROFILE_INTEGRATION.md b/apps/api/agents/tax_calculator/PROFILE_INTEGRATION.md index 0fbbee8..b145555 100644 --- a/apps/api/agents/tax_calculator/PROFILE_INTEGRATION.md +++ b/apps/api/agents/tax_calculator/PROFILE_INTEGRATION.md @@ -1,6 +1,6 @@ # 자산정리·은퇴설계 → 상속세 연동 -## 이번 변경 범위 +## 연동 범위와 원칙 - `payload.financial_profile`을 읽고 상속세 상태 안에 확인 전 자료와 후보 합계를 저장한다. - 계산 엔진(`calculator.py`), 공용 스키마, 라우터, 팀원 에이전트는 변경하지 않는다. @@ -8,7 +8,7 @@ - 후보를 질문에 보여주고 사용자가 `네` 또는 수정 금액을 입력한 뒤 계산에 사용한다. - `모름`, `알 수 없어요`, `정보 없어요`는 0원이 아니다. 결과를 보류하며 이전 세액도 반환하지 않는다. -## 팀원 문의 1~4에 대한 처리 +## 공유 정보 처리 기준 ### 1. 금융재산 @@ -62,10 +62,10 @@ shared `financial_assets=0`은 기존 브릿지의 임시값일 수 있으므로 기존 `to_tax_input()`에서 미확인 0원·보험금 합계를 자동 생성하여 `context.tax_input`으로 보내는 동작은 병행하지 말 것. 같은 자료는 shared profile로 보내고 이 모듈에서 후보로 처리한다. -이미 전달한 임시 0원은 공유 스키마의 None 병합으로 삭제되지 않으므로 과거 테스트 세션과 -새 연동 확인용 세션을 구분하는 것이 좋다. +이미 전달한 임시 0원은 공유 스키마의 None 병합으로 삭제되지 않으므로 기존 세션과 +새 연동 확인용 세션을 구분한다. -### develop 병합 시 입력 경로 통일 (PR #56 CI 수정) +### 입력 경로 통일 공유 자료를 바로 `values`와 `confirmed_fields`에 넣던 `_apply_shared_estate()`는 제거한다. `_apply_financial_profile()`로 후보를 만들고 자료 범위와 금액을 확인하는 @@ -77,19 +77,8 @@ shared `financial_assets=0`은 기존 브릿지의 임시값일 수 있으므로 후보를 제시하고 `네` 또는 수정 금액으로 확인받는다. 일부 flat 항목이 `None`이면 이를 0원으로 간주해 전체액으로 확정하지 않는다. -공유 컨텍스트 회귀 테스트도 "즉시 자동 확정"이 아니라 "후보 제시 → 확인 → 반영"을 -검증한다. 가족관계 공용 분류와 유언장 판정 요약 전달은 develop 구현을 유지한다. - -### 로컬 검증 결과 (2026-08-31) - -- 상속세·공유 컨텍스트·플래너 관련 테스트: 163 passed. -- 백엔드 전체 수집 후 오프라인 실행: 664 passed, 32 skipped, 1 deselected, - 1 warning. DB가 필요한 32개는 건너뛰었고, 실제 API 테스트 1개는 기본 규칙으로 제외했다. -- 백엔드 전체 `ruff check .`, `black --check .`(132개 파일), `git diff --check` 통과. -- 검증 프로세스에서는 `.env` 자동 로딩과 공유 DB·외부 API 연결을 차단했다. - Windows 테스트 도구의 내부 socketpair 통신만 허용했다. -- PostgreSQL 마이그레이션과 DB 연동 결과는 수정 커밋 push 후 GitHub CI에서 재확인해야 한다. - 이 로컬 결과를 DB 포함 전체 CI 통과로 해석하지 않는다. +공유 컨텍스트 회귀 테스트는 "즉시 자동 확정"이 아니라 "후보 제시 → 확인 → 반영"을 +검증한다. 가족관계 공용 분류와 유언장 판정 요약 전달은 현재 구현을 유지한다. ## 상태와 갱신 @@ -121,4 +110,4 @@ shared `financial_assets=0`은 기존 브릿지의 임시값일 수 있으므로 - [국세청 상속재산가액 안내](https://www.nts.go.kr/nts/cm/cntnts/cntntsView.do?cntntsId=7950&mi=6596): 보험금·신탁재산·퇴직금 등의 개요. 위 자료를 바탕으로 확인 항목을 정했으며, 법률 전체를 구현하거나 개별 신고의 정확성을 -보증하는 기능은 아니다. 이번 변경은 기존 계산식·세율표를 변경하지 않는다. +보증하는 기능은 아니다. 이 연동 계층은 계산식·세율표를 변경하지 않는다. diff --git a/apps/api/agents/tax_calculator/agent.py b/apps/api/agents/tax_calculator/agent.py index ac1f76c..8127574 100644 --- a/apps/api/agents/tax_calculator/agent.py +++ b/apps/api/agents/tax_calculator/agent.py @@ -106,9 +106,7 @@ ), } -# 생전 준비와 사후 처리에서 계산에 필요한 슬롯은 같지만, 이용자에게 보이는 -# 표현은 달라야 한다. 기본 QUESTIONS는 기존 사후 상담 문구로 유지하고, -# pre_need 요청에서만 아래 문구를 덮어쓴다. +# 계산 슬롯은 같지만 상담 축에 맞게 질문 표현을 분리한다. PRE_NEED_QUESTIONS = { "decedent_is_resident": ( "상속을 미리 준비하는 분이 현재 국내에 거주하고 있는지 알려주세요. " @@ -386,10 +384,8 @@ def _apply_family_graph( _mark_confirmed(state, "spouse_exists") _mark_confirmed(state, "children_count") - # spouse_is_sole_heir는 부모(2순위) 정보까지 있는 완전한 상속인 목록 - # (형태 A: {"heirs": [...]})일 때만 확정한다. 레거시 형태 - # ({"spouse_alive", "num_children"})는 부모 생존 여부를 알 수 없으므로 - # 기존처럼 사용자에게 물어본다. + # 부모 생존 여부까지 알 수 있는 완전한 상속인 목록에서만 단독상속을 확정한다. + # 축약 형식은 정보가 부족하므로 사용자에게 확인한다. has_full_heir_list = isinstance(family_graph, dict) and isinstance( family_graph.get("heirs"), list ) @@ -645,8 +641,7 @@ def run(payload: AgentInput) -> AgentOutput: # 수집·검토·지원 불가 응답에 이전 턴의 세액이 남지 않도록 한다. state["last_result"] = None - # 공유 자료는 이 경로에서 후보로만 읽는다. 별도 자동 입력을 병행하면 - # 범위 거절·자료 변경 시에도 미확인 금액이 확정값으로 되살아난다. + # 공유 자료는 후보로만 읽어 미확인 금액이 확정값으로 되살아나지 않게 한다. profile_changed = _apply_financial_profile(payload, state) _apply_structured_context(payload, state) _apply_family_graph(payload.family_graph, state) @@ -715,11 +710,7 @@ def run(payload: AgentInput) -> AgentOutput: and values.get("children_count") == 0 and values.get("spouse_is_sole_heir") is False ): - # calculator.calculate_spouse_legal_share는 배우자+자녀 공동상속 또는 - # 배우자 단독상속만 지원한다 — 배우자가 피상속인의 부모님과 함께 - # 공동상속받는 경우는 아직 계산할 수 없다. 이 경우를 계산까지 보냈다가 - # ValueError로 걸리면 "입력이 서로 안 맞는다"는 오해를 주므로 여기서 - # 먼저 걸러 정확한 이유를 안내한다. + # 배우자와 직계존속의 공동상속은 미지원이므로 계산 전에 정확한 이유를 안내한다. state["status"] = "unsupported" state["asked_slot"] = None state["missing_fields"] = [] diff --git a/apps/api/agents/tax_calculator/calculator.py b/apps/api/agents/tax_calculator/calculator.py index f6908a3..d392e58 100644 --- a/apps/api/agents/tax_calculator/calculator.py +++ b/apps/api/agents/tax_calculator/calculator.py @@ -150,11 +150,7 @@ def calculate_basic_or_lump_sum_deduction( def calculate_spouse_legal_share( data: InheritanceTaxInput, ) -> tuple[int, int]: - """배우자 법정상속분을 분자와 분모로 반환한다. - - 현재 런타임에서 법정상속분 비율을 쓰는 실제 구현입니다. - family_graph와의 단일화는 후속 PR에서 다룹니다. - """ + """배우자 법정상속분을 분자와 분모로 반환한다.""" if not data.spouse_exists: return (0, 1) diff --git a/apps/api/tests/test_tax_calculator.py b/apps/api/tests/test_tax_calculator.py index ef21493..3383e1d 100644 --- a/apps/api/tests/test_tax_calculator.py +++ b/apps/api/tests/test_tax_calculator.py @@ -607,9 +607,7 @@ def test_result_includes_inheritance_deduction_breakdown() -> None: def test_nts_rate_table_golden_case_tax_base_400m() -> None: """국세청 세율표 기준 과세표준 4억원의 산출세액을 검증한다.""" - # 출처: - # https://nts.go.kr/nts/cm/cntnts/cntntsView.do - # ?cntntsId=7720&mi=2326 + # 출처: https://nts.go.kr/nts/cm/cntnts/cntntsView.do?cntntsId=7720&mi=2326 result = calculate_base_tax(400_000_000) assert result.inheritance_tax_base == 400_000_000