feat: add ledger backup safety workflow
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
This commit is contained in:
+42
@@ -0,0 +1,42 @@
|
||||
# BAT-002 Design
|
||||
|
||||
## Architecture Summary
|
||||
BAT-002 adds a small operational-safety layer around the existing SQLite ledger without changing transaction schemas. The service layer produces metadata-only DB evidence, creates backups with SQLite's online backup API, lists backup files, and validates one backup file. MCP exposes only non-destructive backup/status operations. Restore remains a repo script/runbook workflow requiring explicit user approval before overwriting a target DB.
|
||||
|
||||
## Changed Areas
|
||||
- `jarca_ledger_mcp/service.py`
|
||||
- New constants: default backup directory and restore policy.
|
||||
- New helpers: sha256, file metadata, read-only SQLite status, safe table counts, aggregate totals.
|
||||
- New public functions: `get_ledger_db_status`, `create_ledger_backup`, `list_ledger_backups`, `get_ledger_backup_status`.
|
||||
- `jarca_ledger_mcp/server.py`
|
||||
- New additive MCP tools for backup/status/list/hash only.
|
||||
- No restore MCP tool.
|
||||
- `scripts/ledger_restore_smoke.py`
|
||||
- Script-only restore smoke helper with explicit overwrite approval token.
|
||||
- Docs/tests
|
||||
- Synthetic tests and operational runbook/baseline docs.
|
||||
|
||||
## Key Decisions
|
||||
1. Backup creation uses SQLite online backup API rather than raw copy so WAL-mode DBs are copied consistently.
|
||||
2. Backup evidence returns metadata only: path, size, mtime, sha256, integrity result, table row counts, and aggregate totals by cashflow kind.
|
||||
3. Retention policy implements "recent 30 days OR recent 20 files" by pruning only files that are both older than the retention window and outside the newest count.
|
||||
4. Restore is deliberately excluded from MCP. The script exists for fixture/validation DB restore smoke and requires `RESTORE_APPROVED` for overwriting any existing target.
|
||||
5. Existing success response shapes are preserved; all new response fields are additive under new tools/functions.
|
||||
|
||||
## Edge Cases
|
||||
- Missing source DB: backup/status returns `not_found` rather than initializing or mutating a new DB.
|
||||
- Empty backup directory: list returns success with zero backups.
|
||||
- Invalid/corrupt backup: backup status includes integrity error metadata and restore smoke fails before copying.
|
||||
- Existing target restore path: restore smoke fails unless `--allow-overwrite --approval-token RESTORE_APPROVED` are supplied.
|
||||
- Sensitive row data: metadata collection never selects merchant, counterparty, account number, raw_payload, or raw financial file content.
|
||||
|
||||
## Architecture Impact
|
||||
- runtime-flows: updated with backup/status and restore-restricted operational flow.
|
||||
- data-model: updated with backup artifact and evidence policy notes.
|
||||
- interface-contract: updated with new MCP tools and explicit no-restore-MCP rule.
|
||||
|
||||
## Reference Doc Update Plan
|
||||
- Update `docs/runtime-flows.md` with operational backup/validation/restore-smoke flow and high-risk flow constraints.
|
||||
- Update `docs/data-model.md` with backup artifact/evidence persistence boundary.
|
||||
- Update `docs/interface-contract.md` with additive backup/status tools and restore non-exposure.
|
||||
- Add `docs/runbooks/ledger-backup-restore.md`.
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
# BAT-002 Implementation
|
||||
|
||||
## Plan Summary
|
||||
Implemented REQ-002 as a staged additive operational-safety change. No transaction schema migration, operating DB restore, or broad data rewrite was performed.
|
||||
|
||||
## Changed Files
|
||||
- `jarca_ledger_mcp/service.py`
|
||||
- Added metadata-only DB status helpers.
|
||||
- Added SQLite online backup creation with retention enforcement.
|
||||
- Added backup list/status/hash functions.
|
||||
- Added explicit restore policy metadata (`mcp_restore_exposed: false`).
|
||||
- `jarca_ledger_mcp/server.py`
|
||||
- Added MCP tools: `get_ledger_db_status`, `create_ledger_backup`, `list_ledger_backups`, `get_ledger_backup_status`.
|
||||
- Did not add any restore MCP tool.
|
||||
- `scripts/ledger_restore_smoke.py`
|
||||
- Added script-only restore smoke helper with overwrite approval token.
|
||||
- `tests/test_backup_workflow.py`
|
||||
- Added synthetic DB tests for metadata-only status, backup create/list/status/hash, retention pruning, and sensitive evidence exclusion.
|
||||
- `docs/runbooks/ledger-backup-restore.md`
|
||||
- Added operator runbook and QC checklist.
|
||||
- `docs/runtime-flows.md`
|
||||
- Added operational backup/validation/restore smoke runtime flow.
|
||||
- `docs/data-model.md`
|
||||
- Added `LedgerBackupArtifact` and metadata-only persistence notes.
|
||||
- `docs/interface-contract.md`
|
||||
- Added backup/status MCP contract and restore non-exposure rule.
|
||||
- StagePilot docs
|
||||
- `docs/srs/Non-Functional/req-002_operational-safety-backup-restore-validation-db.md`
|
||||
- `docs/srs/index.md`
|
||||
- `docs/discovery/dcy-002_20260627_operational-safety-backup-restore-validation-db.md`
|
||||
- `docs/batches/index.md`
|
||||
- `docs/batches/bat-002_20260627_operational-safety-backup-restore-validation-db/*`
|
||||
|
||||
## Execution Log
|
||||
- RED test first:
|
||||
- Command: `source .venv/bin/activate && pytest tests/test_backup_workflow.py -q`
|
||||
- Initial result: failed with missing `service.get_ledger_db_status`, `create_ledger_backup`, `list_ledger_backups`, `get_ledger_backup_status` attributes.
|
||||
- Implemented service/server/script/docs changes.
|
||||
- Targeted test:
|
||||
- Command: `source .venv/bin/activate && pytest tests/test_backup_workflow.py -q`
|
||||
- Result: `3 passed`.
|
||||
- Full syntax/test:
|
||||
- Command: `source .venv/bin/activate && python -m py_compile jarca_ledger_mcp/*.py dashboard/app.py && pytest tests/test_backup_workflow.py -q && pytest -q`
|
||||
- Result: backup tests passed, full suite passed with `...........ss.........ss [100%]`.
|
||||
- Full pytest summary:
|
||||
- Command: `source .venv/bin/activate && pytest -ra`
|
||||
- Result: `20 passed, 4 skipped in 16.02s`; skips are sample KB/Toss PDF tests without sample files/passwords.
|
||||
- Restore smoke:
|
||||
- Command: created synthetic tmp DB, created backup via `service.create_ledger_backup`, then ran `python scripts/ledger_restore_smoke.py --backup <tmp backup> --target <tmp restored.sqlite3>`.
|
||||
- Result: `success: true`, backup and restored target `integrity_check: ok`, table counts `{accounts: 1, transactions: 1, budgets: 0, import_batches: 0, category_rules: 0, ledger_categories: 0}`, health check `active_transactions: 1`.
|
||||
- MCP surface check:
|
||||
- Command: `source .venv/bin/activate && hermes mcp test jarca-ledger`
|
||||
- Result: connected, `Tools discovered: 45`, including backup/status tools and no restore tool.
|
||||
|
||||
## Validation
|
||||
- Synthetic DB tests confirmed no operating DB is needed for backup/status/list/hash verification.
|
||||
- Restore smoke used `/tmp/...` source/target only, not `/root/.local/share/jarca/ledger.sqlite3`.
|
||||
- Evidence captured only path, size, mtime, sha256, integrity, row counts, aggregate totals, and health/test results.
|
||||
|
||||
## Remaining Risks
|
||||
- Real operating DB restore remains intentionally untested and requires separate explicit user approval.
|
||||
- Browser/UI copy is not changed in this batch; operator safety guidance is runbook/MCP/script level only.
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
# BAT-002: 운영 안전 백업·복구·검증 DB 워크플로우
|
||||
|
||||
## Metadata
|
||||
- BAT ID: BAT-002
|
||||
- Profile: standard
|
||||
- Status: release-candidate
|
||||
- Source Discovery: dcy-002
|
||||
- Included REQ: REQ-002
|
||||
- Created At (KST): 2026-06-27 10:17
|
||||
- Owner: 렛저장인
|
||||
|
||||
## Scope
|
||||
- Add metadata-only DB status, backup create/list/status helpers.
|
||||
- Expose backup/status/list/hash as additive MCP tools.
|
||||
- Keep restore execution out of MCP and document script/runbook approval path.
|
||||
- Verify with synthetic DB tests and safe restore smoke.
|
||||
- Update runtime, data-model, and interface baseline docs.
|
||||
|
||||
## Out of Scope
|
||||
- 실제 운영 DB restore 실행.
|
||||
- 원본 운영 DB 직접 mutation.
|
||||
- 파괴적 SQLite migration 또는 대량 data rewrite.
|
||||
- 신규 금융기관 parser, CI/CD 구축, 배포 서비스화.
|
||||
|
||||
## Documents
|
||||
- [planning.md](planning.md)
|
||||
- [design.md](design.md)
|
||||
- [implementation.md](implementation.md)
|
||||
- [verification.md](verification.md)
|
||||
|
||||
## Notes
|
||||
- Restore is intentionally script/runbook only; no `restore_*` MCP tool should be added.
|
||||
- Evidence must remain metadata-only and exclude merchant/counterparty full dumps, raw_payload, account numbers, passwords, and source financial files.
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
# BAT-002 Planning
|
||||
|
||||
## Included REQ
|
||||
- REQ-002: 운영 안전 백업·복구·검증 DB 워크플로우
|
||||
|
||||
## Delivery Plan
|
||||
1. Add service helpers for non-sensitive DB status evidence and SQLite online backup creation.
|
||||
2. Add additive MCP tools for backup creation, backup list, backup status/hash, and DB status.
|
||||
3. Add a non-MCP restore smoke script requiring explicit approval for overwriting an existing target DB.
|
||||
4. Add synthetic DB tests for status evidence, backup/list/status/hash, retention, and restore smoke policy.
|
||||
5. Update runtime/data/interface docs and add a runbook.
|
||||
6. Run targeted/full verification and request jarcaledgerqc QC gate.
|
||||
|
||||
## Dependencies
|
||||
- Existing SQLite initialization and additive migration behavior in `jarca_ledger_mcp/db.py`.
|
||||
- Existing service response convention: `{"success": True, ...}` and `fail(...)` error shape.
|
||||
- Synthetic pytest tmp DBs for safe evidence.
|
||||
|
||||
## Design Gate
|
||||
Design required: yes.
|
||||
|
||||
Reason: this batch changes the MCP interface surface and runtime/data safety baseline, and must explicitly preserve restore non-exposure and sensitive evidence restrictions.
|
||||
|
||||
## Milestones
|
||||
- M1: REQ-002 Approved and BAT-002 scaffolded.
|
||||
- M2: Backup/status/list/hash helpers and MCP tools implemented.
|
||||
- M3: Restore smoke script and runbook documented without MCP restore surface.
|
||||
- M4: Synthetic tests and docs evidence complete.
|
||||
- M5: QC gate PASS/PASS_WITH_NOTES, then REQ-002 Implemented.
|
||||
|
||||
## Risks
|
||||
- Accidentally exposing restore as MCP would violate dcy-002 policy.
|
||||
- SQLite WAL copy must be consistent; implementation should use SQLite online backup API rather than raw file copy for backup creation.
|
||||
- Evidence must not serialize sensitive row-level details.
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user