# BAT-017 Implementation Evidence - Status: implemented-awaiting-qc - Created At (KST): 2026-07-08 11:33 KST - Last Updated (KST): 2026-07-09T13:16:10+09:00 ## Implementation Summary ### Slice 01 — provenance foundation, import preview/write sanitization - Added a shared provenance policy module for source-hash labeling, allowlisted raw-payload JSON serialization, and CSV preview column filtering. - Stopped new import preview/import write paths from exposing or persisting full local source paths for: - KB Bank PDF - Toss Bank PDF - Toss Securities PDF - SeoulPay XLSX - CSV preview - Changed `import_batches.filename` new writes to `masked-basename#source_hash_prefix`. - Minimized `transactions.raw_payload` for current supported import sources through explicit allowlists. - Added targeted regression tests for path redaction and forbidden-field non-leak assertions. ## Changed Files - `jarca_ledger_mcp/application/imports_service.py` - `jarca_ledger_mcp/kb_bank_pdf.py` - `jarca_ledger_mcp/seoulpay_xlsx.py` - `jarca_ledger_mcp/toss_bank_pdf.py` - `jarca_ledger_mcp/toss_securities_pdf.py` - `jarca_ledger_mcp/provenance_policy.py` - `tests/test_import_provenance_policy.py` ## Execution Evidence - `python -m pytest -q tests/test_import_provenance_policy.py` - result: pass (`.....`) - `python -m ruff check jarca_ledger_mcp/application/imports_service.py jarca_ledger_mcp/kb_bank_pdf.py jarca_ledger_mcp/seoulpay_xlsx.py jarca_ledger_mcp/toss_bank_pdf.py jarca_ledger_mcp/toss_securities_pdf.py jarca_ledger_mcp/provenance_policy.py tests/test_import_provenance_policy.py` - result: pass (`All checks passed!`) - `pytest -q tests/test_import_provenance_policy.py tests/test_kb_bank_pdf.py tests/test_seoulpay_xlsx.py tests/test_toss_securities_pdf.py` - result: pass via `dev-impl` - `pytest -q tests/test_kb_bank_pdf.py tests/test_seoulpay_xlsx.py tests/test_toss_securities_pdf.py tests/test_service.py` - result: pass via `dev-impl` - `pytest -q tests/test_import_provenance_policy.py tests/test_kb_bank_pdf.py tests/test_seoulpay_xlsx.py tests/test_toss_securities_pdf.py tests/test_service.py` - result: pass via `dev-impl` - `pytest -q` - result: pass via `dev-impl` ## Evidence Notes - Targeted regression confirms preview responses no longer emit full absolute paths. - CSV preview regression confirms arbitrary raw columns such as `secret_note` and `local_path` are suppressed by default. - Import persistence regression confirms `import_batches.filename` stores masked basename plus source-hash prefix rather than full paths. - Import persistence regression confirms `transactions.raw_payload` stores only the source-specific allowlisted minimum fields for the implemented sources. ## Residual Risks / Follow-up - Slice 01 does not yet complete the MCP provenance exposure contract (`minimal` / `operator-summary` / `debug-gated`). - Import/read surfaces beyond the new-write preview/import boundary still need review for finance-agent privacy alignment. - Baseline docs still need BAT-017-specific updates once the exposure contract and final runtime boundary are settled. - Existing operating DB sanitization remains intentionally out of scope and must stay in the separate follow-up Todo. ## Notes - Implementation must not use Kanban unless the user explicitly re-allows it. ### Slice 02A — provenance exposure helper + tests - Added explicit provenance exposure constants and helper APIs in `jarca_ledger_mcp/provenance_policy.py` for `minimal`, `operator-summary`, and `debug-gated`. - Added sanitizer behavior that keeps normalized provenance fields while suppressing full paths, raw document/raw text dumps, passwords, tokens, secrets, and non-allowlisted raw payload keys. - Added alias helpers `sanitize_provenance_envelope(...)` and `sanitize_provenance_for_exposure(...)` for bounded downstream adoption. - Added helper-level regression coverage in `tests/test_import_provenance_policy.py` for exposure-level behavior and forbidden-field suppression. ## Additional Changed Files (Slice 02A) - `jarca_ledger_mcp/provenance_policy.py` - `tests/test_import_provenance_policy.py` ## Additional Execution Evidence (Slice 02A) - Supervised impl child result - artifact: `.stagepilot/worker-supervision/impl-20260709T030219Z/final-result.json` - result: `done` (`child_exit_code=0`) - `python -m pytest -q tests/test_import_provenance_policy.py` - result: pass (`7 passed`) - `python -m py_compile jarca_ledger_mcp/provenance_policy.py tests/test_import_provenance_policy.py` - result: pass - `python -m ruff check jarca_ledger_mcp/provenance_policy.py tests/test_import_provenance_policy.py` - result: initially blocked in runner environment (`No module named ruff` from current Python) - Lead follow-up verification after environment check: - `. .venv/bin/activate && python -m ruff check jarca_ledger_mcp/provenance_policy.py tests/test_import_provenance_policy.py` - result: pass (`All checks passed!`) - `. .venv/bin/activate && python -m pytest -q tests/test_import_provenance_policy.py` - result: pass (`7 passed`) - `. .venv/bin/activate && python -m py_compile jarca_ledger_mcp/provenance_policy.py tests/test_import_provenance_policy.py` - result: pass - `. .venv/bin/activate && python -m ruff check .` - result: pass (`All checks passed!`) - `. .venv/bin/activate && python -m pytest -q` - result: pass (`55 passed, 4 skipped`) ## Slice 02B — import batch read-surface wiring + baseline docs - Wired `list_ledger_import_batches(...)` through the BAT-017 provenance sanitizer so default responses now return `minimal` provenance and scrub the raw `memo` field from user-facing payloads. - Added bounded operator-summary support for import batch listing so masked filename, source-hash prefix, sheet reference, and validation summary are available only when explicitly requested. - Added MCP adapter pass-through for `provenance_exposure` on `list_ledger_import_batches(...)`. - Added explicit `debug_provenance_gate=True` enforcement before `debug-gated` provenance can be requested from the import batch listing surface. - Extended provenance regression coverage for: - default/minimal import batch responses - explicit operator-summary import batch responses - debug-gated access denial without the explicit gate and allow-path with the gate - MCP adapter pass-through of the exposure level - Updated baseline docs (`docs/data-model.md`, `docs/project-structure.md`, `docs/runtime-flows.md`) to record the provenance envelope boundary, `raw_payload=minimize`, masked filename policy, and read-time exposure split. ## Additional Changed Files (Slice 02B) - `docs/data-model.md` - `docs/project-structure.md` - `docs/runtime-flows.md` - `jarca_ledger_mcp/adapters/mcp/server.py` - `jarca_ledger_mcp/application/imports_service.py` - `tests/test_import_provenance_policy.py` ## Additional Execution Evidence (Slice 02B) - `. .venv/bin/activate && python -m ruff check jarca_ledger_mcp/application/imports_service.py jarca_ledger_mcp/adapters/mcp/server.py tests/test_import_provenance_policy.py` - result: pass (`All checks passed!`) - `. .venv/bin/activate && python -m pytest -q tests/test_import_provenance_policy.py` - result: pass (`11 passed`) - `. .venv/bin/activate && python -m ruff check .` - result: pass (`All checks passed!`) - `. .venv/bin/activate && python -m pytest -q` - result: pass (`59 passed, 4 skipped`) ## Updated Residual Risks / Follow-up - Independent QC, PR creation/push, GitHub CI, and post-merge `confirm-req-implemented` remain pending. - StagePilot doctor entrypoint is not present in the current workspace/runtime; this should be classified during QC as environment/tooling debt unless the lead requires a separate setup action before closure.