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
5 changes: 3 additions & 2 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -1948,10 +1948,11 @@ def _design_fraction(cfg: dict) -> float:
if not plan:
continue
key = _rebalance_live_strategy_id(name)
# get_cash_flows는 (occurred_at, amount) 튜플 목록을 준다 — 객체가
# 아니다. getattr로 읽으면 항상 None이 잡혀 '입금 0건'으로 오판한다.
flows = get_cash_flows(account_key=key, mode="paper")
last_flow = max(
(getattr(f, "occurred_at", None) for f in flows if
getattr(f, "occurred_at", None) is not None), default=None,
(f[0] for f in flows if f and f[0] is not None), default=None,
)
# 트랙 개시일 = 이 계정의 첫 스냅샷. 개시 직후에는 아직 적립 시점이
# 오지 않았을 수 있으므로 판정에 필요하다.
Expand Down
50 changes: 50 additions & 0 deletions tests/test_cash_flows.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,3 +395,53 @@ def test_rejects_unknown_basket(self, monkeypatch):
["record_deposit.py", "--basket", "no_such_basket", "--amount", "1000"],
)
assert rd.main() == 1


class TestCashFlowShapeContract:
"""get_cash_flows의 반환 형태를 고정한다.

2026-08-26에 헬스의 적립 이행 점검이 이 목록을 '객체'로 읽어(getattr(f, "occurred_at"))
항상 None을 잡았다. 입금을 기록해 둔 상태인데도 헬스가 '입금 기록 0건'이라고
보고했다 — 조용히 틀린 사실을 말하는, 이 저장소에서 가장 비싼 종류의 버그다.
"""

def test_returns_occurred_at_amount_tuples(self):
from database.repositories import get_cash_flows

init_database()
key = "basket_rebalance:shape_contract"
record_cash_flow(amount=100000, account_key=key, mode="paper", note="계약 확인")

flows = get_cash_flows(account_key=key, mode="paper")
assert flows, "기록한 입금이 조회되지 않았다"
first = flows[0]
assert isinstance(first, tuple) and len(first) == 2, (
f"(occurred_at, amount) 튜플이어야 한다 — 실제: {type(first)}"
)
occurred_at, amount = first
assert isinstance(occurred_at, datetime)
assert amount == pytest.approx(100000)
# 객체 접근은 실패해야 한다 — 이 계약이 바뀌면 호출부가 조용히 None을 얻는다
assert getattr(first, "occurred_at", None) is None

def test_contribution_check_sees_a_recorded_deposit(self):
"""기록된 입금이 적립 이행 점검에 실제로 잡히는지 — 헬스 배선 회귀 방지."""
from core.operator_health import summarize_contribution_plan
from database.repositories import get_cash_flows

init_database()
key = "basket_rebalance:contrib_wiring"
record_cash_flow(amount=100000, account_key=key, mode="paper", note="8월 적립")

flows = get_cash_flows(account_key=key, mode="paper")
last_flow = max((f[0] for f in flows if f and f[0] is not None), default=None)
assert last_flow is not None, "입금 시각을 못 읽었다 — 반환 형태 오해"

state = summarize_contribution_plan(
"kr_pocket",
{"enabled": True, "cadence": "monthly", "amount": 100000},
last_flow,
(datetime.now() - timedelta(days=60)).date(),
datetime.now().date(),
)
assert state["verdict"] == "OK", state["note"]
Loading