Files
jarca-ledger-mcp/docs/requirements/req-003_account-valuation-history.md
T

31 KiB

schema, id, title, revision, status, depends_on, applies_to, language, issue, implementation_pr
schema id title revision status depends_on applies_to language issue implementation_pr
gitea-agent.requirement/v1 REQ-003 계좌 기준일 평가 이력과 자산 마감 연동 1.1 approved
ledger
dashboard
mcp
ko #15 미정

REQ-003 — 계좌 기준일 평가 이력과 자산 마감 연동

1. 목적

계좌의 기준일 평가 증거를 append-only 이력으로 저장·선택하고, 검증 가능한 자산만 자산/마감 및 월정산의 역사적 순자산에 반영한다.

2. 배경

구현은 SQLite schema 13를 schema 11에 additive하게 적용한다. 계좌 잔액·import 결과는 실제 증거가 없는 한 unverified 후보이고, 기존 거래·인증·메뉴 계약을 바꾸지 않는다.

3. 범위

포함

  • account_valuations, asset_snapshot_runs, asset_snapshots 확장과 exact/as_of 선택
  • idempotency, append-only correction, 투자 optional metrics, loan 대표 부채
  • read-only preview, explicit approval conditional close, immutable evidence, correction/re-close
  • 계좌·import 후보, reconciliation, MCP·Dashboard·월정산 공통 read model

제외

  • credential/실제 금융 데이터, 자동 추정 거래 생성, fake investment transaction, 거래 원장 재작성
  • 외부 자산 가격 API, 환율 변환, 자동 승인, unverified/future/unknown 값 승인
  • Dashboard 인증·logout·cookie, MCP 인증의 신규 도입, 기존 메뉴 순서 변경

4. 용어와 기준

  • verified leaf: supersedes_id로 더 최신 child가 없는 verification_status=verified 행.
  • exact: 요청 basis_date와 일치하는 verified leaf만 선택한다.
  • as_of: 미래를 보지 않고 요청일 이전 최신 verified leaf를 선택하며 carry-forward와 age를 표시한다.
  • last_balance: opening evidence가 아니라 외부 현재값과 비교하는 external current comparison이다. opening evidence와 balance_after가 모두 없으면 INCOMPLETE_CALCULATION이다.
  • principal 물리 필드: principal은 investment의 reported principal amount 또는 loan의 outstanding principal이며, reported_principal_kind와 reported_principal_label만 source-declared 의미를 보존한다. generic label 필드는 없다.
  • 대표 부채: valuation_kind가 loan/loan_balance이고 representative_liability_definition이 principal_only 또는 principal_interest_fees인 하나의 대표 금액만 합산한다. loan purpose, definition, ambiguity는 report에 보존한다.
  • 정본 구현: jarca_ledger_mcp/application/account_valuation_service.py, assets_service.py, reconciliation_service.py, migrations.py 및 named tests.

5. 요구사항

REQ-003.01 — additive 이력과 legacy 보존

schema 11의 테이블·필드·거래를 삭제하거나 추측 이주하지 않고 schema 13의 account_valuations, asset_snapshot_runs를 추가하며 asset_snapshots에 필요한 필드를 additive하게 확장한다. migration은 idempotent다.

영향 범위

  • 인터페이스: 기존 service/MCP 응답 envelope 유지, 신규 valuation/snapshot fields additive
  • 영속성: SQLite schema 11→12, 기존 rows 보존
  • 후속 사용 주체: service, MCP tool, Dashboard gateway/page, 월정산
  • 마이그레이션: migrate_db()의 CREATE TABLE IF NOT EXISTS/ADD COLUMN
  • 호환성: REQ-001 auth, cookie/logout, REQ-002 메뉴 10개/order, query/shell/browser evidence 유지
  • 배포 전제 조건: SQLite write 권한과 기존 DB 백업

REQ-003.02 — verified leaf 선택과 범위

exact/as_of 선택은 account/currency/valuation_kind scope를 적용하고 future, unverified, rejected, unknown을 authority에서 제외한다. newer unverified candidate는 warning으로 남기며 investment는 total_value, balance, cash_balance 우선, loan은 loan_balance, loan, balance 우선이다.

