"""Ledger-gap operational check tests (REQ-055 / dcy-011 FR-5, issue #11). PostgreSQL-gated (TREX_POSTGRESQL_TEST_DSN). Inserts closed slots + outbox rows directly and asserts find_ledger_gap_slots detects only the gaps. """ from __future__ import annotations import uuid from datetime import date from trex_core.adapters.persistence.ops_checks import find_ledger_gap_slots _DAY = date(2026, 6, 8) def _insert_slot(conn, *, status, portfolio_id, symbol="005930"): sid = str(uuid.uuid4()) with conn.cursor() as cur: cur.execute( "INSERT INTO daily_slot (slot_id, trading_date, status, symbol, portfolio_id) " "VALUES (%s, %s, %s, %s, %s)", (sid, _DAY, status, symbol, portfolio_id), ) return sid def _insert_outbox(conn, *, asset_id, order_id="O1", execution_id="E1"): with conn.cursor() as cur: cur.execute( "INSERT INTO ledger_outbox (correlation_id, asset_id, order_id, execution_id, " "side, qty, price) VALUES (%s, %s, %s, %s, 'buy', 1, 1000)", (f"{asset_id}:{order_id}:{execution_id}", asset_id, order_id, execution_id), ) def test_detects_only_gap_slots(pg_clean): import psycopg dsn = pg_clean with psycopg.connect(dsn, autocommit=True) as conn: gap_null = _insert_slot(conn, status="closed", portfolio_id=None) # gap (no pf) gap_no_outbox = _insert_slot(conn, status="closed", portfolio_id="PF-GAP") # gap (no outbox row) ok = _insert_slot(conn, status="closed", portfolio_id="PF-OK") # not a gap _insert_outbox(conn, asset_id="PF-OK") _insert_slot(conn, status="holding", portfolio_id=None) # not closed → ignored gaps = find_ledger_gap_slots(dsn, trading_date=_DAY) gap_ids = {str(g["slot_id"]) for g in gaps} assert gap_null in gap_ids assert gap_no_outbox in gap_ids assert ok not in gap_ids def test_no_gaps_when_all_recorded(pg_clean): import psycopg dsn = pg_clean with psycopg.connect(dsn, autocommit=True) as conn: _insert_slot(conn, status="closed", portfolio_id="PF-1") _insert_outbox(conn, asset_id="PF-1") assert find_ledger_gap_slots(dsn, trading_date=_DAY) == []