import uuid import pytest from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.models.account import Account from app.models.flow_proposal import FlowProposal from app.models.l1_walk_session import L1WalkSession from app.models.user import User def test_flow_proposal_accepts_l1_session_id_without_source_session(): p = FlowProposal( account_id=uuid.uuid4(), l1_session_id=uuid.uuid4(), source_session_id=None, proposal_type="new_flow", title="AI L1 draft", proposed_flow_data={"tree_structure": {"id": "root"}}, source="ai_realtime_l1", status="pending", ) assert p.l1_session_id is not None and p.source_session_id is None @pytest.mark.asyncio async def test_deleting_l1_session_cascades_proposal_not_check_violation(test_db: AsyncSession): """Finding 6: an L1-sourced proposal has source_session_id NULL by the exactly-one CHECK. With ondelete=CASCADE the proposal dies with its session; the old SET NULL would have NULLed both columns and aborted the DELETE on the CHECK (time bomb).""" s = str(uuid.uuid4())[:8] account = Account(id=uuid.uuid4(), name=f"Acct {s}", display_code=s.upper()) test_db.add(account) await test_db.flush() user = User( id=uuid.uuid4(), email=f"u-{uuid.uuid4()}@example.com", name="U", account_id=account.id, account_role="l1_tech", role="engineer", is_active=True, ) test_db.add(user) await test_db.flush() session = L1WalkSession( account_id=account.id, created_by_user_id=user.id, ticket_id="t-cascade", ticket_kind="internal", session_kind="ai_build", ) test_db.add(session) await test_db.flush() proposal = FlowProposal( account_id=account.id, l1_session_id=session.id, source_session_id=None, proposal_type="new_flow", title="AI L1 draft", proposed_flow_data={"tree_structure": {"id": "root"}}, source="ai_realtime_l1", status="pending", ) test_db.add(proposal) await test_db.flush() pid = proposal.id # Delete the session — must succeed and cascade to the proposal. await test_db.delete(session) await test_db.flush() remaining = (await test_db.execute( select(FlowProposal).where(FlowProposal.id == pid) )).scalar_one_or_none() assert remaining is None