영향 범위

  • 인터페이스: select_account_valuation(), _account_valuation_items(), report warnings
  • 영속성: 상태·기준일·통화·kind와 candidate evidence 보존
  • 후속 사용 주체: snapshot preview/close, Dashboard 계좌·자산, reconciliation
  • 마이그레이션: 없음
  • 호환성: 기존 last_balance fallback은 basis-date 없는 legacy report에서만 유지
  • 배포 전제 조건: ISO date와 허용 currency/kind

REQ-003.03 — idempotency와 append-only correction

같은 idempotency payload는 기존 row/run을 재사용하고 다른 payload는 idempotency_conflict다. source_ref와 fingerprint가 evidence idempotency를 이룬다. correction은 원본을 갱신하지 않고 단일 child를 append한다. correction parent scope는 same account/date/currency/purpose이고 cyclic parent와 self parent는 거절한다. parent당 one child만 허용하며 correction_reason은 필수다. reason 누락, parent 불일치, cyclic/self parent, 다른 child 및 DB 충돌은 no-write correction_conflict다. source_ref는 account-scoped evidence identity이며 explicit key가 있어도 evidence identity에 적용한다. key/source mismatch는 conflict다.

영향 범위

  • 인터페이스: register_account_valuation(), correct_account_valuation(), close_asset_snapshot()
  • 영속성: unique idempotency 및 single-correction indexes
  • 후속 사용 주체: retry caller와 history/report
  • 마이그레이션: unique indexes additive
  • 호환성: 성공/실패 envelope와 기존 error_code 유지
  • 배포 전제 조건: transaction-scoped SQLite write

REQ-003.04 — 금액·옵션·대출 의미

amount와 principal/interest/fee/cost_basis/net_contributed/profit은 exact integer이고 NULL은 미제공, 0은 명시적 영(0)이다. 투자 optional metrics는 저장하되 total valuation을 다시 합산하지 않는다. loan은 대표 정의를 필수로 하고 principal/interest/fee의 unknown을 NULL로 보존하며 대표 금액만 총부채에 합산한다.

영향 범위

  • 인터페이스: valuation input/output fields, validation errors
  • 영속성: INTEGER/REAL return_rate와 nullable optional columns
  • 후속 사용 주체: net-worth formula와 UI labels
  • 마이그레이션: 없음
  • 호환성: 기존 integer ledger amounts와 double-sum 금지
  • 배포 전제 조건: caller가 currency/definition을 명시

REQ-003.05 — current와 historical authority

current latest display와 historical authority를 분리한다. last_balance는 opening evidence가 아니라 external current comparison이며, balance_after/opening evidence가 모두 없으면 INCOMPLETE_CALCULATION이다. 늦게 도착한 historical row는 current를 과거로 되돌리지 않으며 cannot roll back newer current cache. account/import writes는 real dated evidence가 있을 때만 dated unverified candidate를 만든다. 대출 cache write는 대표 부채 정의가 없으면 이력 후보를 추가하지 않는다. 이때 current cache와 import 처리는 유지하고 정의를 추정하지 않는다. 기존 valuation이 있는 계좌를 loan으로 변환할 때는 모든 valuation에 유효한 대표 부채 정의가 있어야 하며, 위반 시 계좌와 이력을 변경하지 않고 validation_error를 반환한다. valuation이 없는 변환은 허용한다.

영향 범위

  • 인터페이스: account update/import candidate, list/select/report
  • 영속성: basis_date/recorded_at 분리
  • 후속 사용 주체: 계좌 화면, reconciliation, monthly settlement
  • 마이그레이션: 없음
  • 호환성: account name-only update는 candidate를 만들지 않음
  • 배포 전제 조건: source date와 source_ref/hash

REQ-003.06 — preview·close·approval

preview는 DB를 쓰지 않고 complete_exact, incomplete_draft, conditional 상태와 warnings/exclusions를 반환한다. close response는 run, approval, correction, warnings, exclusions를 포함한다. close는 need-based explicit approved_by, approval_reason, approval_reference와 flags를 요구하며 immutable run evidence를 기록한다. explicit dated manual asset은 검증된 manual evidence로 취급할 수 있다. unverified/future/unknown/ambiguous, including future unknown, 은 승인 없이 close할 수 없다.

영향 범위

  • 인터페이스: preview_asset_snapshot_close(), close_asset_snapshot() 및 error codes
  • 영속성: run applied/excluded/carried evidence와 approval metadata
  • 후속 사용 주체: Dashboard 자산/마감, MCP operator
  • 마이그레이션: asset_snapshot_runs 신규
  • 호환성: preview read-only, 기존 report response fields 유지
  • 배포 전제 조건: operator approval identity와 reference

