chore(jarca-ledger): finalize approved batch docs, dashboard, and CI smoke updates

This commit is contained in:
Jarca
2026-06-30 16:06:47 +09:00
parent 67d8d4871b
commit 4929e52189
75 changed files with 8367 additions and 252 deletions
@@ -0,0 +1,64 @@
# 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.
@@ -0,0 +1,106 @@
# 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.
@@ -0,0 +1,32 @@
# 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 기록
@@ -0,0 +1,41 @@
# 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 이름을 안정화하고 문서에 후속 운영 설정으로 기록한다.
@@ -0,0 +1,154 @@
# 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.