"""Hier-Decomp-1 코퍼스 격리 회귀 테스트 (committed).
in_corpus=false hier leaf 가 corpus_chunks 검색에 누출되지 않음을 단언.
부분 ivfflat(WHERE in_corpus=true) + corpus_chunks 뷰 choke point 이중 보장 검증.
실행: docker exec -w /app fastapi python tests/hier_decomp/test_corpus_isolation.py
"""
import asyncio, sys
sys.path.insert(0, "/app")
from sqlalchemy import text
from core.database import async_session
from ai.client import AIClient

MARKER = "ZQXJ7F3A 격리회귀 sentinel do-not-match-anything unique probe phrase"


async def main():
    cid = None
    try:
        emb = await AIClient().embed(MARKER)
        assert emb and len(emb) == 1024
        emb_str = "[" + ",".join(repr(float(x)) for x in emb) + "]"
        async with async_session() as s:
            doc_id = await s.scalar(text("SELECT id FROM documents WHERE deleted_at IS NULL ORDER BY id DESC LIMIT 1"))
            cid = await s.scalar(text("""
                INSERT INTO document_chunks
                  (doc_id, chunk_index, chunk_type, domain_category, text, embedding,
                   source_type, chunker_version, is_leaf, in_corpus, level, node_type)
                VALUES (:d, 999777, 'section_md', 'general', :t, cast(cast(:e AS text) AS vector),
                   'hier_section', 'hier-rule-v1', true, false, 4, 'leaf') RETURNING id"""),
                {"d": doc_id, "t": MARKER, "e": emb_str})
            await s.commit()
            corpus = [r.cid for r in (await s.execute(text(
                "SELECT c.id cid FROM corpus_chunks c WHERE c.embedding IS NOT NULL "
                "ORDER BY c.embedding <=> cast(:e AS vector) LIMIT 5"), {"e": emb_str})).all()]
            raw = [r.cid for r in (await s.execute(text(
                "SELECT c.id cid FROM document_chunks c WHERE c.embedding IS NOT NULL "
                "ORDER BY c.embedding <=> cast(:e AS vector) LIMIT 5"), {"e": emb_str})).all()]
        leaked = cid in corpus
        in_raw = cid in raw
        print(f"corpus_chunks top5={corpus}")
        print(f"document_chunks top5={raw}")
        assert not leaked, f"LEAK: synthetic {cid} in corpus_chunks!"
        print(f"PASS — in_corpus=false leaf {cid} corpus 누출 0 (raw 검출={in_raw})")
        return 0
    finally:
        if cid:
            async with async_session() as s:
                await s.execute(text("DELETE FROM document_chunks WHERE id=:i"), {"i": cid})
                await s.commit()


sys.exit(asyncio.run(main()))
