dot-iu-cutter v0.4 — RealPostgresAdapter Transaction Lifecycle Fix Completion Report (2026-05-17)
dot-iu-cutter v0.4 — RealPostgresAdapter Transaction Lifecycle Fix — Completion Report
Date: 2026-05-17 · Phase: bounded code-authoring — fix the RealPostgresAdapter transaction/pool defect that the PG-backed dry-run found at S4. Code SSOT = VPS /opt/incomex/dot. No PG-backed dry-run rerun, no production connection/secret/CUT/VERIFY, no deploy, no schema/index/JSONB/vector work.
1. Defect (from the dry-run FAIL) & fix
phases.py calls adapter.find() outside a transaction before with adapter.transaction(). The accepted RealPostgresAdapter.find() ran that SELECT on a pooled connection with autocommit=False and returned it to _ConnPool without commit/rollback, leaving an open implicit transaction; the next phase _begin then could not issue SET TRANSACTION ISOLATION LEVEL as the first statement (psycopg3 25001). Latent because the unit suite's FakeConn did not model that rule.
Fix (db_adapter.py only):
find()out-of-transaction (owns == False) —finallynowconn.rollback()(clears the implicit read txn and any failed txn) then releases to the pool; if rollback itself fails the connection isdiscard()-ed. In-phase reads (owns == True) are untouched (the phase owns its single atomic txn)._begin()defensive clean —conn.rollback()(a method call, not a query, soSET TRANSACTION ISOLATION LEVELremains the first executed statement) beforeSET; if the SET /SELECT current_user/ identity check fails, the connection is rolled back anddiscard()-ed andself._conncleared before propagating (never leaves a dirty connection in the pool).- No global autocommit change; one-atomic-transaction-per-phase, principal routing, and the no
DELETE/TRUNCATE/DDL/GRANTruntime surface all preserved.
2. Fix-requirement compliance
| Req | Status |
|---|---|
| 1 out-of-txn find() must not leave pooled conn in open txn | ✅ rollback before release |
| 2 begin can SET ISOLATION as first statement | ✅ defensive rollback() (method) precedes SET; regression-tested |
| 3 pooled conn returns clean | ✅ find() + _begin both clean/discard |
| 4 query exception rolls back before pool return | ✅ find() finally rollback (discard on rollback failure); _begin failure path rolls back+discards |
| 5 no global autocommit change | ✅ autocommit=False unchanged; only per-conn rollback added |
| 6 one atomic txn per phase | ✅ in-phase find() (owns) untouched; defensive rollback is pre-first-statement |
| 7 principal routing preserved | ✅ unchanged |
| 8 no DELETE/TRUNCATE/DDL/GRANT surface | ✅ none added (rollback/commit are txn control, not data DDL) |
| 9 no hardcoded DSN/password/IP/container | ✅ none introduced (see §4) |
| 10 no production connection/secret in tests | ✅ injected FakeConn/fixture env only; no psycopg3 needed |
3. Tests
- Enhanced
FakeConn(tests/test_real_postgres_adapter.py) now models psycopg3: autocommit-off queries open an implicit txn;SET TRANSACTION ISOLATION LEVELraises SQLSTATE 25001 if a txn is already open; commit/rollback close it. - New
tests/test_pg_transaction_lifecycle.py(9 tests): fake models the 25001 rule; out-of-txnfind()thentransaction()does not fail;find()exception rolls back before pool return; pooled connection clean/reusable after out-of-txnfind(); transaction still sets requested isolation first; construction does not connect; fixture env is fake/no-DSN. - Command & result:
python3 -m unittest discover -s tests→Ran 110 tests … OKon VPS py3.12 (101 prior + 9 new; all existing pass).
4. No-hardcode static grep (honest)
grep -nE 'postgres://|PGPASSWORD|password=|<ipv4>|incomex-*|qdrant|collection_name' db_adapter.py → 3 hits, all pre-existing benign redaction code, none a literal secret/IP/container:
545: self._password = password(assignment into_Secretholder)569: f"… password=<redacted-secret>)"(the redacting repr)605: password = _Secret(_req(pwd_key))(wraps the env value in the redactor)
No IP / container / DSN / vector-collection literal matched. My edits added only rollback()/discard() calls and comments — zero literals. The accepted security regression test_no_secret_pattern_in_module_source (forbids PGPASSWORD / postgres://) passes within 110/110.
5. Git SSOT proof
- Branch:
main - Parent commit:
84c52c57aa296de921998910d85b0d4a85ad0746 - New commit:
6060e1ae8b958fcb8a61ed45b597dc553b8688be - Files changed (scoped, 3):
cutter_agent/db_adapter.py(M),tests/test_real_postgres_adapter.py(M),tests/test_pg_transaction_lifecycle.py(A) —3 files changed, 206 insertions(+), 8 deletions(-). No change to ledger.py/phases.py/schema_binding.py/state_machine.py/idempotency.py/signing.py/signal.py/cli.py (none needed → no STOP required). - Scoped add: explicit 3 paths; no
git add -A; no unrelated WIP. git status --short -- iu-cutter(excluding the throwaway dry-run WD): empty (clean).- Test command & result:
python3 -m unittest discover -s tests→Ran 110 tests … OK.
6. Limitations / next gate
- No PG-backed dry-run rerun performed (forbidden until this fix PASSes review).
- No production connection/secret/row write/CUT/VERIFY/deploy; no schema migration / index DDL / JSONB normalization / vector integration.
- The earlier honest-FAIL artefacts/logs remain under the throwaway WD (secrets shredded at that run's teardown); the DR env from the failed run was torn down exact-name; prod + 3 protected envs untouched.
Next gate: GPT review of commit 6060e1a + this report. On PASS, the PG-backed dry-run may be re-authorised (command-review r1 / verification-plan r3 unchanged; binding count-invariant). No self-advance.