SSOT 대시보드:
- 한신대 기술분석 PDF(19쪽) 정합성 분석 + 이번 세션 발견 섹션 추가
- 섹션 폴드아웃(접기)·상단 목차(드릴다운)·모두 펼치기/접기 — 내용 보존, 레이아웃만 정리
페르소나 반응 강화('저항·반응 조절' 핵심 차별):
- PersonaCard.triggers(역린) 필드 + CCD 핵심상처 파생 역린 블록
- L0에 무례·모욕·조롱 시 현실적 동맹 균열 반응 지침
버그·성능 수정(라이브/E2E로 포착):
- 게이트웨이 페르소나 격리: --append-system-prompt를 --system-prompt(교체)로 + --exclude-dynamic-system-prompt-sections (내담자 캐릭터 붕괴·개발맥락 누출 차단)
- RAG: 임베더 동기 로드(약 7-13초)를 _warm_rag_caches 백그라운드 warm으로(세션 생성 블로킹 회귀 수정)
- voice TTS RMS 데드힌트 제거, init_state OpennessParams 파라미터객체화
- 한국어 PII(날짜·금액·주소) 마스킹 보강
- 레이아웃 시각 게이트: 폼 컨트롤 값 스크롤 오탐 제외(7/7)
검증: 백엔드 84/84, E2E 42(데스크톱 27·모바일 11·아바타 4), 시각 게이트 7/7
73 lines
2.9 KiB
Python
73 lines
2.9 KiB
Python
"""Regression tests for the deterministic resistance engine."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import unittest
|
|
|
|
from .services import state_machine
|
|
from .services.persona import P1
|
|
|
|
|
|
EMPATHIC_UTTERANCES = [
|
|
"얼마나 힘들었는지 마음이 느껴져요. 어떤 순간이 제일 버거웠나요?",
|
|
"그런 마음을 꺼내는 것 자체가 쉽지 않았을 것 같아요. 더 말해줘도 괜찮아요.",
|
|
"잠도 잘 못 자고 학교도 버거웠다면 하루가 길게 느껴졌겠어요.",
|
|
"지금은 해결책보다 그 마음을 천천히 이해하는 게 먼저인 것 같아요.",
|
|
"그 시간을 버텨온 마음을 함께 살펴보고 싶어요. 무엇부터 이야기해볼까요?",
|
|
]
|
|
|
|
ADVICE_JUMP_UTTERANCES = [
|
|
"그냥 학교는 가야 해요. 노력하면 하면 돼요. 왜 안 하죠?",
|
|
"그건 잘못 생각하는 거예요. 원래 다 힘들어요.",
|
|
"당연히 엄마 말을 들어야죠. 하지 마세요.",
|
|
"내 생각엔 그냥 계획표를 만들면 돼요.",
|
|
"그러니까 더 노력해야 해요. 왜 안 바꾸나요?",
|
|
]
|
|
|
|
|
|
def _initial_p1_state() -> state_machine.SessionState:
|
|
return state_machine.init_state(
|
|
params=P1.openness_params(),
|
|
)
|
|
|
|
|
|
def _run_curve(utterances: list[str]) -> list[state_machine.SessionState]:
|
|
state = _initial_p1_state()
|
|
curve: list[state_machine.SessionState] = []
|
|
for utterance in utterances:
|
|
signal = state_machine.estimate_rapport_signal(utterance)
|
|
state = state_machine.evolve(
|
|
state,
|
|
rapport_signal=signal,
|
|
unlock_rate=P1.unlock_rate(),
|
|
decay_floor=P1.decay_floor(),
|
|
)
|
|
curve.append(state)
|
|
return curve
|
|
|
|
|
|
class ResistanceEngineTest(unittest.TestCase):
|
|
def test_empathy_opens_p1_while_advice_jump_closes_it(self) -> None:
|
|
empathy_curve = _run_curve(EMPATHIC_UTTERANCES)
|
|
advice_curve = _run_curve(ADVICE_JUMP_UTTERANCES)
|
|
empathy_final = empathy_curve[-1]
|
|
advice_final = advice_curve[-1]
|
|
|
|
self.assertGreater(empathy_final.rapport_credit, advice_final.rapport_credit)
|
|
self.assertLess(empathy_final.resistance, advice_final.resistance)
|
|
self.assertGreater(empathy_final.effective_openness, advice_final.effective_openness)
|
|
self.assertEqual(empathy_final.stage, state_machine.Stage.EXPLORE)
|
|
self.assertEqual(advice_final.stage, state_machine.Stage.RAPPORT)
|
|
self.assertGreater(empathy_final.effective_openness, 0.1)
|
|
self.assertEqual(advice_final.effective_openness, 0.0)
|
|
|
|
def test_advice_jump_never_advances_stage_after_five_turns(self) -> None:
|
|
advice_curve = _run_curve(ADVICE_JUMP_UTTERANCES)
|
|
|
|
self.assertTrue(all(state.stage is state_machine.Stage.RAPPORT for state in advice_curve))
|
|
self.assertTrue(all(state.rapport_credit == 0 for state in advice_curve))
|
|
self.assertGreaterEqual(advice_curve[-1].resistance, 0.95)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|