# BAT-025 Implementation Log - Date: 2026-07-15 - Assignee: dev-impl - Scope: REQ-057 portfolio_ledger 수동 장부 메타데이터 명시 Alembic migration ## Implemented Changes 1. Created new Alembic revision `20260715_0028` (`migrations/versions/20260715_0028_portfolio_ledger_manual_metadata.py`) - `down_revision`: `20260628_0027` - Added additive columns: - `source TEXT NOT NULL DEFAULT 'broker'` - `target_ledger_entry_id BIGINT NULL` - `confirmation_evidence TEXT NULL` - `actor_user_id TEXT NULL` - Added idempotent runtime compatibility logic: - If `portfolio_ledger` table missing: no-op - If column already exists: update `source IS NULL` → `'broker'`, enforce `NOT NULL` + `DEFAULT` - Add missing columns only when absent - `downgrade` is forward-only no-op 2. Added migration-focused tests `tests/test_bat025_portfolio_ledger_manual_metadata_migration.py` - Covers: - fresh schema add-all-columns behavior - precreated schema backfill + source constraint enforcement - missing table no-op - forward-only downgrade no-op 3. Added operational runbook - `docs/runbooks/bat-025-req057-portfolio-ledger-manual-metadata-runbook.md` ## Preflight Evidence - `uv run alembic heads` - output: `20260715_0028 (head)` - `uv run alembic history --verbose` - confirms `20260715_0028` parent is `20260628_0027` and it is the current tail of the migration chain. - `PYTHONPATH=. uv run pytest -q -o addopts='' tests/test_bat025_portfolio_ledger_manual_metadata_migration.py` - output: `4 passed in 0.24s` ## Evidence notes - Migration is idempotent by design: no-op if `portfolio_ledger` is missing, and for pre-created runtimes it backfills `source` and enforces `NOT NULL DEFAULT 'broker'`. - No DB upgrade was executed in this scope (code-only + evidence-only in repo). ## Commit - Commit SHA: `850e970`