vignette/apps/api/app/test_review_summary_josa.py
Yun Chan 4511383cd9 전수 E2E 순회·소유자 결정 6건 구현·디자인 감사 반영
- 전수 순회: IA 전 라우트 412개 기능 인벤토리를 체크리스트 백로그로 관리
  (docs/ops/e2e-full-sweep-2026-07-27.md), 신규 full-sweep 스펙 10파일 추가.
  RED→GREEN으로 결함 12건 수정: 관리자 무한 렌더 프리즈(TanStack autoReset
  루프), 복수 코호트 저장 유실, 페르소나 보관 503(SQL 컬럼 모호성), PII 과잉
  마스킹, /admin/ai watchdog 오탐 오버레이, 모바일 겹침 2건, 설정 스크롤
  스파이, 온보딩 전화번호 무검증, 리뷰 조사·난도 라벨, pending 피드백 등.
- 소유자 결정 구현: 설정 아바타 변경, 동의 철회·재동의 전체 흐름, 신규
  학습자 기초 우선 추천, 학생 분석 테이블 가상화(@tanstack/react-virtual),
  저작 모드 죽은 레일 정리, 감정 밸런스 타임라인 차트(deep turn_valence +
  결정론 파생 폴백).
- 디자인 감사(142차): 라이트 팔레트 AA 대비, 다크 토큰 별칭 통일, 미정의
  CSS 변수 정리, 한글 keep-all 전역화, 탭 타깃 24px, LCP preconnect.
- 검증: npm run e2e 병렬 432 수집 GREEN + 직렬 49/49 exit 0, 백엔드 pytest
  421, gateway 29, typecheck/build/design-ssot/dead-code/중복 게이트 통과,
  layout-visual-gate 15/15, session-layout 8/8. 상세는 SSOT 대시보드
  142~144차 노트.
2026-07-27 14:25:24 +09:00

50 lines
2 KiB
Python

"""리뷰 요약 문장의 한국어 조사(와/과) 선택 회귀 테스트.
2026-07-27 전수 순회에서 발견: 받침 있는 내담자 이름(하늘) 뒤에도 "와의"
붙어 "하늘와의 회기는"으로 표기됐다. 마지막 글자 받침 유무에 따라 와/과를
골라야 한다.
"""
from __future__ import annotations
import unittest
from .session_read_model import ReviewTurn, _review_summary
def _turns() -> list[ReviewTurn]:
return [
ReviewTurn(id="t1", ts="0:00", speaker="learner", who="", text="안녕하세요."),
ReviewTurn(id="t2", ts="0:01", speaker="client", who="하늘", text="...네."),
]
class ReviewPersonaLabelTest(unittest.TestCase):
def test_difficulty_is_localized_to_korean(self) -> None:
from .session_read_model import _persona_label
self.assertEqual(_persona_label("P4", "easy"), "P4 · 기초")
self.assertEqual(_persona_label("P2", "moderate"), "P2 · 중간")
self.assertEqual(_persona_label("P1", "hard"), "P1 · 고난도")
# 알 수 없는 값은 원문 유지(빈 라벨로 숨기지 않는다)
self.assertEqual(_persona_label("P9", "custom"), "P9 · custom")
class ReviewSummaryJosaTest(unittest.TestCase):
def test_name_with_final_consonant_uses_gwa(self) -> None:
summary = _review_summary(client_name="하늘", reached_phase="라포", turns=_turns())
self.assertIn("하늘과의 회기는", summary)
self.assertNotIn("하늘와의", summary)
def test_name_without_final_consonant_uses_wa(self) -> None:
summary = _review_summary(client_name="지우", reached_phase="라포", turns=_turns())
self.assertIn("지우와의 회기는", summary)
self.assertNotIn("지우과의", summary)
def test_non_hangul_tail_falls_back_to_gwa_slash_wa(self) -> None:
summary = _review_summary(client_name="P4", reached_phase="라포", turns=_turns())
self.assertIn("P4와(과)의 회기는", summary)
if __name__ == "__main__":
unittest.main()