vignette/docs/ops/backlog-2026-06-26.md
2026-06-27 18:42:09 +09:00

21 KiB
Raw Blame History

Vignette 백로그 — 2026-06-26

이 세션(레이아웃 시각 수용 마감 + live 운영 증거 라운드) 이후 남은 항목을 한곳에 모은다. 대시보드(docs/dev_dashboard.html)의 상태와 일치한다. 운영 원칙상 가짜 증거로 DONE 표기하지 않으므로, 실증/외부 의존/소유자 결정이 필요한 항목은 여기서 추적한다.

분류: B1 비차단 폴리시 · B2 환경 제약(증거 생산 불가) · B3 소유자 결정 · B4 외부 거버넌스

B0. 원천문서 갭 분석 (2026-06-26 추가) — 한신대 산학협력 원천문서 5종 정독으로 도출한 "부족한 부분"(critical 3 / high 4 / medium+ 6)은 SSOT 대시보드 docs/dev_dashboard.html "원천문서 갭 분석" 섹션과 상세 docs/ops/source-docs-gap-analysis-2026-06-26.md에서 추적한다. C1 사례개념화 산출물, C2 위기개입 프로토콜, C3 이론모드 스레딩은 1차 구조를 만들었다. 콘텐츠 정의는 임상팀(구훈정·어유경) 소유라 코드는 구조를 선제 구축하되 임상 문안과 평가기준은 외부 정의로 받는다.


B1. 비차단 코스메틱 폴리시

  • 공용 셸 사이드바 구분선 전체 높이 — (2026-06-26 처리) .vg-nav border-right(sticky·뷰포트 높이)를 제거하고, .vg-shell__body 컨테이너 배경 하어라인(linear-gradient 1px×100%, --nav-cur로 그리드·구분선 폭 동기화)으로 본문 그리드 전체 높이를 따라가는 세로 구분선을 그린다. 1024 축소폭은 --nav-cur: var(--nav-w-collapsed)로, 720 이하(상단 가로바 전환)는 background-image:none으로 정합. components/shell/shell.css. 검증: npm run typecheck PASS + vite build PASS. 시각 회귀 게이트(gate 7/7 + 포커스 E2E + session-layout 8/8)는 web+api+DB 스택(Docker 미기동·secrets 부재)으로 이 환경 미실행 — 스택 가용 시 1회 시각 확인 권장.
  • 세션 종료 UX와 dark theme SSOT — (2026-06-27 처리) 오발동과 모바일 조작 불안을 줄이기 위해 세션 하단의 드래그형 SlideToEnd를 명시 확인 다이얼로그로 교체했다. Topbar/Settings의 vignette.theme 읽기·저장·data-theme 적용은 apps/web/src/lib/theme.ts 단일 경로로 통합했고, 저장값이 없으면 dark 기본값을 부팅 전에 적용한다. API 기본 preference system은 Settings에서 light로 오해하지 않고 현재 초기 테마를 따른다. 회기 리뷰·설정 포함 주요 페이지의 흰 섹션 잔재도 dark 작업면으로 맞췄다. 검증: npm run typecheck, npm run build, npx playwright test e2e/layout-visual-gate.spec.ts e2e/settings.spec.ts e2e/session-review.spec.ts --project=chromium-desktop --project=chromium-mobile --project=chromium-single-run --workers=1 22 passed.
  • 빈상태 컬럼 높이 여백 — session-review 1280 masonry 우측 컬럼, session-prestart 우측 '진행 초점' 컬럼, learner-home 1440 하단 등 데이터 0건 빈상태에서만 두드러지는 컬럼 높이 불균형/여백. 실데이터면 채워진다. (미착수, 의도적) 0건 전용 시각 균형이라 러닝 앱에서의 시각 반복 없이 블라인드 수정 시 악화 위험 → 스택 가용 시 시각 확인하며 처리. 빈상태 전용 균형 레이아웃 채택 자체가 별도 폴리시 결정.
  • learner-home 로딩 스켈레톤 밀도(390) — (2026-06-26 처리) '연습 대상' 로딩 스켈레톤을 빈 div 단일 셰이머에서 실제 카드 구조(마크 박스 + 이름/메타/요약 2줄 플레이스홀더)를 모사하도록 밀도 보강. LearnerHome.tsx (.lh-skel__box/.lh-skel__line*), reduced-motion 분기 동반 갱신. 검증: npm run typecheck PASS + vite build PASS.