REQ-003.07 — correction/re-close와 formula

같은 basis date close는 correction_reason을 요구하고 새 run/rows를 append한다. 최신 run만 historical report authority이며 순자산은 asset_buckets - loan, missing valuation은 transaction inference 없이 제외한다.

영향 범위

  • 인터페이스: close/report/timeseries
  • 영속성: correction_of_run_id, is_correction, closed_at
  • 후속 사용 주체: timeseries와 월정산
  • 마이그레이션: asset snapshot columns/indexes
  • 호환성: legacy asset_snapshots rows are readable
  • 배포 전제 조건: close transaction atomicity

REQ-003.08 — reconciliation과 monthly propagation

investment가 verified valuation으로 관리되면 reconciliation status는 VALUATION_MANAGED이고 fake transaction을 만들지 않는다. report는 unavailable investment를 명시한다. investment unavailable과 reconciliation completeness를 report에 명시한다. regular ledger calculation은 calculation_basis/calculation_basis_at provenance를 유지한다. monthly settlement는 read-only로 동일 snapshot/report를 전파하며 no fake writes를 보장한다. live/current, closed, timeseries, monthly 각각은 actual valuation_date, age, carry, verification, run, approval, correction, warnings, exclusions를 보존한다. monthly_source_snapshot_id는 snapshot_run_id의 read-model alias이며 persistence field가 아니다.

영향 범위

  • 인터페이스: get_balance_reconciliation_report(), get_monthly_settlement_summary()
  • 영속성: reconciliation session/transaction은 valuation 때문에 자동 변경하지 않음
  • 후속 사용 주체: 월정산·overview·reconciliation UI
  • 마이그레이션: 없음
  • 호환성: existing reconciliation statuses and reports additive
  • 배포 전제 조건: service read model available

canonical D04-D06 contract: snapshot close aliases valuation_date, age_days, verification_status, evidence_kind, and monthly_source_snapshot_id at the top level while preserving the same meanings in nested provenance. Replay requires request-fingerprint equality and reconstructs from persisted evidence, never replay-only reused fields. Recursive close_metadata is allowlisted/redacted. Preview fingerprint input/output and authority drift rejection are mandatory. Dashboard missing DB is stable unavailable with no-create; initialized reads are no-write. Reconciliation requires opening evidence and coverage; incomplete state is INCOMPLETE_CALCULATION/reconciliation unavailable, with no inferred balance or fake transaction.

REQ-003.09 — shared application과 보안 경계

MCP와 Dashboard는 shared service/gateway를 사용한다. 기존 success/error envelope를 유지한다. Dashboard는 auth-before-DB이며 MCP auth를 claim하지 않는다. render는 read-only이고 implicit write를 일으키지 않는다.

영향 범위

  • 인터페이스: MCP @mcp.tool, Streamlit gateways/pages
  • 영속성: render/preview에는 write 없음; explicit form/close만 write
  • 후속 사용 주체: browser/operator/automation
  • 마이그레이션: 없음
  • 호환성: REQ-001 gate, cleanup/logout, MCP transport/auth scope 유지
  • 배포 전제 조건: Dashboard auth config, MCP runtime config

REQ-003.10 — privacy, compatibility, excluded scope

문서·tests·fixtures는 synthetic data만 사용하고 actual credential/account/financial data를 저장하지 않는다. Issue #12 밖의 OAuth, external prices, FX, automatic approval, transaction inference, redesign는 구현하지 않는다.

영향 범위

  • 인터페이스: redacted evidence와 generic errors
  • 영속성: synthetic source_note/memo only
  • 후속 사용 주체: tests/operator
  • 마이그레이션: 없음
  • 호환성: 기존 auth/menu/query/shell/browser evidence semantic inventory 0 missing
  • 배포 전제 조건: secret redaction과 fixture DB

REQ-003.11 — 월정산 초안·승인·원자적 마감 (Issue #15)

월말 기준일의 durable draft는 자료가 없어도 생성되며 생성 자체로 run/rows를 만들지 않는다. 월별 활성 초안은 일반·정정 공통으로 하나다. 대상 구성은 명시적 refresh만 반영하고 검토는 frozen evidence의 version/fingerprint에 묶인다. Finalize는 drift를 거절하고 BEGIN IMMEDIATE에서 run, rows, completion/link를 함께 기록하며 동일 요청은 persisted response로 replay한다.

영향 범위

  • 인터페이스: shared settlement draft service, MCP tools, authenticated Dashboard gateway; monthly summary read-only
  • 영속성: schema 12→13 additive settlement_drafts, settlement_draft_items; legacy 11→12 보존
  • 후속 사용 주체: Dashboard operator, MCP caller, close reports/timeseries/monthly read model
  • 마이그레이션: additive/idempotent; historical drafts backfill 없음
  • 호환성: existing valuation/auth/menu/query/shell/MCP contracts 유지
  • 배포 전제 조건: explicit writer init, SQLite transaction, synthetic tests

6. 제약과 불변조건

  • Automatic exact/as_of selection and legacy direct close exclude future, unverified, rejected, and unknown valuations from authority. The sole future-valuation exception is an explicitly selected, verified manual_substitute in a settlement draft, with reason, review, approval, and original valuation/basis dates preserved; a future valuation is never chosen automatically. Unverified, rejected, or unknown amounts are never authority on any path.
  • 동일 idempotency payload는 같은 ID를 반환하고 다른 payload는 conflict다.
  • correction과 re-close는 append-only이고 parent당 child/run은 하나다.
  • NULL과 0을 구별하고 모든 금액은 integer precision이다.
  • loan representative만 liability sum에 들어가고 investment metrics는 double sum하지 않는다.
  • preview와 render는 DB write가 없고 close는 하나의 transaction 경계다.
  • current display와 historical basis authority는 분리된다.
  • Dashboard auth gate는 DB보다 먼저이며 MCP 인증은 이 요구사항이 주장하지 않는다.
  • 실제 credential·token·cookie·account data는 문서·로그·fixture에 없다.

7. 인수 기준

REQ-003.11-AC01 — 빈 월 초안 영속 생성

판정 기준

자료가 없어도 월말 기준일의 초안이 저장되고 생성만으로 snapshot run/rows가 생기지 않는다.

검증

tests/test_monthly_settlement_drafts.py::test_empty_draft_persists_without_closing_and_has_consistent_public_shape

검증 분류

  • 수준: integration
  • 백엔드: sqlite
  • 케이스: 정상 empty draft; 경계 no targets; 실패 invalid month

상태 불변조건

Create는 close side effect가 없다.

REQ-003.11-AC02 — 월말 기준일 및 create replay

판정 기준

월말만 허용하고 같은 key/payload는 idempotent, 다른 payload는 충돌한다.

검증

tests/test_monthly_settlement_drafts.py::test_basis_must_be_calendar_month_end_and_create_key_is_idempotent

검증 분류

  • 수준: integration
  • 백엔드: sqlite
  • 케이스: normal month-end; boundary leap month; failure non-month-end

상태 불변조건

거절된 create는 초안을 추가하지 않는다.

판정 기준

Normal/correction 초안을 합쳐 월별 active는 하나이며 취소 후 월 재개가 가능하다.

검증

tests/test_monthly_settlement_drafts.py::test_one_active_draft_across_normal_and_correction_and_cancellation_reopens_month

검증 분류

  • 수준: integration
  • 백엔드: sqlite
  • 케이스: normal competing create; boundary correction lineage; failure second active

상태 불변조건

Correction lineage는 명시적이고 유일하다.

REQ-003.11-AC04 — 입력·버전·행위자 검증

판정 기준

잘못된 값과 stale version을 거절하고 include/exclude 사유 및 actor를 기록한다.

검증

tests/test_monthly_settlement_drafts.py::test_input_validation_versions_actors_and_include_exclude_reason

검증 분류

  • 수준: integration
  • 백엔드: sqlite
  • 케이스: normal valid mutation; boundary version; failure invalid type

상태 불변조건

거절된 mutation은 상태와 version을 변경하지 않는다.

REQ-003.11-AC05 — 명시적 target refresh와 read-only review

판정 기준

대상 membership은 refresh 전 고정되고 review는 읽기 전용이다.

검증

tests/test_monthly_settlement_drafts.py::test_targets_are_frozen_until_explicit_refresh_and_review_is_read_only

검증 분류

  • 수준: integration
  • 백엔드: sqlite
  • 케이스: normal refresh; boundary changed sources; failure implicit refresh

상태 불변조건

Review는 DB 상태를 쓰지 않는다.

REQ-003.11-AC06 — exact, carry, manual substitute 날짜 구분

판정 기준

선택 모드는 valuation date와 basis date 차이를 보존하며 future substitute는 명시적이다.

검증

tests/test_monthly_settlement_drafts.py::test_explicit_future_substitute_and_late_recorded_exact_are_distinguished

검증 분류

  • 수준: integration
  • 백엔드: sqlite
  • 케이스: normal exact; boundary future substitute; failure implicit future choice

상태 불변조건

date_difference_days = valuation_date - basis_date를 보존한다.

REQ-003.11-AC07 — unverified 후보는 authority 아님

판정 기준

Unverified 후보 금액은 표시 가능하나 authority amount는 NULL이며 verified child는 재선택을 요구한다.

검증

tests/test_monthly_settlement_drafts.py::test_unverified_candidate_has_no_authority_and_verified_child_requires_reselection

검증 분류

  • 수준: integration
  • 백엔드: sqlite
  • 케이스: normal verified selection; boundary candidate; failure candidate authority

상태 불변조건

NULL은 0이나 verified 금액으로 대체되지 않는다.

REQ-003.11-AC08 — 수동 evidence drift와 future 차단

판정 기준

수동 source 변경은 명시적 refresh가 필요하고 future evidence가 자동 선택되지 않는다.

검증

tests/test_monthly_settlement_drafts.py::test_manual_sources_drift_requires_explicit_refresh_and_future_not_auto_selected

검증 분류

  • 수준: integration
  • 백엔드: sqlite
  • 케이스: normal unchanged source; boundary drift; failure auto-select future

상태 불변조건

Frozen source hash는 refresh 전까지 불변이다.

REQ-003.11-AC09 — 승인 fingerprint 및 drift gate

판정 기준

Mutation/source drift는 approval을 무효화하고 finalize를 막는다.

검증

tests/test_monthly_settlement_drafts.py::test_approval_fingerprint_mutation_and_external_drift_block_finalize

검증 분류

  • 수준: integration
  • 백엔드: sqlite
  • 케이스: normal unchanged approval; boundary drift; failure stale finalize

상태 불변조건

Finalize는 승인된 version/fingerprint만 받는다.

REQ-003.11-AC10 — 원자적 finalize 및 persisted replay

판정 기준

Finalize는 immutable provenance를 저장하고 동일 요청에 persisted response를 반환한다.

검증

tests/test_monthly_settlement_drafts.py::test_finalize_persists_immutable_provenance_replays_exact_response_and_conflicts_key

검증 분류

  • 수준: integration
  • 백엔드: sqlite
  • 케이스: normal finalize; boundary replay; failure conflicting key

상태 불변조건

Replay는 저장된 결과를 재구성하며 중복 run을 만들지 않는다.

REQ-003.11-AC11 — DB 실패 rollback

판정 기준

SQLite write 실패 시 run, rows, completed 상태가 모두 rollback된다.

검증

tests/test_monthly_settlement_drafts.py::test_sqlite_trigger_failure_rolls_back_run_rows_and_completion

검증 분류

  • 수준: integration
  • 백엔드: sqlite
  • 케이스: normal successful commit; boundary trigger failure; failure mid-transaction

상태 불변조건

부분 마감 결과는 남지 않는다.

REQ-003.11-AC12 — additive schema 13 migration

판정 기준

Migration은 legacy rows를 보존하고 반복 실행에 안전하다.

검증

tests/test_monthly_settlement_drafts.py::test_schema13_migration_is_additive_and_idempotent

검증 분류

  • 수준: integration
  • 백엔드: sqlite
  • 케이스: normal new DB; boundary schema 12; failure repeated migration

상태 불변조건

Schema 11→12 의미와 데이터는 보존된다.

REQ-003.11-AC13 — 동시 create와 stale finalize

판정 기준

동시 create는 active uniqueness를 지키고 stale version finalize는 거절한다.

검증

tests/test_monthly_settlement_drafts.py::test_concurrent_create_and_stale_version_finalization_are_safe

검증 분류

  • 수준: integration
  • 백엔드: sqlite
  • 케이스: normal sequential mutation; boundary concurrent create; failure stale finalize

상태 불변조건

한 달에 active 초안은 최대 하나다.

REQ-003.11-AC14 — draft adapter public contract

판정 기준

Gateway/MCP는 실제 service signature와 결과를 그대로 노출한다.

검증

tests/test_settlement_draft_adapters.py::test_gateway_exports_exact_contract_signature_and_delegates

검증 분류

  • 수준: integration
  • 백엔드: application
  • 케이스: normal delegation; boundary signature; failure service error

상태 불변조건

Adapter는 authority 판단이나 응답 변형을 하지 않는다.

REQ-003.11-AC15 — Dashboard auth 및 render 경계

판정 기준

인증은 DB 접근 전 수행되고 render는 lifecycle mutation을 하지 않는다.

검증

tests/test_settlement_draft_adapters.py::test_dashboard_authentication_entrypoint_precedes_database_resolution

검증 분류

  • 수준: integration
  • 백엔드: dashboard
  • 케이스: normal authenticated read; boundary unauthenticated; failure DB access before auth

상태 불변조건

인증 없는 요청은 DB에 접근하지 않는다.

REQ-003.11-AC16 — missing DB read no-create

판정 기준

Read-only gateway missing database를 생성하거나 migrate하지 않는다.

검증

tests/test_settlement_draft_adapters.py::test_read_only_gateway_calls_do_not_create_missing_database

검증 분류

  • 수준: integration
  • 백엔드: sqlite
  • 케이스: normal initialized read; boundary missing DB; failure implicit create

상태 불변조건

Read path는 no mkdir, no migrate, no commit이다.

REQ-003.11-AC17 — legacy contract regression

판정 기준

Valuation correction, monthly summary read-only, menu/auth compatibility regressions remain green.

검증

tests/test_settlement_draft_adapters.py::test_service_reexports_every_lifecycle_operation

검증 분류

  • 수준: integration
  • 백엔드: application
  • 케이스: normal legacy call; boundary old schema; failure incompatible export

상태 불변조건

New draft operations are additive and legacy entrypoints remain available.

REQ-003.01-AC01 — migration and preservation

Cases (정상/경계/실패): 정상 schema 13 init twice; 경계 schema 11 legacy DB; 실패 malformed legacy DB.

State Invariants: legacy tables/rows remain; migration repeats without duplicate columns.

판정 기준: schema_version=13, required tables/columns/indexes exist and old rows remain.

검증: tests/test_account_valuations.py::test_account_valuation_schema_is_v12_and_idempotent, tests/test_issue_12_regressions.py::test_schema12_migration_preserves_legacy_rows_indexes_and_is_idempotent. 검증 분류: level=integration; backend=sqlite

REQ-003.02-AC01 — selection policy

Cases (정상/경계/실패): exact verified; as_of carry-forward; future/unverified/ambiguous excluded/warned.

State Invariants: no future/unverified row is selected.

판정 기준: exact returns same-date verified leaf; as_of returns latest prior verified and age/warning.

검증: tests/test_account_valuations.py::test_select_exact_and_as_of_excludes_unverified_and_reports_carry_forward, source _account_valuation_items(). 검증 분류: level=unit; backend=application

REQ-003.03-AC01 — idempotent correction

Cases (정상/경계/실패): same payload reuse; different payload conflict; second correction fails.

State Invariants: one row/child per operation and original immutable.

판정 기준: exact error codes and count 2 after one correction.

검증: tests/test_account_valuations.py::test_register_same_idempotency_payload_reuses_row_and_changed_payload_conflicts, tests/test_account_valuations.py::test_correction_is_append_only_reasoned_and_single_child, tests/test_issue_12_regressions.py::test_empty_conditional_close_is_closed_and_second_close_requires_correction. 검증 분류: level=integration; backend=sqlite

REQ-003.04-AC01 — precision and representative loan

Cases (정상/경계/실패): integer zero; NULL optional metrics; loan missing definition rejected.

State Invariants: no float amount and no double sum.

판정 기준: optional fields round-trip exactly and loan definition validation is enforced.

검증: test_correction_preserves_optional_fields_unless_overridden, _validate_common() and schema static checks. 검증 분류: level=static; backend=sqlite

REQ-003.05-AC01 — authority separation

Cases (정상/경계/실패): dated candidate; late historical candidate; name-only update.

State Invariants: current/latest display cannot roll backward and candidate is unverified.

판정 기준: dated account write creates only unverified candidate; name-only does not.

검증: test_account_balance_write_records_unverified_candidate_only_with_real_basis_date, test_account_name_only_update_does_not_create_candidate. 검증 분류: level=unit; backend=application

REQ-003.06-AC01 — preview and approval

Cases (정상/경계/실패): complete exact close; incomplete draft; missing approval rejected.

State Invariants: preview row count unchanged; no unsafe evidence approved.

판정 기준: preview is read-only and close returns conditional_approval_required without metadata.

검증: test_manual_asset_update_deactivate_preview_and_close_correction_policy, preview_asset_snapshot_close(). 검증 분류: level=integration; backend=application

REQ-003.07-AC01 — immutable close correction

Cases (정상/경계/실패): first close; same-date correction; second unreasoned close.

State Invariants: old run/rows remain and latest run alone reports.

판정 기준: correction_of_run_id, count, and net worth match.

검증: test_manual_asset_update_deactivate_preview_and_close_correction_policy, assets_service.py close path. 검증 분류: level=integration; backend=sqlite

REQ-003.08-AC01 — reconciliation/monthly

Cases (정상/경계/실패): regular ledger calculation; verified investment; missing baseline.

State Invariants: no fake transaction; provenance fields present; monthly read is non-mutating.

판정 기준: status VALUATION_MANAGED for verified investment and monthly summary reads report.

검증: tests/test_service.py::test_statement_status_account_update_and_balance_reconciliation, tests/test_issue_12_regressions.py::test_reconciliation_uses_corrected_investment_leaf_without_transaction_count_change, tests/test_service.py::test_monthly_settlement_summary_read_model_foundation. 검증 분류: level=unit; backend=application

REQ-003.09-AC01 — shared adapters and auth

Cases (정상/경계/실패): MCP stdio/http config; authenticated Dashboard render; unauthenticated gate.

State Invariants: auth precedes DB; render does not write; response envelope has success.

판정 기준: actual tool/gateway names resolve and existing auth/menu tests pass.

검증: tests/test_mcp_http_runtime.py, tests/test_dashboard_authentication_app.py, tests/test_dashboard_menu_transition.py, server.py and gateways. 검증 분류: level=integration; backend=dashboard

REQ-003.10-AC01 — privacy and compatibility

Cases (정상/경계/실패): synthetic fixture; redaction search; actual secret/data detection.

State Invariants: no credential/token/cookie/real financial data in docs/tests/evidence.

판정 기준: semantic inventory missing=0 and ambiguous=0; placeholder=0.

검증: tests/test_requirement_docs.py, auth/menu evidence tests, repository redaction/static search. 검증 분류: level=static; backend=dashboard

8. 오류 및 충돌 계약

공통 envelope는 성공 시 success: true, 실패 시 success: false, error_code, error를 유지한다. 주요 codes는 validation_error, not_found, idempotency_conflict, correction_conflict, ambiguous_valuation, conditional_approval_required, db_error다. SQLite unique/transaction conflict는 추가 write 없이 실패한다.

9. 데이터 및 인터페이스 계약

서비스는 jarca_ledger_mcp.service re-export를 통해 호출되고 MCP는 jarca_ledger_mcp.adapters.mcp.server tools를 노출한다. Dashboard는 adapters/streamlit/accounts_gateway.py, assets_gateway.py와 dashboard/page_views/accounts.py, assets.py를 사용한다. 실제 fields/signatures는 docs/interface-contract.md에 고정한다.

10. 하위 호환성

REQ-001의 auth gate·cookie/cleanup/logout, REQ-002의 메뉴 10개와 order(월정산, 요약, 자산/마감, 거래내역, 확인필요 큐, 미분류, 분류 규칙, 카테고리, 계좌, Import), query/shell/background와 browser evidence 계약을 삭제·축약하지 않고 additive하게 유지한다. 기존 MCP stdio/streamable-http transport와 success/error envelope를 유지한다.

11. 추적성

  • 근거 이슈: #12
  • 구현 PR: #13
  • 관련 설계 문서: docs/data-model.md, docs/interface-contract.md, docs/project-structure.md, docs/runtime-flow.md
  • 관련 요구사항: REQ-001, REQ-002
  • DB lifecycle: writer/bootstrap은 명시적 init_db() 호출로만 생성·마이그레이션하고, read_db()는 SQLite mode=ro로 연다. missing DB는 db_not_initialized이며 read path는 no mkdir, no migrate, no commit이다. first-use write만 init_db를 수행하고 auth-before-DB 순서를 보존한다.