vignette/docs/ops/hanshin-feedback-improvement-plan-2026-07-03.md
2026-07-03 19:53:14 +09:00

318 lines
25 KiB
Markdown

# 한신대 실사용 피드백 개선 계획
작성일: 2026-07-03
상태: 1차 구현 완료 / 레드팀·대레드팀 반영
근거 자료: 한신대 실사용 오류분석 DOCX/HWP, 저장소 정적 조사, 서브에이전트 4축 조사, 레드팀 2축 적대 검토, 대레드팀 2축 균형 검토
> 이 문서는 구현 계획이다. 현재 상태·검증 수치·로드맵 권위 기준은 `docs/dev_dashboard.html`이고, 열린 작업 인덱스는 `docs/TODO.md`가 소유한다.
## 1. 결론
한신대 자료에서 나온 문제는 단일 원인이 아니다. 가장 큰 축은 다음 네 가지다.
1. **대화 컨텍스트가 엔진 입력까지 안정적으로 전달되지 않는 구조**
2. **내담자 응답 출력 품질 게이트 부재**
3. **리뷰 화면에서 저장/AI용 마스킹·평가 오류 코드가 그대로 노출되는 UX 문제**
4. **교수자에게 설명해야 할 작동 원리와 남은 임상팀 게이트가 제품 안에서 충분히 드러나지 않는 문제**
구현 순서는 대화 컨텍스트 안정화가 먼저다. 다만 레드팀 검토 결과, 컨텍스트 보존은 단독 패치가 아니라 **role mapping 수정과 gateway history 소비 변경을 같은 패치에서 원자적으로 처리**해야 한다. 현재 매핑이 잘못된 상태에서 history만 보존하면 상담자 발화를 내담자 과거 발화처럼 먹이는 역효과가 난다.
표시 UX도 같은 원칙이다. `[NAME]`을 없애 보이게 만드는 것이 목표가 아니다. **API·저장값·평가 입력·export의 privacy proof는 마스킹 토큰을 유지**하고, 사람에게 보이는 UI 표시층만 별도로 부드럽게 만드는 것이 목표다.
대레드팀 검토 결과, 레드팀 경고는 유지하되 사용자 가치 기준으로 등급화한다. **P1 내부의 role mapping + history injection은 원자 패치**로 유지한다. 반면 **P2/P3/P4는 독립적으로 빠르게 배포 가능한 1차 개선**으로 분리한다. 안전 조건이 “최종형을 한 번에 닫는 것”으로 비대해지면 한신대 사용자가 당장 겪은 불편을 줄이는 본래 목적을 잃는다.
2026-07-03 1차 구현 결과:
- P1: `persona.build_turn_messages()` role mapping을 `counselor -> user`, `client -> assistant`로 수정하고, gateway는 `ai_role=client` 요청에만 `[직전 대화]` history를 주입한다. evaluator/structured 요청은 history를 받지 않는다.
- P2: 역할 메타발화, 반복 인사, 직전 내담자 near-duplicate를 저장 전 차단한다. generate는 1회 재생성 후 실패 시 client turn을 저장하지 않고 `client_reply_quality_retryable`로 반환한다. SSE stream은 응답 전체를 buffer한 뒤 품질 가드 통과 시에만 token을 방출한다.
- P3: 리뷰 일반 transcript 표시층만 `[NAME]`/`[ORG]` 등을 자연어화하고, quote/evidence/API/export 마스킹 증거는 유지한다. raw 평가 오류는 학습자/교수자 UI에서 재시도 가능 문구로 매핑한다. fast-loop 턴 노트와 deep-loop 요약 라벨을 구분하고 `clientFeedback` 라벨을 “마지막 내담자 반응”으로 바꿨다.
- P4: 교수자 리뷰 카드 안에 “AI 평가 범위” 패널을 추가해 현재 구현과 임상팀 확정 필요 범위를 분리했다.
- 검증: backend focused 84 passed, `npm run typecheck`, `npm run check:api-types`, session-review focused E2E 8 passed, `layout-visual-gate.spec.ts` 12 passed, `session-layout.spec.ts` 8 passed.
## 2. 안전 조건과 MVP 등급
레드팀 차단 조건은 사용자 가치 기준으로 등급화한다.
| 영역 | 등급 | 적용 |
|---|---|---|
| P1 컨텍스트 | 1차 하드 게이트 | `persona.build_turn_messages()` role mapping 수정과 gateway client-only history injection은 같은 패치로 처리한다. history 보존만 먼저 배포하지 않는다. |
| Gateway 계약 | 1차 하드 게이트 | `_split_messages()` 변경은 기존 테스트 계약 변경이다. 다만 P1 차단 테스트는 persona role mapping, gateway client-only history injection, evaluator no-history 계약으로 한정한다. |
| Evaluator 분리 | 1차 하드 게이트 | gateway history 직렬화는 `ai_role=client` 요청에만 적용한다. evaluator/deep-loop/structured output 요청은 client history를 받지 않는다. |
| Resident session | 2차 안정화 | 1차 구현은 stateless history injection으로 한정한다. resident session 재사용/prompt caching 복구는 client/eval namespace, cleanup, restart recovery 설계 뒤에만 켠다. |
| History window | 1차 단순 구현 + 2차 정교화 | 1차는 최근 대화를 라벨링해 주입하되, 가능하면 완성 turn pair를 우선한다. K-pair window 정교화는 P1 차단 조건이 아니라 2차 안정화다. |
| Quality fallback | 1차는 저장하지 않음 | 1차 품질 게이트는 fallback 저장을 목표로 하지 않는다. 재생성 후에도 역할 메타발화가 남으면 client turn을 저장하지 않고 재시도 가능한 오류로 표시한다. 저장형 fallback은 synthetic/fallback 메타데이터와 평가 제외 규칙이 준비된 뒤 도입한다. |
| Stream | 1차 안전 구현 완료 + 2차 UX 정교화 | SSE stream은 전체 응답을 buffer한 뒤 품질 가드 통과 시에만 token을 방출한다. 나쁜 출력은 token leak 없이 `client_reply_quality_retryable`로 끝낸다. 2차는 지연을 줄이는 안전한 부분 버퍼링/초기문장 정책이다. |
| Review privacy | 1차 하드 게이트 + UX 허용 | 마스킹 토큰 보존은 API·저장·export 계약이다. 리뷰 화면의 일반 transcript 표시는 동일 데이터를 렌더링 단계에서 자연어화할 수 있다. |
| Error copy | 1차 UX | DB/schema급 정비 전이라도 raw error를 학습자 UI에 직접 노출하지 않는 display mapper를 먼저 둔다. |
| fast-loop 라벨 | 1차 UX | “이 턴 직후 기준” 라벨은 완전한 reconciliation이 아니라 즉시 혼란을 줄이는 1차 개선이다. 후속 해명 반영 배지는 deep-loop 확장으로 분리한다. |
| 임상 설명 | 1차 신뢰 회복 | 교수자 설명은 “못 한다”가 아니라 현재 제품이 하는 것과 임상팀 확정이 필요한 것을 분리해 답한다. 확정되지 않은 진단·처방·루브릭 표현만 금지한다. |
| SSOT | 항상 유지 | 상태와 검증 수치는 `docs/dev_dashboard.html`만 소유하고, TODO/가이드/계획서는 링크와 요약만 둔다. |
## 3. 현상 정리
| 현상 | 분류 | 1차 판단 |
|---|---|---|
| 내담자가 같은 말을 2~3번 반복 | 대화 컨텍스트 / 출력 품질 | 최근 턴 보존과 중복 응답 게이트 필요 |
| 상담자가 질문했는데 내담자가 답하지 않고 다시 상담자 순서 | 대화 컨텍스트 / 턴 처리 | 엔진 입력 맥락과 스트림 완료 저장 경로 재검증 필요 |
| 이미 인사했는데 다시 인사 | 출력 품질 | 2턴 이후 반복 인사 차단 가능 |
| “내담자 역할로 응답하겠습니다” | 출력 품질 | 역할 메타발화 하드 차단 필요 |
| 문맥 오해 후 나중에 해명했는데 피드백은 이전 기준처럼 보임 | 평가 UX | fast-loop는 해당 턴 직후 기준임을 표시하고, 회기 전체 평가는 별도 라벨 필요 |
| `[NAME]`이 리뷰 화면에 표시 | 표시 계층 / privacy proof | API 증거는 유지하고 UI 표시층만 자연어화 |
| `no_structured_output` 평가 실패 | 평가 UX / 운영 관측 | 내부 오류 코드와 사용자 설명 문구 분리 |
| 진단기준·CBT·개방도 산식 질문 | 설명 가능성 / 임상 게이트 | 구현된 구조와 임상팀 확정 잔여를 분리해 설명 |
## 4. 근거가 된 코드 관찰
### 4.1 대화 컨텍스트
- `apps/api/engine_gateway/gateway.py``_split_messages()`는 system 메시지를 합치고 마지막 `user`만 남긴다. 중간 `assistant`/`user` 히스토리는 현재 payload에서 사라진다.
- `_split_messages()`의 기존 테스트는 “마지막 user만 보낸다”를 계약처럼 고정하고 있다. 변경 시 테스트 추가가 아니라 계약 갱신이다.
- `apps/api/engine_gateway/gateway.py``_resolve_session()`은 같은 `session_id`가 살아 있으면 새 system prompt를 무시하고 resident session을 재사용한다.
- `apps/api/app/routes/sessions.py``start_session()`은 DB/app 세션은 만들지만 gateway `/session`을 호출해 resident session을 만들지는 않는다.
- `apps/api/app/services/orchestrator.py`는 앱 세션 ID를 `GenerateRequest`/`StreamRequest``session_id`로 넘긴다. 그러나 이 ID는 gateway resident ID와 명시 매핑되어 있지 않다.
- `apps/api/app/services/persona.py``recent_turns``EngineMessage`로 추가하지만, 현재 gateway split 구조에서는 그 히스토리가 소비되지 않는다.
- 같은 파일의 recent turn role 매핑은 주석과 반대로 보인다. 내담자 AI 관점에서는 `counselor -> user`, `client -> assistant`가 맞다.
### 4.2 출력 품질
- `persona.py`의 L0 프롬프트는 “끝까지 내담자”, “메타 대화 금지”, “말투 유지”를 지시한다.
- `guardrail.py``sanitize_client_reply()`는 자살수단 차단, ideation cap, 일부 placeholder 자연어화 중심이다.
- 역할 메타발화, 반복 인사, 직전 답변 중복, 너무 이른 회복/감사 표현은 실행 후 검사로 막고 있지 않다.
- generate 경로는 저장 전 전체 응답을 보고 정제할 수 있다. stream 경로는 이미 token을 내보내는 구조라 첫 문장 또는 일정 문자 수 버퍼링을 넣을 경우 화면/저장/평가 텍스트 동등성을 별도 검증해야 한다.
- voice 경로는 stream이 아니다. generate 전체 응답 후 TTS를 시작하므로 검증 포인트는 버퍼링보다 generate 지연, TTS 시작, persistence 실패 시 learner-only 기록 방지다.
### 4.3 평가와 리뷰
- fast-loop 평가는 “해당 상담자 발화 + 이어진 내담자 응답 + 제한된 직전 맥락” 중심의 턴 직후 평가다.
- deep-loop 평가는 회기 종료 후 전체 축어록을 본다.
- fast-loop 평가는 해당 학습자 발화 직후의 스냅샷이며 후속 해명을 소급 반영하지 않는다. 회기 전체 판단은 deep-loop 또는 교수자 검토에서 별도 표시한다.
- 리뷰 read-model은 턴 텍스트에 `text_masked`를 사용하므로 `[NAME]`이 표시 화면까지 올라올 수 있다.
- 평가 오류는 `no_structured_output`, `engine_error`, `parse_error` 같은 내부 코드가 사용자에게 그대로 보일 수 있다.
- `clientFeedback`는 실제 별도 피드백 산출물이 아니라 마지막 client turn으로 읽히는 경로라, 라벨과 포함 조건을 재검토해야 한다.
## 5. 실행 계획
### P0. 재현과 계측
목표: 고친 것처럼 보이는 패치를 막고, 한신대 자료의 주요 현상을 테스트로 고정한다.
작업:
- gateway 단위 테스트로 새 `_split_messages()` 계약을 고정한다.
- persona 메시지 테스트로 `counselor -> user`, `client -> assistant` 매핑을 검증한다.
- sessions/orchestrator fake engine 테스트로 generate/stream 주요 경로의 gateway payload에 최근 대화가 들어가는지 검증한다.
- evaluator/structured output 요청에는 client history가 들어가지 않는지 검증한다.
- 리뷰 read-model/API 테스트로 raw PII 미포함과 masked token 보존을 동시에 검증한다.
- fast-loop 오류 테스트로 내부 오류 코드가 학습자용 문구로 매핑되는지 검증한다.
- P2 1차는 fallback 저장이 아니라 명백한 출력 결함 감지/재시도/미저장 오류 응답을 검증한다.
검증 후보:
- `Push-Location apps/api; py -3.11 -X utf8 -m pytest -p no:cacheprovider engine_gateway/test_gateway_model.py app/test_orchestrator_masking.py app/test_evaluator_model_routing.py -q; Pop-Location`
- 통합 검증 단계: `app/test_session_turn_persistence.py`, `app/test_voice_ws.py`, session-review/session-persistence focused E2E
- `Push-Location apps/web; npm run typecheck; Pop-Location`
- 필요 시 `Push-Location apps/web; npx playwright test e2e/session-review.spec.ts --project=chromium-desktop --workers=1; Pop-Location`
- DB/engine 가능 시 `Push-Location apps/web; npx playwright test e2e/session-persistence.spec.ts --project=chromium-single-run --workers=1 --grep "Korean PII|manual AI evaluation retry|case worksheet|selected CBT theory mode"; Pop-Location`
### P1. 대화 컨텍스트 안정화
목표: 반복, 재인사, 문맥 오해, 질문 맥락 미반영을 일으킬 수 있는 구조적 원인을 먼저 닫는다.
작업:
1. `persona.build_turn_messages()`의 recent turn role 매핑을 수정한다.
- `counselor -> user`
- `client -> assistant`
2. gateway `_split_messages()`가 client history를 버리지 않게 한다.
- 단기 구현은 `ai_role=client` 요청에만 non-system history를 current user payload 앞에 `[직전 대화]` 블록으로 직렬화한다.
- evaluator/deep-loop/structured output 요청에는 client history 직렬화를 적용하지 않는다.
- 1차는 최근 대화를 라벨링해 주입하고, 가능하면 완성 turn pair를 우선한다.
- 예시:
- `상담자: 왜 무슨 일 있어?`
- `내담자: 엄마가 가보라고 해서요...`
- `[이번 상담자 발화] ...`
3. resident session 매핑은 2차로 미룬다.
- 바로 도입하면 evaluator/deep-loop가 client resident를 재사용할 위험이 있다.
- `client:{session_id}`, `eval:{session_id}` 네임스페이스, 프로세스 정리, gateway 재시작 복구가 함께 필요하다.
검증:
- gateway payload에 직전 상담자 질문과 내담자 답변이 정확히 1회 포함되는지 unit test.
- generate/stream fake engine에서 최근 대화 주입 확인.
- fast/deep evaluator 요청이 client history resident를 재사용하지 않는지 회귀 테스트.
- `_split_messages()` 기존 골든을 새 계약으로 갱신하고, 계약 변경을 문서화한다.
### P2. 내담자 출력 품질 게이트
목표: 모델이 역할을 깨거나 반복·재인사를 출력했을 때 저장/표시 전에 막는다.
1차 하드 차단:
- 역할 메타발화
- 예: “내담자 역할로 응답하겠습니다”, “AI로서”, “상담자 입장에서”, “제 핵심신념은”
- 반복 인사
- 2턴 이후 “안녕하세요”, “처음 뵙겠습니다”, “반갑습니다”로 시작하는 응답
1차 보수적 차단 또는 재생성:
- 직전 내담자 발화와 거의 같은 응답
- exact/subsequence/높은 유사도만 차단한다.
- 너무 이른 회복/감사 표현
- 라포 초기, 낮은 openness, 회복/종결 뉘앙스가 함께 있을 때만 retryable로 둔다.
구현 원칙:
- retry는 1회만 허용한다.
- 1차에서는 fallback 저장을 하지 않는다. 재시도 후에도 실패하면 client turn을 저장하지 않고 재시도 가능한 오류로 표시한다.
- 저장형 fallback은 2차에서만 도입한다. 이때 `synthetic`/`fallback` 메타데이터를 남기고 평가·워크시트·carry-over·`clientFeedback` 기본 입력에서 제외한다.
- 사용자 화면에는 내부 raw reason 대신 “응답을 안정적으로 생성하지 못했어. 다시 시도해줘.”처럼 학습자용 문구를 표시한다.
- stream 첫 문장 또는 80~120자 버퍼링 전면 도입은 2차 안정화로 둔다. 1차는 generate 경로와 명백한 출력 결함 차단부터 닫는다.
- 품질 게이트 reason은 audit 또는 운영자용 payload에 남긴다. 단, 사용자에게 내부 raw reason을 그대로 노출하지 않는다.
검증:
- `guardrail` 또는 신규 품질 모듈의 table-driven unit test.
- generate fake engine retry 1회 테스트.
- 재생성 후 실패 시 client turn 미저장 + 재시도 가능 오류 응답 테스트.
- stream/voice 버퍼링·persistence 경로는 통합 검증 또는 2차 안정화에서 별도 테스트.
- 필요 시 Playwright로 역할 메타발화가 화면에 보이지 않는지 focused 확인.
### P3. 리뷰·평가 UX 개선
목표: 안전한 저장/평가 경로를 유지하면서 사람에게 보이는 리뷰는 자연스럽고 설명 가능하게 만든다.
작업:
1. 리뷰 표시 계층을 분리한다.
- 저장값, 상세 API, 평가 입력, 데이터셋 export, privacy proof에는 `[NAME]`/`[ORG]`/`[PHONE]` 유지.
- 리뷰 화면의 일반 transcript 표시는 동일 데이터를 렌더링 단계에서 자연어화할 수 있다.
- 축어록, 근거 quote, worksheet evidence에는 마스킹 토큰 보존을 기본으로 둔다.
- `humanize_pii_placeholders()`는 내담자 응답 표시용 helper라는 현재 목적을 넘어서 남용하지 않는다.
2. 내부 오류 코드와 사용자 문구를 분리한다.
- `errorKind`: `no_structured_output`, `engine_error`, `parse_error`
- 학습자용 문구:
- “자동 평가를 완료하지 못했어. 다시 시도할 수 있어.”
- 교수자/운영자용 문구:
- 오류 종류와 raw detail을 별도 접힘/관리자 영역에서 확인
- DB/log에는 운영 진단용 raw error를 유지한다.
3. 평가 범위 라벨을 명확히 한다.
- 턴 노트: “이 턴 직후 기준”
- 회기 전체 평가: “회기 전체 기준”
- 사용자가 후속 해명을 했더라도 fast-loop 카드가 소급 변경되지 않는다는 점을 UI에 반영한다.
- 라벨은 완전한 reconciliation이 아니라 즉시 혼란을 줄이는 1차 UX 개선이다. deep-loop 또는 교수자 검토와의 구분을 같이 보여준다.
4. `clientFeedback` 라벨을 조정한다.
- 완전한 의미 재설계 전에도 “내담자가 남긴 것” 대신 “마지막 내담자 반응”처럼 사실에 가까운 표현으로 바꾼다.
2차 후보:
- deep-loop schema에 `turn_reconciliations`를 추가한다.
- fast-loop 노트 옆에 “후속 회복됨 / 부분 회복 / 미해결” 배지를 붙인다.
- 이 작업은 임의 휴리스틱으로 처리하지 않는다. 평가 신뢰도가 떨어질 수 있다.
검증:
- `/review` JSON은 raw PII 미포함 + masked token 보존.
- UI 표시만 humanized 되는지 별도 테스트.
- raw 오류 코드 미노출.
- `clientFeedback` 표시 라벨 변경.
- session-review E2E의 평가 실패 문구 기대값 갱신.
- 저장/상세 API/평가 입력/export에서는 마스킹이 유지되는지 별도 테스트로 보존.
- 공유 payload도 원문 축어록과 학습자 식별 정보를 싣지 않는지 확인.
### P4. 교수자 설명 패널과 SSOT 반영
목표: 한신대 질문에 제품 안에서 답하고, 구현 완료와 임상팀 게이트를 섞지 않는다. 설명 패널은 “못 한다”는 방어문이 아니라 현재 구현, 교육적 의도, 임상팀 미검수 범위를 분리해 설명하는 신뢰 회복 장치다.
교수자 질문별 답변 초안:
1. 진단기준이 입력됐는가?
- 진단명을 붙이는 용도는 아니다.
- DSM-5-TR 기반 요약과 페르소나별 증상 차원은 seed persona/DB catalog에 연결되어 있다.
- seed persona 기준인지 DB catalog 기준인지 UI와 문서에서 구분한다.
- 내담자 발화나 학습자 피드백에는 진단명·정답·내부 수치를 직접 노출하지 않고, 관찰 가능한 말·정서·행동으로 번역한다.
2. 약물치료나 심리평가 권유에 왜 주저하는가?
- Vignette는 교육용 시뮬레이션이지 처방·진단·공식 평가 대체 도구가 아니다.
- 약물/검사 권유는 바로 제시하기보다 라포, 동의, 안전, 기능 손상 확인을 먼저 하도록 설계한다.
- 약물 권유 기준·문안은 임상팀 확정 전 자동화하지 않는다.
3. CBT는 어디서 오는가?
- 계약 원천문서 요구, 페르소나 `theory_target`, 세션 `theory_mode`, 평가 프롬프트에 연결되어 있다.
- 현재는 CBT 반응 프레이밍 수준이다.
- 임상팀 확정 CBT 단계 프롬프트 체인, citation 구조, 이론부합 루브릭은 아직 남은 게이트다.
4. 개방도 점수는 어떻게 계산되는가?
- LLM 감이 아니라 결정론 상태머신 값이다.
- “점수”보다 “시뮬레이션 상태값”으로 설명한다.
- 단계 기본값 + 라포 크레딧 * unlock rate - 저항 * decay를 0~1로 clamp한다.
- 공감·반영·개방질문은 라포를 올리고, 성급한 조언·평가·유도질문은 저항을 올린다.
반영 위치:
- 제품: `SessionReview` 교수자 검토 카드 아래 “AI 평가/코칭 작동 원리와 한계” 패널
- 권장 구조: “현재 구현” / “임상팀 확정 필요” 2열 또는 “현재 구현됨” / “제품 한계” / “임상팀 검수 필요” 3단
- 문서:
- `docs/dev_dashboard.html`: 상태·검증 수치·로드맵 권위 기준
- `docs/TODO.md`: 열린 작업 링크/요약
- 이 계획 문서: 구현 순서와 차단 조건
- `docs/redteam/hanshin-feedback-plan-redteam-2026-07-03.md`: 적대 검토 결과
- `docs/redteam/hanshin-feedback-plan-counter-redteam-2026-07-03.md`: 대레드팀 균형 검토 결과
검증:
- `Push-Location apps/web; npm run typecheck; Pop-Location`
- `Push-Location apps/web; npx playwright test e2e/session-review.spec.ts --project=chromium-desktop --workers=1; Pop-Location`
- `Push-Location apps/web; npx playwright test e2e/layout-visual-gate.spec.ts --project=chromium-single-run --workers=1; Pop-Location`
- `py -3.11 -X utf8 scripts\check-dev-dashboard-ssot.py --json`
## 6. 레드팀에 맡긴 질문과 반영 상태
| 질문 | 1차 반영 |
|---|---|
| 컨텍스트 보존 패치가 실제 반복/문맥오해를 줄인다는 가정이 과도하지 않은가? | 컨텍스트 보존은 필요조건일 뿐이라고 명시했다. role mapping, gateway 계약, 출력 품질 게이트, 평가 라벨을 같이 닫는다. |
| `_split_messages()`에 history를 넣으면 resident context와 중복되어 역효과가 나지 않는가? | 1차는 stateless injection으로 제한하고 resident session은 별도 설계 전까지 켜지 않는다. |
| stream 첫 문장 버퍼링이 UX 지연이나 token 순서 버그를 만들 가능성은? | 화면/저장/평가 텍스트 동등성과 차단 문구 미노출을 검증 조건으로 추가했다. |
| `[NAME]`을 표시 계층에서 자연어화하면 개인정보 보호 증거가 약해졌다고 오해될 위험은? | 리뷰 API/quote/export는 masked token을 유지하고 UI 표시만 분리한다. |
| fast-loop “이 턴 직후 기준” 라벨이 실제 사용자의 혼란을 충분히 줄이는가? | 라벨만으로 부족할 수 있음을 인정하고 deep-loop/교수자 검토와의 구분을 같이 표시한다. |
| 교수자 설명 패널이 임상팀 확정 전 내용을 과장하지 않는가? | DSM/CBT/약물/루브릭/골든셋은 임상팀 검수와 source/citation 범위 안에서만 확정 표현을 쓴다. |
| 문서와 SSOT/TODO가 중복되어 어긋날 위험은? | 상태·검증 수치는 dev_dashboard만 소유하고 계획/TODO/가이드는 링크와 요약만 둔다. |
## 7. 대레드팀 반영 상태
| 대레드팀 질문 | 반영 |
|---|---|
| 레드팀이 P2/P3/P4까지 P1처럼 묶어 본래 목적을 약화시켰는가? | P1 내부 원자성만 하드 게이트로 유지하고, P2/P3/P4는 독립 배포 가능한 1차 개선으로 분리했다. |
| P1 테스트 범위가 과도한가? | P1 차단 테스트를 persona role mapping, gateway client-only history injection, evaluator no-history 계약으로 한정했다. voice/Playwright/전체 review 회귀는 통합 검증 단계로 내렸다. |
| privacy proof가 UI 자연어화를 막는가? | API·저장·export 마스킹 불변식은 유지하되, 리뷰 화면 일반 transcript는 렌더링 단계 자연어화를 허용했다. |
| synthetic fallback 요구가 품질 게이트를 늦추는가? | 1차 품질 게이트는 fallback 저장을 하지 않는다. 재생성 실패 시 client turn 미저장 + 재시도 가능 오류로 처리한다. |
| 임상 안전 문구가 교수자 설명을 무력화하는가? | 교수자 패널은 현재 구현과 임상팀 확정 필요 범위를 분리해 답하는 신뢰 회복 장치로 먼저 배포한다. |
## 8. 현재 결정
구현 완료한 1차 범위:
- P0/P1a: persona role mapping + client-only stateless history injection + evaluator no-history focused test
- P3a: API 마스킹 불변식 보존 + 리뷰 UI 표시 자연어화 + raw error display mapper + fast/deep 라벨 + `clientFeedback` 라벨 변경
- P2a: 역할 메타발화, 2턴 이후 재인사, 직전 내담자 발화와 거의 같은 응답만 먼저 차단. fallback 저장 없이 재시도 가능 오류로 처리. SSE stream은 full-response buffer로 token leak을 막음.
- P4a: 교수자 설명 패널을 “현재 구현 / 임상팀 확정 필요” 구조로 먼저 배포
후속 설계 확인 필요:
- 지연을 줄이는 안전한 partial stream 버퍼링 방식
- 저장형 fallback synthetic 메타데이터와 평가 제외 규칙
- fast-loop/deep-loop reconciliation
- resident session namespace와 prompt caching 복구
- 교수자 설명 패널의 최종 임상 문구
임상팀 게이트:
- CBT 단계 프롬프트 체인
- 이론부합 루브릭
- 약물/심리평가/의뢰 권유 기준과 문안
- C1 루브릭 anchor·가중치·컷오프
- H2 평가 골든셋