정식 승격 상태판과 증거를 동기화

This commit is contained in:
Yun Chan 2026-08-30 00:06:45 +09:00
parent 34aff65cb0
commit be08c0b573
16 changed files with 1160 additions and 63 deletions

View file

@ -291,7 +291,7 @@
<div class="brand"><span class="mark" aria-hidden="true"></span><span>Vignette 커맨드센터<small>팀장 리뷰 · dev status</small></span></div>
<div class="head-right">
<a class="owner-pill" href="#owner"><span class="d" aria-hidden="true"></span>내 차례 <b id="pill-owner">0</b></a>
<span class="stamp">2026-08-28 KST</span>
<span class="stamp">2026-08-29 KST</span>
</div>
</header>
@ -300,11 +300,13 @@
<section class="pulse">
<div class="pulse-main">
<span class="eyebrow">project pulse</span>
<h1>지금 위치: <em>G0~G6 · G8 증거 DONE</em>. <em>G7 external proof · C-001 · 재부팅 실증</em> 남았다.</h1>
<p class="pulse-state"><b>현재:</b> 공개 앱·API·DB와 current NAS 실회기는 GREEN이고 재부팅 복구 task 계약도 보강했다. <b>다음:</b> 새 Pages 후보 명시 승인 → 실제 Windows 재부팅 자동복구 → G7 mic·human proof.</p>
<h1>지금 위치: <em>공개 정적 Web은 유지</em>, <em>Public API·DB는 OUTAGE</em>. 이미지 fail-closed 후보·E2E와 C-001·REQ-008 사람 게이트가 남았다.</h1>
<p class="pulse-state"><b>현재:</b> 배포된 API/task 기준선은 <code>dba9b75a…</code>, Pages는 <code>0c60261e…</code>(source <code>5bf89ff…</code>)지만 Docker daemon 부재로 local 8001은 연결 거부, public API는 530이다. 아바타 decode fail-closed 변경은 후보 코드일 뿐 미배포라 운영 GREEN이 아니다. G8 차단·보류·반려·승인의 격리 local 내장 브라우저 proof는 GREEN이다. <b>다음:</b> 전체 통합 GREEN과 G8 실DB/public proof를 확인한 뒤 push/Pages/runtime/task 전환 승인을 받고, 실제 재부팅은 별도 승인으로 실행한다.</p>
<details class="pulse-details">
<summary>운영 복구·watchdog·배포 상세 보기</summary>
<p class="pulse-state"><b>2026-08-28 재부팅 복구 hardening:</b> 로그온·5분 watchdog을 detached-clean <code>99779a6a…fbc8</code>·tree <code>57da86aa…6b91</code>에 재등록했다. 두 task는 <code>ExecutionTimeLimit=PT1H</code>·<code>MultipleInstances=IgnoreNew</code>이고 scheduler 이중 재시도는 제거했다. launcher는 exclusive mutex, API 180초·voice 90초·web build 600초 상한, timeout 시 parent+child process-tree 종료를 적용했고 watchdog은 cloudflared 누락 또는 API/web/voice-sidecar 전체 다운을 debounce 없이 즉시 복구한다. focused 회귀 <code>50 passed</code>, watchdog 18:10:57 KST·boot 18:14:27 KST 수동 실행 결과 0·failcount 0을 확인했다. 이것은 로그인 뒤 복구 증거이며 실제 Windows 재부팅 smoke와 PC 비종속 상시 호스트 이전은 여전히 별도 gate다.</p>
<p class="pulse-state"><b>2026-08-29 최신 read-only 상태:</b> <code>VignettePublicRuntime</code>과 watchdog은 여전히 old <code>dba9b75a…</code> root를 가리키며, Docker Desktop Linux engine pipe가 없어 DB/API 복구에 실패한다. 정적 로그인 Web 200은 동적 API 정상 증거가 아니다. 운영 변경 승인 전에는 Docker 시작·API/tunnel 재시작·task 재등록·DB/avatar URL 수정·stable upload root cutover를 하지 않는다.</p>
<p class="pulse-state"><b>2026-08-29 아바타 무결성:</b> 허용 source union은 <code>93 objects · 52,973 bytes · SHA-256 9d703126…e6aa</code>다. 실제 decode는 정상 3·실패 90, 현 DB 참조는 정상 2·실패 6·missing 0이다. 후보는 손상 bytes와 참조를 private forensic으로 보존하되 public serve는 404/fallback으로 막고, decode-valid 객체만 immutable public cache에 싣는다. 이 후보는 전체 API/Web/E2E·내장 브라우저·운영 배포 검증 전까지 GREEN이 아니다.</p>
<p class="pulse-state"><b>2026-08-29 재부팅 복구 hardening의 이전 성공 증거:</b> Windows PowerShell 5.1의 timed <code>WaitForExit()</code>가 process handle 선확보 없이는 성공한 web build의 <code>ExitCode</code>를 null로 남겨 실패로 오판하는 경계를 수정했다. 실제 PS5.1 계약 <code>32 passed</code>, detached-clean <code>44b7835c…</code>·tree <code>06133249…</code>에 로그온·5분 watchdog을 같은 핀으로 재등록했다. 당시 watchdog 3회차 복구로 5174가 자동 기동해 HTTP 200을 반환했고 후속 실행은 <code>LastTaskResult=0</code>·failcount 0, local/public health <code>status=ok·db=true·engine=true</code>였다. 기존 <code>ExecutionTimeLimit=PT1H</code>·<code>MultipleInstances=IgnoreNew</code>·exclusive mutex·bounded wait·process-tree 종료·hard-down 즉시복구 계약도 유지한다. 이것은 로그인 뒤 과거 복구 증거이며 현재 장애나 실제 Windows 재부팅 smoke를 대신하지 않는다.</p>
<p class="pulse-state"><b>2026-08-27 Docker stale socket 인시던트·복구:</b> 공개 로그인 화면은 유지됐지만 API가 <code>db=false</code> degraded 뒤 502가 됐다. 원인은 Docker Desktop 4.82.0 백엔드가 이전 비정상 종료에서 남은 0바이트 AF_UNIX reparse socket <code>Docker\run\dockerInference</code><code>docker-secrets-engine\engine.sock</code>을 ERROR 1920으로 제거하지 못해 startup crash-loop한 결함이다. Docker 전체 종료 후 두 부모 IPC 디렉터리를 <code>run.stale-20260827-232006</code>·<code>docker-secrets-engine.stale-20260827-232006</code>으로 이동해 복구 가능하게 보존했고, container·image·volume 생성/삭제/교체 없이 기존 <code>vignette-dev-db</code><code>vignette_recovered_prod_20260807</code>만 시작했다. API는 detached-clean <code>bf5f7352…0092</code>·tree <code>c39f917b…c88</code>에서 routine API-only 복구했고 public health 3/3 <code>status=ok·db=true·engine=true</code>를 확인했다. 로그온·5분 watchdog도 같은 root/commit/tree와 exact boot/watchdog/start SHA에 재등록했으며 watchdog <code>LastTaskResult=0</code>·failcount <code>0</code>이다. 실제 공개 로그인 브라우저는 console error/warning 0이다. authenticated public <code>/turn</code>은 2026-08-28 폐루프를 통과했고 실제 Windows 재부팅만 별도 gate다.</p>
<p class="pulse-state"><b>2026-08-18 엔진 readiness 장애·수정:</b> 06:30~10:05 KST 공개 API가 <code>engine=false</code>로 약 3.5시간 degraded였다. 원인은 (1) <code>reasoning_effort=high</code> 콜드 프로브가 20초 타임아웃을 넘기면 실패가 성공과 같은 TTL(운영 1800초)로 캐시되는 게이트웨이 결함, (2) 공개 엔진 <code>claude -p</code>가 소유자 Claude 구독을 개발 에이전트 작업과 공유해 사용량 한도 소진 시 생성이 실패하는 운영 경계다. 워치독은 기본 <code>/ready</code>의 캐시 200만 보고 엔진을 healthy로 오판해 API만 재시작하는 루프에 빠졌다. 수정: 실패 전용 <code>ENGINE_READY_FAILURE_TTL_SECONDS</code>(기본 30초) 분리 + 프로브 타임아웃 20→45초, 회귀 4건 신설(게이트웨이 62/62·backend 986). detached-clean <code>4771b97c…c880</code>·tree <code>286723de…c1fa</code>로 API/게이트웨이/워치독·부트 task를 재승격·재등록했고 명시 실행 <code>LastTaskResult=0</code>, 공개 health ok·OpenAPI 126·local voice exact를 재확인했다. 1차 승격은 새 worktree에 <code>apps/api/.env</code>(gitignored 비밀값)가 없어 fail-closed로 실패했다 — 승격 절차에 env 이관 단계가 필요함을 기록한다(약 4분 다운타임).</p>
<p class="pulse-state"><b>2026-08-12 인시던트(NAS relay 복구 대기):</b> 공개 API는 health ok·db/engine true·OpenAPI 126·auth 401과 local voice를 유지한다. NAS 프리뷰는 앞선 3/3 <code>degraded·db=true·engine=false</code>에서 15:24 KST local health 3회 타임아웃으로 악화됐고 정적 로그인 화면만 계속 보인다. NAS API의 고정 <code>ENGINE_URL=http://192.168.0.223:9100</code> 대상 listener가 사라졌으며 공개 엔진은 별도 loopback <code>127.0.0.1:9099</code>에서 정상이다. G8 clean-head candidate 112/112·실제 origin 112/112와 rollback receipt는 완료 증거로 보존하지만, 현 NAS runtime은 relay를 source/secret/task에 결속해 복구하고 health 3/3·auth·OpenAPI·assets·실제 회기를 다시 통과할 때까지 DEGRADED다. 자동 재시작·포트 노출·배포는 실행하지 않았다. G7은 별도로 명시 동의 mic·동시 high-water·human evidence가 남는다.</p>
@ -318,9 +320,13 @@
<span class="mchip good">Outcome clean E2E <b>126</b> · visual <b>15/15</b></span>
<span class="mchip good">Alliance G1 baseline 1.2 <b>9/9</b> · 내부 DONE</span>
<span class="mchip">Tailnet <b>이전 확인 OK</b></span>
<span class="mchip good">Public API <b>126 paths · G1~G8</b></span>
<span class="mchip crit">Public API <b>OUTAGE · 530/local refused</b></span>
<span class="mchip">이전 OpenAPI 증거 · Public API <b>126 paths · G1~G8</b></span>
<span class="mchip good">Direct-runtime preflight <b>APP ROLE OK</b></span>
<span class="mchip crit">critical 3 <b>1차 완료·gate</b></span>
<span class="mchip crit">Avatar decode <b>3 valid · 90 invalid</b></span>
<span class="mchip">Workbook <b>완료 9 · 검토 2</b></span>
<span class="mchip good">Human gate local <b>10/10 · IAB GREEN</b></span>
<span class="mchip">Human gate <b>실DB/public pending</b></span>
<span class="mchip">Decision <b>P0 조건부</b></span>
</div>
</div>
@ -344,7 +350,7 @@
<div class="ocol">
<div class="ocol-h">🚧 GO를 막는 블로커 <span class="ct" id="ct-block">0</span></div>
<div class="ostack" data-owner-col="block">
<article class="ocard" data-owner="1"><div class="otop"><span class="otag block">블로커</span><span class="oblocks">Web production 승격</span></div><h3>Cloudflare Pages production 배포 승인</h3><p class="ask">필요: 준비된 <code>99779a6a…fbc8</code> Web 후보를 Cloudflare Pages production에 업로드한다는 명시 승인.</p><p class="why">왜 당신인가: 저장소 코드와 번들을 외부 배포 서비스로 전송하는 운영 변경이다.</p><span class="opt">승인 문구: Cloudflare Pages production 배포 승인</span></article>
<article class="ocard" data-owner="1"><div class="otop"><span class="otag block">블로커</span><span class="oblocks">Web/API/runtime 승격</span></div><h3>통합 후보 정식 배포 승인</h3><p class="ask">필요: 전체 API/Web/PowerShell 회귀와 내장 브라우저 E2E가 GREEN이고 exact commit SHA가 고정된 뒤, push·Cloudflare Pages·public API/tunnel·두 task·upload root cutover 범위를 한 번 더 확인한다.</p><p class="why">왜 당신인가: 외부 배포와 이 PC 운영 런타임·예약 작업을 함께 바꾸는 운영 변경이다. 현재 public API 장애가 있어도 승인 전 mutation은 금지한다.</p><span class="opt">승인 전제: 후보 SHA·다운타임·보존 범위·rollback 영수증 제시</span></article>
<article class="ocard" data-owner="1"><div class="otop"><span class="otag block">게이트</span><span class="oblocks">Phase 3 파일럿 · 데이터</span></div><h3>한신대 데이터/SSO 거버넌스</h3><p class="ask">필요: SSO claim 스키마, 추가 축어록 수급, 미성년 원본 활용동의, 개인정보 처리방침에 대한 한신대/데이터 steward의 written evidence.</p><p class="why">왜 당신인가: 기관 공문·협의 영역. 로컬 문서 골격은 준비됨(<code>hanshin-data-governance-gate.md</code>).</p></article>
</div>
</div>
@ -365,7 +371,7 @@
<div class="ocol">
<div class="ocol-h">🤝 외부·임상팀 조율 <span class="ct" id="ct-ext">0</span></div>
<div class="ostack" data-owner-col="ext">
<article class="ocard" data-owner="1"><div class="otop"><span class="otag ext">조율</span><span class="oblocks">위기게이트·평가·이론</span></div><h3>임상팀 콘텐츠 (구훈정·어유경)</h3><p class="ask">필요: C1 루브릭 항목·척도·가중치·anchor 예시·컷오프·검수 기준의 임상팀 확정본, CBT 이론별 단계 프롬프트 체인, 위기 스크립트·생명유지서약 문안, H2 평가 골든셋. 코드는 C1 schema/loader/validation scaffold까지만 준비됨.</p><p class="why">왜 당신인가: doc3 R&R상 콘텐츠는 임상팀 산출물. 코드는 '편집 가능 구조'만 선제 구축 → 조율·수급 필요.</p></article>
<article class="ocard" data-owner="1"><div class="otop"><span class="otag ext">조율</span><span class="oblocks">C-001·위기게이트·평가·이론</span></div><h3>임상팀 콘텐츠·적격 외부 검수 (구훈정·어유경)</h3><p class="ask">필요: C1 루브릭·CBT 체인·위기 문안·H2 골든셋의 임상팀 확정본과, C-001 실제 검수자의 이름·소속·자격·검토 시각, 사례별 판정·근거·수정 요구·재검토·서명 증거를 package/version/hash에 결속한다. 외부 입력 46칸은 현재 의도적으로 공란이다.</p><p class="why">코드·내부 브라우저·운영 배포로 대신할 수 없다. 검수자 증거 없이 <code>review_complete=true</code>를 만들거나 워크북을 완료로 조작하지 않는다.</p></article>
<article class="ocard" data-owner="1"><div class="otop"><span class="otag ext">거버넌스</span><span class="oblocks">계약·일정</span></div><h3>스택 정합성·저작권 등재 (L1)</h3><p class="ask">방향은 Node.js 교체 가능성 우선으로 정했다. 남은 일은 FastAPI 유지 사유, 계약 우선 전환 계획, 저작권 등재 문서 반영을 거버넌스 증거로 남기는 것이다.</p><p class="why">권고: <code>docs/decisions/backend-node-transition.md</code> 기준으로 신청서/등재 문서의 스택 설명을 정합화한다.</p></article>
</div>
</div>
@ -694,11 +700,15 @@
<p class="dg-note">211차 복구·재검증(2026-08-18 15:05 자동화): 엔진 구독 한도 리셋 직후 NAS 엔진 릴레이 실제 1회 시작이 4종 SHA pin 그대로 <b>passed</b>(영수증 receipt-actual-20260818.json, PID 65328, ready 실생 통과). NAS→릴레이 TCP가 막혀 있던 것은 Python311 인바운드 허용 규칙이 Public 프로필뿐인데 이더넷이 Private이라서였고, LAN 서브넷 한정 9100 허용 규칙 추가(소유자 UAC 승인) 뒤 NAS origin health <b>3/3 연속 status=ok·db·engine true</b>, auth 401, OpenAPI 126을 실측 — 2026-08-12 이후 처음이다. current GREEN 표기는 actual-origin 실제 회기 turn→review smoke가 남아 보류. 같은 자동화의 직렬 게이트 재실행은 <b>31 passed/14 failed/12 did-not-run</b>로 실패: 파서 수정 후 첫 실행된 breakpoint 실측 스윕이 settings/learner 협폭 결함 91건을 보고했고(아침 실행에선 연쇄 중단으로 미실행), session-mvp·persistence·voice 실패군은 아침 동일 웹 코드 통과에 근거해 스택·데이터 드리프트가 의심된다 — 원인 조사로 이관, 가짜 증거 금지로 게이트 pending 유지. 증거는 <code>docs/ops/evidence/nas-relay-recovery-2026-08-18.json</code>·<code>usecase-tdd-2026-08-18.json</code>이다.</p>
<p class="dg-note">212차 핫픽스(2026-08-18 오후): 공개 <code>POST /sessions/{id}/end</code> 503(소유자 실사용 보고)의 원인은 회기 종료의 pinned_fact upsert가 <b>learner 역할 연결</b>로 실행된 것이었다. <code>app.pinned_fact</code> RLS는 learner에 INSERT(소유 케이스)만 허용하고 SELECT/UPDATE는 AI 컨텍스트·admin/instructor 전용이라 <code>SELECT … FOR UPDATE + INSERT … ON CONFLICT DO UPDATE</code> 조합이 충돌 후보 가시성에서 <code>InsufficientPrivilegeError</code>로 실패하고 fallback 차단이 503으로 노출됐다. 공개 DB 롤백 재현으로 단순 INSERT는 통과·ON CONFLICT 조합은 거부·<code>ai_view=evaluator</code> 컨텍스트는 전체 upsert 통과를 실증했고(<code>bf5f7352</code>), pinned_fact 저장만 같은 learner uid의 AI evaluator 뷰 연결로 분리했다. 검증: 관련 62 passed·app <b>924 passed</b>, 공개 8001 승격 후 health ok. 엔진이 건강해 deep 평가가 처음 팩트를 반환한 순간 발화한 잠복 결함으로, 아침 degraded 구간엔 팩트가 비어 이 경로가 실행되지 않았다.</p>
<p class="dg-note">213차 복구·전환(2026-08-18 심야): 대청소 사건(node_modules·구 런타임 워크트리·Temp 소실)과 Docker Desktop 사망·whisper 9882 WinNAT 포트 예약·DHCP LAN IP 회수(223→224)가 연쇄 발생했다. 릴레이를 현행 루트 <code>bf5f7352</code>에 같은 4종 핀으로 재기동(r3 영수증)하고 <code>192.168.0.224:9100</code>으로 바인딩(방화벽 규칙 재발행), NAS는 실행 컨테이너 env 전량을 <code>.env(0600)</code>로 재구성해 ENGINE_URL 224 적용 후 api만 재생성했다. 클로드 예산 한도(Reached maximum budget $0.5)가 재발해 NAS ENGINE_MODE를 <code>agy_cli</code>(gemini)로 전환 — 공개는 소유자가 이미 관리자 UI로 agy 전환 완료. 결과: NAS origin health <b>3/3 status=ok·db·engine true</b>, auth 401, OpenAPI 126, <b>actual-origin 실회기 turn→review smoke 통과</b>(agy 턴 2개→종료 200→리뷰 200) — 2026-08-12 이후 처음으로 201차 current GREEN 조건을 모두 충족했다. 회기 종료 503 핫픽스(<code>bf5f7352</code>)도 소유자 실세션 종료 성공으로 운영 검증. 권고: 공유기 DHCP 예약(호스트 MAC), Docker VM 클럭 동기화(호스트 대비 ~4일 선행 — DB 타임스탬프 오염), NAS 로컬 agy 이전. 증거는 <code>docs/ops/evidence/nas-relay-recovery-2026-08-18.json</code>이다.</p>
<p class="dg-note">214차 개선관리 워크북 동기화(2026-08-27): <b>C-002·C-003과 REQ-001~008은 내부 기술 구현 DONE</b>이다. 첫 회기 체크리스트와 종료 회기 기반 훈련 노출 지표를 추가했고, 외부 연구참여자 사전등록은 create에서 <code>pending</code> 고정 뒤 별도 PATCH 승인으로 분리했다. 프로토콜 레지스트리는 <code>draft→active→retired</code>, 라이선스 C/D의 외부 LLM 금지, evaluator-only RAG 색인·rollback을 강제하며 migration 17은 owner-run이고 startup은 readiness-only라 runtime DDL을 하지 않는다. 주호소는 surface보다 우선하고, 새 회기는 <code>persona_id/version</code>을 고정한다. 학습자 AI 피드백은 <b>현재 계정 설정 AND 세션 snapshot</b>일 때만 노출하며 OFF에서는 순수 파생 API 403·기존 share 404·혼합 응답 AI 필드 redaction·UI 파생 endpoint별 요청 0회를 적용한다. 축어록·저장 워크시트·outcome/calibration 입력·multimodal 동의/철회/삭제/raw audio/privacy 원장은 보존하고 alliance는 self-scores-only로 보여주며, privacy 삭제 조작면은 44px 이상·가로 overflow 0을 유지한다. teacher/admin 감독 뷰는 유지한다. 옛 회기 평가 실패는 degraded 리뷰로 남아도 새 회기를 막지 않는다. 헬스는 기본 엔진과 live-client를 함께 확인하고 구조화 <code>done</code> 없는 EOF는 <code>client_stream_incomplete</code>다. 상담자/내담자 이름은 prompt와 구조화 결과에서 <code>[COUNSELOR]</code>/<code>[CLIENT]</code>로 역할 마스킹한다. <b>C-001은 내부 안전 사전검증만 완료</b>했으며 임상 검토자 이름·소속 기관·검토일·서면 결정이 없어 외부 GATE로 계속 연다.</p>
<p class="dg-note">214차 개선관리 워크북 동기화(2026-08-27, 2026-08-29 최종 재생성): <b>C-002·C-003과 REQ-001~007은 완료</b>다. 기존 Gmail 인증 세션의 로그인 이메일·관리자 권한·온보딩 비전환·복구 데이터 가시성을 소유자가 수락해 REQ-001을 완료로 승격했다. REQ-008은 실제 내담자 응답과 복구 task 계약은 통과했지만 실제 Windows 재부팅 smoke가 남아 검토다. 완료본은 6시트·11요구·38수식·수식 오류 0, <b>완료 9·검토 2</b>다. <b>C-001은 내부 안전 사전검증만 완료</b>했으며 적격 외부 검수자의 46개 입력과 서명 증거가 없어 <code>pending-valid</code> 외부 GATE로 유지한다. 외부 검수 입력을 만들거나 완료로 조작하지 않는다.</p>
<p class="dg-note">215차 적용(2026-08-28): 관리자 Provider·모델별 원장에서 <code>gemini-3.7-flash-high</code> 토큰은 있는데 비용이 <code>미산정</code>이던 원인을 최신 모델 누락과 단일 고정 rate card로 좁혀 수정했다. Gemini 3.6/3.7 Flash는 출시일과 2026-08-13~12-31 프로모션, 2027 표준 단가를 호출 시작일 기준으로 선택한다. 기존 0달러 행은 동일 계량 시그니처별로 묶어 요청 단위로 다시 가격화해 200K 입력 경계를 보존하고, 캐시 입력 수가 유실된 과거행은 확정값 대신 <code>≤$0.103489 · 참조 상한</code>, 확정 산정/미산정 혼합은 <code>$…+ · 일부 산정</code>, 상한/미산정 혼합은 <code>미산정 · 일부 상한</code>으로 표시한다. 전체·일별·예산에 비용 확실성을 전파해 불확실한 평균·비중을 숨기고, migration 18의 client turn 기간 인덱스는 <code>CREATE INDEX CONCURRENTLY</code>로 트랜잭션 밖에서 적용해 턴 쓰기를 막지 않는다. 저장된 과거 양수 비용에는 현재 단가 라벨을 덧씌우지 않는다. 화면의 테스트 데이터는 정확한 <code>(e2e, fake-client, input=1, output=1, cost=0)</code> 조합만 원장·예산에서 제외하고 DB 행은 삭제하지 않았다. <b>검증</b>: focused <b>105 passed/1 skipped</b>, app+gateway 전체 <b>1102 passed/1 skipped</b>, 새 빈 PostgreSQL 온라인 마이그레이션+통합 <b>1 passed</b>, release agent <b>31 passed</b>, API type generation/check·typecheck·build, 관리자 desktop/mobile <b>6 passed</b>. 격리 DB는 자동 삭제했고 공개 배포는 하지 않았다.</p>
<p class="dg-note">216차 REQ-001 로그인 단순화(2026-08-29): 실제로 같은 <code>startOAuth</code>를 호출하던 학교용·다른 계정용 중복 버튼을 단일 <b>Google 계정으로 로그인</b> CTA로 통합했다. 보조문구는 <b>모든 Google 계정</b>이며 Google authorize의 <code>prompt=select_account</code>는 남겨 공유 기기에서도 계정을 고를 수 있게 하고 특정 Workspace 도메인을 강제하는 <code>hd</code>는 보내지 않는다. Google이 검증한 이메일은 도메인·사전등록 제약 없이 즉시 승인되는 기존 서버 계약을 유지한다. <b>검증</b>: auth API <b>41 passed</b>, 직접 영향 desktop/mobile <b>32 passed</b>, 인증 시각·경계폭 <b>2 passed</b>, 7폭 전체 레이아웃 <b>15 passed</b>, 세션 무회귀 <b>8 passed</b>, typecheck·lint·build 통과. 이 단일 CTA 번들은 아직 공개 미배포라 현재 공개 Pages의 기존 2버튼 DOM을 새 증거로 대체하지 않는다.</p>
<p class="dg-note">217차 REQ-008 복구 판정 교정(2026-08-29): Windows PowerShell 5.1에서 web build process handle을 먼저 열지 않고 timed <code>WaitForExit()</code>를 호출하면 정상 종료 뒤에도 <code>ExitCode=$null</code>로 남는 런타임 경계를 제거했다. handle 선확보→bounded wait→refresh→null/nonzero guard 순서를 실제 PS5.1 계약 <b>32 passed</b>로 고정하고, detached-clean <code>44b7835c…</code>·tree <code>06133249…</code>에 boot/watchdog을 같은 핀으로 재등록했다. watchdog 복구로 web 5174 HTTP 200, 후속 <code>LastTaskResult=0</code>·failcount 0, local/public health <code>status=ok·db=true·engine=true</code>를 확인했다. 개선관리 완료본 SHA <code>0a64d1bc…1177</code>와 C-001 기술 증거 원장의 14개 artifact SHA도 14/14 일치시켰다. 실제 Windows 재부팅 smoke와 PC 비종속 상시 호스트 이전은 별도 gate다.</p>
<p class="dg-note">218차 Google 계정 데이터 복구·API 승격(2026-08-29): Gmail 로그인이 새 learner로 갈라져 정식 관리자 데이터가 사라져 보인 원인은 Google subject별 <code>app_user</code>가 둘로 생성된 것이었다. 이메일 자동병합 대신 owner-managed <code>auth_identity_alias</code>를 추가해 canonical 관리자에 Google subject 2개를 명시적으로 연결하고, 세션에는 실제 로그인 이메일을 별도 기록한다. 원본 백업 SHA <code>c4725500…f2e9</code><code>pg_restore --list</code>로 확인한 뒤 복제 DB에서 복구 트랜잭션을 먼저 통과시켰다. Gmail 중복 계정의 상담 데이터는 0건이지만 설정 1행이 있어 첫 시도는 가드가 전부 rollback했고, 전체 FK 스캔 뒤 겹치는 설정값이 동일함을 확인해 source-only 알림 키만 canonical에 합치고 원본 설정 행은 보존했다. 활성 DB 결과는 canonical <b>21회기·64턴·평가 6건</b>, 별칭 2·옛 Gmail 세션 0·감사로그 1·고아 0이며 사용자 1175·회기 469·평가 65를 유지한다. API+gateway <b>1111 passed/1 skipped</b>, release agent <b>31 passed</b>. detached-clean <code>dba9b75a…</code>·tree <code>14cd4607…</code>에서 API/cloudflared fresh provenance를 발행하고 public health·DB·engine·voice·OpenAPI 129·auth 401을 확인했으며 boot/watchdog을 같은 핀으로 재등록해 <code>LastTaskResult=0</code>·failcount 0이다. 브라우저의 옛 Gmail 세션은 reload 후 <code>/login</code>으로 철회됐고, 실제 Gmail callback은 사용자 계정 선택 후 최종 확인한다.</p>
<p class="dg-note">219차 단일 Google 로그인 Pages 승격(2026-08-29): detached-clean <code>dba9b75a…</code>에서 typecheck·lint·cosmetic safety와 2회 byte-identical production build를 통과하고 최근 production 5개의 lazy asset 115개를 보존해 714파일을 Pages production <code>ef48c0ae-374e-41fc-b6fd-03f69b26e946</code>로 승격했다. custom domain은 새 entry <code>index-B1rSWL_W.js</code> SHA <code>f8411694…b5bf</code>, login chunk <code>Login-DNNQ624T.js</code> SHA <code>f010f764…9c1d</code>가 clean build와 일치하며, 단일 <b>Google 계정으로 로그인</b> CTA 1개·구 계정 선택 버튼 0·dev login 0·console warning/error 0이다. 격리 Playwright의 공개 OAuth 시작 계약도 <b>1 passed</b>이고 이전 entry는 JavaScript MIME 200으로 보존된다. 배포별 preview origin은 같은 정적 자산을 받지만 서버 연결 진단을 표시하므로 runtime GREEN으로 기록하지 않는다. <b>REQ-001은 실제 Gmail callback과 복구 계정의 관리자·21회기·64턴·평가 6건 확인 전까지 검토</b>다.</p>
<p class="dg-note">220차 개선관리 완료본 현행 증거 동기화(2026-08-29): <code>Vignette_개선관리_완료.xlsx</code>의 상태·수식·서식은 유지하고 <code>개발·기능 이슈!M5:M12</code><code>임상·교육 이슈!M6:M7</code>의 오래된 API/Pages 배포 근거만 현재 <code>dba9b75a…</code>·tree <code>14cd4607…</code>·Pages <code>ef48c0ae…</code>로 갱신했다. artifact-tool import→values-only edit→export→reimport 뒤 6개 전 시트와 수정 집중 4개 렌더를 직접 확인했고 수식 오류 0, 완료 8·검토 3·총 11, 임상 checker <code>pending_external_review</code>·<code>review_complete=false</code>를 유지한다. 새 완료본 SHA는 <code>aab6ef52…e26a</code>다. 기존 C-001 사전검증 원장은 당시 14개 해시의 역사 증거로 보존하고, 현행 원장에서 기술 산출물 13/13 불변과 새 워크북 해시를 결합해 현재 패키지 14/14 연속성을 다시 확인했다. 실제 Gmail callback·Windows 재부팅 smoke·외부 임상 승인 없이 상태를 완료로 올리지 않았다. 기계 판독 증거는 <code>docs/ops/evidence/workbook-runtime-sync-2026-08-29.json</code>이다.</p>
<p class="dg-note">221차 교수자 콘솔 표면 간격 교정·공개 승격(2026-08-29): <code>/teach</code>의 검토 큐와 교수자 요약이 독립 Surface인데 부모 <code>.pf-signal-strip</code><code>gap:0</code> 때문에 테두리·그림자가 맞붙던 원인을 <code>--sp-3</code>=12px로 교정했다. 수정 전 0px를 다시 주입해 새 회귀 검사가 RED가 되는 것을 확인하고 복원 뒤 focused <b>1 passed</b>, 390~1440 7폭 교수자 gate <b>1 passed</b>, 전체 layout visual <b>15 passed</b>, session 무회귀 <b>8 passed</b>, typecheck·design SSOT·lint·build를 통과했다. tracked-clean <code>5bf89ff4…</code>·tree <code>29f76aeb…</code>에서 599파일 build 2회 byte-identical, 이전 자산 172개 보존 후 Pages production <code>0c60261e-cb37-482d-ba42-d91586194c48</code>로 승격했다. 실서비스 1425×1272 DOM은 computed/실측 간격 12px·overflow 0·console warning/error 0이고 custom/preview의 <code>Professor-BfR874KA.css</code> SHA <code>63dbe2c7…7fff</code>가 clean build와 일치한다. 증거는 <code>docs/ops/evidence/professor-summary-gap-deploy-2026-08-29.json</code>이다.</p>
<p class="dg-note">222차 REQ-001 완료·개선관리 재생성(2026-08-29): 기존 실서비스 인증 세션은 <code>yunchan8804@gmail.com</code>으로 설정·관리자 콘솔에 접근하고 온보딩으로 되돌아가지 않으며, 학습 이력 20건·리뷰 필요 6건을 표시했다. 소유자가 복구 데이터 가시성을 수락했고 최신 Pages <code>0c60261e…</code>의 단일 Google CTA 1개·구 선택 버튼 0·dev login 0·무제한 도메인·공개 Playwright 2 passed를 함께 확인해 REQ-001을 완료로 승격했다. 개선관리 완료본은 artifact-tool 구조 추출로 <b>6시트·11개 고유 요구·38수식·오류 0·완료 9/검토 2</b>를 확인했다. C-001은 패키지 8/8·기술 사례 6/6·canonical checker 정상의 <code>pending-valid</code>이며 외부 입력 46칸은 공란으로 보존했다. 완료본 SHA는 <code>c832547f…d8bd</code>, sidecar SHA는 <code>8c9618f0…a610</code>이고 REQ-008 실제 Windows 재부팅 smoke와 C-001 외부 임상 승인만 검토로 남는다.</p>
<div class="dg-principles" aria-label="디자인 생성 가드레일">
<div><b>래스터만 사용</b><span>이미지 생성 도구 산출물은 PNG 기반 시안이다. SVG·벡터·와이어프레임·로고 시트로 해석하지 않는다.</span></div>
<div><b>기능 우선</b><span>메인 라우트의 실제 액션과 정보 구조를 먼저 반영한다. 장식은 기능을 가리지 않는 수준에서만 쓴다.</span></div>
@ -1109,7 +1119,7 @@
<tbody>
<tr><td>Web typecheck</td><td><code>npm run typecheck</code></td><td>Passed</td></tr>
<tr><td>Design SSOT / auth visual</td><td><code>npm run check:design-ssot</code> / <code>npx playwright test e2e/auth-visual.spec.ts --project=chromium-single-run --reporter=line</code> / <code>npx playwright test e2e/layout-visual-gate.spec.ts --project=chromium-single-run --reporter=line</code></td><td>SSOT checker passed; login/onboarding light-dark desktop-mobile 1 passed; 14 core screens × 7 widths visual gate 14 passed.</td></tr>
<tr><td>Full Playwright E2E baseline</td><td><code>npm run e2e:parallel</code> / <code>npm run e2e:single-run</code> / <code>npm run e2e:list</code></td><td>2026-08-28 현재 수집은 <b>1138 tests / 62 files</b>다. 이 숫자는 수집량이며 현 작업트리 전체 GREEN과 동일하지 않다. G8 clean-head release gate는 candidate 112/112와 실제 NAS-origin 112/112를 통과했다. 이전 단일 120/120과 2026-07-15의 fixture desktop/mobile 166/166 + DB/engine/provider 직렬 49/49 = 215/215는 범위가 다른 역사 기준선으로 보존한다.</td></tr>
<tr><td>Full Playwright E2E baseline</td><td><code>npm run e2e:parallel</code> / <code>npm run e2e:single-run</code> / <code>npm run e2e:list</code></td><td>2026-08-29 현재 수집은 <b>1158 tests / 64 files</b>다. 이 숫자는 수집량이며 현 작업트리 전체 GREEN과 동일하지 않다. G8 clean-head release gate는 candidate 112/112와 실제 NAS-origin 112/112를 통과했다. 이전 단일 120/120과 2026-07-15의 fixture desktop/mobile 166/166 + DB/engine/provider 직렬 49/49 = 215/215는 범위가 다른 역사 기준선으로 보존한다.</td></tr>
<tr><td>Refactor governance P1~P8</td><td><code>ruff check app</code> / <code>pytest -q app</code> / <code>pytest -q engine_gateway</code> / <code>npm run typecheck</code> / <code>npm run check:api-types</code> / <code>npm run check:design-ssot</code> / <code>npm run check:dead-code</code> / <code>npm run check:duplication</code> / <code>npm run build</code> / <code>npm audit --audit-level=high</code> / full Playwright</td><td>Backend 400 passed, gateway 29 passed, web gates/build/audit passed, vulnerabilities 0, production duplication 1 clone/15 lines/0.03%, Playwright 215/215 passed. 상세 근거는 <code>ops/refactor-governance-2026-07-15.md</code>.</td></tr>
<tr><td>API typegen SSOT</td><td><code>npm run check:api-types</code></td><td>Passed; FastAPI OpenAPI → <code>src/lib/api.gen.ts</code> stale check</td></tr>
<tr><td>Outcome &amp; Alliance OS G0</td><td><code>py -3.11 -X utf8 -m pytest -p no:cacheprovider apps/api/app/test_measurement_contract.py apps/api/app/test_runtime_schema_ssot.py -q</code> / <code>scripts/check-measurement-ledger.sql</code> / measurement·API contract checks / web typecheck / DB-backed <code>session-persistence</code> focused E2E 3종</td><td>G0 contract/schema 11 passed, 기존 backend 100 passed, auth 39 passed. Python→JSON Schema→TypeScript→PostgreSQL enum·필수필드 계약이 일치하고 8개 deterministic benchmark가 검증됐다. Live PostgreSQL에서 learner/client/evaluator 가시 행 1/1/2, 교차 누수 0, append-only guard 2를 확인했다. 학습자 턴→교수자 대시보드, 워크시트 검수, 종료 deep 평가→durable 리뷰 E2E는 각각 1 passed. G0/AOS-001~004 완료.</td></tr>
@ -1119,11 +1129,11 @@
<tr><td>Outcome &amp; Alliance OS G4/G5 caller</td><td><code>pytest test_session_learning_producer.py test_deliberate_practice.py test_deliberate_practice_store.py test_calibration_transfer.py test_calibration_transfer_store.py</code> / <code>scripts/smoke-session-learning-producer.py</code></td><td>focused 100 passed, 전체 API 855 passed. 실제 종료 회기·durable turn 2개·ready 평가에서 production caller가 G4 처방 원장 5종을 각 1개 생성하고 deterministic replay한다. G5는 prediction lock 전 observation 0, lock callback 뒤 failed 독립 관찰과 evaluator model-run 각 1개이며 replay 중복 0이다. learner/teacher projection이 일치하고 mastery/pass/assessment/transfer 자동 승격은 전부 0건이다. 합성 교육 fixture이며 임상·실제 숙달 주장이 아니다.</td></tr>
<tr><td>학생 자기주도 전체 루프 UI</td><td><code>npx playwright test e2e/self-directed-learning-loop.spec.ts --project=chromium-desktop --project=chromium-mobile --workers=1 --reporter=dot</code> / <code>npx playwright test e2e/alliance-pulse.spec.ts --project=chromium-desktop --project=chromium-mobile --workers=2</code> / <code>npm run typecheck</code> / 고정 캡처 직접 QA</td><td>실제 <code>src</code> 홈 추천→목표 선택→텍스트/SSE 회기→종료·리뷰→G4 처방 키보드 CTA→새 회기 재연습 시작이 desktop/mobile 2/2, typecheck를 통과했다. 페이지 overflow 0, 홈 CTA 44px·4.5:1 이상 대비, typed launch intent와 replay 모드 보존, 내부 criterion/counterevidence/UUID 비노출을 확인했다. 390×844·320×568 활성 회기는 아바타/문구 겹침 0과 축어록/입력창 내부 포함을 통과했다. 320px 리뷰 1~5 척도는 다섯 선택지 44px 이상·내부/페이지 overflow 0이고 전체 desktop/mobile 8/8이다. 모든 미소유 API는 fixture 404이며 실제 로그인/API/DB 증거가 아니다.</td></tr>
<tr><td>Contract SSOT aggregate DTO</td><td><code>py -3.11 -X utf8 -m pytest -p no:cacheprovider app/test_evaluation_persistence.py app/test_evaluator_model_routing.py app/test_teacher_dashboard.py app/test_rbac_idor.py app/test_session_turn_persistence.py -q</code> / <code>npm run check:api-types</code> / <code>npm run typecheck</code> / <code>npm run build</code></td><td>50 backend passed; learner sessions, session review/worksheet, teacher dashboard, session start/detail DTOs use generated <code>ApiSchema</code> aliases with UI fallback. Stage responses are OpenAPI enum unions, including review phase key/label, reached phase, evaluation summary/trigger responses, and teacher session/growth stage. <code>.github/workflows/api-contract.yml</code> runs <code>npm run check:api-types</code> on API/Web contract changes.</td></tr>
<tr><td>개선관리 C-002·C-003 / REQ-001~008</td><td><code>pytest app/ -q</code> / <code>pytest engine_gateway/ -q</code> / 항목별 focused pytest·DB/browser E2E / <code>npm run check:api-types</code> / <code>npm run build</code></td><td><b>내부 기술 DONE.</b> 2026-08-28 최종 API 1002 passed, gateway 68 passed, Ruff·API type check·typecheck·lint·production build PASS. focused: C-002 3, C-003 11, REQ-001 auth 41 + callback access-log redaction 6 + OAuth UI desktop/mobile 4 + route-mock desktop/mobile 2 + 실제 관리자 DB/browser lifecycle 1, REQ-002·005 26(경고 1) + protocol 실제 DB lifecycle 1 + persona 실제 DB/browser lifecycle 1, REQ-003 34, REQ-004 직접 정책 85·관련 route/read-model 163·desktop/mobile 2, REQ-006 24, REQ-007 관련 163·live/session 50·DB E2E 1, REQ-008 health 1 passed. Google OIDC는 provider-verified 이메일을 도메인·사전등록 없이 learner·approved로 허용하고 suspended는 보존한다. 실제 관리자 E2E는 승인 전 403/대기→승인 후 동일 세션 200→피드백 OFF 영속 재조회→비활성화·세션 0을, persona E2E는 작성→승인→catalog→주호소→exact ID/version pin→controlled SSE→DB 2턴과 exact cleanup/설정 원복을 확인했다. 최종 레이아웃 재실행은 시각 게이트 15/15·포커스 106/106·세션 8/8, 실패·skip 0이며 격리 포트와 프로세스를 모두 종료했다. 전체 Playwright 현 작업트리 GREEN 수치로 환산하지 않는다.</td></tr>
<tr><td>개선관리 C-001 외부 임상 승인</td><td><code>scripts/check-clinical-crisis-review.py</code> / <code>run-clinical-crisis-technical-observations.py</code> / <code>data/clinical/p1-crisis-review-cases.json</code> / <code>docs/ops/clinical-crisis-protocol-review-2026-08-27.md</code></td><td><b>내부 기술 READY · 외부 GATE 미완료.</b> v2 P1 합성 사례 6건과 상태별 canonical fail-closed 판정기를 유지한다. 생성·스트림 실제 경로 6/6, 런타임 패키지 8개 HEAD·작업트리 SHA 일치, focused <b>90 passed</b>·Ruff PASS를 확인했다. 개선관리 완료본은 6번째 <code>C-001 외부검토</code> 시트에서 사례별 5필드 30개·청소년 답변 6개·검토자 자격 포함 승인 10필드·서명 증거를 받고 canonical checker와 패키지 해시가 모두 맞을 때만 <code>완료</code>로 전파한다. 현재 gate는 <code>pending-valid</code>지만 외부 결정 0건·<code>review_complete=false</code>라 10 완료/1 검토/총 11을 유지한다.</td></tr>
<tr><td>개선관리 C-002·C-003 / REQ-001~008</td><td><code>pytest app/ -q</code> / <code>pytest engine_gateway/ -q</code> / 항목별 focused pytest·DB/browser E2E / <code>npm run check:api-types</code> / <code>npm run build</code></td><td><b>완료 9 · 검토 2.</b> C-002·C-003과 REQ-001~007은 요구·기술 증거가 완료됐다. 2026-08-29 API <b>1074 passed/1 skipped</b>, gateway <b>68 passed</b>, typecheck와 G8 focused desktop/mobile 10/10이 PASS다. 격리 local Codex 내장 브라우저는 8.5초 overlay 0·heading 정상, content 보류와 증거 없는 release 반려 effect 0, 증거 4종 promote 승인 lifecycle effect 1을 확인했다. 이는 local stateful fixture GREEN이며 실DB/public proof가 아니다. REQ-001은 기존 Gmail 인증 세션의 관리자 권한·온보딩 비전환·복구 이력 가시성을 확인하고 소유자가 수락했다. REQ-008은 공개 P20 실제 응답과 복구 계약을 확인했지만 실제 Windows 재부팅 smoke가 없어 검토다. C-001은 별도 외부 GATE다. 전체 Playwright 현 작업트리 GREEN 수치로 환산하지 않는다.</td></tr>
<tr><td>개선관리 C-001 외부 임상 승인</td><td><code>scripts/check-clinical-crisis-review.py</code> / <code>run-clinical-crisis-technical-observations.py</code> / <code>data/clinical/p1-crisis-review-cases.json</code> / <code>docs/ops/clinical-crisis-protocol-review-2026-08-27.md</code></td><td><b>내부 기술 READY · 외부 GATE 미완료.</b> v2 P1 합성 사례 6건과 상태별 canonical fail-closed 판정기를 유지한다. 생성·스트림 실제 경로 6/6, 런타임 패키지 8개 HEAD·작업트리 SHA 일치, focused <b>90 passed</b>·Ruff PASS를 확인했다. 현행 개선관리 완료본 SHA는 <code>c832547f…d8bd</code>이며, 이전 C-001 기술 사전검증 원장의 <code>0a64d1bc…1177</code>과 8/3 동기화본 <code>aab6ef52…e26a</code>은 역사 스냅샷으로 보존한다. 후속 원장은 6시트·11요구·38수식·오류 0과 현재 package match를 기록한다. 6번째 <code>C-001 외부검토</code> 시트에서 사례별 5필드 30개·청소년 답변 6개·검토자 자격 포함 승인 10필드·서명 증거를 받고 canonical checker와 패키지 해시가 모두 맞을 때만 <code>완료</code>로 전파한다. 현재 gate는 <code>pending-valid</code>지만 외부 입력 46칸은 공란이고 <code>review_complete=false</code>다. REQ-001은 완료됐고 REQ-008 재부팅 실증과 C-001 외부 승인만 남아 9 완료/2 검토/총 11을 유지한다.</td></tr>
<tr><td>SEO/GEO share cards</td><td><code>pytest app/test_session_share.py app/test_session_turn_persistence.py -q</code> / <code>npm run generate:api-types</code> / <code>npm run typecheck</code></td><td>21 passed; session share creates hashed-token public unfurl payload without raw transcript, revoked token returns 404, OpenAPI generated share DTOs, review screen share button typechecks. Static <code>robots.txt</code>/<code>sitemap.xml</code>/<code>llms.txt</code> added.</td></tr>
<tr><td>Backend pytest baseline</td><td><code>pytest -q app</code></td><td>2026-08-28 전체 실행 1002 passed.</td></tr>
<tr><td>X2 evaluator routing/cache/cost trend</td><td><code>python -X utf8 -m pytest -p no:cacheprovider app/test_llm_pricing.py app/test_admin_ops.py app/test_usage_report.py engine_gateway/test_provider_registry.py engine_gateway/test_gateway_model.py -q</code> / API type generation/check / web typecheck/build / admin focused E2E·layout visual gate / authenticated public API smoke</td><td>최신 backend 439 passed, gateway 45 passed, desktop/mobile E2E 2 passed, 7폭 focused visual gate 1 passed. Claude CLI SDK 비용 추정값과 Agy/Gemini·Codex·Claude API 공식 참조단가를 분리하고, 기존 0달러 행의 조회 시 보정·단가 미등록 모델의 <code>미산정</code> 표시·예산 합산·리포트 경고까지 고정했다. Claude 토큰은 전체 agent tree와 캐시 입력을 포함한다. 과거 0/0 Claude 442건은 로컬 JSONL의 실제 usage와 유일 일치한 169건만 백필했고, 273건은 <code>token_unmetered_turns</code>로 남겼다. 인증된 공개 관리자 화면은 확인 시점 30일 Claude 183건 중 계량 125·미계량 58건을 표시했다.</td></tr>
<tr><td>Backend pytest baseline</td><td><code>pytest -q app</code></td><td>2026-08-29 전체 실행 1074 passed / 1 skipped.</td></tr>
<tr><td>X2 evaluator routing/cache/cost trend</td><td><code>python -X utf8 -m pytest -p no:cacheprovider app/test_llm_pricing.py app/test_admin_ops.py app/test_admin_usage_postgres.py app/test_usage_report.py engine_gateway/test_provider_registry.py engine_gateway/test_gateway_model.py -q</code> / 격리 PostgreSQL / API type generation/check / web typecheck/build / admin focused E2E</td><td>2026-08-28 focused 105 passed/1 skipped, app+gateway 전체 1102 passed/1 skipped, 새 빈 PostgreSQL 온라인 마이그레이션+통합 1 passed, release agent 31 passed, desktop/mobile E2E 6 passed. Claude CLI SDK 비용 추정값과 호출 시점 Agy/Gemini·Codex·Claude API 공식 참조단가를 분리한다. Gemini 3.6/3.7 유효기간, 요청별 200K 구간, 과거 캐시 미보존 행의 <code>reference_upper_bound</code>, 확정 산정/미산정 <code>partial</code>, 상한/미산정 <code>partial_upper_bound</code>, 전체·일별·예산 certainty, 정확한 <code>(e2e, fake-client, input=1, output=1, cost=0)</code> 원장 제외와 리포트 경고를 고정했다. 동일 계량 시그니처 SQL 집계와 migration 18의 concurrent 기간 인덱스로 90일 원장의 raw-row fetch/sort를 제거하고 배포 중 turn 쓰기 잠금을 피한다. 과거 0/0 Claude 442건은 로컬 JSONL의 실제 usage와 유일 일치한 169건만 백필했고 273건은 <code>token_unmetered_turns</code>로 남겼다. 이번 변경은 로컬 검증만 했고 공개 런타임은 미배포다.</td></tr>
<tr><td>H3 raw source isolation</td><td><code>python -B -m pytest -p no:cacheprovider app/test_persona_review.py app/test_live_coach_sources.py -q</code></td><td>38 passed; persona source registration records raw hash-only artifacts separately from sanitized evaluator-only RAG chunks, and <code>rag.index_document()</code> rejects <code>sensitivity=3</code>/raw-marker chunks before DB access.</td></tr>
<tr><td>H3 persona itemized authoring UI</td><td><code>npm run typecheck</code> / <code>npm run build</code> / <code>npm run check:api-types</code> / <code>npx playwright test e2e/teacher.spec.ts --project=chromium-single-run --workers=1</code> / <code>npx playwright test e2e/layout-visual-gate.spec.ts --project=chromium-single-run --workers=1</code> / <code>npx playwright test e2e/session-layout.spec.ts --project=chromium-desktop --project=chromium-mobile --workers=1</code></td><td>Typecheck/build/API type drift check passed; teacher PersonaStudio focused 8 passed including structured list payload and labeled prompt preview without raw JSON; visual gate 9 passed with the prompt tab opened; session-layout desktop/mobile 8 passed.</td></tr>
<tr><td>H2 session review 3-column workbench</td><td><code>npm run typecheck</code> / <code>npm run build</code> / <code>npx playwright test e2e/session-review.spec.ts --project=chromium-desktop --workers=1</code> / <code>npx playwright test e2e/layout-visual-gate.spec.ts --project=chromium-single-run --workers=1</code></td><td>Typecheck/build passed; 3 focused review E2E passed; 9 visual gates passed with dark-theme assertion. Filled learner review uses overview/flow, transcript, and evaluation rail as a 3-column desktop workbench with worksheet below; empty review remains 2 columns or less to avoid sparse gaps.</td></tr>
@ -1152,7 +1162,7 @@
<tr><td>OAuth/SAML admin landing</td><td><code>C:\Users\encep\AppData\Local\Programs\Python\Python311\python.exe -X utf8 -m pytest -p no:cacheprovider app/test_auth_providers.py -q</code> / public runtime restart</td><td>36 passed; OAuth/SAML callback now normalizes generic saved <code>next</code> paths such as <code>/learn</code> and <code>/teach</code> to <code>/admin</code> for admin-entitled users while preserving deep links such as <code>/learn/session/...</code>. Live proof after commits <code>998acb44</code>/<code>6b6241f4</code> and latest boot-diagnostic deploy <code>b67fd5d4</code>: local/public <code>/health</code> returned <code>prod</code>, <code>db=true</code>, <code>engine=true</code>; custom domain now serves <code>assets/index-R5KK7hZI.js</code>/<code>assets/index-DzdAkRsn.css</code> plus boot diagnostic HTML; unauthenticated <code>/personas</code> remains <code>401</code>.</td></tr>
<tr><td>Session read-model DB readiness</td><td><code>python scripts\check-deploy-preflight.py --skip-db --env-file infra\.env.example --allow-placeholder-secrets</code> / <code>https://api-vignette.chanpaca.net/health</code></td><td>2026-06-29 prod 503 원인은 운영 DB의 <code>app.turns.provider_events</code> 컬럼 누락이었다. 운영 DB hotfix 후 <code>/teacher/dashboard</code> code path는 <code>source=database</code>로 복구됐다. 현재 <code>db.healthcheck()</code>, runtime table readiness, deploy preflight DB mode는 <code>app.turns</code> 음성 메타 컬럼 5개(<code>audio_ref</code>, <code>silence_ms</code>, <code>speech_rate</code>, <code>barge_in</code>, <code>provider_events</code>), <code>app.session_review_status</code> worksheet 컬럼, <code>app.safety_events</code> 필수 컬럼을 함께 검증한다. 2026-06-30에는 Docker Desktop/DB 중단으로 public API 530/error code 1033이 재발했지만, Docker Desktop/DB 재기동 뒤 public health가 <code>environment=prod</code>, <code>db=true</code>, <code>engine=true</code>로 복구됐다.</td></tr>
<tr><td>Admin usage persistence</td><td><code>python -m pytest app/test_admin_ops.py app/test_runtime_policy.py -q</code> / authenticated local public-API smoke</td><td>26 passed; <code>/admin/usage</code> returns 200 with <code>source=database</code>, <code>durable=true</code>. Cloudflare blocked raw Python public smoke with 1010, so app-level HTTP was verified against <code>127.0.0.1:8001</code> using the same prod process.</td></tr>
<tr><td>Admin AI operations subpage</td><td><code>npx playwright test e2e/admin.spec.ts --project=chromium-desktop --project=chromium-mobile --workers=1 --grep="shows detailed AI metering"</code> / <code>npx playwright test e2e/layout-visual-gate.spec.ts --project=chromium-single-run --workers=1</code> / <code>public-admin-visual.spec.ts --grep="shows the live Codex and Agy model catalogs"</code></td><td><code>/admin/ai</code>는 7·30·90일 DB 원장, 비용·토큰·토큰 계량 커버리지·호출당 단가, 일별 비용, provider/model breakdown, evaluator cache를 표시하고 엔진 설정을 실제 저장한다. 비용은 <code>SDK 추정</code>·<code>Provider 보고</code>·<code>참조단가</code>·<code>미산정</code>을 구분한다. 토큰 입력은 비캐시·캐시 읽기·캐시 생성 합계이며, 실제 usage가 복구된 행은 토큰과 <code>계량/전체 회</code> 커버리지를, 복구 불가 0/0 행은 <code>미계량</code>을 표시한다. 최신 focused desktop/mobile 2 passed, 7폭 layout 1 passed, 실제 공개 관리자 브라우저 1 passed다.</td></tr>
<tr><td>Admin AI operations subpage</td><td><code>npx playwright test e2e/admin.spec.ts e2e/full-sweep-admin-ai.spec.ts --project=chromium-desktop --project=chromium-mobile --workers=1 --grep="shows detailed AI metering|shows partial AI cost|does not present a partial upper bound"</code> / <code>app/test_admin_usage_postgres.py</code></td><td><code>/admin/ai</code>는 7·30·90일 DB 원장, 비용·토큰·토큰 계량 커버리지·호출당 단가, 일별 비용, provider/model breakdown, evaluator cache를 표시하고 엔진 설정을 실제 저장한다. 비용은 <code>SDK 추정</code>·<code>Provider 보고</code>·<code>참조단가</code>·<code>참조 상한</code>·<code>일부 산정</code>·<code>일부 상한</code>·<code>미산정</code>을 구분한다. 과거 캐시 미보존 보정값은 <code>≤$…</code>, 확정 산정/미산정 합계는 <code>$…+</code>, 상한/미산정 혼합은 <code>미산정</code>으로 표시한다. 전체·일별·예산의 불확실한 평균·비중은 숨기고 예산은 <code>indeterminate</code>를 표시한다. 2026-08-28 새 빈 PostgreSQL 마이그레이션+통합 1 passed와 desktop/mobile 6 passed를 확인했고 공개 관리자 브라우저는 이번 변경에서 재검증하지 않았다.</td></tr>
<tr><td>Synthetic health sampler</td><td><code>record_admin_health_sample()</code>, <code>record-admin-health-sample.py</code>, <code>install-health-sampler-task.ps1</code></td><td>Backend focused 31 passed. Python compile/help passed; PowerShell parser + <code>-PrintOnly</code> passed. Local one-shot appended 5 service rows to <code>app.admin_health_event</code>: status ok, engine_mode claude_cli. This remains sample history, not an SLA claim.</td></tr>
<tr><td>Health retention/rollup</td><td><code>admin_health_daily_rollup</code>, <code>maintain-admin-health-events.py</code>, <code>/admin/uptime</code></td><td>Backend focused 36 passed. Python compile/help passed. Local dry-run returned <code>rollup_event_count=0</code>, <code>prunable_event_count=0</code>. Uptime summary now combines raw samples with daily rollups when raw rows have been pruned; detailed events stay raw-only.</td></tr>
<tr><td>Ticket duplicate linking</td><td><code>support_ticket.fingerprint</code>, <code>parent_ticket_id</code>, <code>/admin/tickets</code></td><td>Backend focused 38 passed. API types, web typecheck, and build passed. Admin tickets E2E 2 passed after restarting local API 8000 on the new code. Duplicate handling is deterministic hint + admin manual parent link/unlink only; no automatic merge, escalation, issue, PR, or thread creation.</td></tr>
@ -1206,10 +1216,10 @@
<tr><td>Public OAuth start</td><td><code>/auth/config</code> + <code>/auth/login?provider=google</code></td><td>2026-08-28 public auth config 200, Google configured true, <code>allowed_email_domains=[]</code>, redirect URI <code>https://api-vignette.chanpaca.net/auth/callback</code>, dev-login disabled. 로그인 DOM은 모든 Google 계정을 명시하고 실제 Google 선택기에 <code>yunchan@twentyoz.kr</code><code>yunchan8804@gmail.com</code>이 함께 노출됐다. 기존 Google 계정 선택→callback→<code>/admin</code> 성공을 확인했다. 신규 Gmail 선택은 Vignette 계정 생성이므로 사용자 행동시점 확인 뒤 별도 실증한다.</td></tr>
<tr><td>Persona auth boundary</td><td><code>GET /personas</code></td><td>2026-06-30 복구 후 public unauth <code>/personas</code>는 401 <code>not authenticated</code>를 반환한다.</td></tr>
<tr><td>Public login</td><td><code>auth.spec.ts --grep public login</code></td><td>1 passed</td></tr>
<tr><td>Public runtime scripts · source pin</td><td><code>start/watch/boot-public-runtime*.ps1</code> · <code>install-public-runtime-task.ps1</code> · <code>register-boot-task.ps1</code></td><td>2026-08-28 detached-clean <code>99779a6a…fbc8</code>·tree <code>57da86aa…6b91</code>에 로그온·watchdog 두 task를 재등록했다. action working directory/root/commit/tree/SHA pin, <code>PT1H</code>, <code>IgnoreNew</code>, scheduler retry 0은 PASS다. focused 회귀 50/50 뒤 watchdog 18:10:57 KST·boot 18:14:27 KST 수동 실행은 모두 <code>LastTaskResult=0</code>, failcount 0이었다. 실제 Windows 재부팅 자동복구 smoke는 별도 운영 gate다.</td></tr>
<tr><td>Public API health</td><td><code>http://127.0.0.1:8001/health</code> / <code>https://api-vignette.chanpaca.net/health</code></td><td>2026-08-28 17:11:47 KST local/public 모두 <code>status=ok·environment=prod·db=true·engine=true</code>. voice는 local/public 모두 <code>local_whisper small</code>·<code>melotts-korean</code>·WS queue 4, web은 local/public 200과 동일 asset <code>index-DJPgoeJy.js</code>/<code>index-CXOy3QyV.css</code>를 반환했다. DB는 백업 <code>vignette-dev-db-vignette-20260828-065331Z.dump</code>를 검증하고 recovered named volume을 보존한 채 migration 17을 적용했다.</td></tr>
<tr><td>Public runtime current snapshot</td><td><code>health + provenance + Scheduled Tasks + Pages</code></td><td>현재 동작 중인 API/engine/web/STT/TTS/cloudflared와 Cloudflare Pages production <code>1f1ddf18-9d5c-4d83-95a7-8cd71245e646</code>은 clean source <code>2a396361…89c</code> 계열이다. 다음 장애/로그온 복구 task만 <code>99779a6a…fbc8</code>에 pin했다. 새 학습자 헤더를 포함한 dist는 714파일·assets 164개로 빌드하고 최근 production 5세대를 보존했지만, Pages upload는 명시 승인이 없어 실행하지 않았다.</td></tr>
<tr><td>Public/local/Tailnet login recovery</td><td><code>https://vignette.chanpaca.net/login</code> / <code>https://api-vignette.chanpaca.net/health</code> / <code>https://alpaca-home.taile93291.ts.net/login</code></td><td>2026-08-28 public web 200, public API health 200, auth config 200, Google login start와 callback 성공, P20 실제 회기·응답·종료·평가 폐루프 성공. Earlier Tailnet checks remain recorded separately; vnet DNS A records are still 0.</td></tr>
<tr><td>Public runtime scripts · source pin</td><td><code>start/watch/boot-public-runtime*.ps1</code> · <code>install-public-runtime-task.ps1</code> · <code>register-boot-task.ps1</code></td><td>2026-08-29 최신 read-only 확인에서 두 task는 old detached <code>dba9b75a…</code> runtime을 계속 가리킨다. Docker daemon 부재로 runtime task는 실패했고 watchdog도 DB/API를 복구하지 못한다. 새 total-size/decode receipt 후보는 미배포이며, 후보 통합 GREEN·사용자 승인 전 task 재등록이나 runtime 재시작을 하지 않는다. 실제 Windows 재부팅 자동복구 smoke도 별도 운영 gate다.</td></tr>
<tr><td>Public API health</td><td><code>http://127.0.0.1:8001/health</code> / <code>https://api-vignette.chanpaca.net/health</code></td><td><b>2026-08-29 최신 상태는 OUTAGE다.</b> local 8001은 연결 거부, public API는 530이며 Docker Desktop Linux engine pipe가 없다. 정적 public Web 200은 API·DB GREEN을 뜻하지 않는다. 2026-08-28의 <code>status=ok·db=true·engine=true</code>와 voice exact 값은 과거 성공 증거로만 보존한다.</td></tr>
<tr><td>Public runtime current snapshot</td><td><code>health + provenance + Scheduled Tasks + Pages</code></td><td>배포된 동적 런타임/task 기준선은 clean commit <code>dba9b75a…</code>·tree <code>14cd4607…</code>, Cloudflare Pages production은 <code>0c60261e-cb37-482d-ba42-d91586194c48</code>(source <code>5bf89ff4…</code>)다. 현재 API/DB는 장애이고 fail-closed avatar 후보와 새 upload receipt는 아직 이 기준선에 승격되지 않았다. 후보와 deployed baseline을 분리하며, 승인 전 Docker/API/tunnel/task/DB/upload-root mutation을 하지 않는다.</td></tr>
<tr><td>Public/local/Tailnet login recovery</td><td><code>https://vignette.chanpaca.net/login</code> / <code>https://api-vignette.chanpaca.net/health</code> / <code>https://alpaca-home.taile93291.ts.net/login</code></td><td>2026-08-28 Google callback→관리자·P20 실제 회기 폐루프는 유효한 과거 증거다. 2026-08-29에는 public API 530으로 신규 callback·관리자·G8 실DB E2E를 재검증할 수 없으므로 현재 운영 GREEN으로 재사용하지 않는다. public Web은 정적 로그인 화면만 200이다.</td></tr>
<tr><td>Local 5175 login</td><td><code>PLAYWRIGHT_BASE_URL=http://127.0.0.1:5175 auth.spec.ts</code></td><td>desktop/mobile passed</td></tr>
<tr><td>Learner/readiness E2E</td><td><code>learner.spec.ts + readiness.spec.ts desktop/mobile</code></td><td>14 passed</td></tr>
<tr><td>Learner growth header</td><td><code>uc-learner-home-dashboard.spec.ts --grep "성장 지표 라포 헤더"</code></td><td>2026-08-28 chromium desktop/mobile 2 passed. 라포 문구 부모를 inset surface에서 plain div로 바꾸고 computed background transparent·border/radius/padding 0을 고정했다. typecheck·design SSOT·cosmetic filter safety도 통과했으며 Pages에는 아직 미배포다.</td></tr>
@ -1249,7 +1259,7 @@ $env:E2E_PUBLIC_STORAGE_STATE=".\node_modules\.tmp\public-auth.json"
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\start-public-runtime.ps1</pre>
</div>
<div class="source-note"><b>닫은 항목(live 증거):</b> ① engine config 운영값(<code>claude_cli / 9099 / gateway-default</code>, durable, db). ② 상주 엔진풀 probe — 단일 session_id 2회 reused stream, TTFT 16674199ms, cost 누적 0.068→0.123. ③ 상주 엔진풀 RSS — gateway session 1개에서 <code>claude -p</code> child RSS 363.3MB, gateway RSS 16.2MB. ④ Postgres RLS/audit smoke 5 checks PASS. ⑤ turn cost telemetry — <code>app.turns</code> client_ai 13행에 provider/model/cost_usd 실적재(합 $1.22). ⑥ 레이아웃 시각 게이트 최신 9/9 + 2026-06-28 적대적 재검수 7/7 accept.</div>
<div class="source-note"><b>환경·외부 승인 때문에 아직 못 닫는 항목(정직 표기):</b> 새 학습자 헤더 Cloudflare Pages production upload 명시 승인 · 신규 Gmail 선택→Vignette 계정 생성은 사용자 행동시점 확인 필요 · C-001 사례별 판정·근거·수정 요구·재검토·검토일 30개, 청소년 답변 6개, 임상 검토자 이름·소속·자격·결정 근거를 포함한 승인 10필드와 서명 증거/해시·검토본 고정 · <code>vnet.18ka.net</code>/<code>api-vnet.18ka.net</code> DNS·OAuth redirect 등록 · 한신대 데이터/SSO 거버넌스 · G7 명시 동의 물리 마이크 3,120초와 공통 3,000초 운영 high-water, 독립 human voice-gain pack, canonical checker exit 0 · claude_cli↔Messages API 폴백 동일성 · 실제 Windows 재부팅 후 watchdog smoke · Phase 3 파일럿 게이트. C-001 내부 검토 패킷·canonical 판정기·상한 수리와 <code>pending-valid</code> 검증, current source 공개 배포, generic Google callback, P20 실제 턴·종료·평가, local/public voice exact ready, authenticated WSS 무마이크 rehearsal은 완료했다. 운영 원칙상 가짜 증거로 DONE 표기하지 않는다.</div>
<div class="source-note"><b>환경·외부 승인 때문에 아직 못 닫는 항목(정직 표기):</b> public API/DB 장애 복구와 avatar fail-closed 후보의 전체 회귀·배포·실브라우저 fallback · G8 관리자 사람 게이트의 승인형 실DB append-only 증거와 public proof(local stateful in-app browser는 GREEN) · C-001 사례별 판정·근거·수정 요구·재검토·검토일 30개, 청소년 답변 6개, 임상 검토자 이름·소속·자격·결정 근거를 포함한 승인 10필드와 서명 증거/해시·검토본 고정 · <code>vnet.18ka.net</code>/<code>api-vnet.18ka.net</code> DNS·OAuth redirect 등록 · 한신대 데이터/SSO 거버넌스 · G7 명시 동의 물리 마이크 3,120초와 공통 3,000초 운영 high-water, 독립 human voice-gain pack, canonical checker exit 0 · claude_cli↔Messages API 폴백 동일성 · 실제 Windows 재부팅 후 watchdog smoke · Phase 3 파일럿 게이트. REQ-001은 Gmail 인증 세션·관리자·복구 데이터 수락으로 완료했다. C-001은 <code>pending-valid</code> 기술 사전검증뿐이며 외부 검수 입력을 조작하지 않는다. 운영 원칙상 가짜 증거로 DONE 표기하지 않는다.</div>
</div>
<div class="tab-panel" id="panel-decisions" role="tabpanel" aria-labelledby="tab-decisions" hidden>
<div class="detail-head"><div><h3>윤찬 결정 상세 (전건 확정)</h3><p>람다가 단독으로 정하면 월권인 항목이었다. 2026-06-30 owner 결정으로 전건 확정됐고, 각 결정의 구현·실측은 후속 build/GATE로 남는다.</p></div><div class="mini-metrics"><span>결정 0개(전건 확정)</span><span>조건부 GO 사유</span></div></div>