feat: stabilize category rule operations

approve dcy-001 and add REQ/BAT evidence

pass selected DB path through Streamlit rule actions

expose delete_category_rule MCP tool

add category rule deletion regression
This commit is contained in:
Jarca
2026-06-27 00:02:06 +09:00
parent 97115f6acf
commit 0f881b245f
12 changed files with 459 additions and 5 deletions
@@ -0,0 +1,37 @@
# 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.
@@ -0,0 +1,35 @@
# 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) 증거를 사용했다.
@@ -0,0 +1,21 @@
# 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를 수행한다.
@@ -0,0 +1,47 @@
# 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
View File
@@ -8,3 +8,4 @@
| BAT ID | Profile | Status | Included REQ | Discovery | Folder |
| --- | --- | --- | --- | --- | --- |
| BAT-001 | batch-lite | release-candidate | REQ-001 | dcy-001 | [bat-001_20260626_category-rule-ops](bat-001_20260626_category-rule-ops/) |