feat: add persistent monthly settlement drafts and approved valuation selection

This commit is contained in:
2026-10-10 02:49:34 +00:00
parent 68212e773b
commit 92f44661c3
37 changed files with 2902 additions and 29 deletions
@@ -0,0 +1,42 @@
"""Consumer contracts for immutable draft-close evidence."""
import json
import sqlite3
from jarca_ledger_mcp import service
from jarca_ledger_mcp.db import init_db
def test_closed_draft_evidence_is_additive_and_strictly_redacted(tmp_path):
path = str(tmp_path / "synthetic.sqlite3")
init_db(path)
with sqlite3.connect(path) as conn:
conn.execute("INSERT INTO asset_snapshot_runs(id,basis_date,close_status,selection_policy,draft_id,draft_version,review_fingerprint,applied_evidence,excluded_evidence,carried_evidence,created_at) VALUES(?,?,?,?,?,?,?,?,?,?,?)", (
"run-draft", "2026-09-30", "conditional", "exact", "draft-1", 7, "fingerprint-1",
json.dumps([{"source_type":"manual_asset","source_id":"asset-1","name":"Synthetic","amount":100,"currency":"KRW","valuation_date":"2026-09-29","age_days":1,"carried_forward":True,"selection_mode":"carried_before","reason":"accepted","selected_by":"reviewer","selected_at":"2026-09-30T01:00:00Z","item_version":3,"verification_status":"verified","source_ref":"ref-1","source_attributes":{"bucket":"real_estate","secret":"hidden"},"approval":{"reference":"approval-1","memo":"hidden"},"unknown":{"credential":"hidden"}}]),
json.dumps([{"source_type":"account","source_id":"acct-1","reason":"approved_missing","approval_reference":"ref-2","unknown_secret":"hidden"}]),
json.dumps([{"source_type":"manual_asset","source_id":"asset-1","valuation_date":"2026-09-29","age_days":1,"carried_forward":True,"selection_mode":"carried_before","reason":"accepted","selected_by":"reviewer","selected_at":"2026-09-30T01:00:00Z","item_version":3,"verification_status":"verified","source_ref":"ref-1"}]),
"2026-09-30T02:00:00Z"))
conn.execute("INSERT INTO asset_snapshots(id,basis_date,source_type,source_id,name,amount,currency,liquidity_bucket,snapshot_run_id,valuation_id,created_at) VALUES('snap-1','2026-09-30','manual_asset','asset-1','Synthetic',100,'KRW','real_estate','run-draft','','2026-09-30T02:00:00Z')")
conn.commit()
report = service.get_asset_snapshot_report("2026-09-30", db_path=path)
assert report["success"]
metadata = report["close_metadata"]
assert (metadata["draft_id"], metadata["draft_version"], metadata["review_fingerprint"]) == ("draft-1", 7, "fingerprint-1")
assert metadata["contains_carried"] is True and metadata["contains_substitutions"] is False and metadata["has_approved_missing"] is True
evidence = metadata["applied_evidence"][0]
for key in ("valuation_date", "age_days", "selection_mode", "reason", "selected_by", "selected_at", "item_version", "verification_status", "source_ref", "source_attributes", "approval"):
assert key in evidence
serialized = json.dumps(report)
assert "hidden" not in serialized and "credential" not in serialized and "unknown" not in serialized
series = service.get_net_worth_timeseries("2026-09-01", "2026-09-30", db_path=path)
assert series["points"][0]["draft_id"] == "draft-1"
assert series["points"][0]["contains_carried"] is True
monthly = service.get_monthly_settlement_summary("2026-09", db_path=path)
assert monthly["source_coverage"]["assets"]["draft_id"] == "draft-1"
def test_active_cancelled_drafts_do_not_create_timeseries_points(tmp_path):
path = str(tmp_path / "synthetic.sqlite3")
init_db(path)
result = service.get_net_worth_timeseries("2026-09-01", "2026-09-30", db_path=path)
assert result["success"] and result["points"] == []