검증 기준: 변경 후 npm run typecheck, e2e/layout-visual-gate.spec.ts(7/7), 레이아웃 포커스 E2E(54), e2e/session-layout.spec.ts(8/8) 무회귀. 이번 dark theme 라운드는 로컬 web+api+DB 스택 가용 상태에서 typecheck/build와 Playwright 묶음 22 passed까지 확인했다.


B2. 환경 제약 — 이 워크스테이션에서 증거 생산 불가

  • vnet.18ka.net 공개 live 전환 — 코드/스크립트는 vnet.18ka.net·api-vnet.18ka.net을 허용하도록 갱신 완료. Tailnet 주소 https://alpaca-home.taile93291.ts.net은 dev-login까지 검증됐고, public OAuth redirect가 로컬/Tailnet 세션으로 붙지 않는 혼선을 막기 위해 Tailnet Google 버튼과 직접 Google 시작 URL은 local_oauth_unavailable로 차단한다. 공개 vnet은 현재 (1) vnet.18ka.net/api-vnet.18ka.net DNS 부재, (2) cloudflared 현재 인증 컨텍스트가 18ka.net zone이 아니라 chanpaca.net zone에 route dns를 생성, (3) Google Console redirect URI https://api-vnet.18ka.net/auth/callback 등록 필요 때문에 live 완료 아님. 현재 prod API 8001 자체는 db:true, engine:true로 건강하다. 상세: docs/ops/tailscale-vnet-runtime-2026-06-27.md.
  • 공개 Google OAuth 실제 /turn proof — 로그인 가능한 계정으로 storageState 캡처 후 E2E_PUBLIC_AUTH=1 + chromium-public-auth 1회 통과 필요. (소유자 지시로 이번엔 보류.)
  • 음성 캐스케이드 live — 실제 Deepgram STT / OpenAI TTS provider 키, 물리 마이크, 공개 WSS 50분 양방향 실측. provider 키/하드웨어 부재로 미실행(백엔드 계약·UI synthetic 경로는 단위/E2E로 증명됨).
  • claude_cli ↔ Messages API 폴백 동일성ANTHROPIC_API_KEY가 있어야 Messages API 경로를 돌려 동일성 검증 가능. claude_cli 경로는 게이트웨이 probe로 live 실측 완료.
  • 저항엔진 openness 곡선 DB 실증 — fast-loop 평가의 client_state_readapp.turn_client_state 적재 경로는 추가됨. 다만 dev DB 실데이터/다수 실턴(real LLM) 기반 openness 곡선 증거는 아직 필요. 현재는 app.test_state_machine_resistance 단위테스트와 app.test_evaluation_persistence 매핑 테스트로 1차 증명.
  • 재부팅 후 watchdog smokewatch-public-runtime.ps1 + Scheduled Task가 재부팅 후 엔진/API/터널을 복구하고 public /turn이 통과하는지 실측. 재부팅 불가로 미실행(parser/ check-only 경로는 확인됨). 2026-06-27 점검에서 아직 DNS가 없는 api-vnet.18ka.net은 기본 watchdog 검사에서 제외했고, 개통 후 -AdditionalPublicHealthUrls로 명시 추가하도록 runbook을 보강했다.
  • 상주 엔진풀 RSS 실측 — probe로 TTFT/세션재사용/cost는 live 확인. 프로세스 RSS(메모리)는 별도 OS 계측 항목으로 남김.

B3. 소유자(윤찬) 결정 필요 — 단독 결정 시 월권

