# BAT-025 Implementation Log - Date: 2026-07-15 - Assignee: dev-impl - Scope: REQ-057 `portfolio_ledger` 수동 장부 메타데이터의 명시 Alembic migration - Implementation state: remediation complete; independent QC pending ## Baseline and remediation provenance - Initial implementation baseline: `f6195ff8090d8761d467e15f44255642ca350e80`. - The previously recorded SHA `850e970` does **not** identify the reviewed implementation and is superseded by the baseline above. - The remediation is committed locally as `779d6f7711d700d6f56be22023cb826cc6f2fe28` on the isolated worktree branch. No push, PR, main merge, production migration, deployment, or service activation was performed. ## Implemented changes 1. Explicit revision `20260715_0028` remains the REQ-057 head. - Parent: `20260628_0027`. - Adds `source`, `target_ledger_entry_id`, `confirmation_evidence`, and `actor_user_id` additively. - Handles runtime-precreated columns by backfilling nullable `source`, then converging its default and `NOT NULL` constraint. - Downgrade remains a forward-only no-op; no column deletion was added. 2. Remediation of actual PostgreSQL migration-chain/runtime behavior. - `migrations/versions/20260605_0025_ledger_consolidation.py`: makes the identity `ledger_entry_id` explicitly `nullable=False`. PostgreSQL identity columns are implicitly non-null; the prior explicit trailing `NULL` was incompatible with fresh real-PostgreSQL migration. - `app/db/migrations.py`: programmatic Alembic configuration now carries the caller-provided `Settings`. For a legacy/runtime-precreated schema, bootstrap stamps `20260628_0027` and then executes `upgrade head`, so revision `0028` performs its required source backfill/default/constraint convergence instead of being skipped by a direct head stamp. - `migrations/env.py`: consumes the explicit settings when supplied and preserves existing application loggers when Alembic runs in-process. 3. Real isolated PostgreSQL integration coverage. - `tests/test_bat025_portfolio_ledger_manual_metadata_migration.py` creates a UUID-named temporary database only through an explicitly supplied loopback `postgres` maintenance DSN. - The test rejects non-loopback hosts and any maintenance database other than `postgres`; each test terminates connections and drops only its own UUID-named database. - Coverage includes pre-0028 upgrade/data preservation, runtime-precreated nullable `source` convergence and Alembic current-head state, plus representative broker/manual ledger writes after upgrade. 4. Existing operation runbook is retained. - `docs/runbooks/bat-025-req057-portfolio-ledger-manual-metadata-runbook.md` - It remains a runbook only; no production command in it was executed. ## Executed evidence All commands below used the local Docker PostgreSQL service only. The DSN was supplied from an environment variable and is intentionally omitted here. - `BAT025_LOCAL_POSTGRES_DSN=[REDACTED local loopback maintenance DSN] PYTHONPATH=. uv run --extra dev --with httpx2 python -m pytest -q --override-ini addopts='' -p no:cacheprovider tests/test_bat025_portfolio_ledger_manual_metadata_migration.py` - Result: **3 passed in 6.10s**. - Verifies real 0027→0028 data preservation/source backfill, runtime-precreated compatibility/current revision, and broker/manual write regression in throwaway DBs. - `PYTHONPATH=. uv run --extra dev --with httpx2 python -m pytest -q --override-ini addopts='' -p no:cacheprovider` - Result: **597 passed, 11 warnings in 41.41s**. - Warnings are pre-existing Starlette `HTTP_422_UNPROCESSABLE_ENTITY` deprecations in endpoint tests; no test failed. - `uv run --extra dev ruff check app/db/migrations.py migrations/env.py migrations/versions/20260605_0025_ledger_consolidation.py tests/test_bat025_portfolio_ledger_manual_metadata_migration.py` - Result: **All checks passed**. - `python3 -m compileall -q app migrations` and `git diff --check` - Result: exit 0. ## Limits / non-claims - This evidence is for isolated local PostgreSQL only; it is not an operational DB upgrade. - Lock contention, backup restore, production access control, deployment, service activation, and M5 release remain unexecuted. - This log is developer evidence only. It does not mark BAT-025 verified or approved; independent QC remains required.