상담자 발화 판정(A)·감정(B)·표현(C) 20문항 질문 세트, 감쇠 없는 이번 턴 반응과 비대칭 기분 전이, 개방도 게이트로 생성 지시를 만들고 ccd.coping_strategy 전달 누락을 고친다.
trace v2와 고정 문구 속마음 요약(migration 24, AI 경로 차단 RLS)을 같은 트랜잭션에 저장하고 피드백 정책이 켜진 경우에만 done·TurnResponse·음성 reply·리뷰로 노출한다. 회기 화면 속마음 보기 토글, 리뷰 접힘 블록, 관리자 감정 관측 v2 표시를 추가한다.
/personas·/admin 응답에 Cache-Control: no-store를 강제한다. E2E에서
미인증 /personas 요청이 일시적으로 인증 응답 본문을 받은 재현 이력이
있어 중간 캐시 재사용을 원천 차단한다.
public-admin-visual 카탈로그 테스트는 운영 데이터에 따라 바뀌는 원장
모델명(claude-opus-4-8 → gpt-5.6-terra)과 엔진 옵션 수(6→9), 모델 수
문구를 고정값으로 기대했어 데이터 종속 실패였다. 계량 행·개수 정규식으로
갱신한다.
claude(setup-token과 동일한 PKCE, code#state 수동 흐름)와
openrouter(헤드리스 코드 표시 모드)는 OAuth 로그인 버튼으로 연결한다.
관리자가 제공자 로그인 뒤 표시되는 인증 코드를 붙여넣으면 서버가
토큰/키로 교환해 저장·게이트웨이 push한다. state는 서버 발급·15분
단일 사용으로 CSRF를 막는다. codex·agy는 붙여넣기 방식을 유지한다.
제공자 연결 패널은 우측 사이드에서 메인 컬럼의 Provider·모델별 사용
원장 아래로 옮기고 반응형 그리드(너비에 따라 1~n열)로 배치한다.
앱 DB 계정에는 스키마 CREATE 권한이 없어 런타임 CREATE TABLE IF NOT
EXISTS가 테이블이 이미 있어도 권한 거부로 실패한다(운영 실측). to_regclass
존재 검사를 먼저 하고, 부트스트랩 SQL(05_runtime_auth.sql)에 DDL을 추가해
신규 볼륨에서도 소유자가 테이블을 만들도록 한다.
관리자 /admin/ai 화면에서 provider 토큰(OAuth 액세스 토큰 또는 API 키)을
발급받아 붙여넣으면 DB에 암호화 저장되고, shared-secret으로 보호되는
게이트웨이 내부 엔드포인트로 push되어 실행 중인 엔진 컨테이너에 즉시
적용된다. NAS처럼 게이트웨이가 컨테이너로 도는 환경에서 CLI·로컬 PC
의존 없이 claude_api·openai·openrouter를 연결할 수 있다.
- 게이트웨이: openrouter 어댑터 신설(chat/completions), OAuth 토큰이면
Anthropic Bearer 헤더, /internal/provider-credentials GET/POST와
boot_id 기반 재동기화
- API: app.admin_provider_credential 테이블(idempotent DDL), stdlib
HMAC-CTR+MAC 암호화 서비스(PROVIDER_CREDENTIAL_SECRET, 폴백
SESSION_SECRET), /admin/providers CRUD·검증 라우트
- 웹: 제공자 연결 패널(저장·검증·해제, 토큰 힌트만 표시), 엔진 선택에
OpenRouter 추가, api.gen.ts 재생성
- compose: api 서비스에 PROVIDER_CREDENTIAL_SECRET 전달(로컬·NAS)
공개 /sessions/{id}/end 503(2026-08-18 실측): app.pinned_fact RLS는 learner 역할에
INSERT(소유 케이스)만 허용하고 SELECT/UPDATE는 AI 컨텍스트 또는 admin/instructor
전용이다. end_session이 learner 연결로 SELECT FOR UPDATE + INSERT ON CONFLICT
DO UPDATE 조합을 돌려 충돌 후보 행 가시성이 막히며 InsufficientPrivilegeError로
실패했고, fallback 차단이 503으로 노출됐다. 엔진이 건강해 deep 평가가 처음으로
pinned 팩트를 반환한 순간 발화한 잠복 결함이다.
- _upsert_pinned_fact_candidates_with_ai_view: 같은 learner uid 로
acquire(ai_view='evaluator') 를 열어 INSERT/SELECT/UPDATE 정책을 모두 충족
- 검증: 공개 DB에서 롤백 재현 — learner 컨텍스트 upsert RLS 거부,
ai_view evaluator 컨텍스트 동일 SQL 통과. app 924 passed·관련 62 passed
공개 런타임 승격 체인이 psutil로 이전 프로세스 환경을 통째로 이식하는 과정에서
SystemRoot 가 유실됐고, Go 계열 CLI(agy)는 시스템 인증서 풀/홈 해석에 SystemRoot 가
필요해 agy models 가 조용히 빈 목록을 반환했다(관리자 AI 운영 화면의
'Agy가 선택 가능한 모델을 반환하지 않았습니다' 두 번째 원인).
- _cli_subprocess_env(): 상속 환경에서 빠진 SystemRoot/SystemDrive/ComSpec 만
기본값으로 백필해 모든 CLI 스폰(_run_process·codex app-server·agy stream·claude 세션)에 적용.
os.environ 의 Windows 대문자 정규화를 고려한 대소문자 무시 조회
- Set-CompleteProcessEnvironment: 이식본에 빠진 Windows 필수 키를 Machine 스코프
표준값으로 병합해 승격 체인 자체의 유실을 원천 보강
- 검증: 신규 2단위 RED→GREEN, engine_gateway 65 passed, app 924 passed,
PS 5.1 parser OK, SystemRoot 제거 환경에서 실제 agy CLI 14모델 live 조회 확인
agy CLI가 2026-08부터 'agy models'를 'model_id<TAB>라벨' 형태로 출력하는데
_discover_agy_cli가 공백 포함 줄을 전부 버려 카탈로그가 비어 available=false가 됐다
(관리자 AI 운영 화면에서 'Agy가 선택 가능한 모델을 반환하지 않았습니다').
- 탭 줄은 왼쪽 토큰을 id로, CLI 라벨을 우선 적용. 탭 없는 공백 줄(상태 문구)은 계속 무시하고
구형 베어 id 출력 계약 유지 — 형식 이중 호환
- _binary가 PATH에 없어도 LOCALAPPDATA agy bin 표준 설치 경로를 폴백으로 탐색
- 검증: 신규 탭 형식 회귀 RED→GREEN, engine_gateway 63 passed, 실제 agy CLI로
15모델 live 조회 확인(default gemini-3.6-flash-high)
Higgs Audio v3 는 연구/비상업 라이선스라 config.py 가 environment != dev 에서
차단하고 있었다. 그 가드를 푸는 건 법적 판단이라 코드로 결정할 수 없어서,
상업 사용이 허용된 설치형을 다시 찾아 MeloTTS Korean 으로 바꿨다. 결과적으로
가드를 건드릴 필요 자체가 사라졌다 — Higgs 가드는 그대로 두고 provider 만
melotts 로 두면 운영에서도 동작한다.
검토 결과:
- MeloTTS MIT 한국어 지원 -> 채택. CPU 실시간, 사전학습 다화자
- Kokoro-82M Apache2.0 한국어 없음 -> 탈락. 공식 VOICES.md 언어 목록에 부재
- Piper GPL -> 탈락
- XTTS-v2 / Fish Speech 비상업 -> 탈락. Higgs 와 같은 문제
사전학습 다화자 모델이라 실존 인물 reference 를 쓰지 않는다. Higgs 경로가
P1 프리셋 한정이던 이유가 없으므로 모든 페르소나 프리셋에 적용된다.
구현:
- scripts/melotts-server.py loopback HTTP 사이드카(/health, POST /tts -> WAV)
- voice_tts_provider=melotts 경로와 VIGNETTE_MELOTTS_TTS_* 설정
- scripts/start-melotts.ps1 런처(설치 순서 안내 포함)
실측:
- CPU 정상 상태 RTF 0.27~0.28(실시간 3.6배). 첫 실행 13.25 는 모델 다운로드
- POST /tts 200, WAV 350,566 bytes, 3.61s, 헤더 provider/model/license
- 빈 텍스트 422, 미지 경로 404 로 fail-closed
- 왕복 검증: MeloTTS 합성음을 로컬 faster-whisper 가 완전 일치 전사
"그렇게 느끼셨군요. 조금 더 이야기해 주실 수 있을까요?" (word timestamp 8개)
설치 함정 3가지를 decisions/local-voice-stack.md 에 남겼다.
librosa 0.9.1 의 pkg_resources(setuptools<81), MeloTTS 가 언어와 무관하게
임포트하는 일본어 unidic 사전, Windows 한국어 g2p 의 eunjeon.
G7 게이트의 TTS 허용목록에 melotts 를 추가했다. 선언/실제 불일치 차단과
배치 STT 배제는 그대로다.
검증: API 914 passed, 사이드카 melotts 16/16 + whisper 37/37, SSOT FAIL 0, ruff clean.
8월 7일까지 워킹트리에만 남아 있던 미커밋 작업을 커밋한다. 여러 사본
폴더(worktree·clone)에 흩어져 있던 중간 스냅샷을 정리하기 전에 원본을
git 이력으로 고정하는 것이 목적이다.
- contracts/routes/services: measurement, outcome_trajectory, rupture_repair,
deliberate_practice, calibration_transfer, supervision_research,
multimodal_alliance, continuous_improvement 계열 신규 모듈과 테스트
- infra/db/init: 07~16 마이그레이션(측정 기반~calibration transfer 실행)
- apps/web: 세션 리뷰 카드·관리 화면·E2E 스펙 추가
- docs/ops: G0~G8 라이브 통합·배포·롤백 증거 문서와 evidence JSON/PNG
- scripts: smoke·ledger·릴리스 에이전트·NAS 프리뷰 운영 스크립트
engine.public 로그 .bak과 apps/web/test-results 산출물은 커밋에서 제외했다.
- 전수 순회: IA 전 라우트 412개 기능 인벤토리를 체크리스트 백로그로 관리
(docs/ops/e2e-full-sweep-2026-07-27.md), 신규 full-sweep 스펙 10파일 추가.
RED→GREEN으로 결함 12건 수정: 관리자 무한 렌더 프리즈(TanStack autoReset
루프), 복수 코호트 저장 유실, 페르소나 보관 503(SQL 컬럼 모호성), PII 과잉
마스킹, /admin/ai watchdog 오탐 오버레이, 모바일 겹침 2건, 설정 스크롤
스파이, 온보딩 전화번호 무검증, 리뷰 조사·난도 라벨, pending 피드백 등.
- 소유자 결정 구현: 설정 아바타 변경, 동의 철회·재동의 전체 흐름, 신규
학습자 기초 우선 추천, 학생 분석 테이블 가상화(@tanstack/react-virtual),
저작 모드 죽은 레일 정리, 감정 밸런스 타임라인 차트(deep turn_valence +
결정론 파생 폴백).
- 디자인 감사(142차): 라이트 팔레트 AA 대비, 다크 토큰 별칭 통일, 미정의
CSS 변수 정리, 한글 keep-all 전역화, 탭 타깃 24px, LCP preconnect.
- 검증: npm run e2e 병렬 432 수집 GREEN + 직렬 49/49 exit 0, 백엔드 pytest
421, gateway 29, typecheck/build/design-ssot/dead-code/중복 게이트 통과,
layout-visual-gate 15/15, session-layout 8/8. 상세는 SSOT 대시보드
142~144차 노트.