회기 무발화 0턴 분리, 자기예측 락 불변식 및 TDD 회귀 검증 완료
Some checks failed
API contract / OpenAPI type drift (push) Failing after 3m27s

This commit is contained in:
Yun Chan 2026-09-08 23:28:06 +09:00
parent a479db7a5a
commit a0311c5957
100 changed files with 4884 additions and 11210 deletions

View file

@ -8,7 +8,7 @@ import unittest
from unittest.mock import patch
from .deps import Principal, Role
from . import session_persistence
from . import session_evaluation_repository, session_persistence
from .routes import sessions
from .services import evaluator, guardrail, session_metrics
from .services import persona as persona_service
@ -256,7 +256,7 @@ class EvaluationPersistenceMappingTest(unittest.IsolatedAsyncioTestCase):
turns_evaluated=2,
)
write = session_persistence.SessionEvaluationWrite.from_result(
write = session_evaluation_repository.SessionEvaluationWrite.from_result(
session_id="session-1",
learner_id="learner-1",
result=result,
@ -306,7 +306,7 @@ class EvaluationPersistenceMappingTest(unittest.IsolatedAsyncioTestCase):
error="보라별 평가 경고",
)
write = session_persistence.SessionEvaluationWrite.from_result(
write = session_evaluation_repository.SessionEvaluationWrite.from_result(
session_id="session-privacy",
learner_id="learner-privacy",
result=result,
@ -330,7 +330,7 @@ class EvaluationPersistenceMappingTest(unittest.IsolatedAsyncioTestCase):
supervisor_rationale="윤찬과 서연의 상호작용을 확인했다.",
)
write = session_persistence.SessionEvaluationWrite.from_result(
write = session_evaluation_repository.SessionEvaluationWrite.from_result(
session_id="session-role-privacy",
learner_id="learner-role-privacy",
result=result,
@ -345,7 +345,7 @@ class EvaluationPersistenceMappingTest(unittest.IsolatedAsyncioTestCase):
self.assertIn("[CLIENT]", blob)
def test_session_evaluation_write_from_error_preserves_fallback_shape(self) -> None:
write = session_persistence.SessionEvaluationWrite.from_error(
write = session_evaluation_repository.SessionEvaluationWrite.from_error(
session_id="session-1",
learner_id="learner-1",
scope="session_end",
@ -361,7 +361,7 @@ class EvaluationPersistenceMappingTest(unittest.IsolatedAsyncioTestCase):
self.assertEqual(write.error, "engine timeout")
def test_session_evaluation_write_from_error_names_empty_exception(self) -> None:
write = session_persistence.SessionEvaluationWrite.from_error(
write = session_evaluation_repository.SessionEvaluationWrite.from_error(
session_id="session-1",
learner_id="learner-1",
scope="session_end",
@ -381,7 +381,7 @@ class EvaluationPersistenceMappingTest(unittest.IsolatedAsyncioTestCase):
guardrail.set_ko_pii_recognizer(FakeKoRecognizer())
self.addCleanup(guardrail.set_ko_pii_recognizer, None)
write = session_persistence.SessionEvaluationWrite.from_error(
write = session_evaluation_repository.SessionEvaluationWrite.from_error(
session_id="session-1",
learner_id="learner-1",
scope="session_end",
@ -405,7 +405,7 @@ class EvaluationPersistenceMappingTest(unittest.IsolatedAsyncioTestCase):
guardrail.set_ko_pii_recognizer(FakeKoRecognizer())
self.addCleanup(guardrail.set_ko_pii_recognizer, None)
conn = FakeEvaluationConn()
write = session_persistence.SessionEvaluationWrite(
write = session_evaluation_repository.SessionEvaluationWrite(
session_id="11111111-1111-1111-1111-111111111111",
learner_id="22222222-2222-2222-2222-222222222222",
status="ready",
@ -417,10 +417,10 @@ class EvaluationPersistenceMappingTest(unittest.IsolatedAsyncioTestCase):
)
with (
patch.object(session_persistence, "get_pool", return_value=object()),
patch.object(session_persistence, "acquire", return_value=FakeAcquire(conn)),
patch.object(session_evaluation_repository, "get_pool", return_value=object()),
patch.object(session_evaluation_repository, "acquire", return_value=FakeAcquire(conn)),
):
saved = await session_persistence.save_session_evaluation(write)
saved = await session_evaluation_repository.save_session_evaluation(write)
self.assertTrue(saved)
_, args = conn.executed[0]
@ -439,20 +439,20 @@ class EvaluationPersistenceMappingTest(unittest.IsolatedAsyncioTestCase):
error = {"status": "error", "error": "late timeout"}
self.assertFalse(
session_persistence._should_replace_evaluation_record(ready, error)
session_evaluation_repository._should_replace_evaluation_record(ready, error)
)
self.assertTrue(
session_persistence._should_replace_evaluation_record(error, ready)
session_evaluation_repository._should_replace_evaluation_record(error, ready)
)
self.assertTrue(
session_persistence._should_replace_evaluation_record(ready, ready)
session_evaluation_repository._should_replace_evaluation_record(ready, ready)
)
async def test_fallback_cache_keeps_ready_result_when_late_error_arrives(self) -> None:
session_id = "11111111-1111-1111-1111-111111111111"
session_persistence._EVALUATION_CACHE[session_id] = {"status": "ready"}
self.addCleanup(session_persistence._EVALUATION_CACHE.pop, session_id, None)
write = session_persistence.SessionEvaluationWrite.from_error(
session_evaluation_repository._EVALUATION_CACHE[session_id] = {"status": "ready"}
self.addCleanup(session_evaluation_repository._EVALUATION_CACHE.pop, session_id, None)
write = session_evaluation_repository.SessionEvaluationWrite.from_error(
session_id=session_id,
learner_id="22222222-2222-2222-2222-222222222222",
scope="session_end",
@ -461,14 +461,14 @@ class EvaluationPersistenceMappingTest(unittest.IsolatedAsyncioTestCase):
)
with (
patch.object(session_persistence, "runtime_fallback_allowed", return_value=True),
patch.object(session_persistence, "get_pool", side_effect=RuntimeError("offline")),
patch.object(session_persistence, "require_runtime_fallback_allowed"),
patch.object(session_evaluation_repository, "runtime_fallback_allowed", return_value=True),
patch.object(session_evaluation_repository, "get_pool", side_effect=RuntimeError("offline")),
patch.object(session_evaluation_repository, "require_runtime_fallback_allowed"),
):
saved = await session_persistence.save_session_evaluation(write)
saved = await session_evaluation_repository.save_session_evaluation(write)
self.assertFalse(saved)
self.assertEqual(session_persistence._EVALUATION_CACHE[session_id]["status"], "ready")
self.assertEqual(session_evaluation_repository._EVALUATION_CACHE[session_id]["status"], "ready")
def test_rebuild_turn_evaluation_restores_review_shape(self) -> None:
rebuilt = session_persistence._rebuild_turn_evaluations(