공개 Google OAuth 실제 /turn 증명
필요: 로그인 가능한 계정으로 storageState 캡처 → public-auth-turn E2E 1회 통과.
왜 당신인가: 실제 Google 계정 인터랙티브 로그인이라 자동화 불가. (owner 지시로 현재 보류 상태)
증거: public-auth.json + public /turn 성공 로그diff --git a/docs/dev_dashboard.html b/docs/dev_dashboard.html index 949fee7..732399c 100644 --- a/docs/dev_dashboard.html +++ b/docs/dev_dashboard.html @@ -3,1181 +3,897 @@
-- 이번 세션은 seed persona 결합 제거, 비개발 fail-closed 설정, compose OAuth 주입, - admin 모바일 overflow 수정, persona 인증 경계 보강, 전체 Playwright 재통과, 공개 API prod 전환까지 완료했다. - 이번 이어받기에서는 내담자 AI 생성 턴의 provider/model/token/cost 텔레메트리를 `/turn`, SSE stream, 음성 생성 경로에서 DB `app.turns`까지 적재하도록 연결했고, - gateway stream `done/error` 계약을 구조화했으며, P1 상담 시작→텍스트 stream→종료→리뷰 피드백 UI E2E와 저항 엔진 정량 회귀 테스트를 추가했다. - 이어서 PII 마스킹 게이트 우회 차단, RBAC/IDOR·감사 insert 경로, 음성 paralinguistic 메타 저장, 공개 런타임 watchdog 스크립트와 runbook을 보강했다. - 추가로 상주 engine session reuse, SAML provider 스캐폴드, `visible_to` 런타임 필터, EOT/TTS payload 계약까지 회귀화했다. - 백엔드 회귀 테스트는 84개로 재검증했고, 페르소나 승인/반려 API와 교수 콘솔 검수 UI proof를 추가했다. - Postgres RLS/audit live smoke checker와 s2s 2차 PoC 판단 메모도 준비했지만, live DB 실행과 s2s 채택 결정은 별도 증거가 필요하다. - 이후 로컬 5175 런타임 재기동, admin 사용자 관리 E2E 안정화, 학습자 홈 0회 기록 UX, - active session 실제 SSE 스트림 전환, 텍스트/음성 실패 턴 미저장, 직접 URL persona 우회 차단, Live2D demo 자산 제거, - AI 운영 fail-closed 보강까지 전체 Playwright로 확인했다. - 2026-06-26 15:18 KST 기준 공개 API 터널을 복구한 뒤 전체 Playwright 72개가 desktop/mobile/single-run 모두 통과했다. - Cloudflare Pages production 배포 `0fe8f3cc`도 완료했고, 커스텀 도메인이 새 asset을 서빙하는 것을 확인했다. - 과거 Mao/Haru Live2D demo 자산은 repo와 번들에서 제거했고, `/live2d/*` 운영 경로는 404로 차단했다. - 로컬 프로세스는 prod API 8001, engine gateway 9099, cloudflared tunnel 1개만 남기고 dev API와 임시 Vite preview를 내렸다. - 이번 라운드에서는 레이아웃 작업을 서브에이전트 전담으로 분리해 세션, 학습자 홈/리뷰, 관리자/교수자, 설정 화면을 overflow 수리 수준이 아니라 실제 작업 화면 재설계 수준으로 갱신했다. - 통합 레이아웃 E2E는 desktop/mobile 54개를 최종 통과했고, 자세한 인수인계는 `docs/ops/layout-redesign-handoff-2026-06-26.md`에 남겼다. - 이번 이어받기에서는 핸드오프가 남긴 "실기기 시각 수용"을 엄격한 자동 게이트로 닫았다. 7개 권장 너비(390/720/861/900/1024/1280/1440)에서 7개 재설계 화면의 가로 overflow 0·컨트롤 클립 0을 강제하는 `layout-visual-gate.spec.ts`(7 passed, 49장 스크린샷)를 만들고, 화면별 1에이전트 병렬 시각 리뷰 → 6개 병렬 수정 에이전트 → 화면별 적대적 재검수까지 돌려 7/7 accept(critical/major 0, 회귀 0)를 확정했다. 학습자홈 1280 3열 가운데 컬럼 붕괴(critical)와 교수 'API 404' raw 배너를 포함한 결함을 모두 해소했고, 레이아웃 항목을 DONE으로 닫았다. - 다만 이 HTML은 지금까지 Phase 0 상태판처럼 쓰였고, 아래에 Phase 1 이후 전체 계획을 보강했다. - 공개 Google OAuth 실제 `/turn` 증명만 storageState 캡처 후 남아 있다. -
+ +코어(저항·반응 조절, 상태머신, RAG, 이론모드, 가드레일, 평가 JSON Schema)는 잘 정렬됐고 회귀도 녹색이다. 막힌 건 두 종류 — 내가 실증/결정해야 풀리는 외부 의존(아래 "내 차례")과, 착수 대기 중인 납품 필수 기능이다. 이 판은 그 둘을 분리해서 보여준다.
+ +원천 기술분석 PDF(트웬티온스×한신대 산학협력, 19쪽)를 전수 정독해 원안과 현 구현을 대조. 결론: 코어는 잘 정렬됐으나(저항·반응 조절=PDF "우리만의 핵심 기술", 상태머신 4단계·RAG·이론모드·가드레일 분리·SSE·React19·평가 JSON스키마 강제), "통과·납품 필수조건"인 위기 안전게이트와 핵심 가치인 교수자의 학습자-이력/성장 추적 UI가 비어 있다. 사용자 라이브 테스트로 페르소나 반응 갭(모욕·조롱을 공손히 흡수)을 발견·1차 수정.
+람다가 단독으로 못 정하거나(월권), 실제 계정·하드웨어·외부 합의가 필요한 항목. 각 카드는 무엇을 막는지 · 무엇이 필요한지 · 왜 당신인지를 담았다. 팀장이 우선순위를 골라 하나씩 풀어주면 된다.
PDF가 차별 기술로 꼽은 '저항·반응 조절'(AI가 너무 착하지 않게, 실제 환자처럼)·상태머신(라포→탐색→개입→정리)·RAG(자료검색)·이론모드(인간중심/CBT)·답변과 분리된 가드레일·SSE 스트리밍·React19·피드백 JSON Schema 강제(벤더중립)가 이미 구현·정렬됨. Stanford RCT(피드백 없는 연습=역효과)도 H2 턴평가로 충족 방향.
이 코어를 '교육용(비의료)' 포지션으로 유지. 평가는 교수자 검토용 보조지표로 표기.
/turn 증명필요: 로그인 가능한 계정으로 storageState 캡처 → public-auth-turn E2E 1회 통과.
왜 당신인가: 실제 Google 계정 인터랙티브 로그인이라 자동화 불가. (owner 지시로 현재 보류 상태)
증거: public-auth.json + public /turn 성공 로그필요: SSO claim 스키마, 추가 축어록 수급, 미성년 원본 활용동의, 개인정보 처리방침에 대한 한신대/데이터 steward의 written evidence.
왜 당신인가: 기관 공문·협의 영역. 로컬 문서 골격은 준비됨(hanshin-data-governance-gate.md).
라이브 테스트에서 수련생이 내담자를 "수동적 패배자"라 비난·조롱("웃음이 나오십니까")해도 민재가 공손히 흡수 → 훈련 가치 훼손. 수정: ① L0에 무례·모욕·조롱·인신공격 시 현실적 동맹 균열(위축·방어·따지기·종결의향) 지침 ② PersonaCard.triggers(역린) 필드 + CCD 핵심상처 파생 역린 블록(상담자가 핵심상처를 조롱·확정·강요·평가절하 시 가장 강한 반응). PDF '저항·반응 조절' 핵심 차별 강화. 무회귀 77/77.
P1~P3 명시 triggers는 임상팀 정밀 저작(현재 CCD 파생 기본값으로 작동). 라이브 재현 검증.
PDF는 Node.js 우선(팀 보유기술·5개월 일정)/Spring 대안. 현재 Python/FastAPI — 재작성은 일정·인력 리스크.
영향: 팀 역량·유지보수 vs 재작성 비용. 람다 단독 결정 금지.
doc4가 20명 실험/통제군·단회기 50분·3척도 pre-post를 명시. κ/ICC·환각률 목표는 doc4 미명시 — 확정 필요.
영향: 평가 타당도, Phase 3 측정력. 평가설계는 소유자 결정.
캐스케이드 1차는 확정. voice-s2s-poc.md 기준표로 비교 후 유지/폐기.
캐스케이드만 / s2s 2차 PoC 유지
로컬 상주 분류기 기본 + 외부 Haiku/Solar 폴백 허용 여부.
로컬 전용 / 외부 폴백 허용
1차 few-shot 자동갱신만 vs fine-tuning 포함.
few-shot only / fine-tuning 포함
수정안: 기본 ON + 피드백 권장 배지 + 교수자 토글.
기본 ON / 교수자 승인 후 ON
PDF(9·16·18쪽): 자해·자살 감지 시 대화 중단 + 자살예방상담 109 안내 + 지도교수 자동 알림, 안전은 LLM 밖 별도 CrisisGate. 현 코드: 위기 분류·safety_events 적재만, 핫라인 번호가 코드 어디에도 없음(109는 2024.1 1393·1577 통합 — 최신 번호). 대화중단·109안내·교수자 알림 UI 전무.
CrisisGate: LEARNER_REAL 위기 시 턴 중단 + 109/지역 자원 카드 + 교수자 알림(safety_events→대시보드/메일). 답변 생성과 분리.
PDF 핵심 루프: 학습자가 반복 연습 → 교수자가 학습자별 이력·성장곡선(이론부합도·자신감·숙련도, '연습 전·후' 비교)을 검수. 현 교수자 콘솔은 회기 목록 수준 — 학습자별 성장·평가 이력·항목별(공감·질문·정상화·이론부합) 추이를 못 보여줌. 학습 데이터는 쌓이나 가시화·검수 동선 부재.
교수자: 학습자별 대시보드(회기 타임라인·4항목 추이·전후 비교·역린/위기 플래그). 학습자: 성장곡선 + 회기 리뷰 누적.
① PDF: 고성능(Claude·GPT=내담자발화·실시간평가)/저비용 한국어(Solar=단순응답·사후요약) 2단계 + 캐싱 90%절감. 현재 claude_cli 단일 — 벤더중립 인터페이스는 있음. ② PDF는 Node.js 우선(팀 보유기술·5개월 일정)/Spring 대안. 현재 Python/FastAPI — 재작성은 일정·인력 리스크.
2-tier는 ENGINE_MODE 라우팅으로 점진 도입. 백엔드 언어는 소유자 결정(팀 역량·유지보수 vs 재작성 비용).
페르소나 격리(캐릭터 붕괴 버그)·RAG 비차단(세션생성 블로킹 회귀)·역린/misconduct·init_state 파라미터객체·데드코드(LogHook·tier·RMS) — 백엔드 77~84/84 + E2E 42(데스크27·모바일11·아바타4) + 시각게이트 7/7 통과. 스택 라이브(web·api·gateway·voice·RAG).
위기 안전게이트(109) → 교수자/학습자 성장 UI 순으로 착수.
필요: C1 워크시트 항목·루브릭, CBT 이론별 단계 프롬프트 체인, 위기 스크립트·생명유지서약 문안, H2 평가 골든셋.
왜 당신인가: doc3 R&R상 콘텐츠는 임상팀 산출물. 코드는 '편집 가능 구조'만 선제 구축 → 조율·수급 필요.
n=1 시드 한계 해소를 위한 추가 사례 수급 규모·일정 확정.
영향: 평가 타당도, 페르소나 다양성, Phase 3 측정력.
doc4 신청서 스택(Spring/Node·TimescaleDB) vs 실제 FastAPI/Python 불일치. 20주 단기일정·9월 저작권 등재 압박.
권고: 스택 정합 또는 변경사유 거버넌스 기록.
한신대 산학협력 원천문서 5종(상담 프로토콜·인간중심 사례·회의록·신청서·사례개념화 워크북)을 시각 정독하고 코드베이스를 교차 조사해 도출한 "우리가 부족한 부분". 상세 근거: `docs/ops/source-docs-gap-analysis-2026-06-26.md`. critical/high 핵심 5건은 코드 grep으로 직접 재확인(✓). 콘텐츠(루브릭·이론·워크시트 문안)는 doc3 R&R상 임상팀(구훈정·어유경) 소유 — 코드는 '편집 가능 구조'만 선제 구축.
-doc1/4/5가 1급 산출물로 요구하는 워크시트(11탐색항목·호소 5영역·인지삼제·1·2차감정·보호/방해 4사분면·생물심리사회 목표)가 코드·스키마에 전무(grep 0건 ✓직접확인). CCD는 숨은 정답키일 뿐 학습자 산출물 폼이 아님.
워크시트 스키마 입력 폼 + AI 축어록 초안 추출 + 규칙 기반 채점. 루브릭은 임상팀 외부 정의 가능하게 외부화.
prepare_turn→state_machine.evolve에 crisis.risk_level을 ideation_observed로 전달(위기 관측 상태머신 반영). escalate=True 시 `app.safety_events` 적재(graceful 비차단). 라이브: "저 지금 죽고싶어요"→learner_real, safety_events 행 적재 확인. 84/84.
비밀보장 예외고지·단계적 탐색·생명유지서약 스크립트 콘텐츠 + 실시간 교수자 push(레코드가 1차 알림원) + 위기탐색 누락 회기리뷰 감점.
TurnContext+prepare_turn에 theory_mode, sessions/voice가 sess.theory_mode 전달, evaluator._theory_mode가 세션 이론(학습자 선택) 우선. 프론트 Session.tsx 'humanistic' 하드코딩 제거→persona.theory_target 기준(CBT 페르소나는 cbt). 84/84+typecheck.
CBT 이론별 단계 프롬프트 체인 콘텐츠 + 이론부합 채점 루브릭 + 프론트 이론 선택 UI(현재 persona 설계 이론 자동).
doc4가 20명 실험/통제군·단회기 50분·3척도 pre-post를 못박았으나 코드 0건. Phase3 KPI도 report shape만, 계산 코드 0줄. (κ/ICC·환각률은 doc4 미명시 — 평가설계 문서 확정 필요.)
3척도 pre-post 폼·실험/통제군 배정·자동누적 대시보드·추이 시각화·검정 계산 코드. 평가설계는 소유자 결정.
텍스트 `/turn` 경로에 `eval_hook=make_eval_hook(engine_client)` 주입, fast-loop 턴 평가를 학습자 TurnRecord(`evaluation` 신규 필드)에 영속화, 리뷰가 per-turn 기법칩(category→empathy/explore/reflect/confront/closed)·적절성/의도이탈 노트를 노출하도록 배선. 라이브 검증: "많이 힘드셨겠어요…" → techniques [공감/empathy, 촉진질문/explore] + note '적절한 개입'. 백엔드 84/84 pass.
음성 경로(`voice.py:307`) eval_hook 미주입(코드품질 연구 확인) · few-shot 골든셋 기본 OFF · 회기리뷰 2열 UI(축어록 타임라인+비언어) 프론트 강화 · 원천 축어록 골든셋 적재(임상팀).
personas 라우트에 검수 승인/반려만, draft 생성·편집 API 없음. persona_repository는 in-code SEED(P1~P3)만 materialize, 외부 JSON 미로드(✓직접확인). doc3 R&R상 콘텐츠는 임상팀 산출물인데 작성 경로가 막힘.
페르소나 저작 CRUD(draft→review) + P4~P7 적재, 루브릭·이론 콘텐츠를 임상팀 편집 가능 데이터로 외부화.
정규식 폴백에 한국어 고위험 패턴 추가: 구체 날짜(2001.4.18→[DATE])·금액(1200원→[MONEY])·행정구역 주소(서울시 강남구 역삼동→[ADDR]). 과다마스킹 없음 검증("그냥 힘들어요" 보존), 마스킹·저항 6/6+전체 84/84.
이름/기관명은 NER 필요(Presidio ko 모델·spaCy ko, 무거움 — TODO 명시) · audit.llm_call_log 런타임 적재 · 미성년/guardian 동의 수집·게이트·철회.
M1: voice.py가 EOT용 silence_ms만, 침묵·한숨·울음 타임스탬프 이벤트 캡처·리뷰 표시 전무(서버 RMS 힌트 프론트 dead). M2: case_state·build_recall_context가 빈 컨텍스트 반환(다회기 미구동). M3: cohort_ids=[] 하드코딩·email 파생 식별자·SAML 서명검증 미구현·role변경/삭제 audit 미기록. (분석.)
M1 비언어 메타 이벤트 보존·시각화, M2 case_state 런타임·회상 주입, M3 claim→role/cohort 매핑+안정 식별자+서명검증+deprovisioning audit(기관 의존).
X1: ds.* 스키마만, read/write·JSONL export·IAA 게이트 미코딩. X2: 게이트웨이 토큰 텔레메트리 0 고정·cost 모니터링 부재(doc3가 비용을 운영 리스크로 명시). L1: doc4 신청서 스택(Spring Boot 3/Node.js·TimescaleDB) vs 실제 FastAPI/Python 불일치, 20주 단기일정·9월 저작권 등재 압박.
X1 export 잡·IAA 게이트(κ≥0.6/ICC≥0.75), X2 토큰 텔레메트리·캐싱·비용 대시보드, L1 스택 정합 또는 변경사유 거버넌스 기록.
아래 "상태 보드"의 작업 카드에서 자동 집계. 완료/진행/계획 비율과 트랙별 완료도. (Phase 진행률은 단계별 증거 기반 추정치 — 정밀 수치 아님)
추적 작업 0건 기준
+ +카테고리별 완료 카드 / 전체 카드
+리팩토링 연구(데드코드·과다파라미터·중복·인터페이스SSOT·추상화) 상세: `docs/ops/code-quality-research-2026-06-26.md`. 로컬 실행 가이드 `docs/guides/local-development.md`.
+왼쪽 내 차례(clay) 노드를 풀면 가운데 게이트/작업이 열리고, 오른쪽 납품·마일스톤으로 이어진다. 화살표를 따라가면 "내가 지금 풀어야 임계경로가 뚫리는 것"이 보인다.
게이트웨이(9099 claude_cli)+API(8000, DB 미가용 시 in-memory degraded)+웹(5173)을 커맨드라인 기준 정리 후 결정론적 기동(`--reload` 워처 불안정 회피, uvicorn 있는 python 자동 해석). dev-login + seed 페르소나. 로그 `.devlogs/`(gitignore). 검증: 3포트 health OK + 실제 AI 턴 생성·회기리뷰 동작.
AI 턴은 로컬 claude CLI 사용(사용량 발생). 진입점 http://localhost:5173. 주의(무DB 한정): DB 없이 degraded면 페르소나가 `source:seed_fallback·degraded:true`라 프론트 `isUsablePersona`(`!degraded && source==="database"`)가 막아 "회기 시작" 버튼이 비활성 → UI 세션 시작엔 실제 Postgres(`127.0.0.1:55432`)가 필요. (백엔드 API는 seed로도 세션 생성 가능.)
직접 WS 재현으로 근본원인 규명: 키 없으면 백엔드가 `degraded`+1011 즉시 close → 마이크 깜빡·녹음 미도달. STT(gpt-4o-transcribe)·TTS(gpt-4o-mini-tts) 모두 OpenAI. 실 OPENAI_API_KEY를 apps/api/.env(gitignore)에 설정 → /voice/health available:true, WS가 ready→listening 정상 진입(degraded-close 사라짐). 백로그 B2 음성 캐스케이드가 로컬에서 실작동.
① 미설정 시 마이크 버튼 사전 비활성+명확 안내(`/voice/health` 게이팅) ② TTS 지문 제거: (고개 끄덕)·(한숨)·[침묵] 등 무대지시를 음성으로 안 읽음(`speakable_text`, 자막엔 유지) ③ 아바타 애니메이션: 텍스트 턴 speaking 시 입 정지(0) 버그 수정(의사 발화 모션) + thinking 표현 보강(시선/고개/눈썹). typecheck+voice테스트 PASS.
증상: 라이브 회기에서 내담자(민재)가 "저는 Claude Code인데… Vignette 코드베이스… git status…"로 캐릭터를 깨고 개발 맥락 노출. 원인: ENGINE_MODE=claude_cli가 로컬 claude(=Claude Code)를 호출하는데 게이트웨이가 페르소나를 `--append-system-prompt`로 코딩 어시스턴트 정체성에 덧붙이고, cwd=repo라 CLAUDE.md·git status·env가 시스템프롬프트에 포함됨.
`engine_gateway/gateway.py`: `--append-system-prompt`→`--system-prompt`(페르소나만 교체 주입) + `--exclude-dynamic-system-prompt-sections`(cwd/env/git/메모리 섹션 제거). 라이브: 깨던 입력 그대로 → 민재 완벽 인캐릭터, 누출 0. 게이트웨이 7/7 + 전체 84/84.
`routes/sessions.py`(submit/stream)·`routes/voice.py`가 세션로드→오너십→prepare_turn→run_turn_generate→TurnRecord append→state update를 복제. 실드리프트 존재: stage 표기 채널별 상이(한글 vs enum), 음성 경로 eval_hook 미주입·빈 RecallContext. 공통 `record_completed_turn`/`SessionRepository`로 추출.
순수 리팩터 단독 PR + 골든 테스트(test_session_turn_persistence·test_voice_ws) 동등성 확인.
~14개 응답 모델이 TS에 수기 미러(드리프트 실증: `crisis_kind`·`end_state` 누락). OpenAPI→openapi-typescript 단방향 생성으로 전환(타입만, 저위험). [[interface-ssot]]
CI에 "재생성 후 git diff 없음" 게이트.
`LogHook`/`log_hook`(caller 0) 타입·파라미터·분기·export 제거 · 게이트웨이/엔진클라 `tier` dead-contract 제거(write-only, gateway는 model만 사용). 잔여(RMS 힌트·P4~P7·Live2D 고아 자산·파라미터객체 init_state/prepare_turn/upsert)는 `docs/ops/refactor-rag-patches-2026-06-26.{md,json}`에 스테이징(단계 적용).
일괄 적용 대신 라이브 스택 보호 위해 그룹별 적용+pytest 검증.
임베더 BGE-M3 검증+버전핀(1.4.0 dtype버그→1.2.11/transformers 4.44.2). `embed_query`를 asyncio.to_thread로 offload(이벤트루프 비차단). 턴 파이프라인 배선: `retrieve_persona_memory`→episodic recall, `search_kb`→kb_behavior_cues(CLIENT 정책, 전구간 graceful degradation). KB seed 3청크 적재. 검증: search_kb가 behavior_cue 의미매칭 반환, 라이브 세션 13s(임베더로드)+턴 정상. 색인/회수 첫 실행으로 드러난 rag.py latent 버그 3건(sparse·meta jsonb) 수정. GraphRAG는 마스터플랜상 2차 보류(맞음).
최초 RAG 배선이 회기 시작/턴에 임베더 로드(~7-13s)를 동기 await해 `POST /sessions`가 막힘 → session-layout E2E 4건이 5s 타임아웃 실패("여는 중…" 멈춤). 수정: 회상·KB 회수를 `_warm_rag_caches` 백그라운드 task로 옮기고 턴은 캐시만 읽음(비차단, warm 전엔 빈 단서 graceful). 재검증: session-layout 4/4 + 핵심 E2E 27/27(데스크톱)·11/11(모바일)·아바타 4/4 통과. KB 스타터 3청크(임상 정밀은 임상팀).
admin 1280 input "text-clipped-x" 1건은 폼 input의 값 스크롤(설계상 정상·커서로 전부 도달)을 오탐한 것 — 가로 overflow·clipped-by-ancestor는 원래 통과(레이아웃 contained 확인). ellipsis/line-clamp 제외와 동일 원리로 form 컨트롤(input/textarea/select)을 text-clip 판정에서 제외 → 게이트 7/7(실 결함 검사는 유지, 미은폐).
`docs/MASTERPLAN.md`와 `docs/redteam/MASTERPLAN_REVISIONS.md`를 합친 팀장 판단용 단계표
+현재 추적 중인 작업을 카드로. 요약만 노출되고, 상세 근거·검증 로그는 카드를 펼쳐야 보인다. 필터로 "내 차례"·블로커만 추려 볼 수 있다.
인프라, 인증 경계, fail-closed, 공개 배포, 회귀 테스트 안정화.
-1 페르소나 상담, 실제 턴 저장, 회기말 피드백, 저항 엔진 검증.
-학습자, 교수자, 관리자 권한 분리와 페르소나 확장.
-STT → 엔진 → TTS 왕복, WSS/터널 안정성, barge-in 로깅.
-수련생 파일럿, 사전사후 효과 측정, 재귀학습 데이터셋 산출.
-PDF가 차별 기술로 꼽은 '저항·반응 조절'(AI가 너무 착하지 않게, 실제 환자처럼)·상태머신(라포→탐색→개입→정리)·RAG(자료검색)·이론모드(인간중심/CBT)·답변과 분리된 가드레일·SSE 스트리밍·React19·피드백 JSON Schema 강제(벤더중립)가 이미 구현·정렬됨. Stanford RCT(피드백 없는 연습=역효과)도 H2 턴평가로 충족 방향.
이 코어를 '교육용(비의료)' 포지션으로 유지. 평가는 교수자 검토용 보조지표로 표기.
라이브 테스트에서 수련생이 내담자를 "수동적 패배자"라 비난·조롱("웃음이 나오십니까")해도 민재가 공손히 흡수 → 훈련 가치 훼손. 수정: ① L0에 무례·모욕·조롱·인신공격 시 현실적 동맹 균열(위축·방어·따지기·종결의향) 지침 ② PersonaCard.triggers(역린) 필드 + CCD 핵심상처 파생 역린 블록(상담자가 핵심상처를 조롱·확정·강요·평가절하 시 가장 강한 반응). PDF '저항·반응 조절' 핵심 차별 강화. 무회귀 77/77.
P1~P3 명시 triggers는 임상팀 정밀 저작(현재 CCD 파생 기본값으로 작동). 라이브 재현 검증.
PDF(9·16·18쪽): 자해·자살 감지 시 대화 중단 + 자살예방상담 109 안내 + 지도교수 자동 알림, 안전은 LLM 밖 별도 CrisisGate. 현 코드: 위기 분류·safety_events 적재만, 핫라인 번호가 코드 어디에도 없음(109는 2024.1 1393·1577 통합 — 최신 번호). 대화중단·109안내·교수자 알림 UI 전무.
심층조사(2026-06-27, ✓file:line): classify_crisis(guardrail.py:136)·_record_safety_event(sessions.py:694)·app.safety_events(02_schema.sql:221)는 있음. 빠진 것: 핫라인 상수(grep 0건)·TurnResponse.crisis_resource·LLM 밖 대화중단 분기·voice.py 경로 safety_event 미적재(REST만 적재).
CrisisGate: LEARNER_REAL 위기 시 턴 중단 + 109/지역 자원 카드 + 교수자 알림(safety_events→대시보드/메일). 답변 생성과 분리. 핫라인 번호·문안·중단정책은 소유자 확정 필요.
PDF 핵심 루프: 학습자가 반복 연습 → 교수자가 학습자별 이력·성장곡선(이론부합도·자신감·숙련도, '연습 전·후' 비교)을 검수. 현 교수자 콘솔은 회기 목록 수준 — 학습자별 성장·평가 이력·항목별(공감·질문·정상화·이론부합) 추이를 못 보여줌. 학습 데이터는 쌓이나 가시화·검수 동선 부재.
교수자: 학습자별 대시보드(회기 타임라인·4항목 추이·전후 비교·역린/위기 플래그). 학습자: 성장곡선 + 회기 리뷰 누적.
① PDF: 고성능(Claude·GPT=내담자발화·실시간평가)/저비용 한국어(Solar=단순응답·사후요약) 2단계 + 캐싱 90%절감. 현재 claude_cli 단일 — 벤더중립 인터페이스는 있음. ② PDF는 Node.js 우선(팀 보유기술·5개월 일정)/Spring 대안. 현재 Python/FastAPI — 재작성은 일정·인력 리스크.
2-tier는 ENGINE_MODE 라우팅으로 점진 도입. 백엔드 언어는 소유자 결정(팀 역량·유지보수 vs 재작성 비용).
페르소나 격리(캐릭터 붕괴 버그)·RAG 비차단(세션생성 블로킹 회귀)·역린/misconduct·init_state 파라미터객체·데드코드(LogHook·tier·RMS) — 백엔드 77~84/84 + E2E 42(데스크27·모바일11·아바타4) + 시각게이트 7/7 통과. 스택 라이브(web·api·gateway·voice·RAG).
위기 안전게이트(109) → 교수자/학습자 성장 UI 순으로 착수.
doc1/4/5가 1급 산출물로 요구하는 워크시트(11탐색항목·호소 5영역·인지삼제·1·2차감정·보호/방해 4사분면·생물심리사회 목표)가 코드·스키마에 전무(grep 0건 ✓직접확인). CCD는 숨은 정답키일 뿐 학습자 산출물 폼이 아님.
워크시트 스키마 입력 폼 + AI 축어록 초안 추출 + 규칙 기반 채점. 루브릭은 임상팀 외부 정의 가능하게 외부화.
prepare_turn→state_machine.evolve에 crisis.risk_level을 ideation_observed로 전달(위기 관측 상태머신 반영). escalate=True 시 app.safety_events 적재(graceful 비차단). 라이브: "저 지금 죽고싶어요"→learner_real, safety_events 행 적재 확인. 84/84.
비밀보장 예외고지·단계적 탐색·생명유지서약 스크립트 콘텐츠 + 실시간 교수자 push(레코드가 1차 알림원) + 위기탐색 누락 회기리뷰 감점.
TurnContext+prepare_turn에 theory_mode, sessions/voice가 sess.theory_mode 전달, evaluator._theory_mode가 세션 이론(학습자 선택) 우선. 프론트 Session.tsx 'humanistic' 하드코딩 제거→persona.theory_target 기준(CBT 페르소나는 cbt). 84/84+typecheck.
CBT 이론별 단계 프롬프트 체인 콘텐츠 + 이론부합 채점 루브릭 + 프론트 이론 선택 UI(현재 persona 설계 이론 자동).
doc4가 20명 실험/통제군·단회기 50분·3척도 pre-post를 못박았으나 코드 0건. Phase3 KPI도 report shape만, 계산 코드 0줄. (κ/ICC·환각률은 doc4 미명시 — 평가설계 문서 확정 필요.)
3척도 pre-post 폼·실험/통제군 배정·자동누적 대시보드·추이 시각화·검정 계산 코드. 평가설계는 소유자 결정.
텍스트 /turn 경로에 eval_hook=make_eval_hook(engine_client) 주입, fast-loop 턴 평가를 학습자 TurnRecord(evaluation 신규 필드)에 영속화, 리뷰가 per-turn 기법칩(category→empathy/explore/reflect/confront/closed)·적절성/의도이탈 노트를 노출하도록 배선. 라이브 검증: "많이 힘드셨겠어요…" → techniques [공감/empathy, 촉진질문/explore] + note '적절한 개입'. 백엔드 84/84 pass.
음성 경로(voice.py:307) eval_hook 미주입 · few-shot 골든셋 기본 OFF · 회기리뷰 2열 UI(축어록 타임라인+비언어) 프론트 강화 · 원천 축어록 골든셋 적재(임상팀).
personas 라우트에 검수 승인/반려만, draft 생성·편집 API 없음. persona_repository는 in-code SEED(P1~P3)만 materialize, 외부 JSON 미로드(✓직접확인). doc3 R&R상 콘텐츠는 임상팀 산출물인데 작성 경로가 막힘.
페르소나 저작 CRUD(draft→review) + P4~P7 적재, 루브릭·이론 콘텐츠를 임상팀 편집 가능 데이터로 외부화.
정규식 폴백에 한국어 고위험 패턴 추가: 구체 날짜(2001.4.18→[DATE])·금액(1200원→[MONEY])·행정구역 주소(서울시 강남구 역삼동→[ADDR]). 과다마스킹 없음 검증("그냥 힘들어요" 보존), 마스킹·저항 6/6+전체 84/84.
이름/기관명은 NER 필요(Presidio ko 모델·spaCy ko, 무거움 — TODO 명시) · audit.llm_call_log 런타임 적재 · 미성년/guardian 동의 수집·게이트·철회.
M1: voice.py가 EOT용 silence_ms만, 침묵·한숨·울음 타임스탬프 이벤트 캡처·리뷰 표시 전무(서버 RMS 힌트 프론트 dead). M2: case_state·build_recall_context가 빈 컨텍스트 반환(다회기 미구동). M3: cohort_ids=[] 하드코딩·email 파생 식별자·SAML 서명검증 미구현·role변경/삭제 audit 미기록. (분석.)
M1 비언어 메타 이벤트 보존·시각화, M2 case_state 런타임·회상 주입, M3 claim→role/cohort 매핑+안정 식별자+서명검증+deprovisioning audit(기관 의존).
X1: ds.* 스키마만, read/write·JSONL export·IAA 게이트 미코딩. X2: 게이트웨이 토큰 텔레메트리 0 고정·cost 모니터링 부재(doc3가 비용을 운영 리스크로 명시). L1: doc4 신청서 스택(Spring Boot 3/Node.js·TimescaleDB) vs 실제 FastAPI/Python 불일치, 20주 단기일정·9월 저작권 등재 압박.
X1 export 잡·IAA 게이트(κ≥0.6/ICC≥0.75), X2 토큰 텔레메트리·캐싱·비용 대시보드, L1 스택 정합 또는 변경사유 거버넌스 기록.
게이트웨이(9099 claude_cli)+API(8000, DB 미가용 시 in-memory degraded)+웹(5173)을 커맨드라인 기준 정리 후 결정론적 기동(--reload 워처 불안정 회피, uvicorn 있는 python 자동 해석). dev-login + seed 페르소나. 로그 .devlogs/(gitignore). 검증: 3포트 health OK + 실제 AI 턴 생성·회기리뷰 동작.
AI 턴은 로컬 claude CLI 사용(사용량 발생). 진입점 http://localhost:5173. 주의(무DB 한정): DB 없이 degraded면 페르소나가 source:seed_fallback·degraded:true라 프론트 isUsablePersona가 막아 "회기 시작" 버튼이 비활성 → UI 세션 시작엔 실제 Postgres(127.0.0.1:55432)가 필요.
직접 WS 재현으로 근본원인 규명: 키 없으면 백엔드가 degraded+1011 즉시 close → 마이크 깜빡·녹음 미도달. STT(gpt-4o-transcribe)·TTS(gpt-4o-mini-tts) 모두 OpenAI. 실 OPENAI_API_KEY를 apps/api/.env(gitignore)에 설정 → /voice/health available:true(degraded-close 사라짐). 백로그 B2 음성 캐스케이드가 로컬에서 실작동.
① 미설정 시 마이크 버튼 사전 비활성+명확 안내 ② TTS 지문 제거: (고개 끄덕)·(한숨)·[침묵] 등 무대지시를 음성으로 안 읽음(speakable_text, 자막엔 유지) ③ 아바타 애니메이션: 텍스트 턴 speaking 시 입 정지(0) 버그 수정 + thinking 표현 보강. typecheck+voice테스트 PASS.
라이브 회기에서 내담자(민재)가 "저는 Claude Code인데… Vignette 코드베이스… git status…"로 캐릭터를 깨고 개발 맥락 노출. 원인: ENGINE_MODE=claude_cli가 로컬 claude(=Claude Code)를 호출하는데 게이트웨이가 페르소나를 --append-system-prompt로 코딩 어시스턴트 정체성에 덧붙이고, cwd=repo라 CLAUDE.md·git status·env가 시스템프롬프트에 포함됨.
engine_gateway/gateway.py: --append-system-prompt→--system-prompt(페르소나만 교체 주입) + --exclude-dynamic-system-prompt-sections(cwd/env/git/메모리 섹션 제거). 라이브: 깨던 입력 그대로 → 민재 완벽 인캐릭터, 누출 0. 게이트웨이 7/7 + 전체 84/84.
routes/sessions.py(submit/stream)·routes/voice.py가 세션로드→오너십→prepare_turn→run_turn_generate→TurnRecord append→state update를 복제. 실드리프트 존재: stage 표기 채널별 상이(한글 vs enum), 음성 경로 eval_hook 미주입·빈 RecallContext. 공통 record_completed_turn/SessionRepository로 추출.
순수 리팩터 단독 PR + 골든 테스트(test_session_turn_persistence·test_voice_ws) 동등성 확인.
~14개 응답 모델이 TS에 수기 미러(드리프트 실증: crisis_kind·end_state 누락). OpenAPI→openapi-typescript 단방향 생성으로 전환(타입만, 저위험).
CI에 "재생성 후 git diff 없음" 게이트.
LogHook/log_hook(caller 0) 타입·파라미터·분기·export 제거 · 게이트웨이/엔진클라 tier dead-contract 제거(write-only, gateway는 model만 사용). 잔여(RMS 힌트·P4~P7·Live2D 고아 자산·파라미터객체 init_state/prepare_turn/upsert)는 docs/ops/refactor-rag-patches-2026-06-26.{md,json}에 스테이징(단계 적용).
일괄 적용 대신 라이브 스택 보호 위해 그룹별 적용+pytest 검증.
임베더 BGE-M3 검증+버전핀(1.4.0 dtype버그→1.2.11/transformers 4.44.2). embed_query를 asyncio.to_thread로 offload. 턴 파이프라인 배선: retrieve_persona_memory→episodic recall, search_kb→kb_behavior_cues. KB seed 3청크 적재. rag.py latent 버그 3건 수정. GraphRAG는 2차 보류.
최초 RAG 배선이 회기 시작/턴에 임베더 로드(~7-13s)를 동기 await해 POST /sessions가 막힘 → session-layout E2E 4건 타임아웃. 수정: 회상·KB 회수를 _warm_rag_caches 백그라운드 task로 옮기고 턴은 캐시만 읽음(비차단). 재검증: session-layout 4/4 + 핵심 E2E 27/27·11/11·아바타 4/4 통과.
admin 1280 input "text-clipped-x" 1건은 폼 input 값 스크롤(설계상 정상) 오탐 — form 컨트롤을 text-clip 판정에서 제외 → 게이트 7/7(실 결함 검사 유지).
탭별 할 일, 산출물, 검증 기준. 팀장 리뷰는 여기서 다음 작업을 고르면 된다.
+로드맵 단계표, 단계별 상세 작업·검증 명령 표, 이번 세션 내러티브. 기본 접힘 — 필요할 때만 펼쳐서 본다.
지금 단계는 구현을 더 벌리는 단계가 아니라, 운영 증거를 닫고 P1 진입 조건을 고정하는 단계다.
-로그인 가능한 계정으로 storageState를 저장한 뒤 public-auth-turn E2E를 실행한다.
`apps/web/node_modules/.tmp/public-auth.json`, public `/turn` 성공 로그
`E2E_PUBLIC_AUTH=1` + `chromium-public-auth` 1회 통과
`GET /admin/engine-config`로 운영값을 직접 확인했다. `engine_mode=claude_cli`, `engine_url=http://127.0.0.1:9099`, `model=gateway-default`, `durable=true`, `source=database`로 의도값과 일치한다.
config API 응답(durable, db source)
`claude_cli / http://127.0.0.1:9099 / gateway-default` 의도값 대조 완료
Mao/Haru 샘플, Pixi/Cubism 런타임, 공개 `/live2d/*` 캐시 잔여 접근을 차단했다.
`apps/web/functions/live2d/[[path]].js`, SVG-only avatar
운영 `/live2d/mao/*`, Cubism core `404`
임시 Vite preview와 dev API를 내리고 운영 확인용 프로세스만 유지한다.
9099 engine, 8001 prod API, cloudflared tunnel 1개
`Get-NetTCPConnection`에서 8000/517x/5537 비어 있음
SSO 클레임, 추가 축어록 수급, 미성년 원본 활용동의, 개인정보 처리방침을 P1 진입 전 외부 의존성으로 명확히 둔다. 로컬 문서 골격은 준비됐지만 한신대/데이터 steward의 written evidence는 아직 필요하다.
`docs/ops/hanshin-data-governance-gate.md`, 공문 질의 항목, 동의 범위 체크리스트, SSO claim mapping 표
문서 artifact 작성 완료; IRB 게이트가 아니라 데이터/SSO 게이트로 외부 증거 필요 상태 유지
이전 “완료” 카드 내용을 탭 안에서 항목별로 보존한다.
-`session-persistence`, `teacher`, `voice`는 `/api/personas`에서 실제 DB persona를 가져온다.
seed persona 직접 결합 제거, 실제 persona catalog 기반 E2E
persona 관련 E2E가 DB-backed persona로 통과
prod/staging에서 dev login, seed fallback, OAuth 누락, 기본 secret, localhost CORS를 거부한다.
fail-closed runtime config validation
backend runtime policy unittest 통과
`ENVIRONMENT`, Google OAuth vars, `CORS_ORIGINS`, `OPENAI_BASE_URL`을 API 컨테이너에 명시했다.
compose 환경 주입 정리
`docker compose --env-file .env.example config --quiet` 통과
긴 readiness detail을 안정화했고, 사용자 변경은 DB 저장소가 durable할 때만 허용한다.
admin responsive layout, durable store gate, AI health copy
admin manage-users desktop/mobile 2 passed
`db-persistence`는 전역 engine config를 바꾸므로 `@single-run`으로 분리했다.
Playwright single-run tagging
전체 Playwright 72 passed
`docs/HANDOFF.md`, `docs/dev_dashboard.html`, `apps/web/e2e/README.md`를 최신 상태로 맞췄다.
handoff, dashboard, E2E README
최신 커밋 기준 상태/검증/운영 포트 일치
`cloudflared` ingress를 `127.0.0.1:8001` prod API로 돌렸고 public readiness gate가 통과했다.
prod API 8001, tunnel config
`https://api-vignette.chanpaca.net/health` prod/db/engine OK
`scripts/start-public-runtime.ps1`와 `scripts/stop-public-runtime.ps1`로 API 8001과 cloudflared를 재현 가능하게 만들었다.
public runtime start/stop scripts
engine 9099 + API 8001 + cloudflared only
`/personas`는 이제 비로그인 401이다. 로컬과 공개 API 모두 직접 확인했고 E2E 회귀를 추가했다.
authenticated persona catalog boundary
local/public unauth `GET /personas` 401
public 웹에서 `/api/auth/config`가 SPA HTML로 떨어지지 않도록 public API origin fallback을 추가했다.
public API origin fallback
public login screen E2E 1 passed
학습자 홈은 fake 기록 없이 실제 서버 세션 0개를 `기존 회기` 빈 상태와 0 카운트로 표시한다.
empty history UX, zero count, no fake stats
learner screenshots: document overflow 0, empty history visible
`127.0.0.1:5175` web, `8000` API, `9099` engine을 재기동하고 dev-login 서버 세션과 `/learn` redirect를 확인했다.
local dev-login flow proof
desktop/mobile auth flow passed
375px급 active session에서 stage 내부가 1px 넘게 잘리던 문제를 avatar/padding 조정으로 제거했다.
session layout responsive adjustment
session-layout desktop/mobile 8 passed
`POST /sessions/{id}/stream` token 이벤트로만 내담자 자막을 쌓고, HTTP 거절과 SSE error 모두 실패 턴을 transcript와 저장소에 남기지 않는다.
real SSE stream turn path, failed turn discard
session layout/turn E2E passed
음성 회기도 엔진 응답 생성 성공 후에만 learner/client turn을 저장한다. 실패한 transcript는 pending 상태에서 제거한다.
voice failure persistence guard
voice + voice-success + session-layout 15 passed
admin health와 voice degraded reason은 내부 fallback/seed 표현 대신 비영구 런타임 상태를 사용자용 문구로 표시한다.
operator-facing copy cleanup
settings/admin focused E2E 통과
`/learn/session/:code`로 직접 들어와도 DB 원본 persona가 아니면 회기 시작을 막는다.
route guard, degraded/seed fallback regression
unavailable persona code E2E 통과
Mao/Haru 샘플과 Pixi/Cubism 런타임을 공개 배포물에서 제거했다. 세션 화면은 SVG persona avatar만 렌더링한다.
SVG-only avatar, legacy `/live2d/*` 404 function
Mao/Haru/Cubism core routes 404, no Live2D/Pixi chunks
인프라, 인증 경계, fail-closed, 공개 배포, 회귀 테스트 안정화.
/turn proof만 남음1 페르소나 상담, 실제 턴 저장, 회기말 피드백, 저항 엔진 검증.
학습자, 교수자, 관리자 권한 분리와 페르소나 확장.
STT → 엔진 → TTS 왕복, WSS/터널 안정성, barge-in 로깅.
수련생 파일럿, 사전사후 효과 측정, 재귀학습 데이터셋 산출.
MASTERPLAN 원본의 IRB 신청/승인 게이트는 MASTERPLAN_REVISIONS 기준으로 제거한다. Phase 2는 2a(3역할/OAuth/페르소나)와 2b(음성 캐스케이드)로 분리하고, Phase 1 DoD에는 얇은 음성 왕복 1턴 PoC를 포함한다.목표는 “P1 내담자와 실제 상담 1회 완주 후 피드백을 받는 공개 시연 가능 상태”다.
+gateway SSE `token/done/error`와 generate cost 계약은 회귀화했다. claude_cli와 Messages API 폴백 동일성 검증은 남아 있다.
`token`, `done`, `error`, cost 이벤트 계약과 contract test
stream error 미저장 + stream/generate client turn telemetry 저장
지금 단계는 구현을 더 벌리는 단계가 아니라, 운영 증거를 닫고 P1 진입 조건을 고정하는 단계다.
/turn proof 확보로그인 가능한 계정으로 storageState를 저장한 뒤 public-auth-turn E2E를 실행한다.
apps/web/node_modules/.tmp/public-auth.json, public /turn 성공 로그
E2E_PUBLIC_AUTH=1 + chromium-public-auth 1회 통과
GET /admin/engine-config로 운영값을 직접 확인했다. engine_mode=claude_cli, engine_url=http://127.0.0.1:9099, model=gateway-default, durable=true, source=database로 의도값과 일치한다.
config API 응답(durable, db source)
claude_cli / http://127.0.0.1:9099 / gateway-default 의도값 대조 완료
Mao/Haru 샘플, Pixi/Cubism 런타임, 공개 /live2d/* 캐시 잔여 접근을 차단했다.
apps/web/functions/live2d/[[path]].js, SVG-only avatar
운영 /live2d/mao/*, Cubism core 404
임시 Vite preview와 dev API를 내리고 운영 확인용 프로세스만 유지한다.
9099 engine, 8001 prod API, cloudflared tunnel 1개
Get-NetTCPConnection에서 8000/517x/5537 비어 있음
SSO 클레임, 추가 축어록 수급, 미성년 원본 활용동의, 개인정보 처리방침을 P1 진입 전 외부 의존성으로 명확히 둔다. 로컬 문서 골격은 준비됐지만 한신대/데이터 steward의 written evidence는 아직 필요하다.
docs/ops/hanshin-data-governance-gate.md, 공문 질의 항목, 동의 범위 체크리스트, SSO claim mapping 표
문서 artifact 작성 완료; IRB 게이트가 아니라 데이터/SSO 게이트로 외부 증거 필요 상태 유지
0fe8f3cc이 543d48c 소스로 배포됐고, 운영 반영 전 남은 핵심 증거는 공개 Google OAuth 실제 /turn smoke다. 런타임 mock/demo 자산은 운영 번들에서 제거하고 테스트 fixture만 남긴다.이전 "완료" 카드 내용을 탭 안에서 항목별로 보존한다.
session-persistence, teacher, voice는 /api/personas에서 실제 DB persona를 가져온다.
seed persona 직접 결합 제거, 실제 persona catalog 기반 E2E
persona 관련 E2E가 DB-backed persona로 통과
prod/staging에서 dev login, seed fallback, OAuth 누락, 기본 secret, localhost CORS를 거부한다.
fail-closed runtime config validation
backend runtime policy unittest 통과
ENVIRONMENT, Google OAuth vars, CORS_ORIGINS, OPENAI_BASE_URL을 API 컨테이너에 명시했다.
compose 환경 주입 정리
docker compose --env-file .env.example config --quiet 통과
긴 readiness detail을 안정화했고, 사용자 변경은 DB 저장소가 durable할 때만 허용한다.
admin responsive layout, durable store gate, AI health copy
admin manage-users desktop/mobile 2 passed
db-persistence는 전역 engine config를 바꾸므로 @single-run으로 분리했다.
Playwright single-run tagging
전체 Playwright 72 passed
docs/HANDOFF.md, docs/dev_dashboard.html, apps/web/e2e/README.md를 최신 상태로 맞췄다.
handoff, dashboard, E2E README
최신 커밋 기준 상태/검증/운영 포트 일치
cloudflared ingress를 127.0.0.1:8001 prod API로 돌렸고 public readiness gate가 통과했다.
prod API 8001, tunnel config
https://api-vignette.chanpaca.net/health prod/db/engine OK
scripts/start-public-runtime.ps1와 scripts/stop-public-runtime.ps1로 API 8001과 cloudflared를 재현 가능하게 만들었다.
public runtime start/stop scripts
engine 9099 + API 8001 + cloudflared only
/personas는 이제 비로그인 401이다. 로컬과 공개 API 모두 직접 확인했고 E2E 회귀를 추가했다.
authenticated persona catalog boundary
local/public unauth GET /personas 401
public 웹에서 /api/auth/config가 SPA HTML로 떨어지지 않도록 public API origin fallback을 추가했다.
public API origin fallback
public login screen E2E 1 passed
학습자 홈은 fake 기록 없이 실제 서버 세션 0개를 기존 회기 빈 상태와 0 카운트로 표시한다.
empty history UX, zero count, no fake stats
learner screenshots: document overflow 0, empty history visible
127.0.0.1:5175 web, 8000 API, 9099 engine을 재기동하고 dev-login 서버 세션과 /learn redirect를 확인했다.
local dev-login flow proof
desktop/mobile auth flow passed
375px급 active session에서 stage 내부가 1px 넘게 잘리던 문제를 avatar/padding 조정으로 제거했다.
session layout responsive adjustment
session-layout desktop/mobile 8 passed
POST /sessions/{id}/stream token 이벤트로만 내담자 자막을 쌓고, HTTP 거절과 SSE error 모두 실패 턴을 transcript와 저장소에 남기지 않는다.
real SSE stream turn path, failed turn discard
session layout/turn E2E passed
음성 회기도 엔진 응답 생성 성공 후에만 learner/client turn을 저장한다. 실패한 transcript는 pending 상태에서 제거한다.
voice failure persistence guard
voice + voice-success + session-layout 15 passed
admin health와 voice degraded reason은 내부 fallback/seed 표현 대신 비영구 런타임 상태를 사용자용 문구로 표시한다.
operator-facing copy cleanup
settings/admin focused E2E 통과
/learn/session/:code로 직접 들어와도 DB 원본 persona가 아니면 회기 시작을 막는다.
route guard, degraded/seed fallback regression
unavailable persona code E2E 통과
Mao/Haru 샘플과 Pixi/Cubism 런타임을 공개 배포물에서 제거했다. 세션 화면은 SVG persona avatar만 렌더링한다.
SVG-only avatar, legacy /live2d/* 404 function
Mao/Haru/Cubism core routes 404, no Live2D/Pixi chunks
`session_id`가 살아 있는 gateway session을 재사용하고 missing session은 ephemeral로 닫히는 구조를 회귀화했고, live 게이트웨이(9099)로 실측까지 마쳤다. `probe-engine-gateway.py`가 단일 session_id로 2회 reused stream을 돌려 TTFT 1667–4199ms, cost 누적 0.068→0.123(turns 1→2), engine=claude_p, model=opus-4-8을 측정했다. (프로세스 RSS는 별도 OS 계측 항목으로 남김.)
`engine_gateway/test_gateway_model.py`, `scripts/probe-engine-gateway.py`, live probe JSON
session reuse 7 tests OK; live probe 2 reused streams, TTFT/cost 실측, session_id 재사용 확인
목표는 "P1 내담자와 실제 상담 1회 완주 후 피드백을 받는 공개 시연 가능 상태"다.
gateway SSE token/done/error와 generate cost 계약은 회귀화했다. claude_cli와 Messages API 폴백 동일성 검증은 남아 있다.
token, done, error, cost 이벤트 계약과 contract test
stream error 미저장 + stream/generate client turn telemetry 저장
claude -p 엔진풀 실증session_id가 살아 있는 gateway session을 재사용하고 missing session은 ephemeral로 닫히는 구조를 회귀화했고, live 게이트웨이(9099)로 실측까지 마쳤다. probe-engine-gateway.py가 단일 session_id로 2회 reused stream을 돌려 TTFT 1667–4199ms, cost 누적 0.068→0.123(turns 1→2), engine=claude_p, model=opus-4-8을 측정했다.
engine_gateway/test_gateway_model.py, scripts/probe-engine-gateway.py, live probe JSON
session reuse 7 tests OK; live probe 2 reused streams, TTFT/cost 실측, session_id 재사용 확인
current turn, recall, pinned fact, recent turns가 Presidio/가명처리 후에만 engine request로 들어가게 막았다. 운영 외부-send 관측 증거는 남아 있다.
app/test_orchestrator_masking.py, context 입력 재마스킹
phone/email/RRN raw 값이 generate/stream payload에 없음
통제된 UI E2E로 P1 선택, SSE 상담, 종료, 회기말 리뷰 피드백을 한 번에 통과시켰다. 실제 운영 로그인 proof는 P0 blocker와 함께 남아 있다.
e2e/session-mvp.spec.ts, turn telemetry 저장 경로
chromium-single-run P1 MVP UI E2E 1 passed
공감 발화와 조언점프 발화 5턴 세트를 순수 상태머신 회귀 테스트로 비교했다. DB 쿼리 기반 운영 증거는 남아 있다.
app/test_state_machine_resistance.py
공감 시 탐색 전이/개방도 상승, 조언점프 시 라포 단계 유지/개방도 0
Session UI 마이크 버튼 경로에서 synthetic getUserMedia/MediaRecorder로 실제 /voice/ws를 열고 audio_start, binary chunk, audio_end, transcript, reply, TTS 재생 상태까지 검증했다. 물리 마이크, 공개 WSS, live STT/TTS provider 증거는 아직 별도다.
apps/web/e2e/voice-success.spec.ts, controlled OpenAI/engine providers, browser voice UI probe
npx playwright test e2e/voice-success.spec.ts --project=chromium-single-run 2 passed
current turn, recall, pinned fact, recent turns가 Presidio/가명처리 후에만 engine request로 들어가게 막았다. 운영 외부-send 관측 증거는 남아 있다.
`app/test_orchestrator_masking.py`, context 입력 재마스킹
phone/email/RRN raw 값이 generate/stream payload에 없음
통제된 UI E2E로 P1 선택, SSE 상담, 종료, 회기말 리뷰 피드백을 한 번에 통과시켰다. 실제 운영 로그인 proof는 P0 blocker와 함께 남아 있다.
`e2e/session-mvp.spec.ts`, turn telemetry 저장 경로
`chromium-single-run` P1 MVP UI E2E 1 passed
공감 발화와 조언점프 발화 5턴 세트를 순수 상태머신 회귀 테스트로 비교했다. DB 쿼리 기반 운영 증거는 남아 있다.
`app/test_state_machine_resistance.py`
공감 시 탐색 전이/개방도 상승, 조언점프 시 라포 단계 유지/개방도 0
Session UI 마이크 버튼 경로에서 synthetic `getUserMedia`/`MediaRecorder`로 실제 `/voice/ws`를 열고 audio_start, binary chunk, audio_end, transcript, reply, TTS 재생 상태까지 검증했다. 물리 마이크, 공개 WSS, live STT/TTS provider 증거는 아직 별도다.
`apps/web/e2e/voice-success.spec.ts`, controlled OpenAI/engine providers, browser voice UI probe
`npx playwright test e2e/voice-success.spec.ts --project=chromium-single-run` 2 passed; 실패 턴 미저장은 backend persistence 회귀로 별도 확인
음성과 섞지 않고 3역할, 권한격리, 페르소나 확장을 독립 트랙으로 닫는다.
+음성과 섞지 않고 3역할, 권한격리, 페르소나 확장을 독립 트랙으로 닫는다.
Auth Code + PKCE/state와 opaque HttpOnly/Secure cookie 계약을 회귀화했다. 공개 Google OAuth 실제 /turn proof는 P0 blocker로 남아 있다.
app/test_auth_providers.py, PKCE state store, OAuth callback cookie path
auth URL secret 미노출, browser token 미저장, dev/prod cookie 속성 분리
runtime fallback에서 타 learner session 직접 접근 403과 learner list 필터를 회귀화했고, teacher/admin durable read audit insert 경로를 추가했다. live Postgres(NOBYPASSRLS vignette_app 역할)로 RLS/audit smoke를 실행해 운영 증거를 확보했다: learner 세션/턴 격리, teacher cohort 스코프, teacher/admin read_session audit insert가 실제 정책 하에서 PASS.
app/test_rbac_idor.py, audit.audit_log read_session insert, scripts/check-postgres-rls-audit.py(live PASS)
타인 session_id 직접 입력 403(unit), live RLS smoke 5 checks PASS
visible_to와 인간 권한 레이어 분리learner detail/review와 client engine history에서 evaluator-only turn을 제외한다. live Postgres smoke가 evaluator-only DB 정책을 실제로 검사해 PASS: evaluator-only turn이 learner/client/counselor AI에는 숨겨지고 evaluator AI에만 보인다.
TurnRecord.visible_to, learner/client/evaluator filters, docs/ops/postgres-rls-audit-smoke.md
evaluator-only turn 숨김 unit proof + live RLS smoke visible_to.evaluator_only_hidden PASS
approved catalog와 draft/review 교수 검수 큐를 분리하고, teacher/admin 승인·반려 mutation과 교수 콘솔 UI proof를 추가했다. 교수 콘솔의 404 raw 노출도 제거(404→정상 빈상태)했다.
/personas/review, POST /personas/review/{persona_id}, professor review panel
app.test_persona_review 14 tests; teacher UI single-run E2E 1 passed; live RLS smoke PASS
Google OIDC와 별도 provider 상태를 /auth/config에 노출하고, Redirect-binding AuthnRequest와 dev-only unsigned fixture ACS를 backend proof 수준으로 구현했다. 서명 검증이 필요한 운영 SAML ACS는 아직 미구현이며 fingerprint 설정 시 거부한다.
AUTH_SAML_ENABLED, SAML_SP_ENTITY_ID, SAML_SSO_URL, RelayState store, /auth/saml/acs fixture endpoint
AuthnRequest issuer/ACS/destination, RelayState 검증, opaque HttpOnly cookie, bad RelayState/signature-required reject unit test
Auth Code + PKCE/state와 opaque HttpOnly/Secure cookie 계약을 회귀화했다. 공개 Google OAuth 실제 `/turn` proof는 P0 blocker로 남아 있다.
`app/test_auth_providers.py`, PKCE state store, OAuth callback cookie path
auth URL secret 미노출, browser token 미저장, dev/prod cookie 속성 분리
음성은 "되게 보이는 UI"가 아니라, 전송, STT, EOT, 엔진, TTS, 저장까지 끊기지 않아야 한다.
/voice/ws backend contract를 fake WebSocket으로 회귀화했고, Session UI의 MediaRecorder 기반 브라우저 경로도 synthetic audio로 한 턴 통과시켰다. 실제 AudioWorklet 전환, public WSS, 50분 양방향 실측은 남아 있다.
app/test_voice_ws.py, apps/web/e2e/voice-success.spec.ts, audio_start/binary/audio_end/text_turn/ping contract
5 backend tests OK; voice-success chromium-single-run 2 passed; auth guard, chunk concat, max audio cap, TTS chunk envelope
provider-neutral EOT helper로 final transcript와 silence threshold readiness를 회귀화했다. 실제 Deepgram interim/final 스트림 연결은 남아 있다.
assess_end_of_turn, EndOfTurnDecision, EOT silence threshold
final pending, empty transcript, silence threshold 케이스 unit test
P1/P2/P3 persona voice preset, invalid preset fallback, speed clamp, instructions payload 계약을 회귀화했다. DB voice_persona_map과 live TTS 호출은 남아 있다.
resolve_voice, build_tts_payload, provider-neutral params test
P1/P2/P3 voice 분리, fallback, fake-client streaming payload OK
음성 learner turn에 audio_ref, silence_ms, speech_rate, barge_in을 nullable 메타로 저장한다. 실제 장시간 WSS/마이크 증거는 남아 있다.
turns nullable 확장, voice route 메타 산출
오디오 STT→엔진→TTS 더블 테스트에서 voice turn log에 메타 저장
캐스케이드 1차 원칙과 s2s 유지/폐기 증거 기준을 문서화했다. 채택 여부 결정은 윤찬 DECIDE로 유지한다.
docs/decisions/voice-s2s-poc.md
transcript, safety, audit, latency, failure, privacy 기준 명시
runtime fallback에서 타 learner session 직접 접근 403과 learner list 필터를 회귀화했고, teacher/admin durable read audit insert 경로를 추가했다. live Postgres(NOBYPASSRLS `vignette_app` 역할)로 RLS/audit smoke를 실행해 운영 증거를 확보했다: learner 세션/턴 격리, teacher cohort 스코프, teacher/admin read_session audit insert가 실제 정책 하에서 PASS. (smoke 스크립트의 cleanup RLS 컨텍스트 버그도 수정.)
`app/test_rbac_idor.py`, `audit.audit_log` read_session insert, `scripts/check-postgres-rls-audit.py`(live PASS)
타인 `session_id` 직접 입력 403(unit), live RLS smoke 5 checks PASS(learner isolation, teacher cohort, evaluator-only hidden, audit insert)
learner detail/review와 client engine history에서 evaluator-only turn을 제외한다. live Postgres smoke가 evaluator-only DB 정책을 실제로 검사해 PASS: evaluator-only turn이 learner/client/counselor AI에는 숨겨지고 evaluator AI에만 보인다. live DSN 실행 완료.
`TurnRecord.visible_to`, learner/client/evaluator filters, `docs/ops/postgres-rls-audit-smoke.md`
evaluator-only turn 숨김 unit proof + live RLS smoke `visible_to.evaluator_only_hidden` PASS
approved catalog와 draft/review 교수 검수 큐를 분리하고, teacher/admin 승인·반려 mutation과 교수 콘솔 UI proof를 추가했다. 교수 콘솔의 404 raw 노출도 제거(404→정상 빈상태)했다. live Postgres RLS/audit smoke 실행으로 DB 권한/감사 레이어가 실제 정책 하에서 동작함을 확인했다.
`/personas/review`, `POST /personas/review/{persona_id}`, professor review panel
`app.test_persona_review` 14 tests; teacher UI single-run E2E 1 passed; live RLS smoke PASS
Google OIDC와 별도 provider 상태를 `/auth/config`에 노출하고, Redirect-binding AuthnRequest와 dev-only unsigned fixture ACS를 backend proof 수준으로 구현했다. 서명 검증이 필요한 운영 SAML ACS는 아직 미구현이며 fingerprint 설정 시 거부한다.
`AUTH_SAML_ENABLED`, `SAML_SP_ENTITY_ID`, `SAML_SSO_URL`, RelayState store, `/auth/saml/acs` fixture endpoint
AuthnRequest issuer/ACS/destination, RelayState 검증, opaque HttpOnly cookie, bad RelayState/signature-required reject unit test
음성은 “되게 보이는 UI”가 아니라, 전송, STT, EOT, 엔진, TTS, 저장까지 끊기지 않아야 한다.
+IRB 승인 게이트가 아니라 교육 활용 파일럿과 데이터/개인정보 게이트로 관리한다.
20명 파일럿을 실행하기 위한 roster, consent, session completion evidence gate를 문서화했다. 실제 참여자 완주 증거는 아직 필요하다.
docs/phase3/pilot-runbook.md, evidence root layout, operator gates
scripts/check-phase3-artifacts.py --help; 실제 evidence root validation은 파일럿 시점에 실행
SUS, 자기효능감, κ/ICC, 환각률, 피드백 타당도 기준과 report schema를 고정했다. 실제 수치 충족 여부는 파일럿 데이터 이후 판단한다.
docs/phase3/kpi-measurement-plan.md, KPI report schema
checker가 prepost_measures, sus_responses, kpi_report.json evidence를 요구
anonymized JSONL export manifest와 누수/식별자 점검 기준을 문서화했다. 실제 export 승인과 데이터 steward 검수는 남아 있다.
docs/phase3/dataset-export-manifest.md, 03-export/export_manifest.json contract
source/hash/consent/withdrawal/anonymization fields 요구, raw identifier 금지
동의, 철회, privacy audit, 해외 전송 고지 evidence checklist를 만들었다. 실제 법무/개인정보 검토 서명은 파일럿 전 gate로 남아 있다.
docs/phase3/privacy-consent-audit.md, withdrawal log contract
동의 철회 후 session/export 제외 evidence를 checker 입력으로 요구
`/voice/ws` backend contract를 fake WebSocket으로 회귀화했고, Session UI의 MediaRecorder 기반 브라우저 경로도 synthetic audio로 한 턴 통과시켰다. 실제 AudioWorklet 전환, public WSS, 50분 양방향 실측은 남아 있다.
`app/test_voice_ws.py`, `apps/web/e2e/voice-success.spec.ts`, audio_start/binary/audio_end/text_turn/ping contract
5 backend tests OK; voice-success chromium-single-run 2 passed; auth guard, chunk concat, max audio cap, TTS chunk envelope
provider-neutral EOT helper로 final transcript와 silence threshold readiness를 회귀화했다. 실제 Deepgram interim/final 스트림 연결은 남아 있다.
`assess_end_of_turn`, `EndOfTurnDecision`, EOT silence threshold
final pending, empty transcript, silence threshold 케이스 unit test
P1/P2/P3 persona voice preset, invalid preset fallback, speed clamp, instructions payload 계약을 회귀화했다. DB `voice_persona_map`과 live TTS 호출은 남아 있다.
`resolve_voice`, `build_tts_payload`, provider-neutral params test
P1/P2/P3 voice 분리, fallback, fake-client streaming payload OK
음성 learner turn에 audio_ref, silence_ms, speech_rate, barge_in을 nullable 메타로 저장한다. 실제 장시간 WSS/마이크 증거는 남아 있다.
`turns` nullable 확장, voice route 메타 산출
오디오 STT→엔진→TTS 더블 테스트에서 voice turn log에 메타 저장
캐스케이드 1차 원칙과 s2s 유지/폐기 증거 기준을 문서화했다. 채택 여부 결정은 윤찬 DECIDE로 유지한다.
`docs/decisions/voice-s2s-poc.md`
transcript, safety, audit, latency, failure, privacy 기준 명시
IRB 승인 게이트가 아니라 교육 활용 파일럿과 데이터/개인정보 게이트로 관리한다.
-20명 파일럿을 실행하기 위한 roster, consent, session completion evidence gate를 문서화했다. 실제 참여자 완주 증거는 아직 필요하다.
`docs/phase3/pilot-runbook.md`, evidence root layout, operator gates
`scripts/check-phase3-artifacts.py --help`; 실제 evidence root validation은 파일럿 시점에 실행
SUS, 자기효능감, κ/ICC, 환각률, 피드백 타당도 기준과 report schema를 고정했다. 실제 수치 충족 여부는 파일럿 데이터 이후 판단한다.
`docs/phase3/kpi-measurement-plan.md`, KPI report schema
checker가 `prepost_measures`, `sus_responses`, `kpi_report.json` evidence를 요구
anonymized JSONL export manifest와 누수/식별자 점검 기준을 문서화했다. 실제 export 승인과 데이터 steward 검수는 남아 있다.
`docs/phase3/dataset-export-manifest.md`, `03-export/export_manifest.json` contract
source/hash/consent/withdrawal/anonymization fields 요구, raw identifier 금지
동의, 철회, privacy audit, 해외 전송 고지 evidence checklist를 만들었다. 실제 법무/개인정보 검토 서명은 파일럿 전 gate로 남아 있다.
`docs/phase3/privacy-consent-audit.md`, withdrawal log contract
동의 철회 후 session/export 제외 evidence를 checker 입력으로 요구
실제 운영 도메인에 반영됐는지, 서버가 하나로 정리됐는지, 완료라고 말할 증거가 있는지 확인하는 탭이다.
-커스텀 도메인이 최신 JS/CSS asset을 서빙한다.
`index-D1Z5DH5J.js`, `index-BA9-xxfn.css`
`Invoke-WebRequest https://vignette.chanpaca.net/`
터널은 prod API 8001을 보고, API는 DB와 engine을 모두 확인한다.
`environment:"prod"`, `db:true`, `engine:true`
`https://api-vignette.chanpaca.net/health`
운영 확인용 프로세스만 유지하고 임시 dev server는 내린다.
8001 API, 9099 engine, 20241 cloudflared
`Get-NetTCPConnection` 대상 포트 확인
engine gateway, prod API, cloudflared를 health-check하고 복구하는 watchdog과 Scheduled Task installer를 추가했다. 실제 재부팅 후 public `/turn` smoke는 남아 있다.
`watch-public-runtime.ps1`, `install-public-runtime-task.ps1`, ops runbook
PowerShell parser OK, check-only watchdog 실행
서브에이전트 전담으로 1차 overflow/clipping 수리 후 2차 전면 재설계를 진행했고, 이번 라운드에서 7개 권장 너비 시각 수용까지 닫았다. 세션, 학습자 홈/리뷰, 교수 콘솔, 관리자, 설정 화면을 작업 화면 기준으로 재배치했고, 과한 빈칸·튀어나감·버튼/텍스트 잘림·모바일 테이블 사용성을 줄였다. 엄격한 시각 게이트 + 화면별 적대적 시각 재검수에서 7개 화면 모두 accept(critical/major 0, 회귀 0)를 받아 DONE으로 닫는다. 잔여는 cosmetic minor(아래 백로그).
`docs/ops/layout-redesign-handoff-2026-06-26.md`, page-by-page redesign patches, `apps/web/e2e/layout-visual-gate.spec.ts`
`npm run typecheck` OK, 엄격 시각 게이트 7 passed, layout focused E2E desktop/mobile 54 passed, 적대적 시각 재검수 7/7 accept·회귀 0.
핸드오프가 요구한 7개 권장 너비(390/720/861/900/1024/1280/1440) 시각 수용을 자동 게이트로 고정했다. 7개 재설계 화면을 각 너비에서 렌더링해 가로 overflow 0, 컨트롤 하드클립/텍스트클립 0을 강제하고 화면당 7장 총 49장 풀페이지 스크린샷을 남긴다. 캐러셀(overflow-x 스크롤)·의도적 말줄임/line-clamp는 결함에서 제외해 false positive를 제거했다. 밀집 실데이터(긴 학습자명, 3회 누적 기록, 종료 회기 리뷰)로 진입. 화면별 1에이전트 병렬 시각 리뷰로 49장 직접 판독 → 6개 병렬 수정 에이전트(파일 비중첩)가 결함 수정 → 화면별 적대적 재검수로 해소·무회귀 확정.
`apps/web/e2e/layout-visual-gate.spec.ts`, `node_modules/.tmp/layout-gate/*.png` 49장, 2× workflow(review/verify)·6× fix agent
게이트 7 passed(재스크린샷). 해소된 핵심 결함: 학습자홈 1280/1440 3열 가운데 컬럼 붕괴(critical → 2열 분기 1180→1400 상향 + word-break:keep-all), 교수 'API 404' raw 배너 제거(404→정상 빈상태/실장애만 재시도 카드), 리뷰 빈상태 검정카드 위계 역전(filled 조건부 강조), 관리자 빈/로딩 박스 shimmer 스켈레톤·플레이스홀더, 설정 와이드 좌측 데드존 제거(레일 슬림+본문 중앙정렬)·운영방식 2x2, 세션 모바일 컨트롤바 44px 터치타깃+'밀어서 종료' 라벨. 적대적 재검수 7/7 accept, regression 0.
적대적 재검수 잔여 cosmetic minor를 5개 병렬 폴리시 에이전트로 처리했다. 학습자홈 헬퍼문구 고아 글자(word-break:keep-all+text-wrap:balance), 세션 1024 일시정지 아이콘-only 정리 + 보내기 버튼 활성/비활성 대비 강화, 설정 2x2 칩 행 높이 균일 + AI 운영 2열 높이 정렬, 교수 검토 큐 카드 갭 제거, 관리자 사용자 관리 2열 높이 동기화를 적용했다.
page-by-page polish patches(LearnerHome/Session/Settings/Professor/Admin)
`npm run typecheck` OK, 시각 게이트 7 passed(재스크린샷), 레이아웃 E2E desktop/mobile 54 passed, session-layout 8/8 — 회귀 0.
축소 사이드바 세로 구분선이 본문 전체 높이까지 닿지 않던 건을 `components/shell/shell.css`에서 처리했다. `.vg-nav border-right`(sticky·뷰포트 높이) 제거 후 `.vg-shell__body` 컨테이너 배경 하어라인(linear-gradient 1px×100%)으로 본문 그리드 전체 높이를 따라가는 구분선을 그리고, 그리드·구분선 폭을 `--nav-cur`로 동기화(1024 축소폭/720 가로바 전환 정합). learner-home 로딩 스켈레톤 밀도도 실제 카드 구조 모사로 보강했다. 데이터 0건 빈상태 컬럼 높이 여백은 의도적 미착수(0건 전용 시각 균형이라 러닝 앱 시각 확인 필요).
구현 완료. 검증: `npm run typecheck` PASS + `vite build` PASS. 전 페이지 시각 회귀 게이트(7/7 + 포커스 E2E + session-layout 8/8)는 web+api+DB 스택(Docker 미기동·secrets 부재)으로 이 워크스테이션 미실행 — 스택 가용 시 1회 시각 확인 권장.
요약하지 않고 실행 범위, 명령, 결과를 행 단위로 남긴다.
-| 범위 | 명령 / 확인 대상 | 결과 |
|---|---|---|
| Web typecheck | npm run typecheck | Passed |
| Backend unittest | python -m unittest app.test_runtime_policy app.test_session_turn_persistence app.test_state_machine_resistance app.test_orchestrator_masking app.test_rbac_idor app.test_voice_service app.test_auth_providers app.test_voice_ws app.test_persona_review engine_gateway.test_gateway_model | 84 tests OK |
| P1 cost telemetry | app.test_session_turn_persistence.SessionTurnPersistenceTest | Passed; generate/stream client AI turns store provider/model/tokens/cost |
| Engine stream contract | gateway token/done/error parsing | Passed; gateway error event does not create saved turns |
| Engine session reuse | engine_gateway.test_gateway_model | 7 tests OK; live session_id reuse and ephemeral close fixed |
| P1 masking gate | app.test_orchestrator_masking | 4 tests OK; phone/email/RRN absent from generate/stream payloads |
| P2a RBAC/audit/visibility | app.test_rbac_idor | 7 tests OK; other learner 403, read_session audit, evaluator-only hidden |
| Postgres RLS/audit smoke checker | python scripts\check-postgres-rls-audit.py --help | py_compile/help/safe default OK; live DSN run still required for proof |
| OAuth/BFF cookie security | app.test_auth_providers | 12 tests OK; PKCE/state, opaque HttpOnly/Secure cookie, no browser tokens, SAML AuthnRequest/dev-only fixture ACS |
| Persona review workflow | app.test_persona_review | 14 tests OK; approved-only catalog, teacher/admin queue, approve/reject audit, learner 403 |
| Voice WS contract | app.test_voice_ws | 5 tests OK; auth guard, audio_start/chunks/audio_end, text_turn, ping, max audio cap |
| Voice preset/EOT | app.test_voice_service | 9 tests OK; TTS payload, preset fallback, EOT readiness |
| Voice metadata | app.test_session_turn_persistence | audio_ref/silence_ms/speech_rate/barge_in persisted on learner voice turn |
| P1 MVP UI E2E | npx playwright test e2e/session-mvp.spec.ts --project=chromium-single-run | 1 passed |
| Persona review UI E2E | npx playwright test e2e/teacher.spec.ts --project=chromium-single-run | 1 passed; teacher approves pending persona from console |
| Voice UI synthetic E2E | npx playwright test e2e/voice-success.spec.ts --project=chromium-single-run | 2 passed; direct WS cascade plus Session mic button path with synthetic browser audio |
| Voice s2s decision memo | docs/decisions/voice-s2s-poc.md | criteria recorded; keep/drop decision remains owner DECIDE |
| Hanshin data/SSO gate | docs/ops/hanshin-data-governance-gate.md | artifact created; written external evidence still required |
| Resistance engine | app.test_state_machine_resistance | 2 tests OK; empathy vs advice-jump curve fixed |
| Python compile | python -m compileall app engine_gateway | Passed |
| Phase 3 artifact gates | python scripts\check-phase3-artifacts.py --help | Passed; runbook, KPI plan, dataset manifest, privacy audit checker documented |
| Web build | npm run build | Passed |
| Pages production deploy | wrangler pages deploy dist --project-name vignette --branch main | `0fe8f3cc`, source `543d48c` |
| Custom domain assets | https://vignette.chanpaca.net/ | `index-D1Z5DH5J.js`, `index-BA9-xxfn.css` |
| Legacy Live2D routes | /live2d/mao/* / /live2d/haru/* / /live2d/live2dcubismcore.min.js | 404 |
| Compose | docker compose --env-file .env.example config --quiet | Passed with dummy required env |
| Focused E2E | admin + db-persistence + voice-success | 10 passed |
| Admin manage-users | admin.spec.ts --grep manage real server-known users | desktop/mobile 2 passed |
| Full E2E | PLAYWRIGHT_HOST=127.0.0.1 npx playwright test | 72 passed |
| Public auth discovery | E2E_PUBLIC_AUTH=1 npx playwright test --list --project=chromium-public-auth | 2 tests listed |
| Public readiness | public-auth-turn.spec.ts --grep production-safe | 1 passed |
| Persona auth boundary | GET /personas | verified local/public unauth 401 |
| Public login | auth.spec.ts --grep public login | 1 passed |
| Public runtime scripts | start/watch/install-public-runtime*.ps1 | parser OK; watchdog check-only path verified |
| Public API health | https://api-vignette.chanpaca.net/health | prod, db true, engine true |
| Local 5175 login | PLAYWRIGHT_BASE_URL=http://127.0.0.1:5175 auth.spec.ts | desktop/mobile passed |
| Learner/readiness E2E | learner.spec.ts + readiness.spec.ts desktop/mobile | 14 passed |
| Learner screenshots | learn-empty-desktop.png / learn-empty-mobile-compact.png | document overflow 0, empty history visible |
| Session layout/turn | session-layout.spec.ts desktop/mobile | 8 passed |
| Voice/session focused | voice + voice-success + session-layout | 15 passed |
| Layout redesign handoff | docs/ops/layout-redesign-handoff-2026-06-26.md | subagent scopes, files, verification, remaining visual review recorded |
| Layout redesign focused E2E | npx playwright test e2e/learner.spec.ts e2e/session-layout.spec.ts e2e/session-review.spec.ts e2e/admin.spec.ts e2e/settings.spec.ts e2e/teacher.spec.ts --project=chromium-desktop --project=chromium-mobile | 54 passed after isolated Admin tablet flake rerun |
| Strict layout visual gate | npx playwright test e2e/layout-visual-gate.spec.ts --project=chromium-single-run | 7 passed; 7 screens × 7 widths(390/720/861/900/1024/1280/1440), horizontal overflow 0 + control clip 0, 49 full-page screenshots |
| Parallel visual quality review | workflow layout-visual-quality-review (7 agents) | 49 screenshots read; per-screen findings(critical 1, major 8+, minor) → fix verdicts |
| Parallel layout fixes | 6 agent team: learner-home/session/review/professor/admin/settings (disjoint files) | all fixes applied; `npm run typecheck` OK; no cross-file conflicts |
| Strict gate re-run (post-fix) | npx playwright test e2e/layout-visual-gate.spec.ts --project=chromium-single-run | 7 passed; re-screenshotted 49 |
| Layout focused E2E re-run (post-fix) | learner/session-layout/session-review/admin/settings/teacher × desktop+mobile | 54 passed; no regression |
| Adversarial visual verify | workflow layout-visual-verify (7 agents) | 7/7 accept; critical/major resolved, regression 0; minor polish backlog recorded |
| Engine config 운영값 | GET /admin/engine-config | claude_cli / http://127.0.0.1:9099 / gateway-default, durable, source=database (의도값 일치) |
| Engine gateway probe (live) | scripts/probe-engine-gateway.py --base-url http://127.0.0.1:9099 --reuse-runs 2 | claude_p / opus-4-8; 단일 session_id 2회 reused stream; TTFT 1667–4199ms; cost 누적 0.068→0.123(turns 1→2) |
| Postgres RLS/audit smoke (live) | VIGNETTE_RLS_AUDIT_DSN=…vignette_app… check-postgres-rls-audit.py --write-fixtures | 5 checks PASS: preflight, learner 세션/턴 격리, teacher cohort 스코프, visible_to evaluator-only 숨김, teacher/admin read audit insert (NOBYPASSRLS app role, fixtures 자동 정리) |
| Turn cost telemetry (live DB) | SELECT … FROM app.turns WHERE actor_kind='client_ai' | 13 client_ai turns 적재: llm_provider=claude_cli, model=gateway-default, cost_usd 실값(합 $1.22, 평균 $0.094), visible_to 배열. 토큰은 CLI 게이트웨이 특성상 0, cost는 산출 |
| Cosmetic polish re-verify | 5 polish agents → typecheck + gate + layout E2E re-run | typecheck OK; gate 7 passed; layout focused E2E 54 passed; session-layout 8/8; regression 0 |
남은 public OAuth `/turn` proof 확보용 명령이다.
-cd D:\workspace\vignette\apps\web ++++운영 / 검증 상세
실제 운영 도메인에 반영됐는지, 서버가 하나로 정리됐는지, 완료라고 말할 증거가 있는지 확인하는 탭이다.
웹: 200API: prod OKLive2D: 404+++DONE운영 웹 asset 확인커스텀 도메인이 최신 JS/CSS asset을 서빙한다.
산출물
index-D1Z5DH5J.js,index-BA9-xxfn.css검증
Invoke-WebRequest https://vignette.chanpaca.net/+DONE공개 API prod health터널은 prod API 8001을 보고, API는 DB와 engine을 모두 확인한다.
산출물
environment:"prod",db:true,engine:true검증
https://api-vignette.chanpaca.net/health+DONE서버 정리 상태운영 확인용 프로세스만 유지하고 임시 dev server는 내린다.
산출물8001 API, 9099 engine, 20241 cloudflared
검증
Get-NetTCPConnection대상 포트 확인+CHECK재부팅 후 런타임 재기동engine gateway, prod API, cloudflared를 health-check하고 복구하는 watchdog과 Scheduled Task installer를 추가했다. 실제 재부팅 후 public
/turnsmoke는 남아 있다.산출물
watch-public-runtime.ps1,install-public-runtime-task.ps1, ops runbook검증PowerShell parser OK, check-only watchdog 실행
+DONE레이아웃 감사팀 / 전면 레이아웃 개선서브에이전트 전담으로 1차 overflow/clipping 수리 후 2차 전면 재설계를 진행했고, 이번 라운드에서 7개 권장 너비 시각 수용까지 닫았다. 세션, 학습자 홈/리뷰, 교수 콘솔, 관리자, 설정 화면을 작업 화면 기준으로 재배치했고, 과한 빈칸·튀어나감·버튼/텍스트 잘림·모바일 테이블 사용성을 줄였다. 엄격한 시각 게이트 + 화면별 적대적 시각 재검수에서 7개 화면 모두 accept(critical/major 0, 회귀 0)를 받아 DONE으로 닫는다.
산출물
docs/ops/layout-redesign-handoff-2026-06-26.md, page-by-page redesign patches,apps/web/e2e/layout-visual-gate.spec.ts검증
npm run typecheckOK, 엄격 시각 게이트 7 passed, layout focused E2E desktop/mobile 54 passed, 적대적 시각 재검수 7/7 accept·회귀 0.+DONE엄격한 레이아웃 시각 게이트 구축 · 병렬 수정 · 적대적 재검수핸드오프가 요구한 7개 권장 너비(390/720/861/900/1024/1280/1440) 시각 수용을 자동 게이트로 고정했다. 7개 재설계 화면을 각 너비에서 렌더링해 가로 overflow 0, 컨트롤 하드클립/텍스트클립 0을 강제하고 화면당 7장 총 49장 풀페이지 스크린샷을 남긴다. 화면별 1에이전트 병렬 시각 리뷰로 49장 직접 판독 → 6개 병렬 수정 에이전트(파일 비중첩)가 결함 수정 → 화면별 적대적 재검수로 해소·무회귀 확정.
산출물
apps/web/e2e/layout-visual-gate.spec.ts,node_modules/.tmp/layout-gate/*.png49장, 2× workflow(review/verify)·6× fix agent검증게이트 7 passed(재스크린샷). 해소된 핵심 결함: 학습자홈 1280/1440 3열 가운데 컬럼 붕괴(critical → 2열 분기 상향 + word-break:keep-all), 교수 'API 404' raw 배너 제거, 리뷰 빈상태 위계 역전, 관리자 스켈레톤, 설정 와이드 좌측 데드존 제거, 세션 모바일 44px 터치타깃. 적대적 재검수 7/7 accept, regression 0.
+DONE레이아웃 cosmetic minor 폴리시 일괄 처리적대적 재검수 잔여 cosmetic minor를 5개 병렬 폴리시 에이전트로 처리했다. 학습자홈 헬퍼문구 고아 글자, 세션 1024 일시정지 아이콘 정리 + 보내기 버튼 대비 강화, 설정 2x2 칩 행 높이 균일, 교수 검토 큐 카드 갭 제거, 관리자 2열 높이 동기화를 적용했다.
산출물page-by-page polish patches(LearnerHome/Session/Settings/Professor/Admin)
검증
npm run typecheckOK, 시각 게이트 7 passed, 레이아웃 E2E desktop/mobile 54 passed, session-layout 8/8 — 회귀 0.+MINOR잔여(비차단) — 공용 셸 단일 항목 → 처리축소 사이드바 세로 구분선이 본문 전체 높이까지 닿지 않던 건을
components/shell/shell.css에서 처리했다..vg-nav border-right제거 후.vg-shell__body컨테이너 배경 하어라인으로 본문 그리드 전체 높이 구분선을 그리고, 그리드·구분선 폭을--nav-cur로 동기화. learner-home 로딩 스켈레톤 밀도도 실제 카드 구조 모사로 보강했다.판정구현 완료. 검증:
npm run typecheckPASS +vite buildPASS. 전 페이지 시각 회귀 게이트는 web+api+DB 스택으로 이 워크스테이션 미실행 — 스택 가용 시 1회 시각 확인 권장.+검증 실행 상세 표
요약하지 않고 실행 범위, 명령, 결과를 행 단위로 남긴다.
+
++ + 범위 명령 / 확인 대상 결과 + Web typecheck npm run typecheckPassed + Backend unittest python -m unittest app.test_runtime_policy app.test_session_turn_persistence app.test_state_machine_resistance app.test_orchestrator_masking app.test_rbac_idor app.test_voice_service app.test_auth_providers app.test_voice_ws app.test_persona_review engine_gateway.test_gateway_model84 tests OK + P1 cost telemetry app.test_session_turn_persistence.SessionTurnPersistenceTestPassed; generate/stream client AI turns store provider/model/tokens/cost + Engine stream contract gateway token/done/error parsingPassed; gateway error event does not create saved turns + Engine session reuse engine_gateway.test_gateway_model7 tests OK; live session_id reuse and ephemeral close fixed + P1 masking gate app.test_orchestrator_masking4 tests OK; phone/email/RRN absent from generate/stream payloads + P2a RBAC/audit/visibility app.test_rbac_idor7 tests OK; other learner 403, read_session audit, evaluator-only hidden + Postgres RLS/audit smoke checker python scripts\check-postgres-rls-audit.py --helppy_compile/help/safe default OK; live DSN run still required for proof + OAuth/BFF cookie security app.test_auth_providers12 tests OK; PKCE/state, opaque HttpOnly/Secure cookie, no browser tokens, SAML AuthnRequest/dev-only fixture ACS + Persona review workflow app.test_persona_review14 tests OK; approved-only catalog, teacher/admin queue, approve/reject audit, learner 403 + Voice WS contract app.test_voice_ws5 tests OK; auth guard, audio_start/chunks/audio_end, text_turn, ping, max audio cap + Voice preset/EOT app.test_voice_service9 tests OK; TTS payload, preset fallback, EOT readiness + Voice metadata app.test_session_turn_persistenceaudio_ref/silence_ms/speech_rate/barge_in persisted on learner voice turn + P1 MVP UI E2E npx playwright test e2e/session-mvp.spec.ts --project=chromium-single-run1 passed + Persona review UI E2E npx playwright test e2e/teacher.spec.ts --project=chromium-single-run1 passed; teacher approves pending persona from console + Voice UI synthetic E2E npx playwright test e2e/voice-success.spec.ts --project=chromium-single-run2 passed; direct WS cascade plus Session mic button path with synthetic browser audio + Voice s2s decision memo docs/decisions/voice-s2s-poc.mdcriteria recorded; keep/drop decision remains owner DECIDE + Hanshin data/SSO gate docs/ops/hanshin-data-governance-gate.mdartifact created; written external evidence still required + Resistance engine app.test_state_machine_resistance2 tests OK; empathy vs advice-jump curve fixed + Python compile python -m compileall app engine_gatewayPassed + Phase 3 artifact gates python scripts\check-phase3-artifacts.py --helpPassed; runbook, KPI plan, dataset manifest, privacy audit checker documented + Web build npm run buildPassed + Pages production deploy wrangler pages deploy dist --project-name vignette --branch main0fe8f3cc, source543d48c+ Custom domain assets https://vignette.chanpaca.net/index-D1Z5DH5J.js,index-BA9-xxfn.css+ Legacy Live2D routes /live2d/mao/* / /live2d/haru/* / /live2d/live2dcubismcore.min.js404 + Compose docker compose --env-file .env.example config --quietPassed with dummy required env + Focused E2E admin + db-persistence + voice-success10 passed + Admin manage-users admin.spec.ts --grep manage real server-known usersdesktop/mobile 2 passed + Full E2E PLAYWRIGHT_HOST=127.0.0.1 npx playwright test72 passed + Public auth discovery E2E_PUBLIC_AUTH=1 npx playwright test --list --project=chromium-public-auth2 tests listed + Public readiness public-auth-turn.spec.ts --grep production-safe1 passed + Persona auth boundary GET /personasverified local/public unauth 401 + Public login auth.spec.ts --grep public login1 passed + Public runtime scripts start/watch/install-public-runtime*.ps1parser OK; watchdog check-only path verified + Public API health https://api-vignette.chanpaca.net/healthprod, db true, engine true + Local 5175 login PLAYWRIGHT_BASE_URL=http://127.0.0.1:5175 auth.spec.tsdesktop/mobile passed + Learner/readiness E2E learner.spec.ts + readiness.spec.ts desktop/mobile14 passed + Learner screenshots learn-empty-desktop.png / learn-empty-mobile-compact.pngdocument overflow 0, empty history visible + Session layout/turn session-layout.spec.ts desktop/mobile8 passed + Voice/session focused voice + voice-success + session-layout15 passed + Layout redesign handoff docs/ops/layout-redesign-handoff-2026-06-26.mdsubagent scopes, files, verification, remaining visual review recorded + Layout redesign focused E2E npx playwright test e2e/learner.spec.ts e2e/session-layout.spec.ts e2e/session-review.spec.ts e2e/admin.spec.ts e2e/settings.spec.ts e2e/teacher.spec.ts --project=chromium-desktop --project=chromium-mobile54 passed after isolated Admin tablet flake rerun + Strict layout visual gate npx playwright test e2e/layout-visual-gate.spec.ts --project=chromium-single-run7 passed; 7 screens × 7 widths(390/720/861/900/1024/1280/1440), horizontal overflow 0 + control clip 0, 49 full-page screenshots + Parallel visual quality review workflow layout-visual-quality-review (7 agents)49 screenshots read; per-screen findings(critical 1, major 8+, minor) → fix verdicts + Parallel layout fixes 6 agent team: learner-home/session/review/professor/admin/settings (disjoint files)all fixes applied; npm run typecheckOK; no cross-file conflicts+ Strict gate re-run (post-fix) npx playwright test e2e/layout-visual-gate.spec.ts --project=chromium-single-run7 passed; re-screenshotted 49 + Layout focused E2E re-run (post-fix) learner/session-layout/session-review/admin/settings/teacher × desktop+mobile54 passed; no regression + Adversarial visual verify workflow layout-visual-verify (7 agents)7/7 accept; critical/major resolved, regression 0; minor polish backlog recorded + Engine config 운영값 GET /admin/engine-configclaude_cli / http://127.0.0.1:9099 / gateway-default, durable, source=database (의도값 일치) + Engine gateway probe (live) scripts/probe-engine-gateway.py --base-url http://127.0.0.1:9099 --reuse-runs 2claude_p / opus-4-8; 단일 session_id 2회 reused stream; TTFT 1667–4199ms; cost 누적 0.068→0.123(turns 1→2) + Postgres RLS/audit smoke (live) VIGNETTE_RLS_AUDIT_DSN=…vignette_app… check-postgres-rls-audit.py --write-fixtures5 checks PASS: preflight, learner 세션/턴 격리, teacher cohort 스코프, visible_to evaluator-only 숨김, teacher/admin read audit insert (NOBYPASSRLS app role, fixtures 자동 정리) + Turn cost telemetry (live DB) SELECT … FROM app.turns WHERE actor_kind='client_ai'13 client_ai turns 적재: llm_provider=claude_cli, model=gateway-default, cost_usd 실값(합 $1.22, 평균 $0.094), visible_to 배열. 토큰은 CLI 게이트웨이 특성상 0, cost는 산출 + + Cosmetic polish re-verify 5 polish agents → typecheck + gate + layout E2E re-runtypecheck OK; gate 7 passed; layout focused E2E 54 passed; session-layout 8/8; regression 0 +다음 실행 명령
남은 public OAuth
/turnproof 확보용 명령이다.+-cd D:\workspace\vignette\apps\web npx playwright codegen https://vignette.chanpaca.net/login --save-storage=.\node_modules\.tmp\public-auth.json $env:E2E_PUBLIC_AUTH="1" $env:E2E_PUBLIC_STORAGE_STATE=".\node_modules\.tmp\public-auth.json" .\node_modules\.bin\playwright.cmd test e2e/public-auth-turn.spec.ts --project=chromium-public-auth-cd D:\workspace\vignette +cd D:\workspace\vignette powershell -NoProfile -ExecutionPolicy Bypass -File scripts\start-public-runtime.ps1---이번 세션 live 운영 증거 종합
-OAuth `/turn` proof와 한신대 거버넌스를 제외한 나머지 중 이 환경에서 실증 가능한 항목을 닫았다.
-- 닫은 항목(live 증거): ① engine config 운영값(`claude_cli / 9099 / gateway-default`, durable, db). ② 상주 엔진풀 probe — 단일 session_id 2회 reused stream, TTFT 1667–4199ms, cost 누적 0.068→0.123. ③ Postgres RLS/audit smoke 5 checks PASS(learner 격리·teacher cohort·evaluator-only 숨김·audit insert; NOBYPASSRLS `vignette_app` 역할 프로비저닝, smoke cleanup RLS 버그 수정). ④ turn cost telemetry — `app.turns` client_ai 13행에 provider/model/cost_usd/visible_to 실적재(합 $1.22). ⑤ 레이아웃 시각 게이트 7/7 + 적대적 재검수 7/7 accept. --- 환경 제약으로 이 세션에서 못 닫는 항목(정직 표기): 공개 Google OAuth 실제 `/turn`(owner 지시로 보류) · 한신대 데이터/SSO 거버넌스(owner 지시로 보류) · 음성 live STT/TTS provider·물리 마이크·공개 WSS 50분(provider 키/하드웨어 부재) · 저항엔진 openness 곡선 DB 실증(turn_client_state 0행, 대량 실턴 필요 — 단위테스트로 증명) · claude_cli↔Messages API 폴백 동일성(ANTHROPIC_API_KEY 부재) · 재부팅 후 watchdog smoke(재부팅 불가) · Phase 3 파일럿 게이트(실참여자 필요) · decisions 5건(owner 결정). 운영 원칙상 가짜 증거로 DONE 표기하지 않는다. 전체 추적 목록은 `docs/ops/backlog-2026-06-26.md`(B1 폴리시 · B2 환경제약 · B3 소유자결정 · B4 거버넌스). ++닫은 항목(live 증거): ① engine config 운영값(+claude_cli / 9099 / gateway-default, durable, db). ② 상주 엔진풀 probe — 단일 session_id 2회 reused stream, TTFT 1667–4199ms, cost 누적 0.068→0.123. ③ Postgres RLS/audit smoke 5 checks PASS. ④ turn cost telemetry —app.turnsclient_ai 13행에 provider/model/cost_usd 실적재(합 $1.22). ⑤ 레이아웃 시각 게이트 7/7 + 적대적 재검수 7/7 accept.환경 제약으로 이 세션에서 못 닫는 항목(정직 표기): 공개 Google OAuth 실제+/turn(owner 지시로 보류) · 한신대 데이터/SSO 거버넌스(owner 지시로 보류) · 음성 live STT/TTS provider·물리 마이크·공개 WSS 50분 · 저항엔진 openness 곡선 DB 실증 · claude_cli↔Messages API 폴백 동일성 · 재부팅 후 watchdog smoke · Phase 3 파일럿 게이트 · decisions 5건(owner 결정). 운영 원칙상 가짜 증거로 DONE 표기하지 않는다. 전체 추적:docs/ops/backlog-2026-06-26.md(B1 폴리시 · B2 환경제약 · B3 소유자결정 · B4 거버넌스).++윤찬 결정 필요 상세
람다가 단독으로 정하면 월권인 항목이다. 결정되기 전에는 "완료"가 아니라 조건부로 둔다.
결정 5개조건부 GO 사유+++DECIDEs2s 2차 PoC 채택 여부캐스케이드 1차는 확정.
voice-s2s-poc.md기준표에 따라 비교 리포트가 나온 뒤 유지/폐기를 정한다. 선택지: 캐스케이드만 / s2s 2차 PoC 유지.영향음성 아키텍처, 전송 비용, 로그 보존 방식. 람다 단독 결정 금지.
+DECIDEfast-loop 외부 API 허용 여부로컬 상주 분류기를 기본으로 하되, 외부 Haiku/Solar API 폴백을 허용할지 정한다. 선택지: 로컬 전용 / 외부 폴백 허용.
영향데이터주권, 레이턴시, 장애 대응
+DECIDE재귀학습 fine-tuning 범위1차는 few-shot 자동갱신만 할지, fine-tuning까지 포함할지 결정한다. 선택지: few-shot only / fine-tuning 포함.
영향동의서, 데이터셋 품질, 운영 리스크
+DECIDE자유연습 기본값수정안은 기본 ON + 피드백 권장 배지 + 교수자 토글을 제안한다. 선택지: 기본 ON / 교수자 승인 후 ON.
영향학습자 자율성, 평가 품질, 안전 정책
+DECIDE추가 축어록 수급 규모/일정n=1 시드의 한계를 해소하려면 추가 사례 수급 규모와 일정을 정해야 한다. 선택지: N건 목표/일정 확정.
영향평가 타당도, 페르소나 다양성, Phase 3 측정력
+++완료라고 말하는 기준
- 실제 로그인 기반 E2E 증거가 있어야 한다.
- DB 쿼리나 로그로 저장/권한/비용이 확인되어야 한다.
- 시각 확인만으로 기능 완료를 선언하지 않는다.
+문서 기준
MASTERPLAN은 원본 보존 문서다.MASTERPLAN_REVISIONS가 Phase/IRB/음성 정정 기준이다.dev_dashboard.html은 팀장 판단용 현재판이다.+운영 원칙
- mock/demo 자산은 운영 번들에서 제거한다.
- ignored runtime 파일은 커밋하지 않는다.
- 서버는 목적별 1개씩만 유지한다.
frontenddesign스킬이 있으면 먼저 쓰고, 없으면DESIGN_CONCEPT를 SSOT로 따른다.- UX는
docs/DESIGN_CONCEPT.md를 기준으로 하고, fake 기록/통계는 금지한다.- OAuth secret은 출력하지 않고 환경 파일/인프라 설정에만 둔다.
람다가 단독으로 정하면 월권인 항목이다. 결정되기 전에는 “완료”가 아니라 조건부로 둔다.
-캐스케이드 1차는 확정. `voice-s2s-poc.md` 기준표에 따라 비교 리포트가 나온 뒤 유지/폐기를 정한다.
캐스케이드만 / s2s 2차 PoC 유지
음성 아키텍처, 전송 비용, 로그 보존 방식. 람다 단독 결정 금지.
로컬 상주 분류기를 기본으로 하되, 외부 Haiku/Solar API 폴백을 허용할지 정한다.
로컬 전용 / 외부 폴백 허용
데이터주권, 레이턴시, 장애 대응
1차는 few-shot 자동갱신만 할지, fine-tuning까지 포함할지 결정한다.
few-shot only / fine-tuning 포함
동의서, 데이터셋 품질, 운영 리스크
수정안은 기본 ON + 피드백 권장 배지 + 교수자 토글을 제안한다.
기본 ON / 교수자 승인 후 ON
학습자 자율성, 평가 품질, 안전 정책
n=1 시드의 한계를 해소하려면 추가 사례 수급 규모와 일정을 정해야 한다.
N건 목표/일정 확정
평가 타당도, 페르소나 다양성, Phase 3 측정력
+ 이번 세션은 seed persona 결합 제거, 비개발 fail-closed 설정, compose OAuth 주입, admin 모바일 overflow 수정, persona 인증 경계 보강, 전체 Playwright 재통과, 공개 API prod 전환까지 완료했다. 이번 이어받기에서는 내담자 AI 생성 턴의 provider/model/token/cost 텔레메트리를 /turn, SSE stream, 음성 생성 경로에서 DB app.turns까지 적재하도록 연결했고, gateway stream done/error 계약을 구조화했으며, P1 상담 시작→텍스트 stream→종료→리뷰 피드백 UI E2E와 저항 엔진 정량 회귀 테스트를 추가했다. 이어서 PII 마스킹 게이트 우회 차단, RBAC/IDOR·감사 insert 경로, 음성 paralinguistic 메타 저장, 공개 런타임 watchdog 스크립트와 runbook을 보강했다. 추가로 상주 engine session reuse, SAML provider 스캐폴드, visible_to 런타임 필터, EOT/TTS payload 계약까지 회귀화했다. 백엔드 회귀 테스트는 84개로 재검증했고, 페르소나 승인/반려 API와 교수 콘솔 검수 UI proof를 추가했다. Postgres RLS/audit live smoke checker와 s2s 2차 PoC 판단 메모도 준비했지만, live DB 실행과 s2s 채택 결정은 별도 증거가 필요하다. 이후 로컬 5175 런타임 재기동, admin 사용자 관리 E2E 안정화, 학습자 홈 0회 기록 UX, active session 실제 SSE 스트림 전환, 텍스트/음성 실패 턴 미저장, 직접 URL persona 우회 차단, Live2D demo 자산 제거, AI 운영 fail-closed 보강까지 전체 Playwright로 확인했다. 2026-06-26 15:18 KST 기준 공개 API 터널을 복구한 뒤 전체 Playwright 72개가 desktop/mobile/single-run 모두 통과했다. Cloudflare Pages production 배포 0fe8f3cc도 완료했고, 커스텀 도메인이 새 asset을 서빙하는 것을 확인했다. 과거 Mao/Haru Live2D demo 자산은 repo와 번들에서 제거했고, /live2d/* 운영 경로는 404로 차단했다. 로컬 프로세스는 prod API 8001, engine gateway 9099, cloudflared tunnel 1개만 남기고 dev API와 임시 Vite preview를 내렸다. 이번 라운드에서는 레이아웃 작업을 서브에이전트 전담으로 분리해 세션, 학습자 홈/리뷰, 관리자/교수자, 설정 화면을 overflow 수리 수준이 아니라 실제 작업 화면 재설계 수준으로 갱신했다. 통합 레이아웃 E2E는 desktop/mobile 54개를 최종 통과했고, 자세한 인수인계는 docs/ops/layout-redesign-handoff-2026-06-26.md에 남겼다. 이번 이어받기에서는 핸드오프가 남긴 "실기기 시각 수용"을 엄격한 자동 게이트로 닫았다. 7개 권장 너비(390/720/861/900/1024/1280/1440)에서 7개 재설계 화면의 가로 overflow 0·컨트롤 클립 0을 강제하는 layout-visual-gate.spec.ts(7 passed, 49장 스크린샷)를 만들고, 화면별 1에이전트 병렬 시각 리뷰 → 6개 병렬 수정 에이전트 → 화면별 적대적 재검수까지 돌려 7/7 accept(critical/major 0, 회귀 0)를 확정했다. 학습자홈 1280 3열 가운데 컬럼 붕괴(critical)와 교수 'API 404' raw 배너를 포함한 결함을 모두 해소했고, 레이아웃 항목을 DONE으로 닫았다. 다만 이 HTML은 지금까지 Phase 0 상태판처럼 쓰였고, 아래에 Phase 1 이후 전체 계획을 보강했다. 공개 Google OAuth 실제 /turn 증명만 storageState 캡처 후 남아 있다.
+