confirm dcy-002 and add REQ/BAT evidence add ledger backup/status metadata workflow document restore as runbook/script-only guarded operation add synthetic DB backup/restore smoke tests
112 lines
5.5 KiB
Markdown
112 lines
5.5 KiB
Markdown
# BAT-002 Verification
|
|
|
|
## Verification Status
|
|
- Status: approved
|
|
- Ready for Release: true
|
|
- Verified At (KST): 2026-06-27 10:33
|
|
- Verified By: 렛저장인
|
|
|
|
## Acceptance Mapping
|
|
|
|
### REQ-002 AC1
|
|
Backup creation must write timestamped SQLite files under `/root/.local/share/jarca/backups/ledger/` by default and return source/backup path, size, mtime, sha256, integrity, and table counts.
|
|
|
|
Evidence:
|
|
- `service.create_ledger_backup` uses default `DEFAULT_LEDGER_BACKUP_DIR = ~/.local/share/jarca/backups/ledger` and returns `source_db`, `backup`, `retention`, and `restore_policy`.
|
|
- `tests/test_backup_workflow.py::test_create_list_and_status_ledger_backup_with_retention` verifies backup file creation, sha256 presence, `integrity_check == "ok"`, and source/backup table count equality on synthetic DB.
|
|
|
|
Result: pass.
|
|
|
|
### REQ-002 AC2
|
|
Retention keeps recent 30 days or newest 20 backup files and reports pruned paths.
|
|
|
|
Evidence:
|
|
- `_apply_backup_retention` prunes only backups that are both outside newest count and older than day cutoff.
|
|
- `tests/test_backup_workflow.py::test_backup_retention_keeps_recent_count_and_prunes_older_extras` verifies retention with synthetic old backup files and checks `pruned_paths` length.
|
|
|
|
Result: pass.
|
|
|
|
### REQ-002 AC3
|
|
Backup list/status/hash is additive service/MCP surface and existing response shapes are preserved.
|
|
|
|
Evidence:
|
|
- New service functions: `list_ledger_backups`, `get_ledger_backup_status`, `get_ledger_db_status`.
|
|
- New MCP tools are additive in `server.py`.
|
|
- `hermes mcp test jarca-ledger` result: connected, `Tools discovered: 45`, including `get_ledger_db_status`, `create_ledger_backup`, `list_ledger_backups`, `get_ledger_backup_status`.
|
|
|
|
Result: pass.
|
|
|
|
### REQ-002 AC4
|
|
Restore execution is not MCP-exposed and is script/runbook only with explicit approval for overwrite.
|
|
|
|
Evidence:
|
|
- `server.py` contains no restore MCP tool.
|
|
- `hermes mcp test jarca-ledger` discovered backup/status tools and no restore tool.
|
|
- `scripts/ledger_restore_smoke.py` requires `--allow-overwrite --approval-token RESTORE_APPROVED` before overwriting an existing target.
|
|
- `docs/runbooks/ledger-backup-restore.md` documents restore as script-only and warns not to target the live operating DB without explicit user approval.
|
|
|
|
Result: pass.
|
|
|
|
### REQ-002 AC5
|
|
Validation uses synthetic fixture DB first; operating DB copy evidence is metadata-only if used.
|
|
|
|
Evidence:
|
|
- All tests use pytest `tmp_path` synthetic SQLite DBs.
|
|
- Restore smoke command used `/tmp/.../fixture.sqlite3`, `/tmp/.../backups/...sqlite3`, and `/tmp/.../restored.sqlite3`.
|
|
- No operating DB copy was needed.
|
|
|
|
Result: pass.
|
|
|
|
### REQ-002 AC6
|
|
Baseline docs reflect backup/status/list/hash/restore restrictions and sensitive evidence policy.
|
|
|
|
Evidence:
|
|
- `docs/runtime-flows.md` adds operational backup/validation/restore smoke flow and restore non-MCP constraint.
|
|
- `docs/data-model.md` adds `LedgerBackupArtifact` and metadata-only evidence notes.
|
|
- `docs/interface-contract.md` adds backup/status tools and restore non-exposure compatibility rule.
|
|
- `docs/runbooks/ledger-backup-restore.md` lists allowed/forbidden evidence and QC checklist.
|
|
|
|
Result: pass.
|
|
|
|
### REQ-002 AC7
|
|
Synthetic tests verify backup/status/list/hash/retention/restore smoke or health/status check without operating DB mutation.
|
|
|
|
Evidence:
|
|
- Command: `source .venv/bin/activate && pytest -ra`
|
|
- Result: `20 passed, 4 skipped in 16.02s`.
|
|
- Command: synthetic restore smoke with `scripts/ledger_restore_smoke.py`.
|
|
- Result: `success: true`, backup/target `integrity_check: ok`, matching table counts, `health_check.success: true`.
|
|
|
|
Result: pass.
|
|
|
|
### REQ-002 AC8
|
|
QC gate must verify operating DB mutation absence, restore MCP non-exposure, sensitive evidence absence, smoke evidence, tests/docs.
|
|
|
|
Evidence:
|
|
- This verification document and runbook include QC checklist.
|
|
- `jarcaledgerqc` QC gate returned `PASS`.
|
|
- QC summary confirmed no operating DB restore/direct mutation, backup/status/list/hash policy compliance, no restore MCP tool, synthetic restore smoke success, no real sensitive evidence exposure, and tests/docs evidence.
|
|
|
|
Result: pass.
|
|
|
|
## Evidence Summary
|
|
- Syntax: `python -m py_compile jarca_ledger_mcp/*.py dashboard/app.py` -> exit 0.
|
|
- Targeted tests: `pytest tests/test_backup_workflow.py -q` -> `3 passed`.
|
|
- Full tests: `pytest -ra` -> implementer `20 passed, 4 skipped in 16.02s`; QC rerun `20 passed, 4 skipped in 14.14s`.
|
|
- Restore smoke: synthetic tmp DB restore -> `success: true`, `integrity_check: ok`, table counts `{accounts: 1, transactions: 1, budgets: 0, import_batches: 0, category_rules: 0, ledger_categories: 0}`.
|
|
- MCP surface: `hermes mcp test jarca-ledger` -> connected, `Tools discovered: 45`, backup/status tools present, no restore tool listed.
|
|
|
|
## Sensitive Evidence Review
|
|
- No transaction row dumps, merchant/counterparty full dumps, account numbers, `raw_payload`, source financial files, or passwords were written into docs/tests/logs.
|
|
- Synthetic test data contains placeholder sentinel labels only and asserts those labels are not serialized in status evidence.
|
|
|
|
## QC Gate Result
|
|
- Verdict: PASS
|
|
- Reviewer: jarcaledgerqc
|
|
- Reviewed At (KST): 2026-06-27 10:33
|
|
- Summary: 검수관은 원본 운영 DB restore/direct mutation 없음, backup/status/list/hash 정책 정합성, restore MCP 비노출, synthetic restore smoke 성공, 민감정보 비노출, tests/docs evidence를 확인했다.
|
|
- Notes: 실제 backup MCP 호출은 운영 DB mutation을 피하기 위해 수행하지 않았고, service-level synthetic DB 테스트와 smoke로 대체 검증했다. 이는 비차단 참고사항이다.
|
|
|
|
## Blocking Issues
|
|
- None.
|