Skip to content
Merged
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
3 changes: 1 addition & 2 deletions apps/api/agents/heir_share_analyzer/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
7 changes: 1 addition & 6 deletions apps/api/agents/heir_share_analyzer/calculator.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
"""법정상속분과 기본 유류분을 계산하는 결정론적 엔진.

법정상속인 선택·법정상속분 계산은 공용 모듈(family_graph.heirs)에 위임한다 —
tax_calculator/heir_navigator 와 같은 규칙을 쓰기 위해서다. 이 파일은 유류분
쪽 계산(기초액·유류분율·예정취득액 비교·전문가 핸드오프 요약)만 담당한다.
"""
"""공용 상속인 분류를 이용해 법정상속분과 기본 유류분을 계산한다."""

from __future__ import annotations

Expand Down
12 changes: 1 addition & 11 deletions apps/api/agents/heir_share_analyzer/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
8 changes: 0 additions & 8 deletions apps/api/agents/heir_share_analyzer/rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
27 changes: 8 additions & 19 deletions apps/api/agents/tax_calculator/PROFILE_INTEGRATION.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# 자산정리·은퇴설계 → 상속세 연동

## 이번 변경 범위
## 연동 범위와 원칙

- `payload.financial_profile`을 읽고 상속세 상태 안에 확인 전 자료와 후보 합계를 저장한다.
- 계산 엔진(`calculator.py`), 공용 스키마, 라우터, 팀원 에이전트는 변경하지 않는다.
- 공유 자료의 소유자가 이번 피상속인인지, 사망일 기준 자료인지, 누락이 없는지 먼저 확인한다.
- 후보를 질문에 보여주고 사용자가 `네` 또는 수정 금액을 입력한 뒤 계산에 사용한다.
- `모름`, `알 수 없어요`, `정보 없어요`는 0원이 아니다. 결과를 보류하며 이전 세액도 반환하지 않는다.

## 팀원 문의 1~4에 대한 처리
## 공유 정보 처리 기준

### 1. 금융재산

Expand Down Expand Up @@ -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()`로 후보를 만들고 자료 범위와 금액을 확인하는
Expand All @@ -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 통과로 해석하지 않는다.
공유 컨텍스트 회귀 테스트는 "즉시 자동 확정"이 아니라 "후보 제시 → 확인 → 반영"을
검증한다. 가족관계 공용 분류와 유언장 판정 요약 전달은 현재 구현을 유지한다.

## 상태와 갱신

Expand Down Expand Up @@ -121,4 +110,4 @@ shared `financial_assets=0`은 기존 브릿지의 임시값일 수 있으므로
- [국세청 상속재산가액 안내](https://www.nts.go.kr/nts/cm/cntnts/cntntsView.do?cntntsId=7950&mi=6596): 보험금·신탁재산·퇴직금 등의 개요.

위 자료를 바탕으로 확인 항목을 정했으며, 법률 전체를 구현하거나 개별 신고의 정확성을
보증하는 기능은 아니다. 이번 변경은 기존 계산식·세율표를 변경하지 않는다.
보증하는 기능은 아니다. 이 연동 계층은 계산식·세율표를 변경하지 않는다.
19 changes: 5 additions & 14 deletions apps/api/agents/tax_calculator/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,7 @@
),
}

# 생전 준비와 사후 처리에서 계산에 필요한 슬롯은 같지만, 이용자에게 보이는
# 표현은 달라야 한다. 기본 QUESTIONS는 기존 사후 상담 문구로 유지하고,
# pre_need 요청에서만 아래 문구를 덮어쓴다.
# 계산 슬롯은 같지만 상담 축에 맞게 질문 표현을 분리한다.
PRE_NEED_QUESTIONS = {
"decedent_is_resident": (
"상속을 미리 준비하는 분이 현재 국내에 거주하고 있는지 알려주세요. "
Expand Down Expand Up @@ -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
)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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"] = []
Expand Down
6 changes: 1 addition & 5 deletions apps/api/agents/tax_calculator/calculator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 1 addition & 3 deletions apps/api/tests/test_tax_calculator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading