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 |
|
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_balancefallback은 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_snapshotsrows 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_ofselection and legacy direct close exclude future, unverified, rejected, and unknown valuations from authority. The sole future-valuation exception is an explicitly selected, verifiedmanual_substitutein 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는 초안을 추가하지 않는다.
REQ-003.11-AC03 — 월별 단일 active 초안과 correction link
판정 기준
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()는 SQLitemode=ro로 연다. missing DB는db_not_initialized이며 read path는 no mkdir, no migrate, no commit이다. first-use write만 init_db를 수행하고 auth-before-DB 순서를 보존한다.