Files
hyungi_document_server/tests/policy/test_envelope_contract.py
T
Hyungi Ahn 99672292d3 fix(policy): use container-compatible imports (drop app. prefix)
프로덕션 컨테이너는 /app 을 cwd 로 실행하고 import 는 `from api...`,
`from core...`, `from workers...` 처럼 무접두 스타일을 사용한다.
PR-A 내부 import 가 `from app.policy...`, `from app.ai.envelope` 로
되어 있어서 컨테이너에서 ModuleNotFoundError 발생.

변경:
- app/policy/*.py: `from app.policy.X` → `from policy.X`
- app/services/prompt_versions.py: lazy import 도 `from policy.prompt_render`
- app/ai/envelope.py: 영향 없음 (내부 import 없음)
- tests/policy/*.py: 모두 `from policy.X` / `from ai.envelope` 로 통일
- tests/policy/conftest.py: 로컬 pytest 용 sys.path.insert(app/) 추가
  (MacBook 에서 repo-root 기준 실행 시 app/ 를 package root 로 취급)

CI: pytest tests/policy/ -q → 98 passed (로컬, 동일 결과)
프로덕션: docker exec fastapi python -c "from policy.loader import load_policy" → OK

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 09:42:24 +09:00

88 lines
2.8 KiB
Python

"""EscalationEnvelope JSON round-trip + system injection 형식."""
from __future__ import annotations
import pytest
from ai.envelope import EscalationEnvelope
def test_envelope_round_trip():
env = EscalationEnvelope(
from_stage="summarize_short",
escalation_reasons=("long_context", "risk_flag_requires_26b"),
risk_flags=("safety_legal_interpretation", "multi_doc_dependency"),
distilled_context="법령 조문 인용 다수. 해석 판단 필요.",
original_pointers={"doc_ids": ["a", "b"], "paths": ["/p1"]},
synthesis_directives=("조문 원문 인용 필수.",),
user_intent="조문 적용 여부",
draft_hint="조문 인용 후 분리 기술",
)
s = env.to_json()
env2 = EscalationEnvelope.from_json(s)
assert env == env2
def test_envelope_system_injection_has_key_blocks():
env = EscalationEnvelope(
from_stage="ask_pre",
escalation_reasons=("high_impact",),
risk_flags=("chemical_hazard",),
distilled_context="MSDS 주요 성분 A, B 식별",
synthesis_directives=("MSDS 원문 인용 우선.",),
)
block = env.to_system_injection()
assert "ESCALATION ENVELOPE" in block
assert "chemical_hazard" in block
assert "high_impact" in block
assert "MSDS 원문 인용 우선" in block
def test_envelope_rejects_invalid_from_stage():
with pytest.raises(ValueError):
EscalationEnvelope(
from_stage="nonexistent_stage",
escalation_reasons=(),
risk_flags=(),
distilled_context="",
)
def test_envelope_requires_tuple_reasons():
with pytest.raises(TypeError):
EscalationEnvelope(
from_stage="triage",
escalation_reasons=["long_context"], # list, not tuple
risk_flags=(),
distilled_context="",
)
def test_envelope_requires_tuple_flags():
with pytest.raises(TypeError):
EscalationEnvelope(
from_stage="triage",
escalation_reasons=(),
risk_flags=["pii_present"], # list, not tuple
distilled_context="",
)
def test_envelope_frozen_equality():
"""frozen dataclass — 동일 필드면 == True."""
env_a = EscalationEnvelope(
from_stage="classify",
escalation_reasons=("long_context",),
risk_flags=("pii_present",),
distilled_context="same text",
)
env_b = EscalationEnvelope(
from_stage="classify",
escalation_reasons=("long_context",),
risk_flags=("pii_present",),
distilled_context="same text",
)
assert env_a == env_b
# 참고: original_pointers 가 dict 필드이므로 자동 __hash__ 는 지원되지 않음
# (envelope 은 JSON transport 용 — set/dict key 로 쓸 필요 없음)