소스 정리
@@ -1,37 +0,0 @@
|
||||
# BAT-001 Implementation
|
||||
|
||||
## Status
|
||||
- Status: implemented-qc-passed
|
||||
- Last Updated (KST): 2026-06-26 23:41
|
||||
|
||||
## Changed Files
|
||||
- `jarca_ledger_mcp/server.py`
|
||||
- `delete_category_rule(rule_id: str)` MCP tool을 additive 등록했다.
|
||||
- `dashboard/app.py`
|
||||
- 분류 규칙 page의 `seed_default_category_rules`, `preview_categorization`, `apply_categorization_rules` 호출이 page-level `db_path`를 전달하도록 수정했다.
|
||||
- `tests/test_category_rule_filters.py`
|
||||
- category rule 삭제 성공, 삭제 후 list 제외, missing ID `not_found` regression을 추가했다.
|
||||
- StagePilot 문서
|
||||
- `docs/srs/Interface/req-001_category-rule-ops.md`
|
||||
- `docs/srs/index.md`
|
||||
- `docs/batches/bat-001_20260626_category-rule-ops/*`
|
||||
- `docs/batches/index.md`
|
||||
- `docs/discovery/dcy-001_20260626_streamlit-ux-e2e-categorization-refund-workflows.md`
|
||||
|
||||
## Execution Log
|
||||
- 2026-06-26 23:31 KST: batch-lite 계획 수립.
|
||||
- 2026-06-26 23:33 KST: MCP delete tool, Streamlit db_path 전달, deletion regression test 구현.
|
||||
- 2026-06-26 23:36 KST: service/pytest/MCP/Streamlit AppTest smoke 검증 완료.
|
||||
- 2026-06-26 23:41 KST: 검수관 QC gate `PASS_WITH_NOTES` 확인, blocker 없음.
|
||||
|
||||
## Validation During Implementation
|
||||
- `python -m py_compile jarca_ledger_mcp/*.py dashboard/app.py`: pass.
|
||||
- `pytest tests/test_category_rule_filters.py`: 3 passed.
|
||||
- `pytest tests/test_cross_account_transfer_matching.py`: 3 passed.
|
||||
- `pytest`: 17 passed, 4 skipped.
|
||||
- `hermes mcp test jarca-ledger`: connected, 41 tools discovered, `delete_category_rule` discovered.
|
||||
- Streamlit smoke: port 8502 synthetic fixture DB `/tmp/jarca-ledger-bat-001-smoke.sqlite3`; browser tool unavailable because local Chromium snap is not installed, so `streamlit.testing.v1.AppTest` was used. 분류 규칙 page rendered without exceptions; title/subheader/buttons/rule item were visible; preview/apply buttons ran without errors; default 운영 DB mtime unchanged.
|
||||
|
||||
## Remaining Risks
|
||||
- Browser screenshot evidence was not captured because `/usr/bin/chromium-browser` requires the unavailable chromium snap. AppTest + HTTP 200 smoke was used as substitute evidence.
|
||||
- Import/rollback and cancel/refund workflows remain outside BAT-001 and should be handled by later REQ/BAT.
|
||||
@@ -1,35 +0,0 @@
|
||||
# BAT-001: Category Rule Ops Safety
|
||||
|
||||
## 0. 문서 상태
|
||||
- BAT ID: BAT-001
|
||||
- Profile: batch-lite
|
||||
- Status: release-candidate
|
||||
- Source Discovery: dcy-001_20260626_streamlit-ux-e2e-categorization-refund-workflows
|
||||
- Included REQ: REQ-001
|
||||
- Created At (KST): 2026-06-26 23:31
|
||||
- Last Updated (KST): 2026-06-26 23:41
|
||||
|
||||
## 1. Scope
|
||||
분류 규칙 lifecycle 중 가장 작고 검증 가능한 운영 액션을 안정화한다.
|
||||
|
||||
### Included
|
||||
- Streamlit 분류 규칙 seed/preview/apply 액션이 선택된 `db_path`를 사용하도록 수정.
|
||||
- MCP tool surface에 `delete_category_rule` additive 등록.
|
||||
- service-level category rule deletion regression test 추가.
|
||||
- py_compile, pytest, MCP tool smoke, Streamlit screenshot/browser smoke 증거 기록.
|
||||
|
||||
### Excluded
|
||||
- 신규 parser 추가.
|
||||
- 파괴적 SQLite migration.
|
||||
- 운영 원본 DB 직접 mutation.
|
||||
- import/rollback 전체 E2E와 취소/환급 연결 workflow 구현.
|
||||
|
||||
## 2. Documents
|
||||
- Planning: [planning.md](planning.md)
|
||||
- Implementation: [implementation.md](implementation.md)
|
||||
- Verification: [verification.md](verification.md)
|
||||
|
||||
## 3. Notes
|
||||
- 단일 REQ, additive MCP tool, UI DB-path bug fix만 포함하므로 `batch-lite`로 진행한다.
|
||||
- 구현 중 구조/런타임 flow 변화가 커지면 design 문서를 추가한다.
|
||||
- 검수관 QC gate 결과 `PASS_WITH_NOTES`; blocker 없음. Browser screenshot은 Chromium snap 부재로 대체 smoke(AppTest) 증거를 사용했다.
|
||||
@@ -1,21 +0,0 @@
|
||||
# BAT-001 Planning
|
||||
|
||||
## 1. Goal
|
||||
REQ-001의 분류 규칙 운영 액션을 작은 단위로 구현하고 검증한다.
|
||||
|
||||
## 2. Design Gate
|
||||
- Decision: design.md 생략, batch-lite 유지.
|
||||
- Rationale: schema 변경이나 신규 runtime flow 없이 기존 service function을 MCP에 additive 등록하고 dashboard 호출부의 `db_path` 전달 누락을 수정하는 국소 변경이다.
|
||||
|
||||
## 3. Implementation Plan
|
||||
1. `server.py`에 `delete_category_rule(rule_id: str)` MCP tool을 추가한다.
|
||||
2. `dashboard/app.py`의 분류 규칙 seed/update, preview, apply 호출에 `db_path=db_path`를 전달한다.
|
||||
3. `tests/test_category_rule_filters.py`에 삭제 성공/삭제 후 list 제외/없는 ID 실패 regression을 추가한다.
|
||||
4. 검증 명령을 실행하고 결과를 `verification.md`에 기록한다.
|
||||
5. 검수관 QC gate PASS 후 REQ-001을 Implemented로 전환한다.
|
||||
|
||||
## 4. Risks and Mitigations
|
||||
- Risk: Streamlit smoke 중 기본 운영 DB를 건드릴 수 있음.
|
||||
- Mitigation: `JARCA_LEDGER_DB_PATH`를 tmp synthetic DB로 지정해 dashboard를 실행한다.
|
||||
- Risk: MCP tool 목록이 캐시되어 신규 tool이 보이지 않을 수 있음.
|
||||
- Mitigation: `hermes mcp test jarca-ledger`로 새 프로세스 기준 smoke를 수행한다.
|
||||
@@ -1,47 +0,0 @@
|
||||
# BAT-001 Verification
|
||||
|
||||
## Status
|
||||
- Ready for Release: true
|
||||
- QC Verdict: PASS_WITH_NOTES
|
||||
- Last Updated (KST): 2026-06-26 23:41
|
||||
|
||||
## Acceptance Mapping
|
||||
|
||||
| REQ | AC | Evidence | Result |
|
||||
| --- | --- | --- | --- |
|
||||
| REQ-001 | AC-1 | `dashboard/app.py` diff: `seed_default_category_rules`, `preview_categorization`, `apply_categorization_rules` now receive `db_path=db_path`; Streamlit AppTest preview/apply smoke used `JARCA_LEDGER_DB_PATH=/tmp/jarca-ledger-bat-001-smoke.sqlite3` and default DB mtime stayed unchanged. | Pass |
|
||||
| REQ-001 | AC-2 | `jarca_ledger_mcp/server.py` diff adds `delete_category_rule(rule_id: str)` MCP tool; `hermes mcp test jarca-ledger` discovered 41 tools including `delete_category_rule`. | Pass |
|
||||
| REQ-001 | AC-3 | `pytest tests/test_category_rule_filters.py` includes `test_delete_category_rule_removes_rule_and_reports_missing_ids`; result: 3 passed. | Pass |
|
||||
| REQ-001 | AC-4 | py_compile, targeted pytest, full pytest, and MCP smoke all passed; command outputs summarized below. | Pass |
|
||||
| REQ-001 | AC-5 | Streamlit was run with synthetic fixture DB `/tmp/jarca-ledger-bat-001-smoke.sqlite3`; no original financial file/password/real account fixture used; `/root/.local/share/jarca/ledger.sqlite3` mtime before/after preview/apply smoke remained `1782190349`. | Pass with substitute smoke |
|
||||
|
||||
## Evidence Log
|
||||
- `python -m py_compile jarca_ledger_mcp/*.py dashboard/app.py` → exit 0.
|
||||
- `pytest tests/test_category_rule_filters.py` → `3 passed in 1.77s`.
|
||||
- `pytest tests/test_cross_account_transfer_matching.py` → `3 passed in 1.92s`.
|
||||
- `pytest` → `17 passed, 4 skipped in 17.63s`.
|
||||
- `hermes mcp test jarca-ledger` → connected in 2460ms; 41 tools discovered; `delete_category_rule` listed.
|
||||
- Streamlit server smoke:
|
||||
- port 8501 was occupied, so port 8502 was used.
|
||||
- `curl -I http://127.0.0.1:8502` → `HTTP/1.1 200 OK`.
|
||||
- Browser tool failed before page load because Chromium snap is not installed: `Chrome exited early ... requires the chromium snap to be installed`.
|
||||
- Substitute AppTest smoke output: `exceptions 0`, title `⚙️ 분류 규칙`, subheader `현재 분류 규칙`, buttons `추가`, `변경`, `삭제`, `기본 규칙 seed/update`, `규칙 preview`, `규칙 적용`, synthetic rule text `스모크상점` present.
|
||||
- AppTest preview/apply output: `preview_exceptions 0`, info `스캔 0건 · 매칭 0건 · 미분류 0건`, `apply_exceptions 0`, success `0건 적용`, default DB mtime unchanged.
|
||||
|
||||
## Blocking Issues
|
||||
- 없음.
|
||||
|
||||
## QC Gate
|
||||
- Reviewer profile: `jarcaledgerqc` (검수관)
|
||||
- Command: `jarcaledgerqc chat -q "QC gate 요청..."`
|
||||
- Verdict: `PASS_WITH_NOTES`
|
||||
- Blockers: 없음
|
||||
- Notes:
|
||||
- Browser-level screenshot evidence was unavailable because Chromium snap is not installed; AppTest + HTTP 200 was accepted as substitute evidence for this small BAT.
|
||||
- Future Streamlit UX/E2E batches should restore real browser/screenshot evidence.
|
||||
- Optional future strengthening: temp MCP subprocess create/delete/list actual tool-call E2E.
|
||||
|
||||
## Notes
|
||||
- No destructive migration.
|
||||
- No direct mutation of the original 운영 DB during smoke; only mtime check was performed on default DB.
|
||||
- Browser screenshot evidence was attempted but blocked by missing Chromium; AppTest + HTTP 200 evidence is the recorded semi-automated substitute.
|
||||
@@ -1,42 +0,0 @@
|
||||
# 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`.
|
||||
@@ -1,62 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,33 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,34 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,111 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,28 +0,0 @@
|
||||
# BAT-003 Implementation
|
||||
|
||||
## 코드 변경
|
||||
|
||||
- `jarca_ledger_mcp/db.py`
|
||||
- schema version 7
|
||||
- `accounts.statement_status TEXT NOT NULL DEFAULT 'unknown'`
|
||||
- 기존 DB용 additive column migration
|
||||
- `jarca_ledger_mcp/service.py`
|
||||
- `VALID_STATEMENT_STATUSES` 및 reconciliation 대상 상수
|
||||
- `create_ledger_account`에 `statement_status` 입력 추가
|
||||
- `update_ledger_account` 신규 추가
|
||||
- `get_balance_reconciliation_report` 신규 추가
|
||||
- `jarca_ledger_mcp/server.py`
|
||||
- `create_ledger_account` signature 확장
|
||||
- `update_ledger_account`, `get_balance_reconciliation_report` MCP tool 추가
|
||||
- `dashboard/app.py`
|
||||
- 계좌 화면에 statement 상태 표시/수정 UI 추가
|
||||
- 최소 잔액대조 결과 표 추가
|
||||
- `tests/test_service.py`
|
||||
- schema version 7 반영
|
||||
- statement status validation 및 balance reconciliation 테스트 추가
|
||||
|
||||
## 운영 안전
|
||||
|
||||
- 운영 DB 변경 전 dcy-002 백업 절차를 먼저 수행한다.
|
||||
- 검증 DB에서 preview/reconcile 후 운영 DB에 반영한다.
|
||||
- restore는 사용자의 명시 승인 없이 실행하지 않는다.
|
||||
@@ -1,25 +0,0 @@
|
||||
# BAT-003 Statement-unavailable 수동 증빙 및 잔액대조
|
||||
|
||||
- Profile: batch-lite
|
||||
- Status: release-candidate
|
||||
- Included REQ: REQ-003
|
||||
- Discovery: dcy-003
|
||||
- Owner: 렛저장인
|
||||
- Date (KST): 2026-06-29
|
||||
|
||||
## 목표
|
||||
|
||||
statement 파일이 없거나 일부만 import 가능한 계좌를 `statement_status`로 구분하고, 수동 실행 가능한 잔액대조 report 및 계좌 화면 최소 UI를 제공한다.
|
||||
|
||||
## 산출물
|
||||
|
||||
- `accounts.statement_status` additive migration
|
||||
- service 계좌 update 및 잔액대조 report
|
||||
- MCP tool surface 추가
|
||||
- dashboard 계좌 화면 표시/수정/대조 결과
|
||||
- REQ-003 및 운영 문서 갱신
|
||||
- pytest 기반 regression 검증
|
||||
|
||||
## 범위 제한
|
||||
|
||||
자동 스케줄링/알림, 전용 워크벤치 전체 신설, 자동 확정 mutation, 사용자 승인 없는 restore는 포함하지 않는다.
|
||||
@@ -1,35 +0,0 @@
|
||||
# BAT-003 Verification
|
||||
|
||||
## 검증 계획
|
||||
|
||||
1. Python 문법 검증
|
||||
- `python3 -m py_compile jarca_ledger_mcp/db.py jarca_ledger_mcp/service.py jarca_ledger_mcp/server.py dashboard/app.py tests/test_service.py`
|
||||
2. 대상 테스트
|
||||
- `python3 -m pytest tests/test_service.py -q`
|
||||
3. 전체 테스트
|
||||
- 가능하면 `python3 -m pytest -q`
|
||||
|
||||
## Acceptance Mapping
|
||||
|
||||
- AC-1/2: `test_health_check_initializes_db`, `test_invalid_statement_status_rejected`
|
||||
- AC-3/4: `test_statement_status_account_update_and_balance_reconciliation`
|
||||
- AC-5: dashboard py_compile 및 계좌 page 코드 검증
|
||||
- AC-6: server py_compile 및 tool 함수 추가 확인
|
||||
- AC-7: REQ/batch/data-model/interface/runtime/runbook 문서 갱신
|
||||
|
||||
## 결과
|
||||
|
||||
최종 검증 결과(2026-06-29 KST):
|
||||
|
||||
- `python -m py_compile dashboard/app.py jarca_ledger_mcp/service.py jarca_ledger_mcp/server.py jarca_ledger_mcp/db.py` — PASS
|
||||
- `pytest tests/test_service.py tests/test_categorization.py tests/test_uncategorized_workbench.py -q` — PASS (`12 passed`)
|
||||
- `pytest -q` — PASS (`28 passed, 4 skipped`)
|
||||
- Streamlit `AppTest.from_file('dashboard/app.py')` with synthetic temp DB and `?page=계좌` — PASS; account page rendered without exceptions and exposed `잔액대조 실행`.
|
||||
|
||||
검증 중 발견/수정:
|
||||
|
||||
- `tests/test_ledger_categories.py`의 schema version 기대값이 이전 버전 `6`으로 남아 있어 `7`로 갱신했다.
|
||||
|
||||
남은 범위 외 항목:
|
||||
|
||||
- dcy-004/dcy-005 문서는 현재 작업 범위가 아니므로 구현을 시작하지 않았다.
|
||||
|
Before Width: | Height: | Size: 290 KiB |
@@ -1,62 +0,0 @@
|
||||
{
|
||||
"success": true,
|
||||
"base_url": "http://127.0.0.1:18501",
|
||||
"output_dir": "/root/projects/jarca-ledger-mcp/docs/batches/bat-004_20260629_browser-streamlit-e2e-evidence/evidence/run-20260629-192835",
|
||||
"fixture": {
|
||||
"account_id": "acct_a4f4de4cdd0f",
|
||||
"transaction_ids": [
|
||||
"tx_cba36b3d2c33",
|
||||
"tx_24fa1050eb2b",
|
||||
"tx_8cd3af3d60b6"
|
||||
],
|
||||
"db_path": "docs/batches/bat-004_20260629_browser-streamlit-e2e-evidence/evidence/run-20260629-192835/fixture.sqlite3"
|
||||
},
|
||||
"chrome": "/usr/bin/google-chrome-stable",
|
||||
"streamlit": ".venv/bin/streamlit",
|
||||
"pages": [
|
||||
{
|
||||
"page": "분류 규칙",
|
||||
"url": "http://127.0.0.1:18501/?page=%EB%B6%84%EB%A5%98%20%EA%B7%9C%EC%B9%99",
|
||||
"screenshot": "docs/batches/bat-004_20260629_browser-streamlit-e2e-evidence/evidence/run-20260629-192835/rules.png",
|
||||
"screenshot_bytes": 364876,
|
||||
"snapshot": "docs/batches/bat-004_20260629_browser-streamlit-e2e-evidence/evidence/run-20260629-192835/rules.dom.html",
|
||||
"snapshot_bytes": 174470,
|
||||
"devtools_port": 19222,
|
||||
"inner_text_head": "💰 Jarca Ledger\n\n가계부 · 분류 · Import 운영 콘솔\n\n메뉴\n요약\n거래내역\n확인필요 큐\n미분류\n분류 규칙\n카테고리\n계좌\nImport\nStop\nDeploy\n⚙️ Rule Engine\n분류 규칙\n\n반복되는 사용처와 거래 패턴을 규칙으로 관리해 분류 자동화 품질을 높입니다.\n\n자동 분류\nPreview\nSeed/Update\nkeyboard_arrow_right\n\n🟢 이자 · merchant/contains → 수입 / 이자 · p10 · income\n\nkeyboard_arrow_right\n\n🟢 환급 · merchant/contains → 수입 / 환급 · p10 · income\n\nkeyboard_arrow_right\n\n🟢 급여 · merchant/contains → 수입 / 급여 · p10 · income\n\nkeyboard_arrow_right\n\n🟢 KB카드출금 · merchant/contains → 금융 / 카드대금 · p20 · expense\n\nkeyboard_arro"
|
||||
},
|
||||
{
|
||||
"page": "확인필요 큐",
|
||||
"url": "http://127.0.0.1:18501/?page=%ED%99%95%EC%9D%B8%ED%95%84%EC%9A%94%20%ED%81%90",
|
||||
"screenshot": "docs/batches/bat-004_20260629_browser-streamlit-e2e-evidence/evidence/run-20260629-192835/transfer-review.png",
|
||||
"screenshot_bytes": 275792,
|
||||
"snapshot": "docs/batches/bat-004_20260629_browser-streamlit-e2e-evidence/evidence/run-20260629-192835/transfer-review.dom.html",
|
||||
"snapshot_bytes": 25551,
|
||||
"devtools_port": 19223,
|
||||
"inner_text_head": "💰 Jarca Ledger\n\n가계부 · 분류 · Import 운영 콘솔\n\n메뉴\n요약\n거래내역\n확인필요 큐\n미분류\n분류 규칙\n카테고리\n계좌\nImport\nStop\nDeploy\n🔁 Transfer Review\nKB↔토스뱅크 확인필요 큐\n\n날짜·금액·상대 기준으로 계좌 간 이동 후보를 대조하고, 드라이런 후 안전하게 매칭합니다.\n\n드라이런 우선\n본인계좌이동\n수동 검토\n📌\n확인필요 큐\n\n거래 ID: tx_8cd3af3d60b6\n\n2026-06-29 · SYNTHETIC_TRANSFER · 120,000원"
|
||||
},
|
||||
{
|
||||
"page": "Import",
|
||||
"url": "http://127.0.0.1:18501/?page=Import",
|
||||
"screenshot": "docs/batches/bat-004_20260629_browser-streamlit-e2e-evidence/evidence/run-20260629-192835/import.png",
|
||||
"screenshot_bytes": 297424,
|
||||
"snapshot": "docs/batches/bat-004_20260629_browser-streamlit-e2e-evidence/evidence/run-20260629-192835/import.dom.html",
|
||||
"snapshot_bytes": 23649,
|
||||
"devtools_port": 19224,
|
||||
"inner_text_head": "💰 Jarca Ledger\n\n가계부 · 분류 · Import 운영 콘솔\n\nStop\nDeploy\n\n토스증권 거래내역서 PDF를 업로드하면 투자계좌 거래로 가져옵니다. 매수/매도/환전/입출금은 이체/투자이동, 배당/이자는 실제 수입으로 분류합니다.\n\n토스뱅크 계좌 거래내역 PDF를 업로드하면 입출금/이체/카드결제를 가져옵니다. 타인 이체/출금은 이체/확인필요로 분류됩니다."
|
||||
}
|
||||
],
|
||||
"server_command": [
|
||||
".venv/bin/streamlit",
|
||||
"run",
|
||||
"dashboard/app.py",
|
||||
"--server.address",
|
||||
"127.0.0.1",
|
||||
"--server.port",
|
||||
"18501",
|
||||
"--server.headless",
|
||||
"true",
|
||||
"--browser.gatherUsageStats",
|
||||
"false"
|
||||
],
|
||||
"server_log_tail": ""
|
||||
}
|
||||
|
Before Width: | Height: | Size: 356 KiB |
|
Before Width: | Height: | Size: 269 KiB |
|
Before Width: | Height: | Size: 291 KiB |
@@ -1,62 +0,0 @@
|
||||
{
|
||||
"success": true,
|
||||
"base_url": "http://127.0.0.1:18501",
|
||||
"output_dir": "/root/projects/jarca-ledger-mcp/docs/batches/bat-004_20260629_browser-streamlit-e2e-evidence/evidence/run-20260629-195632",
|
||||
"fixture": {
|
||||
"account_id": "acct_7579e5091359",
|
||||
"transaction_ids": [
|
||||
"tx_22a85feba578",
|
||||
"tx_04e500d0745c",
|
||||
"tx_3ee6a6e14179"
|
||||
],
|
||||
"db_path": "docs/batches/bat-004_20260629_browser-streamlit-e2e-evidence/evidence/run-20260629-195632/fixture.sqlite3"
|
||||
},
|
||||
"chrome": "/usr/bin/google-chrome-stable",
|
||||
"streamlit": ".venv/bin/streamlit",
|
||||
"pages": [
|
||||
{
|
||||
"page": "분류 규칙",
|
||||
"url": "http://127.0.0.1:18501/?page=%EB%B6%84%EB%A5%98%20%EA%B7%9C%EC%B9%99",
|
||||
"screenshot": "docs/batches/bat-004_20260629_browser-streamlit-e2e-evidence/evidence/run-20260629-195632/rules.png",
|
||||
"screenshot_bytes": 364622,
|
||||
"snapshot": "docs/batches/bat-004_20260629_browser-streamlit-e2e-evidence/evidence/run-20260629-195632/rules.dom.html",
|
||||
"snapshot_bytes": 190599,
|
||||
"devtools_port": 19222,
|
||||
"inner_text_head": "💰 Jarca Ledger\n\n가계부 · 분류 · Import 운영 콘솔\n\n메뉴\n요약\n거래내역\n확인필요 큐\n미분류\n분류 규칙\n카테고리\n계좌\nImport\nStop\nDeploy\n⚙️ Rule Engine\n분류 규칙\n\n반복되는 사용처와 거래 패턴을 규칙으로 관리해 분류 자동화 품질을 높입니다.\n\n자동 분류\nPreview\nSeed/Update\n📚\n현재 분류 규칙\nkeyboard_arrow_right\n\n🟢 급여 · merchant/contains → 수입 / 급여 · p10 · income\n\nkeyboard_arrow_right\n\n🟢 이자 · merchant/contains → 수입 / 이자 · p10 · income\n\nkeyboard_arrow_right\n\n🟢 환급 · merchant/contains → 수입 / 환급 · p10 · income\n\nkeyboard_arrow_right\n\n🟢 KB카드출금 · merchant/contains → 금융 / 카드대금 · p20 · expense\n\nke"
|
||||
},
|
||||
{
|
||||
"page": "확인필요 큐",
|
||||
"url": "http://127.0.0.1:18501/?page=%ED%99%95%EC%9D%B8%ED%95%84%EC%9A%94%20%ED%81%90",
|
||||
"screenshot": "docs/batches/bat-004_20260629_browser-streamlit-e2e-evidence/evidence/run-20260629-195632/transfer-review.png",
|
||||
"screenshot_bytes": 282069,
|
||||
"snapshot": "docs/batches/bat-004_20260629_browser-streamlit-e2e-evidence/evidence/run-20260629-195632/transfer-review.dom.html",
|
||||
"snapshot_bytes": 27701,
|
||||
"devtools_port": 19223,
|
||||
"inner_text_head": "💰 Jarca Ledger\n\n가계부 · 분류 · Import 운영 콘솔\n\n메뉴\n요약\n거래내역\n확인필요 큐\n미분류\n분류 규칙\n카테고리\n계좌\nImport\n\n새로고침\n\nStop\nDeploy\n🔁 Transfer Review\nKB↔토스뱅크 확인필요 큐\n\n날짜·금액·상대 기준으로 계좌 간 이동 후보를 대조하고, 드라이런 후 안전하게 매칭합니다.\n\n드라이런 우선\n본인계좌이동\n수동 검토\n\n미리보기(드라이런)\n\n자동 매칭 실행\n\n📌\n확인필요 큐\n\n거래 ID: tx_3ee6a6e14179\n\n2026-06-29 · SYNTHETIC_TRANSFER · 120,000원"
|
||||
},
|
||||
{
|
||||
"page": "Import",
|
||||
"url": "http://127.0.0.1:18501/?page=Import",
|
||||
"screenshot": "docs/batches/bat-004_20260629_browser-streamlit-e2e-evidence/evidence/run-20260629-195632/import.png",
|
||||
"screenshot_bytes": 298123,
|
||||
"snapshot": "docs/batches/bat-004_20260629_browser-streamlit-e2e-evidence/evidence/run-20260629-195632/import.dom.html",
|
||||
"snapshot_bytes": 15721,
|
||||
"devtools_port": 19224,
|
||||
"inner_text_head": "💰 Jarca Ledger\n\n가계부 · 분류 · Import 운영 콘솔\n\nStop\nDeploy\n\n토스증권 거래내역서 PDF를 업로드하면 투자계좌 거래로 가져옵니다. 매수/매도/환전/입출금은 이체/투자이동, 배당/이자는 실제 수입으로 분류합니다.\n\n토스뱅크 계좌 거래내역 PDF를 업로드하면 입출금/이체/카드결제를 가져옵니다. 타인 이체/출금은 이체/확인필요로 분류됩니다."
|
||||
}
|
||||
],
|
||||
"server_command": [
|
||||
".venv/bin/streamlit",
|
||||
"run",
|
||||
"dashboard/app.py",
|
||||
"--server.address",
|
||||
"127.0.0.1",
|
||||
"--server.port",
|
||||
"18501",
|
||||
"--server.headless",
|
||||
"true",
|
||||
"--browser.gatherUsageStats",
|
||||
"false"
|
||||
],
|
||||
"server_log_tail": ""
|
||||
}
|
||||
|
Before Width: | Height: | Size: 356 KiB |
|
Before Width: | Height: | Size: 276 KiB |
@@ -1,44 +0,0 @@
|
||||
{
|
||||
"success": true,
|
||||
"base_url": "http://127.0.0.1:18501",
|
||||
"output_dir": "/root/projects/jarca-ledger-mcp/docs/batches/bat-004_20260629_browser-streamlit-e2e-evidence/evidence/run-20260630-071603",
|
||||
"fixture": {
|
||||
"account_id": "acct_75c4cbc5a305",
|
||||
"transaction_ids": [
|
||||
"tx_2123d9b9c1f5",
|
||||
"tx_a13db72f4885",
|
||||
"tx_3edaa32c38ae",
|
||||
"tx_fe176567300b",
|
||||
"tx_d674d4ddbf1e"
|
||||
],
|
||||
"db_path": "docs/batches/bat-004_20260629_browser-streamlit-e2e-evidence/evidence/run-20260630-071603/fixture.sqlite3"
|
||||
},
|
||||
"chrome": "/usr/bin/google-chrome-stable",
|
||||
"streamlit": ".venv/bin/streamlit",
|
||||
"pages": [
|
||||
{
|
||||
"page": "요약",
|
||||
"url": "http://127.0.0.1:18501/?page=%EC%9A%94%EC%95%BD",
|
||||
"screenshot": "docs/batches/bat-004_20260629_browser-streamlit-e2e-evidence/evidence/run-20260630-071603/overview.png",
|
||||
"screenshot_bytes": 300562,
|
||||
"snapshot": "docs/batches/bat-004_20260629_browser-streamlit-e2e-evidence/evidence/run-20260630-071603/overview.dom.html",
|
||||
"snapshot_bytes": 33871,
|
||||
"devtools_port": 19222,
|
||||
"inner_text_head": "💰 Jarca Ledger\n\n가계부 · 분류 · Import 운영 콘솔\n\n메뉴\n요약\n거래내역\n확인필요 큐\n미분류\n분류 규칙\n카테고리\n계좌\nImport\n\n새로고침\n\nStop\nDeploy\n📊 요약\n가계부 운영 대시보드\n\n이번 달 실제 현금흐름, 자산 유동성, 운영 경고를 우선순위대로 확인합니다.\n\nschema v8\nKST 이번 달\nlast_balance 기준 자산\n\nDB: /root/projects/jarca-ledger-mcp/docs/batches/bat-004_20260629_browser-streamlit-e2e-evidence/evidence/run-20260630-071603/fixture.sqlite3\n\n💎\n이번 달 수입/지출 현황\n\n기준: KST 현재 월 2026-06, transactions.transaction_date, ledger_categories.cashflow_kind 실제 현금흐름\n\n🏦\n자산 유동성 현황\n\n기준: accounts.liquidity_bucket"
|
||||
}
|
||||
],
|
||||
"server_command": [
|
||||
".venv/bin/streamlit",
|
||||
"run",
|
||||
"dashboard/app.py",
|
||||
"--server.address",
|
||||
"127.0.0.1",
|
||||
"--server.port",
|
||||
"18501",
|
||||
"--server.headless",
|
||||
"true",
|
||||
"--browser.gatherUsageStats",
|
||||
"false"
|
||||
],
|
||||
"server_log_tail": ""
|
||||
}
|
||||
|
Before Width: | Height: | Size: 294 KiB |
@@ -1,33 +0,0 @@
|
||||
# BAT-004 Implementation
|
||||
|
||||
## 코드 변경
|
||||
|
||||
- `scripts/streamlit_browser_evidence.py`
|
||||
- synthetic fixture DB 생성.
|
||||
- 운영 DB 기본 경로 사용 거부 안전장치.
|
||||
- Streamlit local server 기동 및 HTTP 200 readiness 확인.
|
||||
- `/usr/bin/google-chrome-stable` headless Chrome DevTools Protocol 연결.
|
||||
- page별 DOM 텍스트 로드 확인 후 PNG screenshot 및 DOM snapshot 저장.
|
||||
- manifest JSON에 evidence path/byte size/fixture DB/command 정보를 기록.
|
||||
- `dashboard/app.py`
|
||||
- Import page의 import batch 조회와 rollback 실행이 현재 dashboard `db_path`를 사용하도록 수정.
|
||||
- 이 수정은 browser evidence fixture DB 원칙을 지키기 위한 안전 보완이며 운영 DB 누수를 막는다.
|
||||
|
||||
## 문서 변경
|
||||
|
||||
- `docs/srs/Testing/req-004_browser-streamlit-e2e-evidence-recovery.md`
|
||||
- `docs/batches/bat-004_20260629_browser-streamlit-e2e-evidence/`
|
||||
- `docs/runbooks/streamlit-browser-evidence.md`
|
||||
- `docs/runtime-flows.md`
|
||||
- `docs/interface-contract.md`
|
||||
- `docs/project-structure.md`
|
||||
- `docs/srs/index.md`
|
||||
- `docs/batches/index.md`
|
||||
- source Discovery의 생성된 REQ 참조
|
||||
|
||||
## 운영 안전
|
||||
|
||||
- evidence script는 `~/.local/share/jarca/ledger.sqlite3`를 fixture DB로 사용하는 것을 거부한다.
|
||||
- fixture에는 `SYNTHETIC_*` 가짜 계좌/거래/상대명만 사용한다.
|
||||
- 원본 금융 파일, 실제 계좌번호, 비밀번호, raw_payload는 screenshot/log/docs에 남기지 않는다.
|
||||
- CI 통합은 이번 batch 범위가 아니며, 로컬 재현 절차만 제공한다.
|
||||
@@ -1,24 +0,0 @@
|
||||
# BAT-004 Browser/Streamlit E2E evidence 환경 복구
|
||||
|
||||
- Profile: batch-lite
|
||||
- Status: release-candidate
|
||||
- Included REQ: REQ-004
|
||||
- Discovery: dcy-004
|
||||
- Owner: 렛저장인
|
||||
- Date (KST): 2026-06-29
|
||||
|
||||
## 목표
|
||||
|
||||
Streamlit UI batch 검증에서 AppTest/HTTP 200 대체 증거에 머물지 않도록, synthetic DB와 `/usr/bin/google-chrome-stable` 기반 로컬 browser screenshot/snapshot evidence 절차를 복구한다.
|
||||
|
||||
## 산출물
|
||||
|
||||
- `scripts/streamlit_browser_evidence.py` 로컬 evidence 수집 스크립트
|
||||
- `docs/runbooks/streamlit-browser-evidence.md` 운영 runbook
|
||||
- REQ-004 및 BAT-004 planning/implementation/verification 문서
|
||||
- runtime/interface/project-structure 문서의 evidence gate 기준 갱신
|
||||
- synthetic DB 기반 browser screenshot/snapshot evidence
|
||||
|
||||
## 범위 제한
|
||||
|
||||
CI 통합, Playwright/Selenium 도입, pixel-diff visual regression, Streamlit 신규 화면 기능 개발은 포함하지 않는다.
|
||||
@@ -1,31 +0,0 @@
|
||||
# BAT-004 Planning
|
||||
|
||||
## 구현 전략
|
||||
|
||||
1. `REQ-004`를 Testing 요구사항으로 정리한다.
|
||||
2. 운영 DB와 실제 금융 파일을 배제한 synthetic fixture DB를 evidence script가 직접 생성한다.
|
||||
3. Streamlit은 `JARCA_LEDGER_DB_PATH=<fixture.sqlite3>`로 기동한다.
|
||||
4. `/usr/bin/google-chrome-stable` headless + Chrome DevTools Protocol로 대상 페이지를 열고, 화면 텍스트 로드 완료를 확인한 뒤 screenshot과 DOM snapshot을 저장한다.
|
||||
5. UI/dashboard 영향 batch의 QC gate 기준을 문서화한다.
|
||||
|
||||
## Design Gate
|
||||
|
||||
- Profile: `batch-lite`
|
||||
- 판단 근거: 신규 도메인 기능이나 DB schema 변경 없이 검증 스크립트와 문서 기준을 추가한다.
|
||||
- 설계 문서 별도 작성 여부: 별도 `design.md`는 만들지 않는다. 구현 결정은 이 planning 및 REQ-004에 충분히 국소적으로 기록한다.
|
||||
|
||||
## Evidence Gate 기준
|
||||
|
||||
| Batch 유형 | 최소 evidence | Gate 판정 |
|
||||
| --- | --- | --- |
|
||||
| Streamlit UI 또는 `dashboard/app.py` 영향 | Browser screenshot + DOM snapshot + manifest | 누락 시 BLOCK 또는 재검증 |
|
||||
| 비-UI service/MCP/parser 변경 | pytest/py_compile 중심, browser evidence 선택 | browser 누락은 비차단 |
|
||||
| docs-only 변경 | 문서 diff/review | browser evidence 불필요 |
|
||||
| Chrome 환경 장애가 입증된 UI 변경 | AppTest + HTTP 200 + 실패 원인 로그 | `PASS_WITH_NOTES`만 허용 |
|
||||
|
||||
## 리스크와 완화
|
||||
|
||||
- Chrome/DevTools 기동 실패: 실행 전 Chrome 경로를 검증하고 명확한 오류를 출력한다.
|
||||
- Streamlit 렌더링 지연: HTTP 200 대기 후 CDP에서 page 제목 텍스트가 실제 DOM에 나타날 때까지 대기한다.
|
||||
- 민감정보 노출: script가 기본 운영 DB 경로를 거부하고 synthetic fixture만 생성한다.
|
||||
- dependency 증가: Playwright/Selenium을 추가하지 않고 현재 dashboard extra에 이미 존재하는 `websockets`를 사용한다.
|
||||
@@ -1,43 +0,0 @@
|
||||
# BAT-004 Verification
|
||||
|
||||
## 검증 계획
|
||||
|
||||
1. Python 문법 검증
|
||||
- `.venv/bin/python -m py_compile scripts/streamlit_browser_evidence.py dashboard/app.py`
|
||||
2. 대상 browser smoke
|
||||
- `.venv/bin/python scripts/streamlit_browser_evidence.py`
|
||||
- 확인 대상: `분류 규칙`, `확인필요 큐`, `Import`
|
||||
3. 전체 테스트
|
||||
- `.venv/bin/python -m pytest -q`
|
||||
4. evidence 민감정보 검토
|
||||
- manifest와 DOM snapshot에는 synthetic fixture 식별자만 포함되어야 한다.
|
||||
- 운영 DB 기본 경로, 원본 금융 파일명, 비밀번호, 실제 raw_payload는 포함하지 않는다.
|
||||
|
||||
## Acceptance Mapping
|
||||
|
||||
- AC-1: `scripts/streamlit_browser_evidence.py`의 `assert_synthetic_db_path` 및 fixture 생성 로직.
|
||||
- AC-2: py_compile 결과.
|
||||
- AC-3: full pytest 결과.
|
||||
- AC-4/5: browser evidence script manifest 및 screenshot/snapshot 파일.
|
||||
- AC-6: `dashboard/app.py` Import page의 `db_path` 전달 수정.
|
||||
- AC-7: REQ/BAT/runtime/interface/project-structure/runbook 문서 갱신.
|
||||
|
||||
## 결과
|
||||
|
||||
최종 검증 결과(2026-06-29 KST):
|
||||
|
||||
- `.venv/bin/python -m py_compile scripts/streamlit_browser_evidence.py dashboard/app.py jarca_ledger_mcp/db.py jarca_ledger_mcp/service.py jarca_ledger_mcp/server.py tests/test_service.py` — PASS.
|
||||
- `.venv/bin/python -m pytest -ra` — PASS (`27 passed, 4 skipped in 27.37s`).
|
||||
- `.venv/bin/python scripts/streamlit_browser_evidence.py` — PASS.
|
||||
- Evidence directory: `docs/batches/bat-004_20260629_browser-streamlit-e2e-evidence/evidence/run-20260629-192835/`
|
||||
- Manifest: `manifest.json` (`success: true`).
|
||||
- Captured pages:
|
||||
- `분류 규칙`: `rules.png` 364,876 bytes, `rules.dom.html` 174,470 bytes.
|
||||
- `확인필요 큐`: `transfer-review.png` 275,792 bytes, `transfer-review.dom.html` 25,551 bytes.
|
||||
- `Import`: `import.png` 297,424 bytes, `import.dom.html` 23,649 bytes.
|
||||
|
||||
## Sensitive Evidence Review
|
||||
|
||||
- Evidence DB path is the generated fixture path under BAT-004 evidence, not the operating DB default path.
|
||||
- Fixture rows use `SYNTHETIC_*` labels and do not include real account numbers, real financial source filenames, passwords, or raw payloads.
|
||||
- DOM/screenshot evidence was generated from synthetic fixture data only.
|
||||
@@ -1,44 +0,0 @@
|
||||
{
|
||||
"success": true,
|
||||
"base_url": "http://127.0.0.1:18501",
|
||||
"output_dir": "/root/projects/jarca-ledger-mcp/docs/batches/bat-005_20260629_dashboard-operations-hub-liquidity-monthly-cashflow/evidence/run-20260629-2111",
|
||||
"fixture": {
|
||||
"account_id": "acct_6cf9a9db8669",
|
||||
"transaction_ids": [
|
||||
"tx_f60380340545",
|
||||
"tx_8c16f1387fb1",
|
||||
"tx_445884ce8638",
|
||||
"tx_ead36edf0c7e",
|
||||
"tx_dc27408a7e81"
|
||||
],
|
||||
"db_path": "docs/batches/bat-005_20260629_dashboard-operations-hub-liquidity-monthly-cashflow/evidence/run-20260629-2111/fixture.sqlite3"
|
||||
},
|
||||
"chrome": "/usr/bin/google-chrome-stable",
|
||||
"streamlit": ".venv/bin/streamlit",
|
||||
"pages": [
|
||||
{
|
||||
"page": "요약",
|
||||
"url": "http://127.0.0.1:18501/?page=%EC%9A%94%EC%95%BD",
|
||||
"screenshot": "docs/batches/bat-005_20260629_dashboard-operations-hub-liquidity-monthly-cashflow/evidence/run-20260629-2111/overview.png",
|
||||
"screenshot_bytes": 303341,
|
||||
"snapshot": "docs/batches/bat-005_20260629_dashboard-operations-hub-liquidity-monthly-cashflow/evidence/run-20260629-2111/overview.dom.html",
|
||||
"snapshot_bytes": 30757,
|
||||
"devtools_port": 19222,
|
||||
"inner_text_head": "💰 Jarca Ledger\n\n가계부 · 분류 · Import 운영 콘솔\n\n메뉴\n요약\n거래내역\n확인필요 큐\n미분류\n분류 규칙\n카테고리\n계좌\nImport\nStop\nDeploy\n📊 요약\n가계부 운영 대시보드\n\n이번 달 실제 현금흐름, 자산 유동성, 운영 경고를 우선순위대로 확인합니다.\n\nschema v8\nKST 이번 달\nlast_balance 기준 자산\n\nDB: /root/projects/jarca-ledger-mcp/docs/batches/bat-005_20260629_dashboard-operations-hub-liquidity-monthly-cashflow/evidence/run-20260629-2111/fixture.sqlite3\n\n💎\n이번 달 수입/지출 현황\n\n기준: KST 현재 월 2026-06, transactions.transaction_date, ledger_categories.cashflow_kind 실제 현금흐름\n\n🏦\n자산 유동성 현황\n\n기준: accounts.liqu"
|
||||
}
|
||||
],
|
||||
"server_command": [
|
||||
".venv/bin/streamlit",
|
||||
"run",
|
||||
"dashboard/app.py",
|
||||
"--server.address",
|
||||
"127.0.0.1",
|
||||
"--server.port",
|
||||
"18501",
|
||||
"--server.headless",
|
||||
"true",
|
||||
"--browser.gatherUsageStats",
|
||||
"false"
|
||||
],
|
||||
"server_log_tail": ""
|
||||
}
|
||||
|
Before Width: | Height: | Size: 296 KiB |
@@ -1,44 +0,0 @@
|
||||
{
|
||||
"success": true,
|
||||
"base_url": "http://127.0.0.1:18503",
|
||||
"output_dir": "/root/projects/jarca-ledger-mcp/docs/batches/bat-005_20260629_dashboard-operations-hub-liquidity-monthly-cashflow/evidence/run-check-20260630-073738",
|
||||
"fixture": {
|
||||
"account_id": "acct_d3b8cccfccb4",
|
||||
"transaction_ids": [
|
||||
"tx_4b8447f7aa07",
|
||||
"tx_b2ca8a05ac82",
|
||||
"tx_8c989e7c3b15",
|
||||
"tx_f48e63972a9e",
|
||||
"tx_4e20d08f8df3"
|
||||
],
|
||||
"db_path": "docs/batches/bat-005_20260629_dashboard-operations-hub-liquidity-monthly-cashflow/evidence/run-check-20260630-073738/fixture.sqlite3"
|
||||
},
|
||||
"chrome": "/usr/bin/google-chrome-stable",
|
||||
"streamlit": ".venv/bin/streamlit",
|
||||
"pages": [
|
||||
{
|
||||
"page": "요약",
|
||||
"url": "http://127.0.0.1:18503/?page=%EC%9A%94%EC%95%BD",
|
||||
"screenshot": "docs/batches/bat-005_20260629_dashboard-operations-hub-liquidity-monthly-cashflow/evidence/run-check-20260630-073738/overview.png",
|
||||
"screenshot_bytes": 301342,
|
||||
"snapshot": "docs/batches/bat-005_20260629_dashboard-operations-hub-liquidity-monthly-cashflow/evidence/run-check-20260630-073738/overview.dom.html",
|
||||
"snapshot_bytes": 29881,
|
||||
"devtools_port": 19222,
|
||||
"inner_text_head": "💰 Jarca Ledger\n\n가계부 · 분류 · Import 운영 콘솔\n\n메뉴\n요약\n거래내역\n확인필요 큐\n미분류\n분류 규칙\n카테고리\n계좌\nImport\nStop\nDeploy\n📊 요약\n가계부 운영 대시보드\n\n이번 달 실제 현금흐름, 자산 유동성, 운영 경고를 우선순위대로 확인합니다.\n\nschema v8\nKST 이번 달\nlast_balance 기준 자산\n\nDB: /root/projects/jarca-ledger-mcp/docs/batches/bat-005_20260629_dashboard-operations-hub-liquidity-monthly-cashflow/evidence/run-check-20260630-073738/fixture.sqlite3\n\n💎\n이번 달 수입/지출 현황\n\n기준: KST 현재 월 2026-06, transactions.transaction_date, ledger_categories.cashflow_kind 실제 현금흐름\n\n🏦\n자산 유동성 현황\n\n기준: accou"
|
||||
}
|
||||
],
|
||||
"server_command": [
|
||||
".venv/bin/streamlit",
|
||||
"run",
|
||||
"dashboard/app.py",
|
||||
"--server.address",
|
||||
"127.0.0.1",
|
||||
"--server.port",
|
||||
"18503",
|
||||
"--server.headless",
|
||||
"true",
|
||||
"--browser.gatherUsageStats",
|
||||
"false"
|
||||
],
|
||||
"server_log_tail": ""
|
||||
}
|
||||
|
Before Width: | Height: | Size: 294 KiB |
@@ -1,44 +0,0 @@
|
||||
{
|
||||
"success": true,
|
||||
"base_url": "http://127.0.0.1:18501",
|
||||
"output_dir": "/root/projects/jarca-ledger-mcp/docs/batches/bat-005_20260629_dashboard-operations-hub-liquidity-monthly-cashflow/evidence/run-verify-20260629-215958",
|
||||
"fixture": {
|
||||
"account_id": "acct_86182dd8b283",
|
||||
"transaction_ids": [
|
||||
"tx_6e7d47621557",
|
||||
"tx_546ed7a78004",
|
||||
"tx_f40ec3aa2df0",
|
||||
"tx_3207e5cdde0d",
|
||||
"tx_fa79d639eda4"
|
||||
],
|
||||
"db_path": "docs/batches/bat-005_20260629_dashboard-operations-hub-liquidity-monthly-cashflow/evidence/run-verify-20260629-215958/fixture.sqlite3"
|
||||
},
|
||||
"chrome": "/usr/bin/google-chrome-stable",
|
||||
"streamlit": ".venv/bin/streamlit",
|
||||
"pages": [
|
||||
{
|
||||
"page": "요약",
|
||||
"url": "http://127.0.0.1:18501/?page=%EC%9A%94%EC%95%BD",
|
||||
"screenshot": "docs/batches/bat-005_20260629_dashboard-operations-hub-liquidity-monthly-cashflow/evidence/run-verify-20260629-215958/overview.png",
|
||||
"screenshot_bytes": 303039,
|
||||
"snapshot": "docs/batches/bat-005_20260629_dashboard-operations-hub-liquidity-monthly-cashflow/evidence/run-verify-20260629-215958/overview.dom.html",
|
||||
"snapshot_bytes": 32797,
|
||||
"devtools_port": 19222,
|
||||
"inner_text_head": "💰 Jarca Ledger\n\n가계부 · 분류 · Import 운영 콘솔\n\n메뉴\n요약\n거래내역\n확인필요 큐\n미분류\n분류 규칙\n카테고리\n계좌\nImport\n\n새로고침\n\nStop\nDeploy\n📊 요약\n가계부 운영 대시보드\n\n이번 달 실제 현금흐름, 자산 유동성, 운영 경고를 우선순위대로 확인합니다.\n\nschema v8\nKST 이번 달\nlast_balance 기준 자산\n\nDB: /root/projects/jarca-ledger-mcp/docs/batches/bat-005_20260629_dashboard-operations-hub-liquidity-monthly-cashflow/evidence/run-verify-20260629-215958/fixture.sqlite3\n\n💎\n이번 달 수입/지출 현황\n\n기준: KST 현재 월 2026-06, transactions.transaction_date, ledger_categories.cashflow_kind 실제 현금흐름\n\n🏦\n자산 유동성 현황\n\n기"
|
||||
}
|
||||
],
|
||||
"server_command": [
|
||||
".venv/bin/streamlit",
|
||||
"run",
|
||||
"dashboard/app.py",
|
||||
"--server.address",
|
||||
"127.0.0.1",
|
||||
"--server.port",
|
||||
"18501",
|
||||
"--server.headless",
|
||||
"true",
|
||||
"--browser.gatherUsageStats",
|
||||
"false"
|
||||
],
|
||||
"server_log_tail": ""
|
||||
}
|
||||
|
Before Width: | Height: | Size: 296 KiB |
@@ -1,37 +0,0 @@
|
||||
# BAT-005 Implementation
|
||||
|
||||
## 코드 변경
|
||||
|
||||
- `jarca_ledger_mcp/db.py`
|
||||
- schema version을 `8`로 올리고 `accounts.liquidity_bucket TEXT NOT NULL DEFAULT 'other'`를 schema 및 additive migration 목록에 추가한다.
|
||||
- `jarca_ledger_mcp/service.py`
|
||||
- `VALID_LIQUIDITY_BUCKETS`와 `normalize_liquidity_bucket` 검증을 추가한다.
|
||||
- `create_ledger_account`/`update_ledger_account`에서 `liquidity_bucket`을 저장·수정한다.
|
||||
- `get_asset_liquidity_report`를 추가해 `accounts.last_balance` 기반 버킷 합계, 총자산, 총부채, 순자산, 미입력 계좌를 반환한다.
|
||||
- `jarca_ledger_mcp/server.py`
|
||||
- MCP account create/update tool signature에 `liquidity_bucket`을 추가하고 `get_asset_liquidity_report` tool을 노출한다.
|
||||
- `dashboard/app.py`
|
||||
- 요약 화면을 REQ-005 운영 허브 순서로 재구성한다.
|
||||
- KST 현재 월 기준 월간 실제 수입/지출/순현금흐름/저축률을 최상단에 표시한다.
|
||||
- 자산 유동성, 자산 구성, 예산/지출, 운영 경고 섹션을 추가한다.
|
||||
- 계좌 화면에 `liquidity_bucket` 표시/수정 control을 추가한다.
|
||||
- `scripts/streamlit_browser_evidence.py`
|
||||
- synthetic fixture에 `cash`, `investment`, `loan`, `real_estate` bucket 계좌와 월간 수입/지출/예산 데이터를 추가한다.
|
||||
- `tests/test_service.py`
|
||||
- schema version, liquidity bucket 검증, account flow, asset liquidity report regression을 추가한다.
|
||||
|
||||
## 문서 변경
|
||||
|
||||
- `docs/batches/bat-005_20260629_dashboard-operations-hub-liquidity-monthly-cashflow/`
|
||||
- `docs/batches/index.md`
|
||||
- `docs/srs/Interface/req-005_dashboard-operations-hub-liquidity-monthly-cashflow.md`
|
||||
- `docs/data-model.md`
|
||||
- `docs/project-structure.md`
|
||||
- `docs/runtime-flows.md`
|
||||
- `docs/interface-contract.md`
|
||||
|
||||
## 운영 안전
|
||||
|
||||
- 운영 DB와 실제 금융 원본 파일은 사용하지 않는다.
|
||||
- browser evidence는 synthetic fixture DB로만 생성한다.
|
||||
- migration은 additive/idempotent이며 기존 계좌의 bucket은 `other` 기본값으로 안전하게 채워진다.
|
||||
@@ -1,25 +0,0 @@
|
||||
# BAT-005 Dashboard operations hub/liquidity/monthly cashflow
|
||||
|
||||
- Profile: standard
|
||||
- Status: release-candidate
|
||||
- Included REQ: REQ-005
|
||||
- Discovery: dcy-005
|
||||
- Owner: 렛저장인
|
||||
- Date (KST): 2026-06-29
|
||||
|
||||
## 목표
|
||||
|
||||
REQ-005에 따라 Streamlit 요약 화면을 월중 운영 허브로 재구성하고, 계좌 단위 `liquidity_bucket`과 `last_balance`를 권위 소스로 하는 자산 유동성/구성/부채/순자산 뷰를 제공한다.
|
||||
|
||||
## 산출물
|
||||
|
||||
- `accounts.liquidity_bucket` additive/idempotent schema migration
|
||||
- 계좌 create/list/update 및 MCP tool signature의 `liquidity_bucket` 지원
|
||||
- `service.get_asset_liquidity_report` 자산 유동성/순자산 report
|
||||
- `dashboard/app.py` 요약 운영 허브 및 계좌 liquidity bucket 편집 UI
|
||||
- BAT-005 planning/implementation/verification 문서와 baseline 문서 갱신
|
||||
- synthetic/validation DB 기반 Streamlit browser evidence
|
||||
|
||||
## 범위 제한
|
||||
|
||||
실시간 금융 연동, 자동 시세 평가, 별도 `asset_snapshots`/`manual_assets` 테이블, 거래/카테고리 단위 liquidity override, dcy-006 범위는 포함하지 않는다.
|
||||
@@ -1,30 +0,0 @@
|
||||
# BAT-005 Planning
|
||||
|
||||
## 구현 전략
|
||||
|
||||
1. REQ-005의 승인 상태를 입력 gate로 확인하고 BAT-005 batch 문서를 생성한다.
|
||||
2. `accounts.liquidity_bucket`을 additive/idempotent column으로 추가한다. 허용값은 `cash`, `investment`, `deposit`, `real_estate`, `loan`, `other`이며 기존/미지정 계좌는 `other`로 폴백한다.
|
||||
3. 서비스 계층에서 create/list/update 계좌 흐름에 `liquidity_bucket`을 노출하고 허용값 검증을 추가한다.
|
||||
4. 자산 유동성 report는 `accounts.last_balance`만 사용한다. `last_balance`가 없는 비거래 자산/부채는 임의 추정하지 않고 missing warning으로 남긴다.
|
||||
5. `page_overview`는 다음 순서로 재구성한다: 이번 달 수입/지출 현황 → 자산 유동성 현황 → 자산 구성 → 지출 구조/예산 → 운영 경고.
|
||||
6. `scripts/streamlit_browser_evidence.py` synthetic fixture에 overview 검증용 자산/부채/예산/월간 현금흐름 데이터를 추가하고, BAT-005 evidence output directory로 실행한다.
|
||||
|
||||
## Design Gate
|
||||
|
||||
- Profile: `standard`
|
||||
- 판단 근거: DB schema, service/MCP contract, Streamlit UI, tests, baseline docs가 함께 변하는 기능 batch다.
|
||||
- 별도 `design.md`: planning에 설계 결정을 포함하고, 구현 상세는 `implementation.md`에서 추적한다.
|
||||
|
||||
## 핵심 설계 결정
|
||||
|
||||
- 유동성 권위 소스는 계좌 단위 `accounts.liquidity_bucket`으로 고정한다.
|
||||
- 자산 평가는 `accounts.last_balance`를 사용하며, 거래 합계로 부동산/예적금/대출 현재가를 추정하지 않는다.
|
||||
- `loan` 버킷은 자산 구성 비율 분모에서 제외하고 총부채/순자산 계산에만 반영한다.
|
||||
- `last_balance`가 없는 계좌는 계산에서 제외하되 운영 경고에 표시한다.
|
||||
|
||||
## 검증 계획
|
||||
|
||||
- `py_compile` for changed Python files
|
||||
- `pytest tests/test_service.py -q`
|
||||
- full `pytest -q`
|
||||
- `scripts/streamlit_browser_evidence.py --page 요약 --output-dir docs/batches/bat-005_.../evidence/run-...` with synthetic DB
|
||||
@@ -1,44 +0,0 @@
|
||||
# BAT-005 Verification
|
||||
|
||||
## 검증 계획
|
||||
|
||||
1. Python 문법 검증
|
||||
- `.venv/bin/python -m py_compile jarca_ledger_mcp/db.py jarca_ledger_mcp/service.py jarca_ledger_mcp/server.py dashboard/app.py scripts/streamlit_browser_evidence.py tests/test_service.py`
|
||||
2. 대상 service regression
|
||||
- `.venv/bin/python -m pytest tests/test_service.py -q`
|
||||
3. 전체 테스트
|
||||
- `.venv/bin/python -m pytest -q`
|
||||
4. Streamlit browser evidence
|
||||
- `.venv/bin/python scripts/streamlit_browser_evidence.py --page 요약 --output-dir docs/batches/bat-005_20260629_dashboard-operations-hub-liquidity-monthly-cashflow/evidence/run-<timestamp>`
|
||||
5. 민감정보 검토
|
||||
- evidence fixture는 synthetic 데이터만 포함한다.
|
||||
- 운영 DB 기본 경로, 실제 금융 원본 파일명, 비밀번호, raw_payload는 포함하지 않는다.
|
||||
|
||||
## Acceptance Mapping
|
||||
|
||||
- AC-1: `db.py` schema/migration 및 schema version 8.
|
||||
- AC-2: `normalize_liquidity_bucket`, create/update validation tests.
|
||||
- AC-3: account create/list/update regression tests 및 MCP signature.
|
||||
- AC-4: `dashboard/app.py` top section 월간 cashflow metrics.
|
||||
- AC-5/6/7: `get_asset_liquidity_report` regression 및 overview asset/liability/missing balance sections.
|
||||
- AC-8: overview operational warning metrics/caption.
|
||||
- AC-9: pytest 및 browser evidence result.
|
||||
- AC-10: baseline docs updated.
|
||||
|
||||
## 결과
|
||||
|
||||
최종 검증 결과(2026-06-29 KST):
|
||||
|
||||
- `source .venv/bin/activate && python -m py_compile jarca_ledger_mcp/db.py jarca_ledger_mcp/service.py jarca_ledger_mcp/server.py dashboard/app.py scripts/streamlit_browser_evidence.py tests/test_service.py tests/test_ledger_categories.py` — PASS.
|
||||
- `source .venv/bin/activate && pytest tests/test_service.py -q` — PASS (`9 passed`).
|
||||
- `source .venv/bin/activate && pytest -q` — PASS (`31 passed, 4 skipped`).
|
||||
- `source .venv/bin/activate && python scripts/streamlit_browser_evidence.py --page 요약 --output-dir docs/batches/bat-005_20260629_dashboard-operations-hub-liquidity-monthly-cashflow/evidence/run-20260629-2111` — PASS.
|
||||
- Evidence directory: `docs/batches/bat-005_20260629_dashboard-operations-hub-liquidity-monthly-cashflow/evidence/run-20260629-2111/`
|
||||
- Manifest: `manifest.json` (`success: true`).
|
||||
- Captured page: `요약` / `overview.png` 303,341 bytes / `overview.dom.html` 30,757 bytes.
|
||||
- DOM evidence includes `schema v8`, `KST 이번 달`, `이번 달 수입/지출 현황`, and `자산 유동성 현황` from a synthetic fixture DB.
|
||||
|
||||
## Sensitive Evidence Review
|
||||
|
||||
- Evidence DB path is the generated fixture path under BAT-005 evidence, not the operating DB default path.
|
||||
- Fixture rows use `Synthetic`/`SYNTHETIC_*` labels and do not include real account numbers, real financial source filenames, passwords, or raw payloads.
|
||||
@@ -1,64 +0,0 @@
|
||||
# BAT-006 Design
|
||||
|
||||
## Architecture Summary
|
||||
|
||||
BAT-006 introduces a CI safety layer around existing test and smoke assets. GitHub Actions becomes the external gate for PR/push validation, while CI wrapper scripts provide deterministic entrypoints for environment setup, synthetic fixture DB creation, Streamlit readiness checks, DB safety smoke invocation, timeout handling, cleanup, and sensitive-output control.
|
||||
|
||||
The required CI gates are pytest, Streamlit AppTest, dashboard HTTP smoke, and DB safety smoke. Browser screenshot E2E remains a local evidence workflow from dcy-004 and is intentionally excluded from the required CI blocker set.
|
||||
|
||||
## Changed Areas
|
||||
|
||||
- `.github/workflows/`
|
||||
- New workflow for `pull_request`, `push` to `main`, and `workflow_dispatch`.
|
||||
- Required jobs should have stable names so branch protection can reference them later.
|
||||
- `scripts/`
|
||||
- New or adapted CI wrapper entrypoint for dashboard HTTP smoke.
|
||||
- New or adapted CI wrapper entrypoint for DB safety smoke using existing `ledger_restore_smoke.py` logic where appropriate.
|
||||
- Wrapper logs must avoid dumping raw transactions, account numbers, `raw_payload`, source file names, passwords, or live DB paths.
|
||||
- `tests/`
|
||||
- Existing pytest and Streamlit AppTest assets are reused. Add fixture helpers only if needed to make CI deterministic.
|
||||
- `pyproject.toml` / dependency setup
|
||||
- Confirm CI installs the extras required for pytest and dashboard/AppTest execution.
|
||||
- Docs
|
||||
- `docs/project-structure.md`: CI workflow and wrapper responsibilities.
|
||||
- `docs/runtime-flows.md`: PR/push -> CI jobs -> gate result flow and synthetic fixture DB boundary.
|
||||
- `docs/runbooks/`: CI failure reproduction runbook if the workflow/wrapper commands need operator guidance.
|
||||
|
||||
## Key Decisions
|
||||
|
||||
1. CI platform is GitHub Actions, with `pull_request`, `push` to `main`, and optional `workflow_dispatch`.
|
||||
2. Required blocker gates are pytest, Streamlit AppTest, dashboard HTTP smoke, and DB safety smoke.
|
||||
3. HTTP smoke and DB safety smoke use CI-specific thin wrappers rather than ad-hoc shell snippets, so exit codes, logs, readiness, timeout, and cleanup are deterministic.
|
||||
4. Every CI run creates or uses synthetic fixture/temporary validation DBs. The operating DB default path is not used.
|
||||
5. Browser screenshot E2E is not a required CI gate. It remains a local/manual evidence path for UI-heavy changes.
|
||||
6. Branch protection enforcement is external GitHub repository configuration; the batch stabilizes workflow/check names and documents the required-check expectation.
|
||||
|
||||
## CI Job Boundary
|
||||
|
||||
- `pytest` gate:
|
||||
- Install project with test dependencies.
|
||||
- Run the repository pytest suite using the standard project command.
|
||||
- Fail the workflow on any test failure.
|
||||
- `dashboard-app-test` gate:
|
||||
- Prepare synthetic fixture DB.
|
||||
- Run Streamlit AppTest coverage, especially `tests/test_dashboard_app.py`.
|
||||
- Fail with test-level logs only.
|
||||
- `dashboard-http-smoke` gate:
|
||||
- Prepare synthetic fixture DB in runner temp space.
|
||||
- Start Streamlit dashboard with that DB and deterministic port policy.
|
||||
- Poll HTTP readiness until 200 or timeout.
|
||||
- Terminate the server and fail if cleanup fails materially.
|
||||
- `db-safety-smoke` gate:
|
||||
- Prepare source/backup/target paths under runner temp space.
|
||||
- Invoke DB restore/safety smoke without live DB paths.
|
||||
- Fail if overwrite approval policy, integrity check, or fixture health check fails.
|
||||
|
||||
## Sensitive Evidence Boundary
|
||||
|
||||
CI output may include command names, job names, synthetic DB temp paths, test identifiers, exit status, row counts for synthetic fixtures, and high-level error messages. CI output must not include live account numbers, real balances, `raw_payload`, original financial file names, passwords, or full transaction row dumps.
|
||||
|
||||
## Reference Doc Update Plan
|
||||
|
||||
- Update `docs/project-structure.md` to replace the current "CI workflow ... not yet defined" baseline with the BAT-006 workflow and wrapper structure.
|
||||
- Update `docs/runtime-flows.md` with the CI validation flow and the local browser evidence boundary.
|
||||
- Add a `docs/runbooks/ci-smoke.md` or equivalent only if local reproduction commands are not already obvious from the workflow/wrappers.
|
||||
@@ -1,106 +0,0 @@
|
||||
# BAT-006 Implementation
|
||||
|
||||
## Implementation Status
|
||||
- Status: completed-for-qc
|
||||
- Completed At (KST): 2026-06-30 15:23:00 KST
|
||||
- Scope: REQ-006 CI automation, synthetic fixture entrypoints, local CI smoke reproduction docs, and StagePilot evidence/state updates.
|
||||
- Boundary: REQ-006 is not marked Implemented yet; QC by `jarcaledgerqc` is the next gate.
|
||||
|
||||
## Changed Files
|
||||
|
||||
### CI workflow
|
||||
- `.github/workflows/ci.yml`
|
||||
- Added GitHub Actions workflow triggers for `pull_request`, `push` to `main`, and `workflow_dispatch`.
|
||||
- Added stable gate jobs/check names:
|
||||
- `pytest-regression`
|
||||
- `dashboard-app-test`
|
||||
- `dashboard-http-smoke`
|
||||
- `db-safety-smoke`
|
||||
- Each job installs with `uv` and runs its narrow CI gate command.
|
||||
|
||||
### CI fixture and smoke wrappers
|
||||
- `scripts/ci_fixture_db.py`
|
||||
- Added deterministic synthetic fixture DB builder for CI/AppTest/smoke checks.
|
||||
- Refuses the operating ledger DB default path and only allows CI fixture filenames.
|
||||
- Seeds synthetic accounts, budget, and transactions, then verifies SQLite integrity.
|
||||
- `scripts/ci_dashboard_http_smoke.py`
|
||||
- Added dashboard HTTP smoke wrapper.
|
||||
- Creates a temp synthetic fixture DB, starts Streamlit on loopback, polls for HTTP 200 readiness, and terminates/kills the process during cleanup.
|
||||
- Emits status-only JSON with fixture/readiness/cleanup result.
|
||||
- `scripts/ci_db_safety_smoke.py`
|
||||
- Added DB safety wrapper.
|
||||
- Creates temp synthetic source/backup/target DB paths, invokes `scripts/ledger_restore_smoke.py`, and refuses the operating DB path.
|
||||
- Emits status-only JSON with restore/integrity/health result.
|
||||
|
||||
### Tests
|
||||
- `tests/test_dashboard_app.py`
|
||||
- Added Streamlit AppTest coverage that creates a synthetic fixture DB through `scripts/ci_fixture_db.py`, sets `JARCA_LEDGER_DB_PATH`, and checks core pages render without Streamlit exceptions.
|
||||
- Existing transfer review helper tests remain covered in the dashboard AppTest command.
|
||||
|
||||
### Documentation
|
||||
- `docs/project-structure.md`
|
||||
- Documented `.github/workflows/ci.yml`, CI fixture builder, HTTP smoke wrapper, DB safety wrapper, stable gate names, and synthetic fixture policy.
|
||||
- `docs/runtime-flows.md`
|
||||
- Added `CI validation gates` flow and clarified that browser screenshot/DOM evidence remains local evidence, not a required CI gate.
|
||||
- `docs/runbooks/ci-smoke.md`
|
||||
- Added local reproduction commands, wrapper responsibilities, stable GitHub Actions job names, browser evidence boundary, and failure triage guidance.
|
||||
- `docs/batches/bat-006_20260630_pytest-apptest-smoke-ci-automation/implementation.md`
|
||||
- Replaced planned placeholder with actual implementation/evidence log.
|
||||
- `docs/batches/bat-006_20260630_pytest-apptest-smoke-ci-automation/verification.md`
|
||||
- Added AC-by-AC verification evidence and command results.
|
||||
- `docs/batches/bat-006_20260630_pytest-apptest-smoke-ci-automation/index.md`
|
||||
- Moved BAT-006 batch status from `planned` to `release-candidate` for QC.
|
||||
- `docs/batches/index.md`
|
||||
- Moved BAT-006 register status from `planned` to `release-candidate`.
|
||||
|
||||
## Execution Log
|
||||
|
||||
All commands below were run from `/root/projects/jarca-ledger-mcp`.
|
||||
|
||||
1. Pytest regression gate
|
||||
- Command: `uv run pytest --ignore=tests/test_dashboard_app.py -q`
|
||||
- Result: PASS, exit code 0.
|
||||
- Output: `............ss...............ss... [100%]`
|
||||
|
||||
2. Streamlit AppTest gate
|
||||
- Command: `uv run pytest tests/test_dashboard_app.py -q`
|
||||
- Result: PASS, exit code 0.
|
||||
- Output: `.... [100%]`
|
||||
|
||||
3. Dashboard HTTP smoke gate
|
||||
- Command: `uv run python scripts/ci_dashboard_http_smoke.py --host 127.0.0.1 --port 18501 --timeout 45`
|
||||
- Result: PASS, exit code 0.
|
||||
- Output summary:
|
||||
- `success: true`
|
||||
- `gate: dashboard-http-smoke`
|
||||
- `fixture: synthetic`
|
||||
- `fixture_integrity: ok`
|
||||
- `http_status: 200`
|
||||
- `cleanup: terminated`
|
||||
|
||||
4. DB safety smoke gate
|
||||
- Command: `uv run python scripts/ci_db_safety_smoke.py --timeout 45`
|
||||
- Result: PASS, exit code 0.
|
||||
- Output summary:
|
||||
- `success: true`
|
||||
- `gate: db-safety-smoke`
|
||||
- `fixture: synthetic`
|
||||
- `fixture_integrity: ok`
|
||||
- `restore_smoke_exit_code: 0`
|
||||
- `restored_exists: true`
|
||||
- `restored_integrity: ok`
|
||||
- `health_success: true`
|
||||
- `operating_db_used: false`
|
||||
|
||||
## Validation Summary
|
||||
|
||||
- GitHub Actions workflow exists with required BAT-006 trigger shape and stable job names.
|
||||
- CI/AppTest/HTTP/DB safety commands pass locally against synthetic/temp DBs.
|
||||
- Wrapper output is status-only and does not expose real account identifiers, operating DB data, raw payloads, source financial filenames, or passwords.
|
||||
- Browser screenshot/DOM evidence is intentionally not a required CI gate and remains covered by the local browser evidence runbook/flow.
|
||||
|
||||
## Remaining Risks / QC Notes
|
||||
|
||||
- Remote GitHub Actions has not been executed in this local handoff; QC should confirm the workflow on GitHub if remote runner access is available.
|
||||
- Branch protection required-check enforcement is repository configuration outside this codebase.
|
||||
- REQ-006 must remain not Implemented until `jarcaledgerqc` completes QC and the requirement implementation state is explicitly confirmed.
|
||||
@@ -1,32 +0,0 @@
|
||||
# BAT-006 pytest/AppTest/Smoke CI 자동화
|
||||
|
||||
- Profile: standard
|
||||
- Status: release-candidate
|
||||
- Included REQ: REQ-006
|
||||
- Discovery: dcy-006
|
||||
- Owner: 렛저장인
|
||||
- Date (KST): 2026-06-30
|
||||
|
||||
## 목표
|
||||
|
||||
REQ-006에 따라 GitHub Actions 기반 CI 계약을 신설하고, push/PR에서 pytest 회귀 스위트, Streamlit AppTest, 대시보드 HTTP smoke, DB safety smoke를 synthetic fixture/임시 검증 DB로 자동 실행하는 필수 게이트를 구성한다.
|
||||
|
||||
## 산출물
|
||||
|
||||
- `.github/workflows/` 아래 GitHub Actions workflow
|
||||
- CI 전용 얇은 smoke wrapper entrypoint: HTTP smoke와 DB safety smoke의 결정적 실행/종료코드/로그/정리 책임
|
||||
- synthetic fixture DB 준비 흐름과 운영 DB 접근 차단 정책
|
||||
- pytest/AppTest/HTTP/DB safety smoke CI job 구성
|
||||
- `docs/project-structure.md`, `docs/runtime-flows.md`, 필요 시 `docs/runbooks/`의 CI 게이트/로컬 browser evidence 경계 문서화
|
||||
- BAT-006 planning/design/implementation/verification 문서와 CI evidence
|
||||
|
||||
## 범위 제한
|
||||
|
||||
browser-screenshot/visual regression의 CI 필수 게이트화, CD/서비스 배포 자동화, 테스트 커버리지 퍼센트 강제, 성능 벤치마크 게이트, 운영 DB 또는 실거래/실계좌 데이터의 CI 반입은 포함하지 않는다.
|
||||
|
||||
## 문서
|
||||
|
||||
- `planning.md`: delivery plan, dependencies, design gate, risks
|
||||
- `design.md`: CI architecture, job boundaries, wrapper policy, evidence boundaries
|
||||
- `implementation.md`: 실제 변경 파일과 로컬 실행 로그 기록
|
||||
- `verification.md`: REQ-006 AC별 검증 evidence 및 QC handoff 기록
|
||||
@@ -1,41 +0,0 @@
|
||||
# BAT-006 Planning
|
||||
|
||||
## Included REQ
|
||||
- REQ-006: pytest/AppTest/Smoke CI 자동화
|
||||
|
||||
## Delivery Plan
|
||||
1. REQ-006 승인 상태와 dcy-006 freeze 결정을 입력 gate로 확인한다.
|
||||
2. GitHub Actions workflow를 `.github/workflows/` 아래에 신설하고 `pull_request`, `main` 대상 `push`, `workflow_dispatch` 트리거를 정의한다.
|
||||
3. CI 실행 환경을 표준화한다: `uv`/Python 설치, project extras 설치, runner temp 경로 사용, 운영 DB 기본 경로 접근 금지.
|
||||
4. pytest 회귀 스위트 job을 구성해 `tests/` 전체 또는 동일 의미의 표준 명령을 필수 게이트로 실행한다.
|
||||
5. Streamlit AppTest job을 synthetic fixture DB 기준으로 실행한다.
|
||||
6. HTTP smoke와 DB safety smoke용 CI wrapper를 추가한다. wrapper는 fixture 준비, 환경 변수 설정, readiness polling, timeout, cleanup, 민감정보 비출력 정책을 담당한다.
|
||||
7. DB safety smoke는 임시 fixture/검증 DB에서만 실행하고 운영 DB 및 원본 금융 파일 경로를 사용하지 않는지 검증한다.
|
||||
8. `docs/project-structure.md`와 `docs/runtime-flows.md`에 CI workflow, smoke wrapper, gate result flow, 로컬 browser evidence(dcy-004)와의 경계를 반영한다. 필요하면 `docs/runbooks/ci-smoke.md`를 추가한다.
|
||||
9. 로컬에서 가능한 범위의 CI 등가 명령을 실행하고, GitHub Actions 실제 로그 또는 로컬 dry-run 한계를 verification에 명확히 기록한다.
|
||||
|
||||
## Dependencies
|
||||
- 기존 pytest 설정: `pyproject.toml`의 `[tool.pytest.ini_options]`와 dev extra의 `pytest`.
|
||||
- 기존 Streamlit AppTest 자산: `tests/test_dashboard_app.py`.
|
||||
- 기존 smoke 자산: `scripts/ledger_restore_smoke.py`, `scripts/streamlit_browser_evidence.py` 내부 로직 중 CI에서 재사용 가능한 부분.
|
||||
- dcy-002 운영 안전 원칙: 검증 DB/fixture 우선, 운영 DB restore/mutation 금지.
|
||||
- dcy-004 evidence 경계: browser screenshot evidence는 로컬 보강 경로이며 CI 필수 게이트가 아니다.
|
||||
|
||||
## Design Gate
|
||||
Design required: yes.
|
||||
|
||||
Reason: 이 batch는 CI workflow, wrapper entrypoint, fixture DB safety boundary, baseline runtime docs를 함께 정의한다. runner 환경·민감정보·운영 DB 접근 차단 규칙이 요구사항의 핵심이므로 구현 전 job 경계와 wrapper 책임을 설계 문서에 고정한다.
|
||||
|
||||
## Milestones
|
||||
- M1: REQ-006 Approved 및 BAT-006 standard batch 생성.
|
||||
- M2: CI workflow/job 구조와 wrapper contract 설계 완료.
|
||||
- M3: Workflow와 wrapper 구현, synthetic fixture 실행 경로 연결.
|
||||
- M4: pytest/AppTest/HTTP/DB safety smoke 로컬 등가 검증 통과.
|
||||
- M5: baseline docs/runbook 갱신 및 verification evidence 작성.
|
||||
- M6: QC gate PASS/PASS_WITH_NOTES 후 REQ-006 Implemented 전환.
|
||||
|
||||
## Risks
|
||||
- Streamlit HTTP smoke가 readiness 대기/포트 충돌로 flaky해질 수 있다. 고정 또는 결정적 포트 할당, polling timeout, 프로세스 cleanup을 wrapper에서 표준화한다.
|
||||
- CI 로그에 실계좌번호, 실잔액, `raw_payload`, 원본 파일명, 비밀번호가 노출될 수 있다. synthetic fixture만 사용하고 wrapper 출력은 요약/상태 중심으로 제한한다.
|
||||
- GitHub Actions runner에는 로컬 browser evidence 환경이 없을 수 있다. browser-screenshot E2E는 CI 필수 게이트에서 제외하고 dcy-004 로컬 evidence 경로로 유지한다.
|
||||
- 브랜치 보호 required check 설정은 저장소 외부 GitHub 설정이므로, 이 batch는 workflow/check 이름을 안정화하고 문서에 후속 운영 설정으로 기록한다.
|
||||
@@ -1,154 +0,0 @@
|
||||
# BAT-006 Verification
|
||||
|
||||
## Verification Status
|
||||
- Status: PASS_WITH_NOTES
|
||||
- Ready for Release: true
|
||||
- Ready for QC: false
|
||||
- Verified At (KST): 2026-06-30 15:29 KST
|
||||
- Verified By: jarcaledgerqc
|
||||
- QC Verdict: PASS_WITH_NOTES
|
||||
- QC Boundary: satisfied
|
||||
|
||||
## Acceptance Mapping
|
||||
|
||||
### REQ-006 AC-1
|
||||
`.github/workflows/` 아래에 GitHub Actions workflow가 생성되고, `pull_request`, `main` 대상 `push`, `workflow_dispatch` 트리거가 정의된다.
|
||||
|
||||
Evidence:
|
||||
- Workflow file: `.github/workflows/ci.yml`.
|
||||
- Trigger excerpt verified in file:
|
||||
- `pull_request:`
|
||||
- `push:` with `branches: [main]`
|
||||
- `workflow_dispatch:`
|
||||
- Stable job/check names in workflow:
|
||||
- `pytest-regression`
|
||||
- `dashboard-app-test`
|
||||
- `dashboard-http-smoke`
|
||||
- `db-safety-smoke`
|
||||
|
||||
Result: PASS.
|
||||
|
||||
### REQ-006 AC-2
|
||||
CI에서 pytest 회귀 스위트가 자동 실행되고, 단일 테스트 실패 시 workflow가 실패 상태로 종료된다.
|
||||
|
||||
Evidence:
|
||||
- Workflow job: `pytest-regression`.
|
||||
- Workflow command: `uv run pytest --ignore=tests/test_dashboard_app.py`.
|
||||
- Local equivalent command:
|
||||
- `uv run pytest --ignore=tests/test_dashboard_app.py -q`
|
||||
- Result: PASS, exit code 0.
|
||||
- Output: `............ss...............ss... [100%]`
|
||||
- GitHub Actions `run:` step uses normal shell exit-code behavior, so a pytest failure fails the job/workflow.
|
||||
|
||||
Result: PASS.
|
||||
|
||||
### REQ-006 AC-3
|
||||
CI에서 Streamlit `AppTest`가 synthetic fixture DB 기준으로 자동 실행되고 통과/실패 결과가 로그에 남는다.
|
||||
|
||||
Evidence:
|
||||
- Workflow job: `dashboard-app-test`.
|
||||
- Workflow command: `uv run pytest tests/test_dashboard_app.py`.
|
||||
- Test evidence: `tests/test_dashboard_app.py` calls `create_ci_fixture_db(tmp_path / "fixture.sqlite3")`, sets `JARCA_LEDGER_DB_PATH`, and runs Streamlit AppTest across core pages.
|
||||
- Local equivalent command:
|
||||
- `uv run pytest tests/test_dashboard_app.py -q`
|
||||
- Result: PASS, exit code 0.
|
||||
- Output: `.... [100%]`
|
||||
- Fixture policy: `scripts/ci_fixture_db.py` refuses `DEFAULT_DB_PATH` and seeds synthetic data only.
|
||||
|
||||
Result: PASS.
|
||||
|
||||
### REQ-006 AC-4
|
||||
CI에서 대시보드 HTTP smoke가 fixture DB 기준으로 Streamlit을 기동한 뒤 HTTP 200 응답을 확인하고, 종료 후 프로세스를 정리한다.
|
||||
|
||||
Evidence:
|
||||
- Workflow job: `dashboard-http-smoke`.
|
||||
- Workflow command: `uv run python scripts/ci_dashboard_http_smoke.py --host 127.0.0.1 --port 18501 --timeout 45`.
|
||||
- Wrapper: `scripts/ci_dashboard_http_smoke.py` creates a temp synthetic fixture DB, starts Streamlit with `JARCA_LEDGER_DB_PATH`, polls a loopback URL for HTTP 200, and performs process cleanup.
|
||||
- Local command:
|
||||
- `uv run python scripts/ci_dashboard_http_smoke.py --host 127.0.0.1 --port 18501 --timeout 45`
|
||||
- Result: PASS, exit code 0.
|
||||
- Output summary: `success: true`, `fixture: synthetic`, `fixture_integrity: ok`, `http_status: 200`, `attempts: 3`, `cleanup: terminated`.
|
||||
|
||||
Result: PASS.
|
||||
|
||||
### REQ-006 AC-5
|
||||
CI에서 DB safety smoke가 운영 DB 기본 경로를 사용하지 않고 임시 fixture/검증 DB에서 통과한다.
|
||||
|
||||
Evidence:
|
||||
- Workflow job: `db-safety-smoke`.
|
||||
- Workflow command: `uv run python scripts/ci_db_safety_smoke.py --timeout 45`.
|
||||
- Wrapper: `scripts/ci_db_safety_smoke.py` creates temp `source`, `backup`, and `target` DB files and refuses `DEFAULT_DB_PATH` before invoking `scripts/ledger_restore_smoke.py`.
|
||||
- Local command:
|
||||
- `uv run python scripts/ci_db_safety_smoke.py --timeout 45`
|
||||
- Result: PASS, exit code 0.
|
||||
- Output summary: `success: true`, `fixture: synthetic`, `fixture_integrity: ok`, `restore_smoke_exit_code: 0`, `restored_exists: true`, `restored_integrity: ok`, `health_success: true`, `operating_db_used: false`.
|
||||
|
||||
Result: PASS.
|
||||
|
||||
### REQ-006 AC-6
|
||||
HTTP smoke/DB safety smoke는 CI 전용 wrapper entrypoint를 통해 실행되며, wrapper가 종료코드·timeout·readiness·cleanup을 일관되게 처리한다.
|
||||
|
||||
Evidence:
|
||||
- HTTP wrapper path: `scripts/ci_dashboard_http_smoke.py`.
|
||||
- Readiness: polls URL until HTTP 200 or timeout.
|
||||
- Timeout/failure: returns non-zero status with status-only JSON.
|
||||
- Cleanup: terminates/kills Streamlit process and reports cleanup state.
|
||||
- DB safety wrapper path: `scripts/ci_db_safety_smoke.py`.
|
||||
- Timeout: catches `subprocess.TimeoutExpired` and returns non-zero status with timeout JSON.
|
||||
- Exit code: reports restore smoke exit code and returns non-zero on failed restore/integrity/health conditions.
|
||||
- Safety: refuses operating DB path and reports `operating_db_used: false` on pass.
|
||||
- Local command results for both wrappers exited 0 and reported success JSON.
|
||||
|
||||
Result: PASS.
|
||||
|
||||
### REQ-006 AC-7
|
||||
CI 로그·아티팩트에는 실계좌번호, 실잔액, `raw_payload`, 원본 금융 파일명, 비밀번호가 평문으로 포함되지 않는다.
|
||||
|
||||
Evidence:
|
||||
- Fixture builder uses synthetic labels such as `CI Synthetic Checking`, `CI_SYNTHETIC_*`, and `ci synthetic ...`; it does not load real statement files or passwords.
|
||||
- Wrapper outputs are status-only JSON. Observed local outputs include gate name, fixture type, integrity, HTTP status, cleanup, restore smoke status, and `operating_db_used: false`; they do not include account numbers, real balances, raw payloads, source financial filenames, or passwords.
|
||||
- `scripts/ci_fixture_db.py` refuses the operating ledger DB default path.
|
||||
|
||||
Result: PASS.
|
||||
|
||||
### REQ-006 AC-8
|
||||
`docs/project-structure.md`와 `docs/runtime-flows.md`가 CI 게이트와 로컬 browser evidence 경계를 반영한다.
|
||||
|
||||
Evidence:
|
||||
- `docs/project-structure.md` documents `.github/workflows/ci.yml`, stable gate names, `scripts/ci_fixture_db.py`, `scripts/ci_dashboard_http_smoke.py`, `scripts/ci_db_safety_smoke.py`, and synthetic fixture policy.
|
||||
- `docs/runtime-flows.md` includes `Flow: CI validation gates` and the constraints that CI gates use synthetic/temp DBs only.
|
||||
- `docs/runbooks/ci-smoke.md` provides reproduction commands and failure triage.
|
||||
|
||||
Result: PASS.
|
||||
|
||||
### REQ-006 AC-9
|
||||
browser-screenshot E2E는 CI 필수 차단 게이트에서 제외되고, dcy-004 로컬 evidence 절차와의 역할 분담이 문서에 명시된다.
|
||||
|
||||
Evidence:
|
||||
- `.github/workflows/ci.yml` contains the four required CI jobs and no browser screenshot/visual regression required job.
|
||||
- `docs/runtime-flows.md` states browser screenshot/DOM evidence is not a required GitHub Actions gate in BAT-006 and remains local evidence for visual/layout-sensitive dashboard changes.
|
||||
- `docs/runbooks/ci-smoke.md` states `scripts/streamlit_browser_evidence.py` remains local evidence and is not a required GitHub Actions gate.
|
||||
|
||||
Result: PASS.
|
||||
|
||||
## Command Evidence Summary
|
||||
|
||||
All commands were run from `/root/projects/jarca-ledger-mcp`.
|
||||
|
||||
| Command | Result | Evidence |
|
||||
| --- | --- | --- |
|
||||
| `uv run pytest --ignore=tests/test_dashboard_app.py -q` | PASS, exit code 0 | `............ss...............ss... [100%]` |
|
||||
| `uv run pytest tests/test_dashboard_app.py -q` | PASS, exit code 0 | `.... [100%]` |
|
||||
| `uv run python scripts/ci_dashboard_http_smoke.py --host 127.0.0.1 --port 18501 --timeout 45` | PASS, exit code 0 | `success: true`, `http_status: 200`, `cleanup: terminated` |
|
||||
| `uv run python scripts/ci_db_safety_smoke.py --timeout 45` | PASS, exit code 0 | `success: true`, `restored_integrity: ok`, `health_success: true`, `operating_db_used: false` |
|
||||
|
||||
## Sensitive Evidence Review
|
||||
|
||||
- No command output observed in this verification exposed real account numbers, operating DB balances, source financial filenames, passwords, or `raw_payload`.
|
||||
- CI fixture/smoke paths are synthetic/temp paths and refuse the default operating ledger DB path.
|
||||
- Remote GitHub Actions logs were not available in this local handoff; `jarcaledgerqc` recorded this as a note rather than a blocker because local equivalent commands passed and the workflow wiring is present.
|
||||
|
||||
## Blocking Issues
|
||||
|
||||
- None for local QC readiness.
|
||||
- QC note: Remote GitHub Actions execution and branch protection required-check setup remain repository/remote configuration checks outside this local evidence update.
|
||||
@@ -1,50 +0,0 @@
|
||||
# BAT-007 Design
|
||||
|
||||
## Contract versioning design
|
||||
|
||||
- Active MCP success response contract version: `1.0`.
|
||||
- Version format: `major.minor`.
|
||||
- Runtime exposure: unexposed. MCP success payloads are not modified to add a common `contract_version` field.
|
||||
- Source of truth: `docs/interface-contract.md`.
|
||||
- Snapshot metadata: `tests/contract_snapshots/response_contract_v1_0.json`.
|
||||
|
||||
## Change classification
|
||||
|
||||
- Breaking / major: required key removal, required key type change, nested object/list shape change that breaks existing consumers.
|
||||
- Additive / minor: optional field additions and documentation/test metadata additions that preserve existing response semantics.
|
||||
- Every response-shape-changing REQ/BAT must record contract impact: none, additive minor, or breaking major.
|
||||
|
||||
## Contract regression design
|
||||
|
||||
Representative first-wave scopes:
|
||||
|
||||
- health/status: `service.health_check`, `service.get_ledger_db_status`
|
||||
- list: `service.list_ledger_accounts`
|
||||
- report: `service.get_monthly_cashflow_report`
|
||||
- mutation success envelope: `service.create_ledger_account`
|
||||
|
||||
The pytest contract checker validates required keys and required types only. Additional keys are allowed, matching the additive policy.
|
||||
|
||||
Synthetic fixture policy:
|
||||
|
||||
- Test DB paths are created under pytest `tmp_path`.
|
||||
- Fixture data uses synthetic names and amounts only.
|
||||
- No operating DB path, source financial filename, password, raw payload, or real account identifier is used.
|
||||
|
||||
## CI design
|
||||
|
||||
Required-check contract job names:
|
||||
|
||||
- `pytest-regression`
|
||||
- `dashboard-app-test`
|
||||
- `dashboard-http-smoke`
|
||||
- `db-safety-smoke`
|
||||
- `contract-regression`
|
||||
- `lint`
|
||||
|
||||
`.github/workflows/ci.yml` adds:
|
||||
|
||||
- `contract-regression`: `uv run pytest tests/test_contract_regression.py`
|
||||
- `lint`: `uv run ruff check .`
|
||||
|
||||
Actual branch protection toggles remain external GitHub repository settings.
|
||||
@@ -1,115 +0,0 @@
|
||||
# BAT-007 Implementation
|
||||
|
||||
## Changed files
|
||||
|
||||
- `.github/workflows/ci.yml`
|
||||
- Added stable required-check candidate jobs: `contract-regression`, `lint`.
|
||||
- `pyproject.toml`, `uv.lock`
|
||||
- Added `ruff` to dev dependencies and conservative `E9`/`F` initial lint config.
|
||||
- `tests/test_contract_regression.py`
|
||||
- Added representative MCP response contract regression tests.
|
||||
- `tests/contract_snapshots/response_contract_v1_0.json`
|
||||
- Added contract `1.0` metadata and required-subset schemas for health/status, list, report, and mutation success envelope scopes.
|
||||
- `docs/interface-contract.md`
|
||||
- Added MCP response contract `1.0` governance, breaking/additive classification, runtime exposure policy, version log, and CI required-check contract.
|
||||
- `docs/project-structure.md`, `docs/runtime-flows.md`
|
||||
- Updated baseline structure/flow docs for contract snapshots/tests, `contract-regression`, `lint`, branch-protection boundary, and synthetic-only invariant.
|
||||
- `docs/batches/index.md`
|
||||
- Registered BAT-007.
|
||||
- `docs/batches/bat-007_20260630_mcp-response-contract-ci-versioning/{index,planning,design,implementation,verification}.md`
|
||||
- Added standard batch delivery docs.
|
||||
- `docs/srs/Interface/req-007_mcp-response-contract-versioning-governance.md`
|
||||
- `docs/srs/Testing/req-008_ci-contract-regression-and-lint-required-checks.md`
|
||||
- `docs/srs/index.md`
|
||||
- Updated REQ state to Implemented after verification evidence.
|
||||
|
||||
## Implementation notes
|
||||
|
||||
- Runtime MCP success payloads were not changed.
|
||||
- Contract version `1.0` is documented in `docs/interface-contract.md` and mirrored in `tests/contract_snapshots/response_contract_v1_0.json`.
|
||||
- Contract regression is representative, not exhaustive.
|
||||
- Lint gate uses conservative `ruff` rules: `E9`, `F`.
|
||||
- All new test data uses pytest temp DBs and synthetic names/amounts only.
|
||||
|
||||
## Verification command log
|
||||
|
||||
Executed from `/root/projects/jarca-ledger-mcp`.
|
||||
|
||||
1. `uv sync --extra dev --extra dashboard`
|
||||
|
||||
Result:
|
||||
|
||||
```text
|
||||
Resolved 72 packages in 1.37s
|
||||
Building jarca-ledger-mcp @ file:///root/projects/jarca-ledger-mcp
|
||||
Downloading ruff (11.0MiB)
|
||||
Downloaded ruff
|
||||
Built jarca-ledger-mcp @ file:///root/projects/jarca-ledger-mcp
|
||||
Prepared 3 packages in 2.94s
|
||||
Uninstalled 2 packages in 18ms
|
||||
Installed 3 packages in 338ms
|
||||
~ jarca-ledger-mcp==0.1.0 (from file:///root/projects/jarca-ledger-mcp)
|
||||
- pytest==9.1.0
|
||||
+ pytest==9.1.1
|
||||
+ ruff==0.15.20
|
||||
```
|
||||
|
||||
2. `uv run pytest tests/test_contract_regression.py`
|
||||
|
||||
Result:
|
||||
|
||||
```text
|
||||
... [100%]
|
||||
3 passed in 0.99s
|
||||
```
|
||||
|
||||
3. `uv run ruff check .`
|
||||
|
||||
Result:
|
||||
|
||||
```text
|
||||
All checks passed!
|
||||
```
|
||||
|
||||
4. `uv run pytest --ignore=tests/test_dashboard_app.py`
|
||||
|
||||
Result:
|
||||
|
||||
```text
|
||||
...............ss...............ss... [100%]
|
||||
33 passed, 4 skipped in 29.37s
|
||||
```
|
||||
|
||||
5. `uv run python scripts/ci_db_safety_smoke.py --timeout 45`
|
||||
|
||||
Result:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"gate": "db-safety-smoke",
|
||||
"fixture": "synthetic",
|
||||
"fixture_integrity": "ok",
|
||||
"restore_smoke_exit_code": 0,
|
||||
"restored_exists": true,
|
||||
"restored_integrity": "ok",
|
||||
"health_success": true,
|
||||
"operating_db_used": false
|
||||
}
|
||||
```
|
||||
|
||||
6. `uv run python scripts/ci_dashboard_http_smoke.py --host 127.0.0.1 --port 18501 --timeout 45`
|
||||
|
||||
Result:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"gate": "dashboard-http-smoke",
|
||||
"fixture": "synthetic",
|
||||
"fixture_integrity": "ok",
|
||||
"http_status": 200,
|
||||
"attempts": 4,
|
||||
"cleanup": "terminated"
|
||||
}
|
||||
```
|
||||
@@ -1,32 +0,0 @@
|
||||
# BAT-007 MCP response contract / CI contract versioning
|
||||
|
||||
- Profile: standard
|
||||
- Status: release-candidate
|
||||
- Included REQ: REQ-007, REQ-008
|
||||
- Discovery: dcy-007
|
||||
- Owner: 렛저장인
|
||||
- Date (KST): 2026-06-30
|
||||
|
||||
## 목표
|
||||
|
||||
REQ-007/REQ-008에 따라 MCP 성공 응답 contract version `1.0` governance를 확정하고, representative contract regression과 `ruff` lint를 CI required-check 계약에 추가한다. 런타임 성공 응답 shape는 보존하며 `contract_version` 필드는 노출하지 않는다.
|
||||
|
||||
## 산출물
|
||||
|
||||
- `docs/interface-contract.md`의 versioning governance, change classification, version log, required-check contract
|
||||
- `docs/project-structure.md`, `docs/runtime-flows.md` baseline gap 해소 및 CI/branch-protection/synthetic-only 경계 반영
|
||||
- `tests/test_contract_regression.py`와 `tests/contract_snapshots/response_contract_v1_0.json`
|
||||
- `.github/workflows/ci.yml`의 `contract-regression`, `lint` stable job 추가
|
||||
- `pyproject.toml`의 `ruff` dev dependency 및 보수적 초기 lint rule set
|
||||
- BAT-007 planning/design/implementation/verification 문서
|
||||
|
||||
## 범위 제한
|
||||
|
||||
모든 MCP 도구 100% snapshot 커버리지, 런타임 `contract_version` 노출, breaking response migration, 실제 GitHub branch protection setting 토글, browser visual regression CI gate는 포함하지 않는다.
|
||||
|
||||
## 문서
|
||||
|
||||
- `planning.md`: delivery plan, dependencies, risks
|
||||
- `design.md`: contract governance and CI gate design
|
||||
- `implementation.md`: changed files and actual execution evidence
|
||||
- `verification.md`: AC별 검증 결과와 REQ state 판단
|
||||
@@ -1,29 +0,0 @@
|
||||
# BAT-007 Planning
|
||||
|
||||
## Scope
|
||||
|
||||
- Implement REQ-007: MCP response contract versioning governance.
|
||||
- Implement REQ-008: representative contract regression and lint required checks.
|
||||
- Preserve existing success response shapes; runtime `contract_version` remains unexposed.
|
||||
- Use synthetic/temp data only for tests and evidence.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- dcy-007 confirmed Discovery and approved REQ-007/REQ-008.
|
||||
- Existing BAT-006 CI workflow and synthetic fixture policy.
|
||||
- Existing service-layer functions that accept `db_path` for temp fixture tests.
|
||||
|
||||
## Work plan
|
||||
|
||||
1. Add BAT-007 standard batch docs and index entry.
|
||||
2. Add contract version `1.0` governance and CI required-check contract to baseline docs.
|
||||
3. Add representative contract snapshot metadata and pytest regression for health/status, list, report, and mutation success envelope scopes.
|
||||
4. Add `ruff` dev dependency/config and CI `lint`/`contract-regression` jobs while preserving existing job names.
|
||||
5. Run narrow local verification: contract pytest, ruff, targeted regression that includes the new test, then full pytest if narrow gates pass.
|
||||
6. If evidence satisfies ACs, move REQ-007 and REQ-008 to Implemented.
|
||||
|
||||
## Risks and mitigations
|
||||
|
||||
- Over-strict snapshot failures: mitigate by required-subset/type checks so optional additive fields pass.
|
||||
- Existing code lint churn: mitigate by conservative initial `ruff` rule set (`E9`, `F`).
|
||||
- Branch protection cannot be toggled from code: document as external operator setting and keep stable job names.
|
||||
@@ -1,48 +0,0 @@
|
||||
# BAT-007 Verification
|
||||
|
||||
## Verification summary
|
||||
|
||||
Status: PASS
|
||||
|
||||
REQ-007 and REQ-008 have sufficient repository evidence to move from Approved to Implemented.
|
||||
|
||||
Evidence commands executed from `/root/projects/jarca-ledger-mcp`:
|
||||
|
||||
| Command | Result |
|
||||
| --- | --- |
|
||||
| `uv sync --extra dev --extra dashboard` | PASS; `ruff==0.15.20` installed and lockfile updated. |
|
||||
| `uv run pytest tests/test_contract_regression.py` | PASS; `3 passed in 0.99s`. |
|
||||
| `uv run ruff check .` | PASS; `All checks passed!`. |
|
||||
| `uv run pytest --ignore=tests/test_dashboard_app.py` | PASS; `33 passed, 4 skipped in 29.37s`. |
|
||||
| `uv run python scripts/ci_db_safety_smoke.py --timeout 45` | PASS; JSON `success: true`, `fixture: synthetic`, `operating_db_used: false`. |
|
||||
| `uv run python scripts/ci_dashboard_http_smoke.py --host 127.0.0.1 --port 18501 --timeout 45` | PASS; JSON `success: true`, `fixture: synthetic`, `http_status: 200`. |
|
||||
|
||||
## Acceptance criteria mapping
|
||||
|
||||
### REQ-007
|
||||
|
||||
- AC-1: PASS. `docs/interface-contract.md` defines `major.minor` and initial `1.0` contract version.
|
||||
- AC-2: PASS. Breaking vs additive rules cover key removal, type changes, nested structure changes, and optional field additions.
|
||||
- AC-3: PASS. `docs/interface-contract.md` contains source-of-truth rules and a version log linking dcy-007/REQ-007/BAT-007.
|
||||
- AC-4: PASS. Runtime `contract_version` exposure is explicitly unexposed for `1.0`.
|
||||
- AC-5: PASS. Response-shape-changing REQ/BAT work must state contract impact: none, additive minor, or breaking major.
|
||||
- AC-6: PASS. Runtime success payloads were not changed; contract tests assert existing representative shapes.
|
||||
|
||||
### REQ-008
|
||||
|
||||
- AC-1: PASS. `tests/test_contract_regression.py` covers health/status, list, report, and mutation success envelope representative scopes.
|
||||
- AC-2: PASS. The checker fails on missing required keys, required type changes, and required nested structure changes; additive fields are allowed.
|
||||
- AC-3: PASS. Tests use pytest `tmp_path` synthetic SQLite DBs and committed schema metadata only. Smoke evidence also reports `fixture: synthetic` and `operating_db_used: false` where applicable.
|
||||
- AC-4: PASS. `.github/workflows/ci.yml` includes a `lint` job running `uv run ruff check .`; local ruff verification passed.
|
||||
- AC-5: PASS. Required-check job names are documented and existing BAT-006 job names are preserved.
|
||||
- AC-6: PASS. `docs/interface-contract.md`, `docs/project-structure.md`, and `docs/runtime-flows.md` reflect contract-regression/lint/required-check/synthetic-only boundaries.
|
||||
- AC-7: PASS. Baseline docs state actual branch protection toggles are external operator-managed GitHub repository settings.
|
||||
|
||||
## Requirement state decision
|
||||
|
||||
- REQ-007: Implemented.
|
||||
- REQ-008: Implemented.
|
||||
|
||||
## Blockers
|
||||
|
||||
None.
|
||||
@@ -1,40 +0,0 @@
|
||||
# BAT-008 Design
|
||||
|
||||
## Schema and persistence design
|
||||
|
||||
- Add `manual_assets` as a first-class table for non-transaction-derived assets/liabilities.
|
||||
- Add `asset_snapshots` as an append-only history table keyed by basis date plus evaluated item identity.
|
||||
- Migrations remain additive/idempotent; existing ledger/account flows must continue to operate when both tables are empty.
|
||||
|
||||
## Authority-source and valuation design
|
||||
|
||||
- Account-backed assets use `accounts.last_balance` as the live authority source.
|
||||
- Non-transaction assets/liabilities use `manual_assets` as the live authority source.
|
||||
- `asset_snapshots` is a historical record layer, not a competing primary input source.
|
||||
- Net worth formula remains: asset buckets (`cash`, `investment`, `deposit`, `real_estate`, `other`) minus `loan`; missing valuations are excluded, not inferred.
|
||||
|
||||
## Read model design
|
||||
|
||||
- Service layer should expose:
|
||||
- manual assets list/report helpers
|
||||
- basis-date asset snapshot read helpers
|
||||
- net-worth timeseries helpers
|
||||
- shared valuation/fallback helpers consumed by both MCP and dashboard
|
||||
- Snapshot read responses must expose basis date, bucket totals, liabilities, net worth, and inclusion/exclusion explanation fields.
|
||||
- Manual assets read responses must expose item name, value, basis date, `liquidity_bucket`, and memo/source metadata.
|
||||
|
||||
## Dashboard alignment design
|
||||
|
||||
- `dashboard/app.py` should consume the same valuation helpers as the MCP read tools.
|
||||
- If no manual assets/snapshots exist, dashboard behavior must safely fall back to REQ-005 account-based display.
|
||||
- Excluded/unvalued items should be explainable instead of silently counted.
|
||||
|
||||
## Verification design
|
||||
|
||||
- Add targeted regression tests for:
|
||||
- additive migration creation
|
||||
- manual asset persistence and retrieval
|
||||
- snapshot accumulation/read behavior
|
||||
- net-worth formula / exclusion policy
|
||||
- dashboard/MCP shared fallback behavior
|
||||
- Prefer synthetic SQLite fixtures and temp DBs only.
|
||||
@@ -1,104 +0,0 @@
|
||||
# BAT-008 Implementation
|
||||
|
||||
## Plan summary
|
||||
|
||||
BAT-008 implemented the new valuation authority model in `service.py`/`db.py`, exposed read-only MCP tools in `server.py`, aligned the Streamlit overview with the shared valuation helper, and updated baseline docs to match the confirmed Discovery/REQ scope.
|
||||
|
||||
## Changed files
|
||||
|
||||
- `jarca_ledger_mcp/db.py`
|
||||
- `SCHEMA_VERSION` → `9`
|
||||
- additive/idempotent tables: `manual_assets`, `asset_snapshots`
|
||||
- migration path updated so existing DBs create the new tables safely
|
||||
- `jarca_ledger_mcp/service.py`
|
||||
- shared valuation helpers for account/manual-asset/snapshot authority sources
|
||||
- new service APIs: `create_manual_asset`, `list_manual_assets`, `create_asset_snapshot`, `get_asset_snapshot_report`, `get_net_worth_timeseries`
|
||||
- `get_asset_liquidity_report` aligned to the same valuation policy while preserving REQ-005 fallback semantics
|
||||
- `jarca_ledger_mcp/server.py`
|
||||
- new read MCP tools: `list_manual_assets`, `get_asset_snapshot_report`, `get_net_worth_timeseries`
|
||||
- `get_asset_liquidity_report` contract text updated for shared valuation source behavior
|
||||
- `dashboard/app.py`
|
||||
- overview asset section now explains the valuation authority source and shows `manual_assets` rows when present
|
||||
- existing account-only fallback remains when new tables are empty
|
||||
- Documentation
|
||||
- `docs/data-model.md`
|
||||
- `docs/interface-contract.md`
|
||||
- `docs/runtime-flows.md`
|
||||
- `docs/project-structure.md`
|
||||
- Tests
|
||||
- new: `tests/test_asset_snapshots.py`
|
||||
- adjusted: `tests/test_service.py`
|
||||
|
||||
## Execution log
|
||||
|
||||
- 2026-06-30 21:26 KST: BAT-008 standard batch scaffold created from approved REQ-009/REQ-010.
|
||||
- 2026-06-30 21:3x~21:4x KST: implementation landed in `db.py`, `service.py`, `server.py`, `dashboard/app.py`, docs, and regression tests via `jarcaledgerdev` handoff + local verification orchestration.
|
||||
- 2026-06-30 21:40 KST: targeted compile/test validation passed.
|
||||
- 2026-06-30 21:41 KST: MCP stdio contract smoke check passed and discovered the three new read tools.
|
||||
- 2026-06-30 21:42 KST: synthetic end-to-end service probe confirmed live-authority fallback, snapshot read behavior, and net-worth timeseries output.
|
||||
|
||||
## Validation
|
||||
|
||||
### Command 1
|
||||
```bash
|
||||
cd /root/projects/jarca-ledger-mcp
|
||||
source .venv/bin/activate
|
||||
python -m py_compile jarca_ledger_mcp/*.py dashboard/app.py
|
||||
pytest tests/test_asset_snapshots.py tests/test_service.py tests/test_contract_regression.py -q
|
||||
```
|
||||
|
||||
Result:
|
||||
- `................. [100%]`
|
||||
- exit code `0`
|
||||
|
||||
### Command 2
|
||||
```bash
|
||||
cd /root/projects/jarca-ledger-mcp
|
||||
source .venv/bin/activate
|
||||
hermes mcp test jarca-ledger
|
||||
```
|
||||
|
||||
Result:
|
||||
- stdio connection success
|
||||
- tools discovered: `51`
|
||||
- new BAT-008 read tools discovered:
|
||||
- `list_manual_assets`
|
||||
- `get_asset_snapshot_report`
|
||||
- `get_net_worth_timeseries`
|
||||
|
||||
### Command 3
|
||||
```bash
|
||||
cd /root/projects/jarca-ledger-mcp
|
||||
source .venv/bin/activate
|
||||
python - <<'PY'
|
||||
from tempfile import TemporaryDirectory
|
||||
from pathlib import Path
|
||||
from jarca_ledger_mcp import service
|
||||
|
||||
with TemporaryDirectory() as td:
|
||||
db_path = str(Path(td) / 'ledger.sqlite3')
|
||||
service.create_ledger_account('현금', last_balance=1000000, last_synced_at='2026-06-30', liquidity_bucket='cash', db_path=db_path)
|
||||
service.create_ledger_account('투자', type='investment', last_balance=2000000, liquidity_bucket='investment', db_path=db_path)
|
||||
service.create_manual_asset('전세보증금', 300000000, '2026-06-30', 'real_estate', source_note='synthetic appraisal', db_path=db_path)
|
||||
service.create_manual_asset('주담대', 120000000, '2026-06-30', 'loan', source_note='synthetic loan balance', db_path=db_path)
|
||||
print(service.list_manual_assets(db_path=db_path))
|
||||
print(service.get_asset_snapshot_report('2026-06-30', db_path=db_path))
|
||||
service.create_asset_snapshot('2026-05-31', 'account', 'acct-a', '현금', 1000000, 'cash', source_note='synthetic', db_path=db_path)
|
||||
service.create_asset_snapshot('2026-05-31', 'manual_asset', 'manual-home', '부동산', 200000000, 'real_estate', source_note='synthetic', db_path=db_path)
|
||||
service.create_asset_snapshot('2026-05-31', 'manual_asset', 'manual-loan', '대출', 80000000, 'loan', source_note='synthetic', db_path=db_path)
|
||||
print(service.get_asset_snapshot_report('2026-05-31', db_path=db_path))
|
||||
print(service.get_net_worth_timeseries(start_date='2026-05-01', end_date='2026-06-30', db_path=db_path))
|
||||
PY
|
||||
```
|
||||
|
||||
Key result excerpts:
|
||||
- `list_manual_assets` returned `count=2` and `authority_source='manual_assets'`
|
||||
- live fallback snapshot report returned `source='live_authority'`, `total_assets=303000000`, `total_liabilities=120000000`, `net_worth=183000000`
|
||||
- stored snapshot report returned `source='asset_snapshots'`, `snapshot_count=3`, `net_worth=121000000`
|
||||
- timeseries returned `points[0].basis_date='2026-05-31'`, `points[0].net_worth=121000000`
|
||||
|
||||
## Remaining risks / follow-up notes
|
||||
|
||||
- Snapshot creation is intentionally service-only in BAT-008. MCP mutation exposure remains future scope by Discovery decision.
|
||||
- Manual-asset edit/delete workflows and month-end operator UX are still procedural/document-driven rather than exposed as first-class CRUD flows.
|
||||
- QC gate still needs to confirm REQ Implemented promotion before commit-stage handoff.
|
||||
@@ -1,36 +0,0 @@
|
||||
# BAT-008 Asset snapshots / manual assets / read MCP
|
||||
|
||||
- Profile: standard
|
||||
- Status: release-candidate
|
||||
- Included REQ: REQ-009, REQ-010
|
||||
- Discovery: dcy-008
|
||||
- Owner: 렛저장인
|
||||
- Date (KST): 2026-06-30
|
||||
|
||||
## 목표
|
||||
|
||||
REQ-009/REQ-010에 따라 `asset_snapshots`/`manual_assets` 저장 모델을 additive/idempotent하게 도입하고, 월말 수동 스냅샷 정책을 수용하는 집계 계층과 조회성 MCP(기준일 스냅샷/순자산 시계열/수기 자산 조회)를 구현한다. 동시에 대시보드 자산/순자산 표시가 동일 권위 소스와 동일 산식을 사용하도록 정렬한다.
|
||||
|
||||
## 산출물
|
||||
|
||||
- `asset_snapshots`, `manual_assets` additive/idempotent schema migration
|
||||
- 수기 자산 저장/조회, 스냅샷 누적, 순자산 시계열 집계 service 함수
|
||||
- 조회성 MCP tool/응답 계약: 기준일 자산 스냅샷, 순자산 시계열, 수기 자산 조회
|
||||
- `dashboard/app.py`의 자산/순자산 표시가 신규 모델과 안전 폴백을 함께 지원하도록 정렬
|
||||
- `docs/data-model.md`, `docs/interface-contract.md`, `docs/project-structure.md`, `docs/runtime-flows.md` baseline 갱신
|
||||
- BAT-008 planning/design/implementation/verification 문서와 synthetic-only 검증 evidence
|
||||
|
||||
## 범위 제한
|
||||
|
||||
- 외부 시세/부동산 자동 평가 연동
|
||||
- 스냅샷 생성 mutation MCP
|
||||
- 수기 자산 생성/수정/삭제 mutation MCP
|
||||
- 투자 조언/리밸런싱/세금/수익률 계산
|
||||
- 운영 DB 실데이터 기반 evidence
|
||||
|
||||
## 문서
|
||||
|
||||
- `planning.md`: delivery plan, dependency, risk, validation entry criteria
|
||||
- `design.md`: schema/authority-source/fallback/read-contract design
|
||||
- `implementation.md`: changed files, execution log, validation commands
|
||||
- `verification.md`: AC mapping, PASS/FAIL, REQ Implemented decision
|
||||
@@ -1,37 +0,0 @@
|
||||
# BAT-008 Planning
|
||||
|
||||
## Scope
|
||||
|
||||
- Implement REQ-009: `asset_snapshots`/`manual_assets` valuation model, authority-source rule, month-end manual snapshot policy support.
|
||||
- Implement REQ-010: asset snapshot read MCP, net-worth timeseries read MCP, manual assets read MCP, dashboard/MCP alignment.
|
||||
- Preserve REQ-005 safety fallback when new tables are empty.
|
||||
- Use synthetic/temp data only for tests and verification evidence.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- dcy-008 confirmed Discovery and approved REQ-009/REQ-010.
|
||||
- Existing REQ-005 dashboard liquidity/net-worth flow and `accounts.last_balance` authority-source baseline.
|
||||
- Existing MCP server/service pattern in `jarca_ledger_mcp/server.py`, `jarca_ledger_mcp/service.py`, `jarca_ledger_mcp/db.py`.
|
||||
- Additive/idempotent SQLite migration discipline and synthetic-only evidence policy.
|
||||
|
||||
## Work plan
|
||||
|
||||
1. Create BAT-008 standard batch docs and register entry.
|
||||
2. Add schema/model support for `manual_assets` and `asset_snapshots` with safe empty-table fallback.
|
||||
3. Add service-layer valuation helpers, snapshot accumulation/report functions, and dashboard alignment logic.
|
||||
4. Add read-only MCP tool endpoints/contracts for snapshot read, net-worth timeseries, and manual assets read.
|
||||
5. Update baseline docs (`docs/data-model.md`, `docs/interface-contract.md`, `docs/project-structure.md`, `docs/runtime-flows.md`).
|
||||
6. Run narrow validation first (targeted tests / lint / smoke as applicable), then broader regression if narrow gates pass.
|
||||
7. If evidence satisfies ACs, move BAT-008 to release-candidate and REQ-009/REQ-010 to Implemented.
|
||||
|
||||
## Design Gate
|
||||
|
||||
- Result: standard batch 유지.
|
||||
- Reason: schema, service, MCP contract, dashboard alignment, baseline docs를 함께 변경하며 interface/data/fallback 설계가 필요하다.
|
||||
|
||||
## Risks and mitigations
|
||||
|
||||
- Authority-source drift between dashboard and MCP: mitigate by centralizing valuation helpers and writing shared regression tests.
|
||||
- Empty new tables breaking existing REQ-005 flows: mitigate by explicit fallback tests and additive migrations only.
|
||||
- Double counting between account-backed assets and manual assets: mitigate by clearly separating source responsibility and documenting inclusion/exclusion rules.
|
||||
- Snapshot history ambiguity: mitigate by storing basis date, source type, and memo for every snapshot row.
|
||||
@@ -1,64 +0,0 @@
|
||||
# BAT-008 Verification
|
||||
|
||||
## Verification summary
|
||||
|
||||
Status: PASS
|
||||
|
||||
Evidence collected against synthetic/temp data only. No production ledger DB mutation or real financial files were used.
|
||||
|
||||
## Acceptance criteria mapping
|
||||
|
||||
### REQ-009
|
||||
|
||||
- AC-1: **PASS**
|
||||
- Evidence: `tests/test_asset_snapshots.py::test_asset_snapshot_schema_is_additive_and_idempotent`
|
||||
- `db.py` adds `manual_assets` and `asset_snapshots` via additive/idempotent schema + migration path.
|
||||
- AC-2: **PASS**
|
||||
- Evidence: `create_manual_asset`/`list_manual_assets` service path + synthetic probe output includes `name`, `valuation_amount`, `valuation_date`, `liquidity_bucket`, `source_note`.
|
||||
- AC-3: **PASS**
|
||||
- Evidence: `create_asset_snapshot` stores basis date/source target/amount/bucket/source note; `test_snapshot_rows_are_append_only_and_timeseries_uses_same_formula` proves append-only readback.
|
||||
- AC-4: **PASS**
|
||||
- Evidence: `valuation_policy` and `authority_source` fields distinguish `accounts.last_balance`, `manual_assets`, and `asset_snapshots`; docs updated in `docs/data-model.md` and `docs/runtime-flows.md`.
|
||||
- AC-5: **PASS**
|
||||
- Evidence: valuation helper formula is `asset_buckets - loan`; synthetic probe returned `303000000 - 120000000 = 183000000`; unvalued items are excluded rather than inferred.
|
||||
- AC-6: **PASS**
|
||||
- Evidence: `tests/test_asset_snapshots.py::test_asset_liquidity_report_empty_new_tables_preserves_req005_fallback` confirms empty new tables preserve REQ-005 path with `source='accounts.last_balance'`.
|
||||
- AC-7: **PASS**
|
||||
- Evidence: `docs/data-model.md`, `docs/runtime-flows.md`, and `docs/project-structure.md` now document the new tables, authority-source rule, and month-end snapshot flow.
|
||||
|
||||
### REQ-010
|
||||
|
||||
- AC-1: **PASS**
|
||||
- Evidence: `server.py` exposes `get_asset_snapshot_report`; synthetic probe returned `basis_date`, per-bucket totals, liabilities, net worth, included/excluded items.
|
||||
- AC-2: **PASS**
|
||||
- Evidence: `server.py` exposes `get_net_worth_timeseries`; service/test coverage proves identical formula per basis date.
|
||||
- AC-3: **PASS**
|
||||
- Evidence: `server.py` exposes `list_manual_assets`; synthetic probe returned name/value/date/bucket/source note payloads.
|
||||
- AC-4: **PASS**
|
||||
- Evidence: `dashboard/app.py` caption explicitly states shared valuation helper; `service.py` centralizes calculation for dashboard + MCP.
|
||||
- AC-5: **PASS**
|
||||
- Evidence: same fallback regression test as REQ-009 AC-6 plus `get_asset_liquidity_report` preserves existing keys while adding optional explanatory fields.
|
||||
- AC-6: **PASS**
|
||||
- Evidence: `docs/interface-contract.md`, `docs/runtime-flows.md`, and `docs/project-structure.md` updated for read MCP contract and dashboard/MCP alignment.
|
||||
|
||||
## Requirement state decision
|
||||
|
||||
- REQ-009: Implemented promotion confirmed.
|
||||
- REQ-010: Implemented promotion confirmed.
|
||||
|
||||
## Validation evidence
|
||||
|
||||
1. `python -m py_compile jarca_ledger_mcp/*.py dashboard/app.py` → pass
|
||||
2. `pytest tests/test_asset_snapshots.py tests/test_service.py tests/test_contract_regression.py -q` → pass (`................. [100%]`)
|
||||
3. `hermes mcp test jarca-ledger` → pass; stdio connected, 51 tools discovered, including the three new BAT-008 read tools
|
||||
4. synthetic service probe → pass; confirmed live-authority fallback, stored-snapshot read path, and net-worth timeseries output
|
||||
|
||||
## Remaining issues
|
||||
|
||||
### Hard blockers
|
||||
- None identified from the collected implementation evidence.
|
||||
|
||||
### Non-blocking follow-up
|
||||
- jarcaledgerqc final re-check returned: `PASS, REQ-009/REQ-010은 이제 Implemented로 전환해도 됩니다.`
|
||||
- fresh Streamlit browser smoke on `http://127.0.0.1:8511` rendered `schema v9`, `자산 유동성 현황`, and produced no browser console JS errors.
|
||||
- Snapshot creation/manual-asset CRUD MCP mutations remain intentionally out of scope for BAT-008.
|
||||
@@ -1,40 +0,0 @@
|
||||
# BAT-009 Design
|
||||
|
||||
## Schema and persistence design
|
||||
|
||||
- Reuse `manual_assets` / `asset_snapshots` tables from BAT-008 and extend them only additively for write workflow metadata as needed.
|
||||
- `manual_assets` write lifecycle must support create/update/deactivate without destroying prior snapshot traceability.
|
||||
- `asset_snapshots` remains append-only; correction runs add new rows/metadata rather than overwriting prior close rows.
|
||||
|
||||
## Write workflow design
|
||||
|
||||
- Service layer should expose:
|
||||
- manual asset create/update/deactivate helpers
|
||||
- snapshot preview helper that returns write-free totals/warnings
|
||||
- snapshot close helper that materializes authority-source rows for one `basis_date`
|
||||
- correction helper/metadata so same-date re-close is represented as a correction append, not overwrite
|
||||
- Close path must preserve `source_type`, `source_id`, display name, valuation amount, `liquidity_bucket`, memo/reason metadata.
|
||||
|
||||
## MCP and contract design
|
||||
|
||||
- `server.py` should expose mutation MCP tools for manual asset CRUD and snapshot preview/close.
|
||||
- Success/error envelopes must match dcy-007 contract conventions.
|
||||
- Preview responses expose `source='live_authority'`, `is_closed_snapshot=false`; close responses expose `source='snapshot'`, `is_closed_snapshot=true`.
|
||||
- Correction close responses must identify that a correction run occurred.
|
||||
|
||||
## Dashboard/operator UX design
|
||||
|
||||
- `dashboard/app.py` should provide manual asset create/edit/deactivate flows and a month-end close panel.
|
||||
- Preview and close actions must be visually distinct.
|
||||
- Screen text should clarify whether displayed values are live authority estimates or closed snapshot values.
|
||||
- Correction history should be explainable at least through summary metadata/messages.
|
||||
|
||||
## Verification design
|
||||
|
||||
- Add targeted regression tests for:
|
||||
- manual asset update/deactivate lifecycle
|
||||
- snapshot preview side-effect freedom
|
||||
- append-only correction behavior for same `basis_date`
|
||||
- mutation MCP contract envelope coverage
|
||||
- dashboard/shared-helper fallback and source labeling
|
||||
- Prefer temp DB + synthetic data + local Streamlit smoke only.
|
||||
@@ -1,47 +0,0 @@
|
||||
# BAT-009 Implementation
|
||||
|
||||
## Plan summary
|
||||
|
||||
BAT-009 extends the BAT-008 valuation/read foundation into a full write workflow: manual asset CRUD, month-end snapshot preview/close/correction, mutation MCP contracts, operator dashboard UX, and baseline doc alignment while preserving shared valuation rules and safe fallback behavior.
|
||||
|
||||
## Changed files
|
||||
|
||||
- `jarca_ledger_mcp/db.py`
|
||||
- `jarca_ledger_mcp/service.py`
|
||||
- `jarca_ledger_mcp/server.py`
|
||||
- `dashboard/app.py`
|
||||
- `tests/test_asset_snapshots.py`
|
||||
- `tests/test_contract_regression.py`
|
||||
- `tests/test_dashboard_app.py`
|
||||
- `tests/test_ledger_categories.py`
|
||||
- `tests/test_service.py`
|
||||
- `tests/contract_snapshots/response_contract_v1_0.json`
|
||||
- `docs/data-model.md`
|
||||
- `docs/interface-contract.md`
|
||||
- `docs/discovery/dcy-009_20260701_manual-asset-crud-month-end-snapshot-close-workflow.md`
|
||||
- `docs/srs/Data/req-011_manual-asset-crud-month-end-snapshot-write-model.md`
|
||||
- `docs/srs/Interface/req-012_manual-asset-crud-snapshot-close-mcp-and-operator-dashboard-alignment.md`
|
||||
- `docs/srs/index.md`
|
||||
- `docs/batches/index.md`
|
||||
- `docs/batches/bat-009_20260701_manual-asset-crud-snapshot-close/index.md`
|
||||
- `docs/batches/bat-009_20260701_manual-asset-crud-snapshot-close/verification.md`
|
||||
|
||||
## Execution log
|
||||
|
||||
- 2026-07-01 09:03 KST: BAT-009 standard batch scaffold created from approved REQ-011/REQ-012.
|
||||
- 2026-07-01 10:52 KST: `manual_assets` write lifecycle(create/update/deactivate), `asset_snapshots` close/correction metadata, latest-run snapshot read selection, mutation MCP 5종, 대시보드 `자산/마감` 페이지, contract snapshot/test, baseline docs 정렬을 반영했다.
|
||||
- 2026-07-01 10:52 KST: stale schema-version expectations(`8`/`9`)을 current schema version `10`에 맞게 `tests/test_ledger_categories.py`, `tests/test_service.py`에서 정렬했다.
|
||||
|
||||
## Validation
|
||||
|
||||
- `python3 -m py_compile jarca_ledger_mcp/*.py dashboard/app.py` → PASS
|
||||
- `python3 -m pytest tests/test_asset_snapshots.py tests/test_contract_regression.py tests/test_dashboard_app.py -q` → PASS (`12 passed`)
|
||||
- `python3 -m pytest -q` → PASS (`42 passed, 4 skipped`)
|
||||
- `hermes mcp test jarca-ledger` → PASS (`Connected`, `Tools discovered: 56`)
|
||||
- Browser smoke: Streamlit app on `http://127.0.0.1:18501/?page=자산/마감` rendered the new page with manual asset CRUD section and snapshot preview/close section; browser console JS errors 없음.
|
||||
|
||||
## Remaining risks / follow-up notes
|
||||
|
||||
- Correction metadata shape must remain compatible with existing read helpers and historical snapshots.
|
||||
- Dashboard UX should not imply production-safe automation; this batch is still synthetic-evidence only.
|
||||
- Automatic valuation feeds and scheduled month-end close remain explicitly out of scope for BAT-009.
|
||||
@@ -1,36 +0,0 @@
|
||||
# BAT-009 Manual asset CRUD / snapshot close
|
||||
|
||||
- Profile: standard
|
||||
- Status: release-candidate
|
||||
- Included REQ: REQ-011, REQ-012
|
||||
- Discovery: dcy-009
|
||||
- Owner: 렛저장인
|
||||
- Date (KST): 2026-07-01
|
||||
|
||||
## 목표
|
||||
|
||||
REQ-011/REQ-012에 따라 `manual_assets` write lifecycle, month-end snapshot preview/close, append-only correction policy, mutation MCP, operator dashboard UX, source/is_closed 표기 정렬을 구현한다. 동시에 기존 BAT-008 read model/REQ-005 dashboard safety fallback/dcy-007 contract regression을 깨지 않도록 write/read 일관성을 유지한다.
|
||||
|
||||
## 산출물
|
||||
|
||||
- `manual_assets` create/update/deactivate write support and validation
|
||||
- snapshot preview/close/correction service APIs and additive persistence metadata
|
||||
- mutation MCP tools/contracts: manual asset CRUD, snapshot preview, snapshot close
|
||||
- `dashboard/app.py` operator UX for manual asset management and month-end close preview/execute
|
||||
- regression tests for write/read consistency, correction policy, contract envelope, dashboard fallback
|
||||
- `docs/data-model.md`, `docs/interface-contract.md`, `docs/project-structure.md`, `docs/runtime-flows.md` baseline write-workflow updates
|
||||
- BAT-009 planning/design/implementation/verification documents and synthetic-only evidence
|
||||
|
||||
## 범위 제한
|
||||
|
||||
- 외부 시세/부동산 자동 평가 연동
|
||||
- 월말 자동 스케줄링/cron close
|
||||
- 투자 조언/리밸런싱/세금/수익률 계산
|
||||
- production ledger DB 실데이터 기반 evidence
|
||||
|
||||
## 문서
|
||||
|
||||
- `planning.md`: delivery plan, dependency, risks, validation entry criteria
|
||||
- `design.md`: write-model/correction/MCP/UI design
|
||||
- `implementation.md`: changed files, execution log, validation commands
|
||||
- `verification.md`: AC mapping, PASS/FAIL, REQ Implemented decision
|
||||
@@ -1,37 +0,0 @@
|
||||
# BAT-009 Planning
|
||||
|
||||
## Scope
|
||||
|
||||
- Implement REQ-011: manual asset create/update/deactivate write model, snapshot preview/close persistence, append-only correction policy.
|
||||
- Implement REQ-012: mutation MCP tools/contracts, operator dashboard UX, source/is_closed_snapshot alignment.
|
||||
- Preserve REQ-005/REQ-010 safe fallback when manual asset write paths are unused or new write metadata is absent.
|
||||
- Use synthetic/temp data only for tests and verification evidence.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- dcy-009 confirmed Discovery and approved REQ-011/REQ-012.
|
||||
- Existing BAT-008 read model in `jarca_ledger_mcp/db.py`, `service.py`, `server.py`, `dashboard/app.py`.
|
||||
- Existing dcy-007 response contract / `tests/test_contract_regression.py` expectations.
|
||||
- Additive/idempotent SQLite migration discipline and dcy-002 backup/approval safety policy.
|
||||
|
||||
## Work plan
|
||||
|
||||
1. Create BAT-009 standard batch docs and register entry.
|
||||
2. Extend schema/service write path for manual asset update/deactivate and snapshot preview/close/correction metadata.
|
||||
3. Add mutation MCP endpoints/contracts for manual asset CRUD and snapshot preview/close.
|
||||
4. Add dashboard operator flows for manual asset management and month-end close preview/execute.
|
||||
5. Update baseline docs (`docs/data-model.md`, `docs/interface-contract.md`, `docs/project-structure.md`, `docs/runtime-flows.md`).
|
||||
6. Run narrow validation first (targeted tests / contract regression / synthetic service probe / dashboard smoke).
|
||||
7. If evidence satisfies ACs, move BAT-009 to release-candidate and REQ-011/REQ-012 to Implemented.
|
||||
|
||||
## Design Gate
|
||||
|
||||
- Result: standard batch 유지.
|
||||
- Reason: schema, service, MCP contract, dashboard UX, correction policy, baseline docs를 함께 바꾸므로 design/verification depth가 필요하다.
|
||||
|
||||
## Risks and mitigations
|
||||
|
||||
- Correction semantics drifting from read model: mitigate by explicit correction metadata, latest-valid-close selection tests, and read-after-close probes.
|
||||
- Mutation contract drift vs dcy-007: mitigate by extending contract regression snapshots/tests for new tools.
|
||||
- Dashboard operator flow accidentally mutating without preview clarity: mitigate by separate preview/close actions and source/is_closed labeling.
|
||||
- Hard delete breaking historical traceability: mitigate by soft delete default plus tests asserting deactivated items do not erase prior snapshots.
|
||||
@@ -1,48 +0,0 @@
|
||||
# BAT-009 Verification
|
||||
|
||||
## Verification summary
|
||||
|
||||
Status: PASS
|
||||
|
||||
Evidence was collected against synthetic/temp data only. No production ledger DB mutation or real financial files were used.
|
||||
|
||||
## Acceptance criteria mapping
|
||||
|
||||
### REQ-011
|
||||
|
||||
- AC-1: PASS — `manual_assets` create/update/deactivate write path and additive schema migration/correction columns implemented in `db.py`/`service.py`; full pytest PASS confirms existing/new DB initialization succeeds.
|
||||
- AC-2: PASS — `preview_asset_snapshot_close` exists and targeted tests verify side-effect-free totals/warnings behavior.
|
||||
- AC-3: PASS — `close_asset_snapshot` writes basis-date authority-source rows with close metadata and is covered by `tests/test_asset_snapshots.py`.
|
||||
- AC-4: PASS — same-date re-close requires correction reasoning and appends correction rows via `snapshot_run_id` / `correction_of_run_id` / `is_correction`; targeted tests verify append-only behavior.
|
||||
- AC-5: PASS — latest-run snapshot read selection plus shared valuation helpers keep read model/report consistency; targeted + full pytest PASS.
|
||||
- AC-6: PASS — `docs/data-model.md` updated for write lifecycle, close/correction metadata, and latest-run read policy.
|
||||
|
||||
### REQ-012
|
||||
|
||||
- AC-1: PASS — MCP tools `create_manual_asset`, `update_manual_asset`, `deactivate_manual_asset` are exposed in `server.py`; `hermes mcp test jarca-ledger` discovered all 56 tools including BAT-009 additions.
|
||||
- AC-2: PASS — `preview_asset_snapshot_close` MCP/service returns preview totals, warnings, `source='live_authority'`, `is_closed_snapshot=false`; targeted tests PASS.
|
||||
- AC-3: PASS — `close_asset_snapshot` MCP/service returns close metadata and correction markers with `source='snapshot'`, `is_closed_snapshot=true`; targeted tests PASS.
|
||||
- AC-4: PASS — `dashboard/app.py` adds `자산/마감` page with manual asset add/update/deactivate and snapshot preview/close UX; browser smoke rendered the page successfully.
|
||||
- AC-5: PASS — browser/render + targeted tests confirm `source`/`is_closed_snapshot` aligned across preview/close/report flows and dashboard messaging.
|
||||
- AC-6: PASS — `tests/test_contract_regression.py` and `tests/contract_snapshots/response_contract_v1_0.json` updated; `docs/interface-contract.md` updated; targeted/full pytest PASS.
|
||||
|
||||
## Requirement state decision
|
||||
|
||||
- REQ-011: Implemented.
|
||||
- REQ-012: Implemented.
|
||||
|
||||
## Validation evidence
|
||||
|
||||
- `python3 -m py_compile jarca_ledger_mcp/*.py dashboard/app.py` → PASS
|
||||
- `python3 -m pytest tests/test_asset_snapshots.py tests/test_contract_regression.py tests/test_dashboard_app.py -q` → PASS (`12 passed`)
|
||||
- `python3 -m pytest -q` → PASS (`42 passed, 4 skipped`)
|
||||
- `hermes mcp test jarca-ledger` → PASS (`Connected`, `Tools discovered: 56`)
|
||||
- Browser smoke on Streamlit `자산/마감` page → PASS, JS errors 없음
|
||||
|
||||
## Remaining issues
|
||||
|
||||
### Hard blockers
|
||||
- None.
|
||||
|
||||
### Non-blocking follow-up
|
||||
- Automatic valuation feeds and scheduled month-end close remain explicitly out of scope for BAT-009.
|
||||
@@ -1,50 +0,0 @@
|
||||
# BAT-010 Design
|
||||
|
||||
## Layering design
|
||||
|
||||
- `jarca_ledger_mcp/application/shared.py`
|
||||
- 공통 helper, validation, clock, dedupe, parser imports, shared policy를 보유한다.
|
||||
- `jarca_ledger_mcp/application/system_services.py`
|
||||
- health/status/backup/account create-list 등 system/persistence-adjacent service를 담당한다.
|
||||
- `jarca_ledger_mcp/application/asset_account_services.py`
|
||||
- account update, manual asset, snapshot, liquidity/net-worth read/write helper를 담당한다.
|
||||
- `jarca_ledger_mcp/application/transaction_report_services.py`
|
||||
- transaction CRUD, budgets, monthly/category/fixed-cost/reporting helper를 담당한다.
|
||||
- `jarca_ledger_mcp/application/import_transfer_services.py`
|
||||
- import preview/import, self-transfer/cancel reconciliation, cross-transfer matching을 담당한다.
|
||||
- `jarca_ledger_mcp/application/categorization_services.py`
|
||||
- category rules, preview/apply, uncategorized workbench, ledger categories를 담당한다.
|
||||
|
||||
## Persistence design
|
||||
|
||||
- `jarca_ledger_mcp/infrastructure/sqlite/connection.py`
|
||||
- DB path resolution, sqlite connect, `db()` context manager를 담당한다.
|
||||
- `jarca_ledger_mcp/infrastructure/sqlite/schema.py`
|
||||
- schema version, DDL, additive column maps를 보유한다.
|
||||
- `jarca_ledger_mcp/infrastructure/sqlite/migrations.py`
|
||||
- idempotent/additive migration과 `init_db()`를 담당한다.
|
||||
- top-level `jarca_ledger_mcp/db.py`는 compatibility shim으로 유지한다.
|
||||
|
||||
## Adapter / gateway design
|
||||
|
||||
- `jarca_ledger_mcp/adapters/mcp/server.py`
|
||||
- 실제 FastMCP registration 위치.
|
||||
- top-level `jarca_ledger_mcp/server.py`
|
||||
- CLI entrypoint shim.
|
||||
- `jarca_ledger_mcp/adapters/streamlit/service_gateway.py`
|
||||
- dashboard가 실제로 사용하는 service surface만 재노출한다.
|
||||
- `dashboard/app.py`
|
||||
- gateway import를 통해 backend core를 호출한다.
|
||||
|
||||
## Compatibility design
|
||||
|
||||
- top-level `service.py`는 public API를 그대로 재노출한다.
|
||||
- monkeypatch 관성을 위해 `service._current_kst_datetime` 변경이 shared/application modules에 전파되도록 module proxy를 유지한다.
|
||||
- 기존 tests/import callers는 `from jarca_ledger_mcp import service` / `from jarca_ledger_mcp.db import init_db` 경로를 그대로 쓴다.
|
||||
|
||||
## Verification design
|
||||
|
||||
- `python -m py_compile`로 새 package tree syntax check.
|
||||
- `pytest -q`로 full regression 및 AppTest 포함 회귀 검증.
|
||||
- `hermes mcp test jarca-ledger`로 MCP tool discovery/registration 확인.
|
||||
- Browser smoke로 synthetic fixture DB 기반 `요약`, `자산/마감` 렌더 및 console JS error 유무 확인.
|
||||
@@ -1,61 +0,0 @@
|
||||
# BAT-010 Implementation
|
||||
|
||||
## Plan summary
|
||||
|
||||
BAT-010 implements the confirmed dcy-010 Phase 0~3 scope by extracting application services, SQLite infrastructure, and thin MCP/Streamlit adapter seams while preserving legacy import paths and response contracts.
|
||||
|
||||
## Changed files
|
||||
|
||||
- `jarca_ledger_mcp/service.py`
|
||||
- `jarca_ledger_mcp/db.py`
|
||||
- `jarca_ledger_mcp/server.py`
|
||||
- `jarca_ledger_mcp/application/__init__.py`
|
||||
- `jarca_ledger_mcp/application/shared.py`
|
||||
- `jarca_ledger_mcp/application/system_services.py`
|
||||
- `jarca_ledger_mcp/application/asset_account_services.py`
|
||||
- `jarca_ledger_mcp/application/transaction_report_services.py`
|
||||
- `jarca_ledger_mcp/application/import_transfer_services.py`
|
||||
- `jarca_ledger_mcp/application/categorization_services.py`
|
||||
- `jarca_ledger_mcp/infrastructure/__init__.py`
|
||||
- `jarca_ledger_mcp/infrastructure/sqlite/__init__.py`
|
||||
- `jarca_ledger_mcp/infrastructure/sqlite/connection.py`
|
||||
- `jarca_ledger_mcp/infrastructure/sqlite/schema.py`
|
||||
- `jarca_ledger_mcp/infrastructure/sqlite/migrations.py`
|
||||
- `jarca_ledger_mcp/adapters/__init__.py`
|
||||
- `jarca_ledger_mcp/adapters/mcp/__init__.py`
|
||||
- `jarca_ledger_mcp/adapters/mcp/server.py`
|
||||
- `jarca_ledger_mcp/adapters/streamlit/__init__.py`
|
||||
- `jarca_ledger_mcp/adapters/streamlit/service_gateway.py`
|
||||
- `dashboard/app.py`
|
||||
- `docs/discovery/dcy-010_20260702_backend-core-layering-mcp-adapter-realignment.md`
|
||||
- `docs/project-structure.md`
|
||||
- `docs/runtime-flows.md`
|
||||
- `docs/srs/index.md`
|
||||
- `docs/srs/Non-Functional/req-013_backend-core-layering-sqlite-infrastructure-service-facade-compatibility.md`
|
||||
- `docs/srs/Interface/req-014_mcp-streamlit-adapter-seam-realignment-contract-preserving-gateway.md`
|
||||
- `docs/batches/index.md`
|
||||
- `docs/batches/bat-010_20260703_backend-core-layering-phase-0-3/index.md`
|
||||
- `docs/batches/bat-010_20260703_backend-core-layering-phase-0-3/planning.md`
|
||||
- `docs/batches/bat-010_20260703_backend-core-layering-phase-0-3/design.md`
|
||||
- `docs/batches/bat-010_20260703_backend-core-layering-phase-0-3/implementation.md`
|
||||
- `docs/batches/bat-010_20260703_backend-core-layering-phase-0-3/verification.md`
|
||||
|
||||
## Execution log
|
||||
|
||||
- 2026-07-03 00:15 KST: BAT-010 standard batch scaffold and REQ-013/REQ-014 문서를 생성하고 승인 상태로 정리했다.
|
||||
- 2026-07-03 00:17 KST: `service.py` giant implementation을 application modules로 분리하고 top-level facade compatibility / monkeypatch proxy를 추가했다.
|
||||
- 2026-07-03 00:17 KST: `db.py` responsibilities를 `infrastructure/sqlite`로 분리하고 기존 init/commit/rollback semantics를 유지하는 shim을 추가했다.
|
||||
- 2026-07-03 00:18 KST: MCP adapter package, Streamlit gateway, baseline docs를 반영하고 regression fixes(`SCHEMA_VERSION import`, `db()` init semantics, underscore helper imports, service monkeypatch proxy)를 정리했다.
|
||||
|
||||
## Validation
|
||||
|
||||
- `python -m py_compile jarca_ledger_mcp/*.py jarca_ledger_mcp/application/*.py jarca_ledger_mcp/infrastructure/sqlite/*.py jarca_ledger_mcp/adapters/mcp/*.py jarca_ledger_mcp/adapters/streamlit/*.py dashboard/app.py` → PASS
|
||||
- `pytest -q` → PASS (`42 passed, 4 skipped`)
|
||||
- `hermes mcp test jarca-ledger` → PASS (`Connected`, `Tools discovered: 56`)
|
||||
- Browser smoke: synthetic fixture DB(`/tmp/fixture.sqlite3`)로 Streamlit `요약`과 `자산/마감` 페이지 렌더 확인, console JS errors 없음.
|
||||
|
||||
## Remaining risks / follow-up notes
|
||||
|
||||
- Phase 4+ write/import/advanced workflow의 더 세밀한 domain/service 분리는 아직 TODO다.
|
||||
- Streamlit gateway는 현재 필요한 surface만 노출하지만, 후속 phase에서 page/domain 기준으로 더 세분화할 수 있다.
|
||||
- application modules는 여전히 큰 편이므로 후속 phase에서 deeper repository/use-case split이 필요하다.
|
||||
@@ -1,37 +0,0 @@
|
||||
# BAT-010 Backend core layering (Phase 0~3)
|
||||
|
||||
- Profile: standard
|
||||
- Status: release-candidate
|
||||
- Included REQ: REQ-013, REQ-014
|
||||
- Discovery: dcy-010
|
||||
- Owner: 렛저장인
|
||||
- Date (KST): 2026-07-03
|
||||
|
||||
## 목표
|
||||
|
||||
REQ-013/REQ-014에 따라 `service.py` giant implementation과 `db.py` persistence 집중을 application / infrastructure / adapter seam으로 분리한다. 동시에 top-level facade/shim 호환, MCP tool contract, Streamlit 핵심 화면, additive migration discipline을 유지해 Phase 4+ 분리의 안전한 기반을 만든다.
|
||||
|
||||
## 산출물
|
||||
|
||||
- `jarca_ledger_mcp/application/` phase-0~3 service modules + shared helpers
|
||||
- `jarca_ledger_mcp/infrastructure/sqlite/` connection/schema/migration split
|
||||
- `jarca_ledger_mcp/adapters/mcp/server.py` + top-level `server.py` shim
|
||||
- `jarca_ledger_mcp/adapters/streamlit/service_gateway.py` + dashboard import seam 정렬
|
||||
- `service.py` / `db.py` compatibility facade & shim
|
||||
- full pytest / MCP discovery / browser smoke evidence
|
||||
- `docs/project-structure.md`, `docs/runtime-flows.md` baseline updates
|
||||
- BAT-010 planning/design/implementation/verification documents
|
||||
|
||||
## 범위 제한
|
||||
|
||||
- Phase 4+ transactional write/import/advanced workflow 분리
|
||||
- 신규 HTTP adapter 추가
|
||||
- response envelope, tool names, dashboard IA 재설계
|
||||
- destructive DB migration
|
||||
|
||||
## 문서
|
||||
|
||||
- `planning.md`: Phase 0~3 delivery plan, risks, validation gate
|
||||
- `design.md`: layering/seam/shim design
|
||||
- `implementation.md`: changed files, execution log, validation commands
|
||||
- `verification.md`: AC mapping, PASS/FAIL, REQ Implemented decision
|
||||
@@ -1,34 +0,0 @@
|
||||
# BAT-010 Planning
|
||||
|
||||
## Scope
|
||||
|
||||
- Implement REQ-013: application/infrastructure split, SQLite persistence extraction, service/db compatibility facade.
|
||||
- Implement REQ-014: MCP adapter split, Streamlit service gateway, contract-preserving verification.
|
||||
- Update architecture baseline docs to reflect the new layering and remaining Phase 4+ TODOs.
|
||||
- Use synthetic/temp data only for verification evidence.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- dcy-010 confirmed Discovery and approved/implemented REQ-013/REQ-014.
|
||||
- Existing BAT-009 runtime behavior, response contract expectations, and Streamlit dashboard pages.
|
||||
- Additive/idempotent SQLite migration discipline from REQ-002.
|
||||
|
||||
## Work plan
|
||||
|
||||
1. Split `service.py` implementation into application modules and preserve top-level facade compatibility.
|
||||
2. Split `db.py` responsibilities into `infrastructure/sqlite` and preserve existing import paths.
|
||||
3. Introduce MCP adapter package and Streamlit service gateway.
|
||||
4. Update baseline docs (`docs/project-structure.md`, `docs/runtime-flows.md`).
|
||||
5. Run py_compile, full pytest, MCP discovery, and browser smoke against synthetic fixture DB.
|
||||
6. If evidence satisfies ACs, mark BAT-010 release-candidate and REQ-013/REQ-014 Implemented.
|
||||
|
||||
## Design Gate
|
||||
|
||||
- Result: standard batch 유지.
|
||||
- Reason: package boundary 변화, compatibility shim, MCP adapter seam, Streamlit browser verification, baseline docs가 함께 변경되므로 planning/design/verification depth가 필요하다.
|
||||
|
||||
## Risks and mitigations
|
||||
|
||||
- Hidden helper coupling after module split: mitigate by full pytest, monkeypatch compatibility, and targeted smoke on boundary-sensitive flows.
|
||||
- DB initialization drift after infrastructure split: mitigate by preserving init/commit/rollback semantics and verifying schema initialization through tests.
|
||||
- MCP/dashboard contract drift: mitigate by `hermes mcp test jarca-ledger`, Streamlit AppTest/full pytest, and browser smoke on key pages.
|
||||
@@ -1,45 +0,0 @@
|
||||
# BAT-010 Verification
|
||||
|
||||
## Verification summary
|
||||
|
||||
Status: PASS
|
||||
|
||||
Evidence was collected against synthetic/temp data only. No production ledger DB mutation or real financial files were used.
|
||||
|
||||
## Acceptance criteria mapping
|
||||
|
||||
### REQ-013
|
||||
|
||||
- AC-1: PASS — `jarca_ledger_mcp/application/` 아래 shared/system/asset-account/transaction-report/import-transfer/categorization modules가 생성됐다.
|
||||
- AC-2: PASS — `jarca_ledger_mcp/infrastructure/sqlite/` 아래 connection/schema/migrations split이 생성됐고 top-level `db.py` shim이 유지된다.
|
||||
- AC-3: PASS — `jarca_ledger_mcp/service.py`는 compatibility facade로 축소됐으며 현재 40 lines 수준이다(실질 구현은 application modules로 이동).
|
||||
- AC-4: PASS — `pytest -q` full regression PASS (`42 passed, 4 skipped`), 기존 `service`/`db` import paths 유지.
|
||||
- AC-5: PASS — `docs/project-structure.md`와 `docs/runtime-flows.md`가 새 계층 구조와 shim/gateway 흐름을 반영한다.
|
||||
|
||||
### REQ-014
|
||||
|
||||
- AC-1: PASS — `jarca_ledger_mcp/adapters/mcp/server.py` 도입 후 `hermes mcp test jarca-ledger` PASS, tools discovered 56.
|
||||
- AC-2: PASS — `jarca_ledger_mcp/adapters/streamlit/service_gateway.py` 도입 후 `dashboard/app.py`가 gateway import를 사용한다.
|
||||
- AC-3: PASS — full pytest PASS로 Streamlit AppTest / contract regression 포함 회귀가 유지된다.
|
||||
- AC-4: PASS — local browser smoke에서 `요약`과 `자산/마감` 페이지 렌더를 확인했고 console JS errors가 없었다.
|
||||
- AC-5: PASS — baseline docs와 BAT-010 implementation/verification 문서가 새 adapter seam을 반영한다.
|
||||
|
||||
## Requirement state decision
|
||||
|
||||
- REQ-013: Implemented.
|
||||
- REQ-014: Implemented.
|
||||
|
||||
## Validation evidence
|
||||
|
||||
- `python -m py_compile jarca_ledger_mcp/*.py jarca_ledger_mcp/application/*.py jarca_ledger_mcp/infrastructure/sqlite/*.py jarca_ledger_mcp/adapters/mcp/*.py jarca_ledger_mcp/adapters/streamlit/*.py dashboard/app.py` → PASS
|
||||
- `pytest -q` → PASS (`42 passed, 4 skipped`)
|
||||
- `hermes mcp test jarca-ledger` → PASS (`Connected`, `Tools discovered: 56`)
|
||||
- Browser smoke on Streamlit `요약` / `자산/마감` → PASS, JS errors 없음
|
||||
|
||||
## Remaining issues
|
||||
|
||||
### Hard blockers
|
||||
- None.
|
||||
|
||||
### Non-blocking follow-up
|
||||
- Phase 4+ transactional write services, import pipeline deeper split, advanced workflow separation, narrower adapter surfaces remain tracked as GitHub Project TODO items.
|
||||
@@ -1,37 +0,0 @@
|
||||
# BAT-011 Design
|
||||
|
||||
## Architecture summary
|
||||
|
||||
- Introduce dedicated write-oriented application modules under `jarca_ledger_mcp/application/` for accounts, transactions, budgets, and category rules/categories.
|
||||
- Keep broad modules (`system_services.py`, `asset_account_services.py`, `transaction_report_services.py`, `categorization_services.py`) as compatibility aggregation layers for read/report/mixed responsibilities that are not yet in scope.
|
||||
- Preserve `service.py` as a thin re-export facade and avoid MCP/Streamlit/dashboard call-site churn.
|
||||
|
||||
## Changed areas
|
||||
|
||||
- `jarca_ledger_mcp/application/accounts_write_services.py`
|
||||
- `jarca_ledger_mcp/application/transactions_write_services.py`
|
||||
- `jarca_ledger_mcp/application/budgets_write_services.py`
|
||||
- `jarca_ledger_mcp/application/category_rules_write_services.py`
|
||||
- Existing application modules that previously held these implementations
|
||||
- `jarca_ledger_mcp/application/__init__.py`
|
||||
- `jarca_ledger_mcp/service.py`
|
||||
|
||||
## Key decisions
|
||||
|
||||
- Move only mutation implementations in BAT-011; read/report/import/advanced workflow logic stays in place.
|
||||
- Favor direct function relocation plus compatibility re-export over new abstraction layers to minimize contract risk.
|
||||
- Keep shared helpers in `application/shared.py`; do not introduce storage-layer refactors in this batch.
|
||||
|
||||
## Edge cases
|
||||
|
||||
- `create_ledger_account` remains paired with `update_ledger_account` even though the old implementations lived in different modules.
|
||||
- Category rule preview/apply remains out of BAT-011 scope if moving it would force read/workbench coupling; mutation extraction takes precedence.
|
||||
- Any dashboard/MCP references must continue resolving through `service.py` without signature changes.
|
||||
|
||||
## Architecture Impact
|
||||
|
||||
- none
|
||||
|
||||
## Reference Doc Update Plan
|
||||
|
||||
- No baseline doc rewrite in BAT-011 unless the final module tree differs materially from the existing dcy-011/REQ-015 description.
|
||||
@@ -1,51 +0,0 @@
|
||||
# BAT-011 Implementation
|
||||
|
||||
## Plan summary
|
||||
|
||||
BAT-011 implements the first dcy-011 delivery slice by extracting transactional write paths into narrower application modules while preserving the top-level `service.py` facade, MCP tool contracts, and Streamlit/dashboard call signatures.
|
||||
|
||||
## Changed files
|
||||
|
||||
- `jarca_ledger_mcp/application/accounts_write_services.py`
|
||||
- `jarca_ledger_mcp/application/transactions_write_services.py`
|
||||
- `jarca_ledger_mcp/application/budgets_write_services.py`
|
||||
- `jarca_ledger_mcp/application/category_rules_write_services.py`
|
||||
- `jarca_ledger_mcp/application/__init__.py`
|
||||
- `jarca_ledger_mcp/application/system_services.py`
|
||||
- `jarca_ledger_mcp/application/asset_account_services.py`
|
||||
- `jarca_ledger_mcp/application/transaction_report_services.py`
|
||||
- `jarca_ledger_mcp/application/categorization_services.py`
|
||||
- `jarca_ledger_mcp/service.py`
|
||||
- `docs/discovery/dcy-011_20260703_backend-refactor-phase4-write-import-workflow-adapter-narrowing.md`
|
||||
- `docs/srs/index.md`
|
||||
- `docs/srs/Non-Functional/req-015_transactional-write-service-split-compatibility.md`
|
||||
- `docs/batches/index.md`
|
||||
- `docs/batches/bat-011_20260703_transactional-write-service-split/index.md`
|
||||
- `docs/batches/bat-011_20260703_transactional-write-service-split/planning.md`
|
||||
- `docs/batches/bat-011_20260703_transactional-write-service-split/design.md`
|
||||
- `docs/batches/bat-011_20260703_transactional-write-service-split/implementation.md`
|
||||
- `docs/batches/bat-011_20260703_transactional-write-service-split/verification.md`
|
||||
|
||||
## Execution log
|
||||
|
||||
- 2026-07-03 07:29 KST: dcy-011에서 REQ-015를 생성하고 source Discovery 역참조/SRS index를 갱신했다.
|
||||
- 2026-07-03 07:30 KST: REQ-015를 Approved로 전환하고 BAT-011 standard batch scaffold(index/planning/design/implementation/verification)를 생성했다.
|
||||
- 2026-07-03 07:34 KST: `accounts_write_services.py`, `transactions_write_services.py`, `budgets_write_services.py`, `category_rules_write_services.py`를 추가하고 account/transaction/budget/category rule-category mutation 구현을 새 모듈로 이동했다.
|
||||
- 2026-07-03 07:35 KST: 기존 broad modules(`system_services.py`, `asset_account_services.py`, `transaction_report_services.py`, `categorization_services.py`)를 compatibility re-export/delegation 레이어로 축소했다.
|
||||
- 2026-07-03 07:35 KST: `service.py` proxy module set에 새 write modules를 추가해 helper monkeypatch/export propagation이 계속 동작하도록 정렬했다.
|
||||
- 2026-07-03 07:36 KST: category create path에서 빠진 `infer_cashflow_kind` 정책을 `category_rules_write_services.py`에 보강해 category mutation 회귀를 복구했다.
|
||||
- 2026-07-03 07:39 KST: targeted regression, full pytest, MCP discovery, service export provenance 검증이 모두 PASS하여 REQ-015를 Implemented로 승격했다.
|
||||
|
||||
## Validation
|
||||
|
||||
- `python3 -m py_compile jarca_ledger_mcp/application/*.py jarca_ledger_mcp/service.py` → PASS
|
||||
- `pytest -q tests/test_service.py tests/test_category_rule_filters.py tests/test_ledger_categories.py tests/test_contract_regression.py` → PASS (`19 passed`)
|
||||
- `pytest -q` → PASS (`42 passed, 4 skipped`)
|
||||
- `hermes mcp test jarca-ledger` → PASS (`Connected`, `Tools discovered: 56`)
|
||||
- `python3` provenance check → PASS (`service.create_ledger_account.__module__ == jarca_ledger_mcp.application.accounts_write_services`, transaction/budget/category mutation exports도 각각 새 write module을 가리킴)
|
||||
|
||||
## Remaining risks / follow-up notes
|
||||
|
||||
- `preview_categorization`, `apply_categorization_rules`, uncategorized workbench/read-side helper는 아직 `categorization_services.py`에 남아 있어 Phase 4 후속 또는 Phase 7 adapter narrowing에서 추가 분리가 가능하다.
|
||||
- import preview/import/rollback 및 cross-transfer/reconciliation/advanced workflow 분리는 BAT-011 범위 밖이며 dcy-011 후속 REQ/BAT로 이어져야 한다.
|
||||
- 이번 배치는 contract-preserving extraction이 목적이므로 data model semantics와 response envelope은 의도적으로 변경하지 않았다.
|
||||
@@ -1,33 +0,0 @@
|
||||
# BAT-011 Transactional write service split
|
||||
|
||||
- Profile: standard
|
||||
- Status: release-candidate
|
||||
- Included REQ: REQ-015
|
||||
- Discovery: dcy-011
|
||||
- Owner: 렛저장인
|
||||
- Date (KST): 2026-07-03
|
||||
|
||||
## 목표
|
||||
|
||||
REQ-015에 따라 account / transaction / budget / category rule-category mutation 경로를 더 좁은 write-oriented application service로 분리한다. 기존 `service.py`, MCP adapter, Streamlit gateway, dashboard 호출부와 response contract는 유지한 채 Phase 4 첫 구현 슬라이스를 실제 코드와 검증 evidence로 마무리한다.
|
||||
|
||||
## 산출물
|
||||
|
||||
- `jarca_ledger_mcp/application/` write-oriented service modules
|
||||
- 기존 broad application modules의 compatibility re-export / delegation 정리
|
||||
- full pytest 및 contract-sensitive regression evidence
|
||||
- BAT-011 planning/design/implementation/verification documents
|
||||
|
||||
## 범위 제한
|
||||
|
||||
- import preview/import/rollback split
|
||||
- advanced workflow(cross-transfer/reconciliation/assets/workbench) 분리
|
||||
- HTTP adapter 추가
|
||||
- destructive migration
|
||||
|
||||
## 문서
|
||||
|
||||
- `planning.md`: Phase 4 첫 delivery plan, risks, validation gate
|
||||
- `design.md`: write service boundary / delegation design
|
||||
- `implementation.md`: changed files, execution log, validation commands
|
||||
- `verification.md`: AC mapping, PASS/FAIL, REQ Implemented decision
|
||||
@@ -1,32 +0,0 @@
|
||||
# BAT-011 Planning
|
||||
|
||||
## Scope
|
||||
|
||||
- Implement REQ-015: transactional write path(account / transaction / budget / category rule-category mutation)를 더 좁은 write-oriented application module로 분리한다.
|
||||
- Preserve top-level service facade, MCP adapter, Streamlit gateway, dashboard call signatures and response envelope contracts.
|
||||
- Leave import/advanced workflow split for follow-up REQ/BAT under dcy-011.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- dcy-011 confirmed Discovery and Approved REQ-015.
|
||||
- BAT-010 application/adapters baseline.
|
||||
- Existing pytest regression and contract-sensitive tests.
|
||||
|
||||
## Work plan
|
||||
|
||||
1. Create write-oriented application modules for accounts / transactions / budgets / category rules.
|
||||
2. Move concrete mutation implementations into those modules and keep existing broad modules as compatibility delegation layers where needed.
|
||||
3. Update `application/__init__.py` and `service.py` import surface to re-export the new modules without changing public API.
|
||||
4. Run focused syntax + regression validation, then full pytest if focused checks remain green.
|
||||
5. Update batch implementation/verification evidence and promote REQ/BAT state if ACs are satisfied.
|
||||
|
||||
## Design Gate
|
||||
|
||||
- Result: standard batch 유지.
|
||||
- Reason: package boundary 변경, compatibility delegation, category/account/transaction write contract preservation, regression evidence 정리가 함께 필요하므로 planning/design/verification depth가 필요하다.
|
||||
|
||||
## Risks and mitigations
|
||||
|
||||
- Hidden import coupling after write extraction: mitigate by preserving re-export layers and running full pytest.
|
||||
- Envelope drift on mutation responses: mitigate by preserving existing function signatures and contract-sensitive tests.
|
||||
- Category rule/category mutation helpers may still share read-side helpers: mitigate by extracting only write-focused logic first and leaving broad read/report paths untouched in this batch.
|
||||
@@ -1,43 +0,0 @@
|
||||
# BAT-011 Verification
|
||||
|
||||
## Verification summary
|
||||
|
||||
Status: PASS
|
||||
|
||||
Evidence was collected against synthetic/temp data only. No production ledger DB mutation or real financial files were used.
|
||||
|
||||
## Acceptance criteria mapping
|
||||
|
||||
### REQ-015
|
||||
|
||||
- AC-1: PASS — `jarca_ledger_mcp/application/` 아래에 `accounts_write_services.py`, `transactions_write_services.py`, `budgets_write_services.py`, `category_rules_write_services.py`가 생성됐고 account/transaction/budget/category rule-category mutation 구현이 그쪽으로 이동했다.
|
||||
- AC-2: PASS — top-level `service.py` public API, MCP tools, Streamlit/dashboard call signatures and mutation envelope contracts are preserved. MCP discovery still reports 56 tools, and export provenance shows the write APIs now resolve to the new modules.
|
||||
- AC-3: PASS — targeted regression (`tests/test_service.py`, `tests/test_category_rule_filters.py`, `tests/test_ledger_categories.py`, `tests/test_contract_regression.py`) PASS, plus full `pytest -q` PASS (`42 passed, 4 skipped`).
|
||||
- AC-4: PASS — BAT-011 implementation/verification docs now record actual changed files, commands, and outcomes.
|
||||
|
||||
## Requirement state decision
|
||||
|
||||
- REQ-015: Implemented.
|
||||
|
||||
## Validation evidence
|
||||
|
||||
- `python3 -m py_compile jarca_ledger_mcp/application/*.py jarca_ledger_mcp/service.py` → PASS
|
||||
- `pytest -q tests/test_service.py tests/test_category_rule_filters.py tests/test_ledger_categories.py tests/test_contract_regression.py` → PASS (`19 passed`)
|
||||
- `pytest -q` → PASS (`42 passed, 4 skipped`)
|
||||
- `hermes mcp test jarca-ledger` → PASS (`Connected`, `Tools discovered: 56`)
|
||||
- Python provenance check on exported write APIs → PASS
|
||||
- `create_ledger_account`, `update_ledger_account` → `accounts_write_services`
|
||||
- `create/update/delete_ledger_transaction` → `transactions_write_services`
|
||||
- `create_ledger_budget` → `budgets_write_services`
|
||||
- `create/update/delete_category_rule`, `create/delete_ledger_category` → `category_rules_write_services`
|
||||
|
||||
## Remaining issues
|
||||
|
||||
### Hard blockers
|
||||
- None.
|
||||
|
||||
### Non-blocking follow-up
|
||||
- categorization preview/apply/workbench read-side extraction
|
||||
- import pipeline split
|
||||
- advanced finance workflow split
|
||||
- narrower adapter surfaces under later dcy-011 batches
|
||||
@@ -1,23 +0,0 @@
|
||||
# BAT-012 Design
|
||||
|
||||
## Architecture summary
|
||||
- Introduce `jarca_ledger_mcp/application/imports_service.py` as the single application-layer home for import preview/import/rollback orchestration.
|
||||
- Introduce `jarca_ledger_mcp/infrastructure/parsers/` as the parser seam so application code no longer imports top-level parser implementations directly.
|
||||
- Keep current top-level parser modules for compatibility if needed, but route application/shared usage through the infrastructure seam.
|
||||
- Preserve `application/import_transfer_services.py` as the advanced workflow home; import-facing public functions become delegations into `imports_service.py`.
|
||||
|
||||
## Changed areas
|
||||
- application import orchestration
|
||||
- infrastructure parser seam
|
||||
- service export surface / compatibility proxy
|
||||
- import regression verification docs
|
||||
|
||||
## Key decisions
|
||||
1. Parser relocation is seam-first, not algorithm rewrite.
|
||||
2. Import account auto-linking/classification stays in the application layer, not in parser modules.
|
||||
3. Public API/tool names remain unchanged.
|
||||
|
||||
## Verification focus
|
||||
- Import preview/import/rollback regression
|
||||
- Evidence field preservation
|
||||
- No breakage in MCP discovery and public exports
|
||||
@@ -1,46 +0,0 @@
|
||||
# BAT-012 Implementation
|
||||
|
||||
## Plan summary
|
||||
|
||||
BAT-012 implements dcy-011 Phase 5 by extracting import preview/import/rollback orchestration into `application/imports_service.py`, introducing an `infrastructure/parsers/*` seam, and shrinking `application/import_transfer_services.py` toward advanced workflow ownership while preserving public contracts.
|
||||
|
||||
## Changed files
|
||||
|
||||
- `jarca_ledger_mcp/application/imports_service.py`
|
||||
- `jarca_ledger_mcp/application/import_transfer_services.py`
|
||||
- `jarca_ledger_mcp/application/shared.py`
|
||||
- `jarca_ledger_mcp/application/__init__.py`
|
||||
- `jarca_ledger_mcp/infrastructure/parsers/__init__.py`
|
||||
- `jarca_ledger_mcp/infrastructure/parsers/kb_bank_pdf.py`
|
||||
- `jarca_ledger_mcp/infrastructure/parsers/toss_bank_pdf.py`
|
||||
- `jarca_ledger_mcp/infrastructure/parsers/toss_securities_pdf.py`
|
||||
- `jarca_ledger_mcp/infrastructure/parsers/seoulpay_xlsx.py`
|
||||
- `jarca_ledger_mcp/service.py`
|
||||
- `docs/srs/index.md`
|
||||
- `docs/srs/Non-Functional/req-016_import-pipeline-application-infrastructure-split.md`
|
||||
- `docs/batches/index.md`
|
||||
- `docs/batches/bat-012_20260703_import-pipeline-split/*`
|
||||
- `docs/discovery/dcy-011_20260703_backend-refactor-phase4-write-import-workflow-adapter-narrowing.md`
|
||||
|
||||
## Execution log
|
||||
|
||||
- 2026-07-03 07:49 KST: dcy-011 Phase 5 범위로 `REQ-016`/`BAT-012`를 생성하고 승인 상태를 정리했다.
|
||||
- 2026-07-03 07:50 KST: `application/import_transfer_services.py`의 AST function ranges를 추출해 import-owned 함수와 advanced workflow 함수를 기계적으로 분리할 준비를 했다.
|
||||
- 2026-07-03 07:51 KST: `application/imports_service.py`를 생성하고 import preview/import/rollback + import-specific account/classification helpers를 이동했다.
|
||||
- 2026-07-03 07:51 KST: `application/import_transfer_services.py`를 advanced workflow 중심 모듈로 축소하고 import-facing public functions는 compatibility delegation으로 전환했다.
|
||||
- 2026-07-03 07:51 KST: `infrastructure/parsers/*` seam을 추가하고 `application/shared.py`가 top-level parser 구현 대신 infrastructure seam을 통해 parser를 가져오도록 정렬했다.
|
||||
- 2026-07-03 07:52~07:53 KST: targeted import regression, full pytest, MCP discovery, export provenance를 검증했고 모두 PASS했다.
|
||||
|
||||
## Validation
|
||||
|
||||
- `python3 -m py_compile jarca_ledger_mcp/application/*.py jarca_ledger_mcp/infrastructure/parsers/*.py jarca_ledger_mcp/service.py` → PASS
|
||||
- `pytest -q tests/test_kb_bank_pdf.py tests/test_seoulpay_xlsx.py tests/test_toss_securities_pdf.py tests/test_service.py` → PASS (`12 passed, 4 skipped`)
|
||||
- `pytest -q` → PASS (`42 passed, 4 skipped`)
|
||||
- `hermes mcp test jarca-ledger` → PASS (`Connected`, `Tools discovered: 56`)
|
||||
- `python3` provenance check → PASS (all import preview/import/rollback exports resolve to `jarca_ledger_mcp.application.imports_service`)
|
||||
|
||||
## Remaining risks / follow-up notes
|
||||
|
||||
- `application/import_transfer_services.py`에는 cross-transfer review/matching advanced workflow가 아직 남아 있으며 Phase 6 배치에서 별도 분리해야 한다.
|
||||
- parser relocation은 seam-first 방식이므로 top-level parser implementation files는 아직 compatibility/implementation 위치로 남아 있다. 필요 시 후속 cleanup은 adapter/baseline 갱신과 함께 진행한다.
|
||||
- UI/adapter 표면 축소와 baseline 문서 갱신은 BAT-012 범위 밖이다.
|
||||
@@ -1,21 +0,0 @@
|
||||
# BAT-012 Import pipeline split
|
||||
|
||||
- Profile: standard
|
||||
- Status: release-candidate
|
||||
- Included REQ: REQ-016
|
||||
- Discovery: dcy-011
|
||||
- Owner: 렛저장인
|
||||
- Date (KST): 2026-07-03
|
||||
|
||||
## 목표
|
||||
|
||||
REQ-016에 따라 import preview/import/rollback 경로를 `application/imports_service.py`와 `infrastructure/parsers/*` 중심으로 재배치하고, `application/import_transfer_services.py`는 advanced workflow 중심 모듈로 축소한다.
|
||||
|
||||
## Delivery checklist
|
||||
|
||||
- [ ] planning complete
|
||||
- [ ] design complete
|
||||
- [ ] implementation complete
|
||||
- [ ] verification complete
|
||||
- [ ] release-candidate promoted
|
||||
- [ ] REQ sync complete
|
||||
@@ -1,28 +0,0 @@
|
||||
# BAT-012 Planning
|
||||
|
||||
## Scope
|
||||
- Implement REQ-016 import pipeline split.
|
||||
- Keep import contract/evidence fields stable while relocating parser access under `infrastructure/parsers/*`.
|
||||
- Leave cross-transfer/reconciliation/advanced workflows in follow-up batches.
|
||||
|
||||
## Dependencies
|
||||
- dcy-011 confirmed Discovery.
|
||||
- REQ-016 Approved.
|
||||
- BAT-011 write-service split baseline.
|
||||
- Existing import regression tests and MCP discovery.
|
||||
|
||||
## Work plan
|
||||
1. Create `application/imports_service.py` and move import preview/import/rollback + import-specific helpers there.
|
||||
2. Create `infrastructure/parsers/*` wrappers or relocated parser modules and point application/shared imports to the infrastructure seam.
|
||||
3. Shrink `application/import_transfer_services.py` to advanced workflow + compatibility delegation for import functions.
|
||||
4. Run focused import regression, then full pytest and MCP discovery.
|
||||
5. Update batch evidence and promote REQ/BAT if ACs pass.
|
||||
|
||||
## Design Gate
|
||||
- Result: standard batch 유지.
|
||||
- Reason: application/infrastructure seam 변경과 compatibility delegation, import evidence preservation, parser path relocation 검증이 함께 필요하다.
|
||||
|
||||
## Risks and mitigations
|
||||
- Import evidence drift: preserve existing payload fields and run import-specific regression.
|
||||
- Hidden helper coupling between import and advanced workflows: move only import-facing helpers in this batch and leave advanced helpers in place when not import-owned.
|
||||
- Parser path breakage: add infrastructure parser wrappers first, then re-point shared/application imports.
|
||||
@@ -1,37 +0,0 @@
|
||||
# BAT-012 Verification
|
||||
|
||||
## Verification summary
|
||||
|
||||
Status: PASS
|
||||
|
||||
Evidence was collected against synthetic/temp data only. No production ledger DB mutation or real financial files were used.
|
||||
|
||||
## Acceptance criteria mapping
|
||||
|
||||
### REQ-016
|
||||
- AC-1: PASS — `application/imports_service.py`와 `infrastructure/parsers/*`가 생성됐고 import preview/import/rollback 구현이 이동했다.
|
||||
- AC-2: PASS — public API/MCP tools/import response envelope and evidence fields remained stable; MCP discovery still reports 56 tools.
|
||||
- AC-3: PASS — import-focused regression and full pytest PASS.
|
||||
- AC-4: PASS — BAT-012 implementation/verification docs record actual changed files, commands, and outcomes.
|
||||
|
||||
## Requirement state decision
|
||||
|
||||
- REQ-016: Implemented.
|
||||
|
||||
## Validation evidence
|
||||
|
||||
- `python3 -m py_compile jarca_ledger_mcp/application/*.py jarca_ledger_mcp/infrastructure/parsers/*.py jarca_ledger_mcp/service.py` → PASS
|
||||
- `pytest -q tests/test_kb_bank_pdf.py tests/test_seoulpay_xlsx.py tests/test_toss_securities_pdf.py tests/test_service.py` → PASS (`12 passed, 4 skipped`)
|
||||
- `pytest -q` → PASS (`42 passed, 4 skipped`)
|
||||
- `hermes mcp test jarca-ledger` → PASS (`Connected`, `Tools discovered: 56`)
|
||||
- Python provenance check on import-facing exports → PASS
|
||||
- preview/import/rollback APIs all resolve to `jarca_ledger_mcp.application.imports_service`
|
||||
|
||||
## Remaining issues
|
||||
|
||||
### Hard blockers
|
||||
- None.
|
||||
|
||||
### Non-blocking follow-up
|
||||
- cross-transfer / reconciliation / asset / workbench advanced workflow split
|
||||
- MCP/Streamlit adapter surface narrowing and baseline docs update
|
||||
@@ -1,13 +0,0 @@
|
||||
# BAT-013 Design
|
||||
|
||||
## Architecture summary
|
||||
- `cross_transfer_service.py` owns matching helpers and review queue APIs.
|
||||
- `reconciliation_service.py` owns manual/partial-import balance reconciliation preview.
|
||||
- `assets_service.py` owns manual asset CRUD, snapshot close/read, liquidity/net-worth reporting, and valuation helpers.
|
||||
- `uncategorized_workbench_service.py` owns uncategorized list/summary/workbench/recommendation apply flows.
|
||||
- Existing broad modules become thin compatibility layers or keep only their non-moved responsibilities.
|
||||
|
||||
## Verification focus
|
||||
- workflow-specific regression for cross-transfer/assets/reconciliation/workbench
|
||||
- full pytest and MCP discovery
|
||||
- provenance checks that public exports resolve to the new owning modules
|
||||
@@ -1,48 +0,0 @@
|
||||
# BAT-013 Implementation
|
||||
|
||||
## Plan summary
|
||||
|
||||
BAT-013 implements dcy-011 Phase 6 by extracting advanced finance workflows into dedicated owning application services: `cross_transfer_service.py`, `reconciliation_service.py`, `assets_service.py`, and `uncategorized_workbench_service.py`. Existing broad modules remain as compatibility layers so MCP/service/dashboard callers keep their contracts.
|
||||
|
||||
## Changed files
|
||||
|
||||
- `jarca_ledger_mcp/application/assets_service.py`
|
||||
- `jarca_ledger_mcp/application/asset_account_services.py`
|
||||
- `jarca_ledger_mcp/application/cross_transfer_service.py`
|
||||
- `jarca_ledger_mcp/application/import_transfer_services.py`
|
||||
- `jarca_ledger_mcp/application/reconciliation_service.py`
|
||||
- `jarca_ledger_mcp/application/transaction_report_services.py`
|
||||
- `jarca_ledger_mcp/application/uncategorized_workbench_service.py`
|
||||
- `jarca_ledger_mcp/application/categorization_services.py`
|
||||
- `jarca_ledger_mcp/application/__init__.py`
|
||||
- `jarca_ledger_mcp/service.py`
|
||||
- `docs/srs/index.md`
|
||||
- `docs/srs/Non-Functional/req-017_advanced-finance-workflow-service-split.md`
|
||||
- `docs/batches/index.md`
|
||||
- `docs/batches/bat-013_20260703_advanced-workflow-service-split/*`
|
||||
- `docs/discovery/dcy-011_20260703_backend-refactor-phase4-write-import-workflow-adapter-narrowing.md`
|
||||
|
||||
## Execution log
|
||||
|
||||
- 2026-07-03 07:55 KST: dcy-011 Phase 6 범위로 `REQ-017`/`BAT-013`를 생성하고 Approved 상태를 확정했다.
|
||||
- 2026-07-03 07:57~07:59 KST: AST-extracted function ranges를 기준으로 assets / cross-transfer / reconciliation / uncategorized workbench 흐름을 새 owning services로 이동했다.
|
||||
- 2026-07-03 07:59 KST: `asset_account_services.py`, `import_transfer_services.py`, `transaction_report_services.py`, `categorization_services.py`를 compatibility delegation 레이어로 축소했다.
|
||||
- 2026-07-03 08:00 KST: `application/__init__.py`와 `service.py` export/proxy surface를 새 owning modules까지 확장했다.
|
||||
- 2026-07-03 08:00~08:01 KST: targeted workflow regression, full pytest, MCP discovery, provenance checks를 실행했고 모두 PASS했다.
|
||||
|
||||
## Validation
|
||||
|
||||
- `python3 -m py_compile jarca_ledger_mcp/application/*.py jarca_ledger_mcp/service.py` → PASS
|
||||
- `pytest -q tests/test_cross_account_transfer_matching.py tests/test_asset_snapshots.py tests/test_categorization.py tests/test_contract_regression.py tests/test_service.py` → PASS (`24 passed`)
|
||||
- `pytest -q` → PASS (`42 passed, 4 skipped`)
|
||||
- `hermes mcp test jarca-ledger` → PASS (`Connected`, `Tools discovered: 56`)
|
||||
- `python3` provenance check → PASS
|
||||
- cross-transfer APIs → `jarca_ledger_mcp.application.cross_transfer_service`
|
||||
- reconciliation API → `jarca_ledger_mcp.application.reconciliation_service`
|
||||
- asset workflows → `jarca_ledger_mcp.application.assets_service`
|
||||
- uncategorized workbench APIs → `jarca_ledger_mcp.application.uncategorized_workbench_service`
|
||||
|
||||
## Remaining risks / follow-up notes
|
||||
|
||||
- broad compatibility layers still exist by design; final dcy-011 batch should narrow MCP/Streamlit adapter imports and refresh baseline docs.
|
||||
- top-level module names remain public to avoid breaking monkeypatch/tests; final cleanup should preserve this constraint.
|
||||
@@ -1,21 +0,0 @@
|
||||
# BAT-013 Advanced workflow service split
|
||||
|
||||
- Profile: standard
|
||||
- Status: release-candidate
|
||||
- Included REQ: REQ-017
|
||||
- Discovery: dcy-011
|
||||
- Owner: 렛저장인
|
||||
- Date (KST): 2026-07-03
|
||||
|
||||
## 목표
|
||||
|
||||
REQ-017에 따라 cross-transfer, reconciliation, assets, uncategorized workbench를 owning application services로 분리하고 broad modules는 compatibility delegation으로 축소한다.
|
||||
|
||||
## Delivery checklist
|
||||
|
||||
- [ ] planning complete
|
||||
- [ ] design complete
|
||||
- [ ] implementation complete
|
||||
- [ ] verification complete
|
||||
- [ ] release-candidate promoted
|
||||
- [ ] REQ sync complete
|
||||
@@ -1,28 +0,0 @@
|
||||
# BAT-013 Planning
|
||||
|
||||
## Scope
|
||||
- Implement REQ-017 advanced workflow service split.
|
||||
- Preserve public API and workflow response contracts while relocating owning helpers with their workflows.
|
||||
- Leave adapter narrowing/baseline docs for the final dcy-011 batch.
|
||||
|
||||
## Dependencies
|
||||
- dcy-011 confirmed Discovery.
|
||||
- REQ-017 Approved.
|
||||
- BAT-011/BAT-012 compatibility seams.
|
||||
- Existing workflow regression tests.
|
||||
|
||||
## Work plan
|
||||
1. Extract cross-transfer workflow from `import_transfer_services.py` into `cross_transfer_service.py`.
|
||||
2. Extract reconciliation preview from `transaction_report_services.py` into `reconciliation_service.py`.
|
||||
3. Extract manual asset/snapshot/liquidity workflows from `asset_account_services.py` into `assets_service.py`.
|
||||
4. Extract uncategorized list/summary/workbench/recommendation flows from `categorization_services.py` into `uncategorized_workbench_service.py`.
|
||||
5. Update application/service export surfaces, run focused workflow regression + full pytest, then record evidence.
|
||||
|
||||
## Design Gate
|
||||
- Result: standard batch 유지.
|
||||
- Reason: multiple domain modules and compatibility layers change together; broad-module decomposition needs explicit verification.
|
||||
|
||||
## Risks and mitigations
|
||||
- Shared helper drift across moved workflows: move helper with first owner and verify with focused tests.
|
||||
- Contract regressions in dashboard/MCP callers: preserve public names and run full pytest + MCP discovery.
|
||||
- Partial extraction leaving dead imports: run py_compile and provenance check after relocation.
|
||||
@@ -1,36 +0,0 @@
|
||||
# BAT-013 Verification
|
||||
|
||||
## Verification summary
|
||||
|
||||
Status: PASS
|
||||
|
||||
Evidence was collected against synthetic/temp data only. No production ledger DB mutation or real financial files were used.
|
||||
|
||||
## Acceptance criteria mapping
|
||||
|
||||
### REQ-017
|
||||
- AC-1: PASS — `cross_transfer_service.py`, `reconciliation_service.py`, `assets_service.py`, `uncategorized_workbench_service.py` were created and now own their workflows.
|
||||
- AC-2: PASS — service/MCP/dashboard contract remained stable; MCP discovery still reports 56 tools.
|
||||
- AC-3: PASS — workflow-focused regression and full pytest both passed.
|
||||
- AC-4: PASS — BAT-013 implementation/verification docs record the actual changed files, commands, and outcomes.
|
||||
|
||||
## Requirement state decision
|
||||
|
||||
- REQ-017: Implemented.
|
||||
|
||||
## Validation evidence
|
||||
|
||||
- `python3 -m py_compile jarca_ledger_mcp/application/*.py jarca_ledger_mcp/service.py` → PASS
|
||||
- `pytest -q tests/test_cross_account_transfer_matching.py tests/test_asset_snapshots.py tests/test_categorization.py tests/test_contract_regression.py tests/test_service.py` → PASS (`24 passed`)
|
||||
- `pytest -q` → PASS (`42 passed, 4 skipped`)
|
||||
- `hermes mcp test jarca-ledger` → PASS (`Connected`, `Tools discovered: 56`)
|
||||
- Python provenance check on advanced workflow exports → PASS
|
||||
|
||||
## Remaining issues
|
||||
|
||||
### Hard blockers
|
||||
- None.
|
||||
|
||||
### Non-blocking follow-up
|
||||
- MCP/Streamlit adapter surface narrowing
|
||||
- dcy-011 baseline/final status refresh and QC evidence sync
|
||||
@@ -1,7 +0,0 @@
|
||||
# BAT-014 Design
|
||||
|
||||
## Architecture summary
|
||||
- `adapters/mcp/tool_contracts.py` becomes the MCP adapter’s narrow contract dependency surface.
|
||||
- `adapters/streamlit/{overview,assets,transactions,categorization,imports,accounts,transfers,reconciliation}_gateway.py` expose page/domain-sized call sets.
|
||||
- `adapters/streamlit/service_gateway.py` remains a compatibility aggregator while `dashboard/app.py` shifts to page/domain gateway aliases.
|
||||
- Baseline docs record the post-Phase-7 structure and runtime flow.
|
||||
|
Before Width: | Height: | Size: 292 KiB |
@@ -1,74 +0,0 @@
|
||||
{
|
||||
"success": true,
|
||||
"base_url": "http://127.0.0.1:18501",
|
||||
"output_dir": "/root/projects/jarca-ledger-mcp/docs/batches/bat-014_20260703_adapter-surface-narrowing-baseline-refresh/evidence/run-20260703-100358",
|
||||
"fixture": {
|
||||
"account_id": "acct_2e22ac8ac63a",
|
||||
"transaction_ids": [
|
||||
"tx_14dd02c2fe6c",
|
||||
"tx_8a75d20fcd87",
|
||||
"tx_88bdacc43404",
|
||||
"tx_c0418db6d784",
|
||||
"tx_7b21f4085a1d"
|
||||
],
|
||||
"db_path": "docs/batches/bat-014_20260703_adapter-surface-narrowing-baseline-refresh/evidence/run-20260703-100358/fixture.sqlite3"
|
||||
},
|
||||
"chrome": "/usr/bin/google-chrome-stable",
|
||||
"streamlit": ".venv/bin/streamlit",
|
||||
"pages": [
|
||||
{
|
||||
"page": "요약",
|
||||
"url": "http://127.0.0.1:18501/?page=%EC%9A%94%EC%95%BD",
|
||||
"screenshot": "docs/batches/bat-014_20260703_adapter-surface-narrowing-baseline-refresh/evidence/run-20260703-100358/overview.png",
|
||||
"screenshot_bytes": 340145,
|
||||
"snapshot": "docs/batches/bat-014_20260703_adapter-surface-narrowing-baseline-refresh/evidence/run-20260703-100358/overview.dom.html",
|
||||
"snapshot_bytes": 31902,
|
||||
"devtools_port": 19222,
|
||||
"inner_text_head": "💰 Jarca Ledger\n\n가계부 · 분류 · Import 운영 콘솔\n\n메뉴\n요약\n자산/마감\n거래내역\n확인필요 큐\n미분류\n분류 규칙\n카테고리\n계좌\nImport\n\n새로고침\n\nStop\nDeploy\n📊 요약\n가계부 운영 대시보드\n\n이번 달 실제 현금흐름, 자산 유동성, 운영 경고를 우선순위대로 확인합니다.\n\nschema v10\nKST 이번 달\nlast_balance 기준 자산\n\nDB: /root/projects/jarca-ledger-mcp/docs/batches/bat-014_20260703_adapter-surface-narrowing-baseline-refresh/evidence/run-20260703-100358/fixture.sqlite3\n\n💎\n이번 달 수입/지출 현황\n\n기준: KST 현재 월 2026-07, transactions.transaction_date, ledger_categories.cashflow_kind 실제 현금흐름\n\n실제 수입\n\n0원\n\n실제 지출\n\n0원\n\n순"
|
||||
},
|
||||
{
|
||||
"page": "분류 규칙",
|
||||
"url": "http://127.0.0.1:18501/?page=%EB%B6%84%EB%A5%98%20%EA%B7%9C%EC%B9%99",
|
||||
"screenshot": "docs/batches/bat-014_20260703_adapter-surface-narrowing-baseline-refresh/evidence/run-20260703-100358/rules.png",
|
||||
"screenshot_bytes": 366052,
|
||||
"snapshot": "docs/batches/bat-014_20260703_adapter-surface-narrowing-baseline-refresh/evidence/run-20260703-100358/rules.dom.html",
|
||||
"snapshot_bytes": 165223,
|
||||
"devtools_port": 19223,
|
||||
"inner_text_head": "💰 Jarca Ledger\n\n가계부 · 분류 · Import 운영 콘솔\n\n메뉴\n요약\n자산/마감\n거래내역\n확인필요 큐\n미분류\n분류 규칙\n카테고리\n계좌\nImport\nStop\nDeploy\n⚙️ Rule Engine\n분류 규칙\n\n반복되는 사용처와 거래 패턴을 규칙으로 관리해 분류 자동화 품질을 높입니다.\n\n자동 분류\nPreview\nSeed/Update\nkeyboard_arrow_right\n\n🟢 환급 · merchant/contains → 수입 / 환급 · p10 · income\n\nkeyboard_arrow_right\n\n🟢 급여 · merchant/contains → 수입 / 급여 · p10 · income\n\nkeyboard_arrow_right\n\n🟢 이자 · merchant/contains → 수입 / 이자 · p10 · income\n\nkeyboard_arrow_right\n\n🟢 국민카드 · raw_summary/equals → 금융 / 카드대금 · p20 · expense\n\nkeyboard"
|
||||
},
|
||||
{
|
||||
"page": "확인필요 큐",
|
||||
"url": "http://127.0.0.1:18501/?page=%ED%99%95%EC%9D%B8%ED%95%84%EC%9A%94%20%ED%81%90",
|
||||
"screenshot": "docs/batches/bat-014_20260703_adapter-surface-narrowing-baseline-refresh/evidence/run-20260703-100358/transfer-review.png",
|
||||
"screenshot_bytes": 303427,
|
||||
"snapshot": "docs/batches/bat-014_20260703_adapter-surface-narrowing-baseline-refresh/evidence/run-20260703-100358/transfer-review.dom.html",
|
||||
"snapshot_bytes": 25158,
|
||||
"devtools_port": 19224,
|
||||
"inner_text_head": "💰 Jarca Ledger\n\n가계부 · 분류 · Import 운영 콘솔\n\n메뉴\n요약\n자산/마감\n거래내역\n확인필요 큐\n미분류\n분류 규칙\n카테고리\n계좌\nImport\n\n새로고침\n\nStop\nDeploy\n🔁 Transfer Review\nKB↔토스뱅크 확인필요 큐\n\n날짜·금액·상대 기준으로 계좌 간 이동 후보를 대조하고, 드라이런 후 안전하게 매칭합니다.\n\n드라이런 우선\n본인계좌이동\n수동 검토\n\n미리보기(드라이런)\n\n자동 매칭 실행\n\n📌\n확인필요 큐\n\n거래 ID: tx_7b21f4085a1d\n\n2026-06-29 · SYNTHETIC_TRANSFER · 120,000원"
|
||||
},
|
||||
{
|
||||
"page": "Import",
|
||||
"url": "http://127.0.0.1:18501/?page=Import",
|
||||
"screenshot": "docs/batches/bat-014_20260703_adapter-surface-narrowing-baseline-refresh/evidence/run-20260703-100358/import.png",
|
||||
"screenshot_bytes": 298860,
|
||||
"snapshot": "docs/batches/bat-014_20260703_adapter-surface-narrowing-baseline-refresh/evidence/run-20260703-100358/import.dom.html",
|
||||
"snapshot_bytes": 25118,
|
||||
"devtools_port": 19225,
|
||||
"inner_text_head": "💰 Jarca Ledger\n\n가계부 · 분류 · Import 운영 콘솔\n\n메뉴\n요약\n자산/마감\n거래내역\n확인필요 큐\n미분류\n분류 규칙\n카테고리\n계좌\nImport\nStop\nDeploy\n📥 Statement Import\nImport\n\nPDF/XLSX 거래내역을 먼저 Preview로 검증한 뒤 원장에 반영합니다.\n\nPreview 우선\n중복 skip\nImport 이력\n📈\n토스증권 거래내역 PDF 가져오기\n\n토스증권 거래내역서 PDF를 업로드하면 투자계좌 거래로 가져옵니다. 매수/매도/환전/입출금은 이체/투자이동, 배당/이자는 실제 수입으로 분류합니다.\n\n🏦\n토스뱅크 거래내역 PDF 가져오기\n\n토스뱅크 계좌 거래내역 PDF를 업로드하면 입출금/이체/카드결제를 가져옵니다. 타인 이체/출금은 이체/확인필요로 분류됩니다.\n\n🧾\nImport 이력"
|
||||
}
|
||||
],
|
||||
"server_command": [
|
||||
".venv/bin/streamlit",
|
||||
"run",
|
||||
"dashboard/app.py",
|
||||
"--server.address",
|
||||
"127.0.0.1",
|
||||
"--server.port",
|
||||
"18501",
|
||||
"--server.headless",
|
||||
"true",
|
||||
"--browser.gatherUsageStats",
|
||||
"false"
|
||||
],
|
||||
"server_log_tail": ""
|
||||
}
|
||||
|
Before Width: | Height: | Size: 332 KiB |
|
Before Width: | Height: | Size: 358 KiB |
|
Before Width: | Height: | Size: 296 KiB |
@@ -1,43 +0,0 @@
|
||||
# BAT-014 Implementation
|
||||
|
||||
## Plan summary
|
||||
|
||||
BAT-014 implements dcy-011 Phase 7 by narrowing the remaining adapter surfaces without changing public MCP tool names or dashboard behavior. The MCP server now depends on `adapters/mcp/tool_contracts.py` instead of a broad direct `service` import, and the Streamlit dashboard now calls page/domain gateways under `adapters/streamlit/*_gateway.py` rather than a flat broad `service_gateway` namespace. `service_gateway.py` remains as a compatibility aggregator.
|
||||
|
||||
## Delivered changes
|
||||
|
||||
1. Added `jarca_ledger_mcp/adapters/mcp/tool_contracts.py` as the MCP adapter contract surface and repointed `adapters/mcp/server.py` wrappers to `contracts.*` callables.
|
||||
2. Added page/domain Streamlit gateways:
|
||||
- `overview_gateway.py`
|
||||
- `assets_gateway.py`
|
||||
- `transactions_gateway.py`
|
||||
- `categorization_gateway.py`
|
||||
- `transfers_gateway.py`
|
||||
- `imports_gateway.py`
|
||||
- `accounts_gateway.py`
|
||||
- `reconciliation_gateway.py`
|
||||
3. Reworked `adapters/streamlit/service_gateway.py` into a compatibility aggregator over the new gateway modules.
|
||||
4. Repointed `dashboard/app.py` static call sites away from `service.*` to the owning page/domain gateway modules.
|
||||
5. Preserved hot-reload fallback by changing `get_service_callable()` to reload the passed gateway module rather than a broad flat service namespace.
|
||||
6. Refreshed `docs/project-structure.md` and `docs/runtime-flows.md` so the baseline reflects post-Phase-7 ownership and adapter seams.
|
||||
|
||||
## Compatibility notes
|
||||
|
||||
- MCP tool names, argument shapes, and response contracts were intentionally preserved.
|
||||
- `adapters/streamlit/service_gateway.py` still exists as a compatibility surface for any legacy dashboard-side imports.
|
||||
- No SQL/UI business-rule ownership was moved into the dashboard; the app still goes through adapter gateways.
|
||||
|
||||
## Files changed
|
||||
|
||||
- `jarca_ledger_mcp/adapters/mcp/tool_contracts.py`
|
||||
- `jarca_ledger_mcp/adapters/mcp/server.py`
|
||||
- `jarca_ledger_mcp/adapters/streamlit/__init__.py`
|
||||
- `jarca_ledger_mcp/adapters/streamlit/service_gateway.py`
|
||||
- `jarca_ledger_mcp/adapters/streamlit/*_gateway.py`
|
||||
- `dashboard/app.py`
|
||||
- `docs/project-structure.md`
|
||||
- `docs/runtime-flows.md`
|
||||
|
||||
## Outcome
|
||||
|
||||
The repository now has explicit MCP contract and Streamlit page/domain gateway seams, satisfying the final dcy-011 narrowing target while preserving all public compatibility surfaces.
|
||||
@@ -1,12 +0,0 @@
|
||||
# BAT-014 Adapter narrowing and baseline refresh
|
||||
|
||||
- Profile: standard
|
||||
- Status: release-candidate
|
||||
- Included REQ: REQ-018
|
||||
- Discovery: dcy-011
|
||||
- Owner: 렛저장인
|
||||
- Date (KST): 2026-07-03
|
||||
|
||||
## 목표
|
||||
|
||||
REQ-018에 따라 MCP/Streamlit adapter surfaces를 더 좁히고 baseline 문서를 갱신해 dcy-011을 완료한다.
|
||||
@@ -1,12 +0,0 @@
|
||||
# BAT-014 Planning
|
||||
|
||||
## Scope
|
||||
- Implement REQ-018 adapter narrowing.
|
||||
- Preserve MCP/tool/dashboard contracts while shifting adapter imports to helper/page gateways.
|
||||
- Refresh structure/runtime baselines and finalize dcy-011 metadata.
|
||||
|
||||
## Work plan
|
||||
1. Add MCP contract helper module and repoint `adapters/mcp/server.py` to it.
|
||||
2. Add Streamlit page/domain gateway modules and repoint `dashboard/app.py` away from a flat broad gateway dependency.
|
||||
3. Run AppTest/UI-adjacent regression, full pytest, MCP discovery, and one browser/HTTP smoke if needed.
|
||||
4. Refresh `docs/project-structure.md`, `docs/runtime-flows.md`, and dcy-011 status.
|
||||
@@ -1,74 +0,0 @@
|
||||
# BAT-014 Verification
|
||||
|
||||
## Verification summary
|
||||
|
||||
Status: PASS
|
||||
|
||||
All required code-path checks for BAT-014 passed, and local browser-level screenshot/DOM evidence was successfully captured against a synthetic fixture DB. No production ledger DB, real financial statement files, passwords, or raw financial payloads were used.
|
||||
|
||||
## Acceptance criteria evidence
|
||||
|
||||
### AC-1. MCP contract/helper seam and Streamlit page/domain gateways exist
|
||||
- Evidence:
|
||||
- `jarca_ledger_mcp/adapters/mcp/tool_contracts.py` added and `adapters/mcp/server.py` now calls `contracts.*`.
|
||||
- `search_files('*_gateway.py')` under `adapters/streamlit` returned 9 gateway/aggregator files.
|
||||
|
||||
### AC-2. `dashboard/app.py` no longer uses a flat broad gateway surface
|
||||
- Evidence:
|
||||
- `search_files(pattern='service\\.', path='dashboard', file_glob='app.py')` returned 0 matches after rewiring.
|
||||
- Dynamic hot-reload lookup now targets passed gateway modules (`categorization_gateway`, `transfers_gateway`) instead of a flat `service` binding.
|
||||
|
||||
### AC-3. Regression, adapter verification, and browser smoke pass
|
||||
- `python3 -m py_compile jarca_ledger_mcp/adapters/mcp/*.py jarca_ledger_mcp/adapters/streamlit/*.py dashboard/app.py` → PASS
|
||||
- `pytest -q tests/test_dashboard_app.py` → PASS (`....`)
|
||||
- `pytest -q` → PASS (`........................ss...............ss...`)
|
||||
- `hermes mcp test jarca-ledger` → PASS, 56 tools discovered
|
||||
- `.venv/bin/python scripts/streamlit_browser_evidence.py` → PASS
|
||||
- Output dir: `docs/batches/bat-014_20260703_adapter-surface-narrowing-baseline-refresh/evidence/run-20260703-100358/`
|
||||
- Artifacts: `overview.png`, `rules.png`, `transfer-review.png`, `import.png` plus matching `*.dom.html` and `manifest.json`
|
||||
- Cleanup check: `search_files('chrome-profile-*')` under the run dir returned 0 results after the retry-cleanup fix
|
||||
|
||||
### AC-4. Baseline docs, discovery metadata, and BAT-local evidence tooling reflect completion
|
||||
- Evidence:
|
||||
- `docs/project-structure.md` updated with new owning services, parser seam, MCP contract helper, and Streamlit page/domain gateways.
|
||||
- `docs/runtime-flows.md` updated with import/parser seam, MCP contract routing, and dashboard gateway flow.
|
||||
- `docs/runbooks/streamlit-browser-evidence.md` now points at the BAT-014 evidence root and includes `요약` in the default capture set.
|
||||
- dcy-011 metadata and close-out notes updated to reference `REQ-015`~`REQ-018` / `BAT-011`~`BAT-014` completion.
|
||||
|
||||
## Browser evidence details
|
||||
|
||||
Evidence source: `docs/batches/bat-014_20260703_adapter-surface-narrowing-baseline-refresh/evidence/run-20260703-100358/manifest.json`
|
||||
|
||||
### Captured pages
|
||||
- `요약`
|
||||
- Screenshot: `overview.png`
|
||||
- DOM: `overview.dom.html`
|
||||
- Evidence text included `📊 요약`, `가계부 운영 대시보드`, and the synthetic fixture DB path under the BAT-014 evidence directory.
|
||||
- `분류 규칙`
|
||||
- Screenshot: `rules.png`
|
||||
- DOM: `rules.dom.html`
|
||||
- Evidence text included `⚙️ Rule Engine`, `분류 규칙`, and seeded default categorization rules.
|
||||
- `확인필요 큐`
|
||||
- Screenshot: `transfer-review.png`
|
||||
- DOM: `transfer-review.dom.html`
|
||||
- Evidence text included `🔁 Transfer Review`, `KB↔토스뱅크 확인필요 큐`, and a synthetic transfer-review row for `2026-06-29` / `SYNTHETIC_TRANSFER` / `120,000원` / `이체` / `확인필요`.
|
||||
- `Import`
|
||||
- Screenshot: `import.png`
|
||||
- DOM: `import.dom.html`
|
||||
- Evidence text included `📥 Statement Import`, Toss Securities import copy, and Toss Bank import copy.
|
||||
|
||||
### Automation script close-out
|
||||
- Script: `scripts/streamlit_browser_evidence.py`
|
||||
- Behavior:
|
||||
- Generates a synthetic fixture DB under the BAT-014 evidence run directory.
|
||||
- Starts Streamlit against that fixture DB only.
|
||||
- Uses local Chrome DevTools Protocol to capture screenshots and DOM snapshots.
|
||||
- Writes `manifest.json` with page/url/path/byte-size evidence.
|
||||
- Retries Chrome profile cleanup and leaves only the intended evidence artifacts in the final run directory.
|
||||
|
||||
## Safety boundary
|
||||
|
||||
- Synthetic/temp DBs only.
|
||||
- No destructive migration.
|
||||
- No production ledger DB mutation.
|
||||
- No real statement files, passwords, or raw payloads in screenshots, DOM snapshots, or manifest output.
|
||||