결정되면 대시보드 결정 필요 탭과 관련 Phase 항목을 갱신한다.

  • s2s 2차 PoC 채택 여부 — 캐스케이드만 / s2s 2차 PoC 유지. 영향: 음성 아키텍처·전송 비용·로그 보존. 기준표 docs/decisions/voice-s2s-poc.md.
  • 서비스용 페르소나 음성 모델·권리 정책 — (2026-06-27) P1 서연 음성 아트 PoC는 Higgs v3 무참조 synthetic seed 방식으로 생성(docs/voice-art/p1-seoyeon-higgs-v3-20260627/). 실존 인물/성우 reference 사용 금지 확정. VIGNETTE_VOICE_POC_SAMPLE_TTS=true 개발 플래그로 /voice/ws P1 sample TTS provider에 연결했지만, 서비스 배포 전 선택 필요: Higgs 상업 라이선스 확보 / 동의 받은 reference voice만 사용 / 배포 가능한 대체 TTS provider 채택.
  • fast-loop 외부 API 허용 — 로컬 전용 / 외부 Haiku·Solar 폴백 허용. 영향: 데이터주권·레이턴시·장애 대응.
  • 재귀학습 fine-tuning 범위 — few-shot 자동갱신만 / fine-tuning 포함. 영향: 동의서·데이터셋 품질·운영 리스크.
  • 자유연습 기본값 — 기본 ON(+피드백 권장 배지+교수자 토글) / 교수자 승인 후 ON. 영향: 학습자 자율성·평가 품질·안전 정책.
  • 추가 축어록 수급 규모·일정 — 목표 N건/일정 확정. 영향: 평가 타당도·페르소나 다양성·Phase 3 측정력.

B4. 외부 거버넌스 — 한신대/데이터 steward 서면 증거

  • 한신대 데이터/SSO 거버넌스 게이트 — SSO claim mapping, 추가 축어록 수급, 미성년 원본 활용동의, 개인정보 처리방침. 로컬 문서 골격 docs/ops/hanshin-data-governance-gate.md 준비됨, 외부 서면 증거 필요. (소유자 지시로 이번엔 보류.)

