# 학생 자기주도 전체 루프 UI 증거 — 2026-08-07 ## 결론 실제 `apps/web/src` 제품 화면에서 학습자 홈의 목표 추천부터 페르소나 선택, 회기 목표 설정, 텍스트 회기 진행, 회기 종료와 리뷰, G4 처방 카드, 처방을 이어받은 새 회기 시작까지 하나의 브라우저 상태 흐름으로 연결했다. 데스크톱과 모바일 각각 1회, 합계 **2/2 passed**다. 이 증거는 로그인 없는 결정론 **route fixture UI 계약**이다. `/api/**`를 먼저 404로 닫고 테스트가 소유한 경로만 응답하므로 실제 API나 개발 DB를 사용하지 않는다. 실제 PostgreSQL production caller가 ready 평가와 durable turn에서 G4 처방 원장을 만드는 증거는 `outcome-os-g4-g5-production-caller-evidence-2026-08-07.md`가 별도로 소유한다. 두 증거를 합쳐 “브라우저 전체 루프가 실 DB에서 통과했다”고 주장하지 않는다. ## 검증한 제품 흐름 1. `/learn`에서 첫 회기 AI 코치와 `난도 확장 검토` 추천을 확인한다. 2. `연습 시작하기`로 `/learn/practice`에 진입해 P1을 고른다. 3. `/learn/session/P1`에서 인간중심 모드와 라포·탐색·개입 목표를 선택한다. 4. 실제 `Session.tsx` 활성 화면에서 텍스트 발화를 보내고 SSE 내담자 응답과 탐색 단계 전환을 확인한다. 5. 회기를 종료하고 `/review`에서 저장 축어록 기반 평가 요약과 G4 공감적 반영 처방을 확인한다. 6. 키보드 Enter로 `이 처방으로 연습 시작`을 실행한다. 7. 학습 홈과 새 회기 사전 설정에서 원본 회기 출처, 사용자용 판정 기준, 익숙한 장면, replay 모드가 보존되는지 확인한다. 원본 UUID와 내부 criterion/counterevidence 키는 화면에 노출하지 않는다. 8. 새 회기를 시작한 뒤 URL의 typed launch intent, 두 번째 시작 요청, 활성 화면의 `data-practice-mode="replay"`가 유지되는지 확인한다. ## Fixture 경계 - 실제 제품 코드: `LearnerHome.tsx`, `Session.tsx`, `SessionReview.tsx`, 제품 라우터와 CSS를 브라우저에서 실행한다. - fixture 소유 API: `auth/me`, `personas`, `sessions` 목록·대시보드·시작·상세·stream·end·review, `practice/learners/me`, pre/post measure, alliance pulse, live coach, voice health다. - 소유하지 않은 모든 `/api/**`: fixture 404. 실 API로 조용히 폴백하지 않는다. - 인증: `auth/me` fixture만 사용한다. 실제 사용자 로그인이나 저장된 세션을 사용하지 않는다. - 음성: voice health를 unavailable로 고정한다. 물리 마이크를 열거나 장치를 열거하지 않는다. - 데이터: 화면의 `source=database` 페르소나 표시는 API 계약값을 재현한 fixture 필드일 뿐 실 DB 증거가 아니다. ## 자동 검증 ```powershell cd apps/web npx playwright test e2e/self-directed-learning-loop.spec.ts ` --project=chromium-desktop --project=chromium-mobile --workers=1 --reporter=dot # 2 passed (18.8s) npm run typecheck # passed ``` 테스트는 각 단계에서 페이지 가로 overflow 0, 홈 핵심 CTA 44px 이상·텍스트 대비 4.5:1 이상, 처방 CTA 키보드 실행, 시작 요청 payload와 launch intent 구조를 단언한다. 자동화 과정에서 홈 `연습 시작하기`가 40px로 렌더되는 결함을 발견해 `learner-home.css`의 최소 높이를 44px로 올렸다. 리뷰·학습 홈·사전 설정에서는 `criterion.reflect-and-check`, `unseen_transfer_not_verified`, 원본 회기 UUID, `humanistic, cbt`가 보이지 않고 각각 사용자용 한국어 기준·근거·출처·이론명으로 표시되는지도 금지 문자열과 허용 문자열을 함께 단언한다. ## 데스크톱·모바일 시각 QA 직접 확인한 고정 캡처: - `evidence/self-directed-loop-home-chromium-desktop-2026-08-07.png` - `evidence/self-directed-loop-home-chromium-mobile-2026-08-07.png` - `evidence/self-directed-loop-active-session-chromium-desktop-2026-08-07.png` - `evidence/self-directed-loop-active-session-chromium-mobile-2026-08-07.png` - `evidence/self-directed-loop-active-session-320x568-chromium-mobile-2026-08-07.png` - `evidence/self-directed-loop-review-prescription-chromium-desktop-2026-08-07.png` - `evidence/self-directed-loop-review-prescription-chromium-mobile-2026-08-07.png` - `evidence/self-directed-loop-repractice-prestart-chromium-desktop-2026-08-07.png` - `evidence/self-directed-loop-repractice-prestart-chromium-mobile-2026-08-07.png` 데스크톱에서는 홈 추천, 3열 활성 회기, 리뷰 처방과 실행 CTA, 재연습 브리핑이 잘림 없이 읽힌다. 모바일에서는 홈 CTA, 처방의 방식·장면·기준, 재연습 출처가 단일 열로 유지되고 페이지 가로 overflow는 없다. 활성 회기는 390×844와 320×568을 각각 렌더해 아바타/내담자 문구 겹침 0, 중복 상태 배지 숨김, 최신 내담자 발화 완전 노출, 축어록 스크롤·텍스트 입력창의 카드 내부 포함을 수치로 고정했다. 320×568은 실시간 대화를 우선해 시작 전 확인한 호소·이론 요약만 접고 핵심 진행·내담자·마이크 상태는 유지한다. 후속 B1 시각 폴리시였던 리뷰 1~5 척도는 360px 이하에서 의미 순서를 유지한 3+2 배열로 전환했다. 320×568 실측에서 다섯 선택지가 모두 44px 이상이고 척도 내부와 페이지 가로 overflow가 0임을 확인했으며, `alliance-pulse.spec.ts` desktop/mobile 전체 **8/8 passed**와 척도 고정 캡처를 직접 확인했다. 기존 `session-layout.spec.ts` 모바일 레이아웃 2개 focused 재검증은 화면 경계 단언에 도달하기 전, 공통 pre Alliance 체크포인트 라디오가 React 재렌더로 교체되며 Playwright `.check()`가 안정화되지 않아 각 30초 타임아웃됐다. 이 실패를 레이아웃 통과로 세지 않았고, G1 소유 체크포인트 안정성 문제와 이 문서의 route-fixture 시각 게이트를 분리한다. ## 남은 증거 한계 - 실제 사용자 로그인 + source API + dev DB를 한 브라우저에서 관통한 E2E는 아니다. - 실제 provider 응답, 물리 마이크, 배포·공개 URL 증거가 아니다. - route fixture의 처방은 `unassessed` 상태이며 mastery, unseen transfer, 임상 효과를 주장하지 않는다. - 실 DB production caller 증거와 이 UI 증거는 서버 생산 경계와 화면 소비 경계를 각각 증명한다. 둘을 잇는 인증된 DB-backed 브라우저 폐루프는 별도 게이트다.