Phase 3 파일럿 게이트 (실참여자 필요)

  • 20명 교육용 파일럿 운영 / 효과성·KPI 측정(SUS·자기효능감·κ/ICC·환각률) / 재귀학습 데이터셋 approved 산출 / 개인정보·동의 감사. 문서/checker와 dry-run exporter는 준비됨(docs/phase3/*, scripts/check-phase3-artifacts.py, scripts/export-recursive-dataset.py). 2026-06-27 checker 강화로 CSV enum, KPI metric required fields, approved export의 PII pass·κ/ICC·withdrawn exclusion·consent scope·file sha256 false-positive 차단을 추가했다. 실제 approved evidence는 파일럿·steward/legal 검수·IAA 통과 시점.

이번 세션에 닫은 것(참고)

  • 레이아웃 시각 수용: 게이트 7/7 + 적대적 재검수 7/7 accept + 코스메틱 폴리시(공용 셸 1건 제외) — DONE.
  • live 운영 증거: engine config 운영값, 상주 엔진풀 probe(TTFT/cost/세션재사용), Postgres RLS/audit smoke 5 checks PASS, turn cost telemetry(app.turns 13행) — DONE.
  • P1 서연 음성 아트 PoC: Higgs v3 무참조 synthetic seed + 5개 정서/속도 변주(mp3/wav) 생성. 실존 reference voice 미사용. /voice/ws에는 dev-only sample TTS provider로 연결했고 live text_turn smoke에서 p1-sample-poc binary 20 chunks/78,573 bytes 수신 확인. 이 provider는 TTS override만 담당한다(마이크/STT는 OpenAI 키 필요). 프로덕션 탑재는 라이선스/권리 결정 전 금지.
  • 부수: RLS smoke 스크립트 cleanup RLS 컨텍스트 버그 수정, vignette_app(NOBYPASSRLS) dev 역할 프로비저닝.
  • 평가 SSOP 2차: TurnRecord.evaluationapp.feedback_scores/turn_technique/turn_client_state/supervisor_comment/alternative_utterance로 정규화 적재·복원하고, submit/stream/voice 저장 경로를 app.turn_runtime으로 공통화했다. 원시 평가 테이블은 evaluator/admin RLS로 제한하고 서버가 evaluator 컨텍스트로 적재한다. app.turns insert는 RETURNING id 확인으로 silent success 제거. 검증: pytest app/test_evaluation_persistence.py -q 6 passed, 관련 회귀 45 passed, pytest app/ 119 passed, pytest engine_gateway/ 7 passed.
  • 계약 SSOT 3차: FastAPI OpenAPI를 apps/web/src/lib/api.gen.ts로 생성하는 npm run generate:api-types와 stale 체크용 npm run check:api-types를 유지한다. TurnResponse/SessionEndResponse에 이어 MeResponse, AuthConfigResponse, ConsentResponse, PersonaSummary, PersonaReviewSummary, admin/user/engine DTO, review leaf DTO, CrisisResourceResponse, teacher safety/growth leaf DTO, LearnerSessionsResponse, SessionReviewResponse, worksheet aggregate, TeacherDashboardResponse, TeacherSessionSummary, TeacherLearnerGrowth를 생성 타입 alias로 전환했다. generated optional/default 차이는 UI form state, notification default helper, 배열 렌더링 fallback으로 흡수한다. 이번 패스에서 .github/workflows/api-contract.yml을 추가해 PR/master push에서 npm run check:api-types가 drift를 막는다. SessionDetail/SessionStart 계열의 stage enum 정리는 후속. 검증: npm run check:api-types, npm run typecheck, npm run build, learner.spec.ts + session-review.spec.ts + teacher.spec.ts + layout-visual-gate.spec.ts 32 passed.
  • 위기게이트 109 1차: 실제 자해·자살 신호는 LLM/엔진 호출 전 중단하고 crisis_resource(109)conversation_stopped를 REST/SSE/voice 응답에 싣는다. app.safety_events detail 적재와 교수자 대시보드 안전 알림 큐까지 연결했다. 안전 이벤트 DB insert payload도 회귀화했다. 임상 문안, 실시간 push/메일, 지역 자원 확장은 후속. 검증: pytest app/test_session_turn_persistence.py app/test_voice_ws.py -q 20 passed, pytest app/test_teacher_dashboard.py app/test_session_turn_persistence.py app/test_voice_ws.py -q 21 passed.
  • 교수자 성장 추적 1차: teacher_dashboard가 정규화된 턴 평가를 기반으로 학습자별 적절성·라포·기술 사용 추이를 집계하고, 교수 콘솔에 최근 회기/항목별 성장 카드와 안전 알림 큐를 함께 표시한다. 검증: pytest app/test_teacher_dashboard.py app/test_session_turn_persistence.py app/test_voice_ws.py -q 21 passed, pytest app/ 119 passed, npm run check:api-types, npm run typecheck, npm run build.
  • 페르소나 저작 CRUD 1차: teacher/admin 전용 POST/GET/PUT /personas/drafts 경로를 추가해 draft 생성·조회·편집·검수요청을 열고, 교수 콘솔에 JSON 초안 작성/불러오기/수정 UI를 연결했다. 승인된 카드만 학습자 catalog에 노출하는 기존 경계는 유지한다. P4~P7 실제 임상 콘텐츠 입력은 후속. 검증: pytest app/test_persona_review.py -q 19 passed, pytest app/ 119 passed, npm run check:api-types, npm run typecheck, npm run build.
  • M1 비언어 이벤트 1차: voice learner turn에 이미 저장하던 audio_ref/silence_ms/speech_rate/barge_in을 리뷰 API nonverbal 이벤트로 노출하고, 회기 리뷰 축어록에 침묵·발화 속도·끼어듦·음성 입력 칩을 표시했다. 한숨·울음 감지와 live 마이크/STT/TTS 실측은 후속. 검증: pytest app/test_session_turn_persistence.py app/test_voice_ws.py -q 17 passed, npm run check:api-types, npm run typecheck, npm run build, session-review.spec.ts 1 passed.
  • M2 다회기 케이스 아크 1차: DB 세션 생성 시 (persona_id, learner_id) 기준 case_profile을 upsert하고, session_no를 트랜잭션 안에서 원자 증가시키며, InProcSession.case_id가 매회 새 runtime_case_id가 아니라 안정 case_id를 가리키게 수정했다. 시작/submit/stream/voice 경로는 직전 session_summary 기반 seed recall을 사용한다. case_digest/pinned_fact 실적재, episodic embedding writer, trajectory 갱신은 후속. 검증: pytest app/test_session_turn_persistence.py app/test_voice_ws.py -q 18 passed, pytest app/ -q 119 passed, npm run check:api-types.
  • C1 사례개념화 워크시트 1차: SessionReviewResponse.caseWorksheet와 리뷰 화면 read-only 카드가 탐색 11항목·호소 5영역·인지삼제/감정·보호/방해·생물심리사회 목표 초안을 축어록 근거 기반으로 제공한다. 편집·DB 저장, 임상 루브릭, AI 추출/채점, 교수자 검수는 후속. 검증: pytest app/test_session_turn_persistence.py -q 15 passed, pytest app/ -q 119 passed, npm run check:api-types, npm run typecheck, npm run build, session-review.spec.ts 1 passed.
  • C3 이론모드 1차: theory_modeTurnContext/sessions/voice/evaluator뿐 아니라 build_turn_messages의 엔진 메시지까지 전달된다. 프론트는 persona.theory_target 기준으로 시작해 humanistic 하드코딩을 제거했다. CBT 체인·이론부합 루브릭·명시적 선택 UI는 후속. 검증: pytest app/test_orchestrator_masking.py app/test_session_turn_persistence.py -q 20 passed, pytest app/ -q 119 passed.
  • M3 인증 claim 1차: Google/SAML/dev-login이 AUTH_EMAIL_COHORT_MAP·AUTH_DOMAIN_COHORT_MAP 및 SAML cohort claim을 cohort_ids로 전달하고, DB app_user.external_id는 provider subject(google:/saml:/dev:) 기반으로 저장한다. 운영 SAML 서명검증, 기관 claim schema/test tenant, deprovisioning audit은 후속. 검증: pytest app/test_auth_providers.py -q 22 passed, pytest app/ -q 119 passed.
  • X2 예산 경고/저비용 평가 라우팅 1차: ADMIN_USAGE_BUDGET_USD 설정값을 기준으로 GET /admin/usagebudget.status=disabled|ok|warn|exceeded, 사용률, 잔여 예산을 반환하고 관리자 콘솔이 예산 상태 배너를 표시한다. 80% 이상 warn, 100% 이상 exceeded. EVALUATOR_FAST_MODEL/EVALUATOR_DEEP_MODEL 설정 시 fast/deep 평가 호출만 해당 모델 override로 gateway에 전달하고, 비워두면 기존 gateway default 라우팅을 유지한다. semantic cache·장기 한도 정책은 후속. 검증: pytest app/test_evaluator_model_routing.py app/test_runtime_policy.py -q 23 passed, pytest app/ -q 122 passed, npm run check:api-types, npm run typecheck.
  • H4 LLM call audit 1차: 상담 생성(generate/stream)·fast-loop 평가·deep-loop 평가의 외부 LLM 호출 직후 audit.llm_call_log에 provider/model/token/cost/inference_geo/latency metadata만 적재한다. prompt/completion 본문은 저장하지 않고 감사 실패는 상담 루프를 막지 않는다. 로컬 dev-login 실제 /turn smoke에서 audit.llm_call_log가 8→11로 3행 증가했다(session 2460d56c-a9cb-4a40-a175-9575d510a5e9). 공개 Google OAuth 실제 /turn proof는 별도 B2 항목에 남긴다. 검증: pytest app/test_orchestrator_masking.py app/test_evaluation_persistence.py app/test_session_turn_persistence.py -q 27 passed, pytest app/ -q 119 passed.
  • H4 동의 게이트 1차: app_user.consent_at를 런타임 테이블 readiness와 SessionUser/Principal에 포함하고, learner 전용 POST /auth/consent·DELETE /auth/consent를 추가했다. 동의가 없는 learner는 POST /sessions와 voice dev persona 시작이 consent_required로 막히고, 프론트 세션 시작 전 동의 체크 UI가 먼저 저장하도록 안내한다. E2E dev-login helper는 세션 테스트 전에 동의를 seed한다. 한국어 이름/기관 NER, guardian/legal 서명 동의서 evidence, 공개 Google OAuth 실제 /turn proof는 후속. 검증: pytest app/ -q 125 passed, pytest app/test_auth_providers.py app/test_session_turn_persistence.py app/test_persona_review.py app/test_voice_ws.py -q 64 passed, npm run check:api-types, npm run typecheck, npm run build, local /sessions no-consent 403 + /auth/consent 200.
  • RAG warm 동시성 안정화: layout/session E2E가 여러 세션을 빠르게 만들 때 BGE-M3 embedder가 동시에 여러 번 지연 로드되며 tqdm lock 예외와 API health/dev-login timeout이 반복됐다. rag.py에서 embedder load/encode를 process-wide RLock으로 직렬화하고, sessions.py_warm_rag_caches를 semaphore 1개로 제한해 warm task가 상담 요청 경로를 막지 않도록 했다. 검증: pytest app/ -q 125 passed, npx playwright test e2e/layout-visual-gate.spec.ts e2e/session-layout.spec.ts --project=chromium-single-run --project=chromium-desktop --workers=1 11 passed.
  • 공개/로컬/Tailnet 로그인 복구: public API 530 원인은 prod에서 개발 전용 VIGNETTE_VOICE_POC_SAMPLE_TTS=true가 fail-close된 것과 DB app.admin_engine_config 기본 행 부재였다. 2026-06-27 모바일 502는 cloudflared 로그의 127.0.0.1:8001 origin refused와 일치했다. scripts/start-public-runtime.ps1는 public prod 기동 시 샘플 TTS를 강제로 끄고, 운영 DB에는 claude_cli/127.0.0.1:9099 engine config 행을 복구했다. 추가로 dev/Tailnet에서는 public OAuth callback이 로컬/Tailnet 세션으로 붙지 않으므로 Google 버튼과 직접 시작 URL을 local_oauth_unavailable로 차단하고 dev-login만 사용한다. public OAuth state는 HttpOnly 쿠키에 묶인 HMAC 서명 토큰으로 복구해 API 재시작 뒤 콜백이 invalid_state로 떨어지지 않는다. callback 실패는 비밀값 없는 reason/status로 남기고, 로그인 화면도 token/state/provider/identity 실패 메시지와 reason code를 분리한다. 2026-06-27 18:25 KST에 stale Vite allowedHosts로 생긴 Tailnet 403을 scripts/start-tailscale-runtime.ps1 재기동으로 복구했다. 검증: https://vignette.chanpaca.net/login 200, https://api-vignette.chanpaca.net/health prod/db/engine true, public Google auth redirect 302 + HttpOnly state cookie, provider callback error → /login?oauth=access_denied, https://alpaca-home.taile93291.ts.net/login 200 + /api/health dev/db/engine true + /api/auth/config 200, local/Tailnet Google direct는 local_oauth_unavailable, local auth E2E 7 passed, Tailnet auth/dev-login E2E 2 passed.
  • Docker dev DB 안전장치: scripts/dev-up.ps1vignette-dev-db healthcheck/pg_isready/role safety를 점검하고, 새 컨테이너 생성 시 vignette_owner와 앱 role을 분리해 healthcheck를 붙인다. infra\.env compose 필수값 누락도 사전 경고한다. scripts/dev-down.ps1은 기본 DB 보존, -Db 지정 시 컨테이너 중지로 정리했다. 검증: 현재 Docker DB accepting connections, vignette_app:false:false, 기존 컨테이너 healthcheck 없음. 추가 확인 결과 기존 DB는 POSTGRES_USER=vignette 기반이고 API startup DDL이 owner 권한을 요구해 런타임 app-role 전환은 마이그레이션 owner/런타임 role 분리 후 진행해야 한다.