diff --git a/docs/README.md b/docs/README.md index 6909f9a..7ddc1c2 100644 --- a/docs/README.md +++ b/docs/README.md @@ -103,6 +103,7 @@ | [`ops/nas-preview-g8-rollback-proof-runbook.md`](./ops/nas-preview-g8-rollback-proof-runbook.md) | G8 실제 receipt-bound image rollback 런북 — Gate6 helper 격리 계약 정정(소속 기준), 실행 순서, 금지 사항, 실패 복구 | | [`ops/evidence/nas-preview-g8-actual-rollback-2026-08-07.json`](./ops/evidence/nas-preview-g8-actual-rollback-2026-08-07.json) | G8 실제 rollback/restore 기계 판독 증거 — helper 격리, 두 executed receipt, HMAC journal 체인, DB lifecycle 집계, 정리 상태 | | [`ops/evidence/google-account-data-recovery-2026-08-29.json`](./ops/evidence/google-account-data-recovery-2026-08-29.json) | Google identity alias 기반 관리자 데이터 복구의 백업·가드 트랜잭션·운영 DB·공개 런타임·Pages 승격 증거(실제 Gmail callback 미완료) | +| [`ops/evidence/admin-openrouter-recovery-2026-09-22.json`](./ops/evidence/admin-openrouter-recovery-2026-09-22.json) | 관리자 OpenRouter 장애의 API/web 복구·실제 PostgreSQL rollback·배포/보존 census 영수증 — 새 OAuth finish 성공 관측만 대기 | | [`ops/evidence/google-account-live-browser-proof-2026-08-29.json`](./ops/evidence/google-account-live-browser-proof-2026-08-29.json) | 기존 실서비스 인증 세션의 `yunchan8804@gmail.com`·관리자 권한·온보딩 비전환·복구 데이터 가시성 및 현행 단일 Google CTA 검증 증거 | | [`ops/evidence/workbook-runtime-sync-2026-08-29.json`](./ops/evidence/workbook-runtime-sync-2026-08-29.json) | 개선관리 완료본의 현행 API·Pages 증거 동기화, 전 시트 수식·시각 검증과 완료 8·검토 3 유지 기록 | | [`ops/evidence/workbook-req001-completion-sync-2026-08-29.json`](./ops/evidence/workbook-req001-completion-sync-2026-08-29.json) | REQ-001 완료 승격 뒤 개선관리 완료본 6시트·11요구·38수식·수식 오류 0·완료 9/검토 2와 C-001 `pending-valid` 재생성 증거 | diff --git a/docs/TODO.md b/docs/TODO.md index 8e8fa13..7e8e26d 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -24,6 +24,7 @@ | G8-EXTERNAL | G8 실DB/public 사람 게이트를 실행한다. | 승인·보류·반려 사유와 append-only effect를 실제 DB·공개 경로에서 증명. local fixture는 대체 불가. | | G7-EXTERNAL | 동의 기반 외부 음성 종료 게이트를 준비한다. | 장치 선택·명시 동의 후 3,120초 양방향 soak, 3,000초 공통 high-water, 독립 human voice-gain pack, canonical checker exit 0. | | ANTHROPIC-001 | `claude_cli`와 Anthropic API live 동일성을 비교한다. | 기관 키를 게이트웨이 호스트에 승인 주입한 뒤 응답·계량·오류 표면화 비교. 키 주입 전에는 실행하지 않는다. | +| ADMIN-OPENROUTER-001 | 새 사용자 OAuth finish 성공을 관측한다. | API/web 복구·실제 PostgreSQL rollback·배포/보존 census·공개 관리자 UI를 수용했다. OpenRouter UI 상태는 미연결이고 health의 Jev `live_verified=false`는 live 검증이 아니며, 새 OAuth finish 성공 관측 전까지 진행 중이다. [운영 영수증](./ops/evidence/admin-openrouter-recovery-2026-09-22.json)을 따른다. | | JEV-001 | 충분한 한국어 독립 평가와 전체 지연 반복 비교를 마친다. | 운영 API, 합성·인증 브라우저 3턴 runtime과 DB 감정 영속화는 수용했지만 품질 승격은 보류한다. 위 품질 게이트를 닫은 뒤 전체 사용자 흐름 완료 여부를 판단하며, 최신 probe·수용/반려 근거는 [Jev 결정문](./decisions/jev-client-affect.md)을 따른다. | | USER-LATENCY (JEV-001) | 실제 경로에서 text display·voice onset·완료 준비를 분리 측정한다. | 안전 검사를 유지한 최적화 뒤 반복 비교로 사용자 체감 지연을 평가한다. 현재 CUA 관측상한과 소수 audit은 속도 개선 증거가 아니다. | | G6-PRODUCER-CONFLICT | 기존 submission id와 content hash를 읽기 전용으로 대조한다. | `SupervisionResearchConflictError`의 동일 id 재실행 idempotency 충돌을 해소하고 해당 테스트와 실제 cycle 성공을 확인한다. Jev·세션 경로와 분리된 기존 운영 충돌이며, 이번 배포 회귀로 단정하지 않는다. | diff --git a/docs/dev_dashboard.html b/docs/dev_dashboard.html index e4fba13..06b4700 100644 --- a/docs/dev_dashboard.html +++ b/docs/dev_dashboard.html @@ -305,6 +305,7 @@

2026-09-12 비넷 UX 감사: DONE · 로컬 시각 검수 수용. 역할별 메뉴·모바일 라벨, 학습자 정보 위계와 긴 목록, 상담 시작 버튼 겹침, 교수·관리자 표의 넘침, 설정과 약관 배치를 수정했다. 전체 레이아웃 15 passed, 마지막 관리자 폭 보정 후 2 passed, 회기 8 passed, 접근성 44개(38+6) 통과와 직접 이미지 검수를 수용했다. 상세 판정·반려 기록·실제 API와 fixture 증거 경계는 감사 기록에 있다. 이후 SHA e8b770e4d9023238bf210b412de75dcb98bfc08e는 Forgejo master에 push했고, 17:55:31 KST 배포 시작 뒤 Pages 공개 배포와 NAS web 전용 교체를 18:06 KST까지 완료했다. API·engine·DB는 유지했다. 인증 내부 UI는 401 세션 만료로 미검증이므로 전체 운영 내부 화면 GREEN이나 전체 기능 출시 완료를 뜻하지 않으며 배포 현황을 따른다.

JEV-001 가상 내담자 감정 판단: 운영 runtime 수용·품질 승격 검증 중. API 1172 passed·1 skipped·0 failed, gateway 82 passed, web typecheck·build·API types 통과와 NAS 합성·인증 브라우저 3턴 runtime, 새로고침 6발화 복원·실제 6발화 review 요약·deep-loop 완료·DB 9축 감정 영속화를 수용했다. 공개 main JS와 health, /sessions CORS preflight는 200이고 Jev가 configured지만, 독립 한국어 품질 평가·성능 우위·정확도·사용자 체감 지연 개선·DONE 주장은 보류한다. 코드 기본값 legacy를 유지하며 SHA 969d9e2c3c94b4f3356defbf02bc863e1c8e30e1와 API image를 적용했다. 배포 중 일시 502가 있어 무중단을 주장하지 않으며, 상세 수용/반려와 다음 게이트는 Jev 결정문을 따른다.

G6-PRODUCER-CONFLICT: API 기동 중 기존 background 연구 producer의 SupervisionResearchConflictError 1건을 관측했다. Jev·세션 경로와 분리됐고 이번 배포 diff에 producer·store 변경이 없어 배포 회귀로 단정하지 않는다. 다음은 기존 submission id/content hash의 읽기 전용 대조, idempotency 충돌 해소, 해당 테스트와 실제 cycle 성공이다.

+

ADMIN-OPENROUTER-001: API/web 복구·배포 수용 · OAuth finish 대기. 관리자 OpenRouter 복구의 SQL 수정은 실제 PostgreSQL 임시 테이블 rollback으로 확인했고 API 1173 passed·1 skipped·0 failed, 웹 정적 검증과 focused 선택 16개도 통과했다. NAS web·Pages 배포, public HTML/entry와 health 200, 이전 자산 174개 추가 보존·수집 실패 0, 공개 관리자 UI의 ready·복구 화면 없음·gpt-5.6-terra 유지를 수용했다. OpenRouter UI는 미연결이며 health의 Jev live_verified=false는 live 검증이 아니다. 남은 조건은 새 사용자 OAuth finish 성공 관측뿐이며, 전체 GREEN은 주장하지 않는다. 상세는 운영 영수증을 따른다.

2026-08-31 배포 파이프라인 재정립(역사 기록): git 관리·배포는 git.chanpaca.net(Forgejo) 중심으로 이관했고, github.com(origin)은 private 백업/미러로 유지한다. 배포 대상은 NAS Production(docker-compose.nas.yml, vignette-prod)이며 이 PC는 개발용이다. Cloudflare tunnel은 NAS ingress의 현재 경로이므로 대체 ingress 검증 전에는 제거하지 않는다. 문서 deployment-pipeline.md.

최근 확인된 배포 증거(2026-09-01 당시): Forgejo master dce85620를 NAS에서 직접 clone·빌드해 vignette-prod api/engine/web을 교체했고, Cloudflare Pages production도 새 빌드(index-BFKGXJQi.js, 이전 세대 자산 보존)로 배포했다. 사전 dump cab6826b…(11.0MB·TOC 1783)·env 백업·구 이미지 보존으로 롤백 경로를 고정했다. 중복 활성 회기 14쌍 30행은 최신 유지 정책으로 종료(영수증 보존·삭제 0)하고 마이그레이션 20/21/22를 온라인 적용했다. 이 과정에서 mig22의 name[]=text[] 캐스트 결함과 master의 게이트웨이 openai provider 누락 회귀를 발견해 즉시 교정했다(테스트 71 passed). 배포 당시 public health ok·db/engine true, OpenAPI 200, /auth/me 401, dev-login 404, 데이터 집계 전후 동일(app_user 1380/sessions 618/turns 1743)을 확인했다. 증거: nas-prod-deploy-2026-09-01.json. headful 실계정 폐루프도 당시 완료: NAS env의 OAuth secret 오류(invalid_client)를 교정한 뒤 소유자 실계정 로그인→기존 회기 20건 표시(데이터 보존)→새 사례 회기 생성(mig22 실증)→실턴 SSE·AI 응답→종료→리뷰 생성까지 GREEN(sessions 619·turns 1745·case_profile 566). 일일 검증형 DB 백업 sidecar 첫 덤프도 11.2MB로 성공했다. 남은 운영·외부 게이트: C-001 외부 임상 검수, NAS 재부팅 자동복구 smoke, 백업 실패 알림·off-host 복제.

@@ -1039,6 +1040,7 @@
DONE
프로세스 난립 정리

운영 확인용 프로세스와 로컬/Tailnet 검증용 dev 프로세스를 의도적으로 분리해 유지한다.

산출물

9099 engine, 8001 prod API, 8000/8010 dev API, 5173 web, cloudflared tunnel 1개

검증

Get-NetTCPConnection에서 대상 포트별 listener 확인

GATE
한신대 공문/데이터 거버넌스 게이트 정리

SSO 클레임, 추가 축어록 수급, 미성년 원본 활용동의, 개인정보 처리방침을 P1 진입 전 외부 의존성으로 명확히 둔다. 로컬 문서 골격은 준비됐지만 한신대/데이터 steward의 written evidence는 아직 필요하다.

산출물

docs/ops/hanshin-data-governance-gate.md, 공문 질의 항목, 동의 범위 체크리스트, SSO claim mapping 표

검증

문서 artifact 작성 완료; IRB 게이트가 아니라 데이터/SSO 게이트로 외부 증거 필요 상태 유지

JEV-001
Jev 감정 판단 실증과 기존 내담자 경로 반복 비교

수용: 신규 artifact 보존 갱신, app 1172 passed/1 skipped/0 failed, engine 82 passed, web typecheck/build/API types 통과, NAS API 배포·공개 JS/CORS preflight, 인증 브라우저 3왕복·6발화와 DB 9축 감정 영속화. 보류: 성능 우위·정확도·품질 승격과 사용자 체감 지연 개선.

산출물

runner/probe·배포 artifact는 Jev 결정문과 운영 증거에서 관리한다.

검증

새로고침 뒤 6발화 복원, 종료 review의 실제 6발화 요약·deep-loop 완료와 DB 종료 상태를 확인했다. USER-LATENCY는 text display·voice onset·완료 준비의 실제 경로 분리 측정과 안전 검사 유지 최적화가 남는다. 일시 502 관측 때문에 무중단을 주장하지 않는다.

+
ADMIN-OPENROUTER-001
관리자 OpenRouter 복구의 웹 검증과 새 OAuth 재시도

수용: AmbiguousColumnError의 기존 refresh column 참조와 EXCLUDED.extra의 text 캐스트 제거(JSONB 비교)를 수정했고, 실제 PostgreSQL rollback·API 교체·보존 census를 확인했다. 웹 focused 선택 16개와 정적 검증, NAS web·Pages 배포, public entry/health 200과 관리자 UI의 ready·복구 화면 없음은 수용했다. 진행 중: 새 사용자 OAuth finish 성공 관측.

산출물

운영 영수증

검증

API 1173 passed·1 skipped·0 failed, focused 16 passed, health ok·DB/engine true. API 교체 직후 census에서 133개 테이블 중 130개 동일이며 활동 메타데이터 3개는 변했다. OpenRouter UI 미연결과 Jev live_verified=false는 live 검증이 아니며, OAuth finish 성공은 아직 주장하지 않는다.

DONE
한신대 실사용 피드백 1차 개선팩

오류분석 자료를 컨텍스트 보존, 내담자 출력 품질, 리뷰 privacy/오류문구 UX, 교수자 설명 가능성으로 분해했고 1차 구현을 완료했다. P1은 role mapping + client-only history injection을 원자 패치로 닫았고, P2/P3/P4는 저장형 fallback 없이 빠른 UX 개선으로 배포 가능한 상태다.

산출물

gateway._split_messages(ai_role=client), guardrail.sanitize_client_reply() 품질 게이트, SSE full-response buffer, 리뷰 표시 자연어화, raw error mapper, 교수자 AI 평가 범위 패널, 계획/레드팀/대레드팀 문서

검증

engine_gateway/test_gateway_model.py app/test_orchestrator_masking.py app/test_client_reply_quality.py app/test_session_turn_persistence.py 84 passed, npm run typecheck, npm run check:api-types, session-review.spec.ts focused 8 passed, layout-visual-gate.spec.ts 12 passed, session-layout.spec.ts 8 passed.

팀장 판정: 로컬 회귀와 공개 prod-safe 게이트는 통과했다. 2026-06-29 수동 Cloudflare Pages production 배포가 현재 custom domain asset으로 확인됐고, 운영 반영 전 남은 핵심 증거는 공개 Google OAuth 실제 /turn smoke다. 런타임 mock/demo 자산은 운영 번들에서 제거하고 테스트 fixture만 남긴다.
@@ -1140,7 +1142,7 @@ Web typechecknpm run typecheckPassed Design SSOT / auth visualnpm run check:design-ssot / npx playwright test e2e/auth-visual.spec.ts --project=chromium-single-run --reporter=line / npx playwright test e2e/layout-visual-gate.spec.ts --project=chromium-single-run --reporter=lineSSOT checker passed; login/onboarding light-dark desktop-mobile 1 passed; 14 core screens × 7 widths visual gate 14 passed. - Full Playwright E2E baselinenpm run e2e:parallel / npm run e2e:single-run / npm run e2e:list2026-09-12 .devlogs/playwright-accepted-list.out.log 기준 현재 수집은 1219 tests / 70 files다. 이 숫자는 수집량이며 현 작업트리 전체 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는 범위가 다른 역사 기준선으로 보존한다. + Full Playwright E2E baselinenpm run e2e:parallel / npm run e2e:single-run / npm run e2e:list2026-09-22 check-dev-dashboard-ssot.py의 실제 수집 기준 현재 수집은 1235 tests / 70 files다. 이 숫자는 수집량이며 현 작업트리 전체 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는 범위가 다른 역사 기준선으로 보존한다. Refactor governance P1~P8ruff check app / pytest -q app / pytest -q engine_gateway / npm run typecheck / npm run check:api-types / npm run check:design-ssot / npm run check:dead-code / npm run check:duplication / npm run build / npm audit --audit-level=high / full PlaywrightBackend 400 passed, gateway 29 passed, web gates/build/audit passed, vulnerabilities 0, production duplication 1 clone/15 lines/0.03%, Playwright 215/215 passed. 상세 근거는 archive/project-cleanup-2026-09-07/refactor-governance-2026-07-15.md. API typegen SSOTnpm run check:api-typesPassed; FastAPI OpenAPI → src/lib/api.gen.ts stale check Outcome & Alliance OS G0py -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 / scripts/check-measurement-ledger.sql / measurement·API contract checks / web typecheck / DB-backed session-persistence focused E2E 3종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 완료. diff --git a/docs/guides/testing.md b/docs/guides/testing.md index b627b19..26d1965 100644 --- a/docs/guides/testing.md +++ b/docs/guides/testing.md @@ -15,12 +15,12 @@ Vignette 저장소의 모든 검증 수단(백엔드 단위 테스트, 웹 타 | 검증 | 작업 디렉터리 | 명령 | DB | API(8000) | 웹(5173) | 엔진GW(9099) | 브라우저 | 현재 통과 | |---|---|---|---|---|---|---|---|---| -| 백엔드 단위 테스트 | `apps/api` | `py -3.11 -m pytest app/ -q` | 불필요 | 불필요 | 불필요 | 불필요 | 불필요 | 2026-09-07 전체 실행 1090 passed / 1 skipped / 1 warning | +| 백엔드 단위 테스트 | `apps/api` | `py -3.11 -m pytest app/ -q` | 불필요 | 불필요 | 불필요 | 불필요 | 불필요 | 2026-09-22 전체 실행 1173 passed / 1 skipped / 0 failed | | 엔진 게이트웨이 테스트 | `apps/api` | `py -3.11 -m pytest engine_gateway/ -q` | 불필요 | 불필요 | 불필요 | 불필요 | 불필요 | 2026-09-07 전체 실행 71 passed / 1 warning | | API 타입 생성 체크 | `apps/web` | `npm run check:api-types` | 불필요 | 불필요 | 불필요 | 불필요 | 불필요 | pass | | 웹 타입체크 | `apps/web` | `npm run typecheck` | 불필요 | 불필요 | 불필요 | 불필요 | 불필요 | pass | | 웹 빌드 | `apps/web` | `npm run build` | 불필요 | 불필요 | 불필요 | 불필요 | 불필요 | pass | -| Playwright E2E(전체) | `apps/web` | `npm run e2e` | **필요(+시드)** | **필요** | 자동기동 | 일부만 | **필요** | 현재 수집 1219 tests / 70 files · 현 작업트리 전체 GREEN 미검증 | +| Playwright E2E(전체) | `apps/web` | `npm run e2e` | **필요(+시드)** | **필요** | 자동기동 | 일부만 | **필요** | 현재 수집 1235 tests / 70 files · 현 작업트리 전체 GREEN 미검증 | 핵심 원칙: **단위 테스트(pytest)와 타입체크/빌드는 외부 서비스 없이 단독 실행된다.** **E2E만 풀스택(DB+API+웹+브라우저)을 요구한다.** 아래 각 절에서 근거와 절차를 설명한다. @@ -48,10 +48,15 @@ Windows에서 기본 `python`이 Python 3.11이 아니거나 pytest를 갖지 ```sh # apps/api -py -3.11 -m pytest app/ -q # 앱 단위 테스트: 2026-09-07 전체 실행 1090 passed / 1 skipped / 1 warning +py -3.11 -m pytest app/ -q # 앱 단위 테스트: 2026-09-22 전체 실행 1173 passed / 1 skipped / 0 failed py -3.11 -m pytest engine_gateway/ -q # 게이트웨이 단위 테스트: 2026-09-07 전체 실행 71 passed / 1 warning +py -3.11 -X utf8 -m pytest -p no:cacheprovider app/test_provider_credentials_service.py app/test_auth_providers.py engine_gateway/test_provider_registry.py -q # ADMIN-OPENROUTER-001 provider 자격증명·인증·registry 회귀 ``` +2026-09-22의 앱 전체 1173 passed / 1 skipped 실행은 해당 실행 환경에서만 VIGNETTE_CLIENT_AFFECT_PROVIDER=legacy를 설정했다. 이는 일반 단위 테스트의 전역 필수 조건이 아니다. + +2026-09-22 ADMIN-OPENROUTER-001 웹 focused는 최초 13 passed·3 failed 뒤 fixture 전제와 stale assertion을 고쳤고, 독립 재검증 3 passed·0 failed(6.2초)로 선택 16개가 통과했다. 이는 OAuth 성공 또는 현 작업트리 전체 GREEN의 증거가 아니다. NAS web/Pages 배포와 공개 관리자 UI 수용은 [운영 영수증](../ops/evidence/admin-openrouter-recovery-2026-09-22.json)을 따른다. + 수집만 빠르게 확인하려면: ```sh @@ -321,9 +326,9 @@ VITE_API_BASE=http://127.0.0.1:8000 npm run e2e # 프록시 대신 API ### 3.6 실측 테스트 개수 (현재) -2026-09-12 `.devlogs/playwright-accepted-list.out.log`의 `npx playwright test --list` 기준 **현재 수집 1219 tests / 70 files**다 +2026-09-22 `py -3.11 -X utf8 scripts/check-dev-dashboard-ssot.py`가 실행한 `npx playwright test --list` 실제 수집 기준 **현재 수집 1235 tests / 70 files**다 (유스케이스 16테마 `uc-*.spec.ts` 239 시나리오 포함). -이 숫자는 수집량이지 통과량이 아니다. 현 작업트리 전체 1109개 완주는 아직 증거가 없으며, +이 숫자는 수집량이지 통과량이 아니다. 현 작업트리 전체 완주는 아직 증거가 없으며, 과거 전체 GREEN 기록과 이번 focused/release gate 결과를 구분해 적는다. NAS-origin 112건은 전부 실 API/DB 회기가 아니다. release receipt는 `session-layout`·`session-persistence` diff --git a/docs/ops/backlog-2026-06-26.md b/docs/ops/backlog-2026-06-26.md index 246be48..15d634f 100644 --- a/docs/ops/backlog-2026-06-26.md +++ b/docs/ops/backlog-2026-06-26.md @@ -36,6 +36,7 @@ npx playwright test e2e/uc-session-conversation.spec.ts --grep '스트림 도중 | G8-EXTERNAL | 실DB/public 사람 게이트 | 승인·보류·반려와 append-only effect의 실제 public proof | local fixture와 route E2E는 대체 불가 | | G7-EXTERNAL | 동의 기반 음성 외부 proof | 3,120초 soak, 3,000초 overlap high-water, 독립 human pack, checker exit 0 | 장치 선택·명시 동의 전 마이크를 열지 않음 | | ANTHROPIC-001 | provider live 동일성 비교 | 승인 주입한 기관 키로 응답·계량·오류 표면화 비교 | credential 취급·주입은 소유자 경계 | +| ADMIN-OPENROUTER-001 | 새 사용자 OAuth finish 성공 관측 | API/web 복구·실제 PostgreSQL rollback·배포/보존 census·공개 관리자 UI를 수용 | OpenRouter UI는 미연결, health Jev `live_verified=false`는 live 검증이 아님. 상세는 [운영 영수증](./evidence/admin-openrouter-recovery-2026-09-22.json)을 따른다. | | JEV-001 | 한국어 독립 평가와 전체 지연 반복 비교 | 운영 API·공개 JS·CORS preflight, 합성·인증 브라우저 3턴 runtime과 DB 감정 영속화를 수용했다. 감정·사실 품질과 지연을 평가한다. | 구현 수용·품질 승격 보류. 상세 수용/반려·최종 probe는 [Jev 결정문](../decisions/jev-client-affect.md)을 따른다. | | USER-LATENCY (JEV-001) | text display·voice onset·완료 준비의 실제 경로 분리 측정 | 안전 검사를 유지한 최적화 뒤 반복 비교 | 소수 CUA 관측상한·audit은 사용자 체감 속도 개선 증거가 아님 | | G6-PRODUCER-CONFLICT | 기존 submission id/content hash 읽기 전용 대조 | 동일 id 재실행 idempotency 충돌을 해소하고 해당 테스트와 실제 cycle 성공을 확인 | 기존 background producer 충돌 관측; Jev·세션 경로와 분리, 이번 배포 회귀로 단정하지 않음 | diff --git a/docs/ops/evidence/admin-openrouter-recovery-2026-09-22.json b/docs/ops/evidence/admin-openrouter-recovery-2026-09-22.json new file mode 100644 index 0000000..3b0c3cb --- /dev/null +++ b/docs/ops/evidence/admin-openrouter-recovery-2026-09-22.json @@ -0,0 +1,160 @@ +{ + "schema_version": 1, + "recorded_on": "2026-09-22", + "scope": "관리자 OpenRouter 복구의 API/web SQL 수정, 실제 PostgreSQL 검증, 배포와 보존 census", + "source": { + "forgejo_commit": "d58eb67764b8e5d6c17472a845bfa4d7cc260973", + "api_image_sha256": "4466081ee51a4c65ce80a927a8a604dc5212d5673a1eb2c553a5e845067cbe33", + "api_container": "0cbd7fd7d3c6" + }, + "root_cause_and_fix": { + "observed_error": "AmbiguousColumnError for the existing refresh column", + "fixes": [ + "기존 refresh column 참조를 명시했다.", + "EXCLUDED.extra의 text 캐스트를 제거해 JSONB끼리 비교한다." + ], + "actual_postgresql_verification": { + "method": "임시 테이블에서 AST 원본 쿼리를 3회 실행한 뒤 rollback", + "passed": true + } + }, + "pre_deploy_preservation": { + "database_dump": { + "name": "pre-deploy-admin-recovery-20260922.dump", + "bytes": 11806566, + "pg_restore_list_passed": true + }, + "environment_and_compose_backups_retained": true + }, + "deployment": { + "api_replaced": true, + "public_health": { + "status": "ok", + "db": true, + "engine": true, + "engine_mode": "openai", + "jev_provider": "openrouter" + }, + "api_tests": { + "passed": 1173, + "skipped": 1, + "failed": 0 + }, + "api_replacement_phase_db_engine_web_containers_unchanged": true + }, + "post_deploy_census": { + "table_count": 133, + "unchanged_table_count": 130, + "activity_metadata_changes": { + "app.app_user": { + "rows": 1382, + "row_count_unchanged": true, + "digest_changed": true + }, + "app.auth_session": { + "rows": 1746, + "row_count_unchanged": true, + "digest_changed": true + }, + "app.admin_health_event": { + "before": 14040, + "after": 14045 + } + }, + "uploads": { + "files": 93, + "bytes": 52973, + "manifest_sha256": "c6f63156cf38be0e551b2d8f64bdc4e76e76a013181a6ff732c04ff102b3a6b1", + "unchanged": true + }, + "api_replacement_phase_non_api_containers_unchanged_assertion_passed": true + }, + "open_gates": [ + "새 사용자 OAuth finish 성공 관측" + ], + "privacy": "키, 인증 코드, 개인 식별 정보, 대화 내용은 이 기록에 포함하지 않는다.", + "web_verification": { + "static_checks": { + "typecheck": "passed", + "build": "passed", + "api_types": "passed", + "build_entry": "index-CFb6KpZF.js" + }, + "focused_checks": { + "initial": { + "passed": 13, + "failed": 3 + }, + "independent_recheck": { + "passed": 3, + "failed": 0, + "duration_seconds": 6.2, + "selected_total_passed": 16 + }, + "fixed_preconditions": [ + "옵션 6에서 9로 stale assertion을 정정했다.", + "인증 fixture와 API 기동 전제를 보완했다." + ] + }, + "forgejo_web_commit": "fb640a75ac674c5bd5f7055daabd81b52112ad53", + "forgejo_push_completed": true, + "nas_web_image_sha256": "a6312d07af56f84a57f0858a74aa4e41b04c2e7031dbe105580b5d4456a5ad68", + "nas_web_replacement": "completed", + "pages_deployed": true, + "whole_worktree_green": false, + "web_deployment_completed": true, + "nas_entry_asset": { + "path": "/assets/index-DJgMn3pJ.js", + "status": 200 + }, + "api_engine_db_containers_unchanged_assertion_passed": true, + "pages_deployment_url": "https://0150d52e.vignette-b1q.pages.dev", + "public_entry_asset": { + "path": "/assets/index-CFb6KpZF.js", + "status": 200 + }, + "asset_preservation": { + "processed": 247, + "preserved": 174, + "existing": 73, + "failed": 0 + }, + "authenticated_public_admin_ui": { + "ready": true, + "boot_diagnostic_visible": false, + "server_recovery_visible": false, + "engine": "openai", + "model": "gpt-5.6-terra", + "openrouter_provider_status": "not_connected" + }, + "public_http": { + "html_status": 200, + "health_status": 200, + "health": { + "status": "ok", + "db": true, + "engine": true + }, + "jev": { + "configured": true, + "live_verified": false, + "provider": "openrouter" + }, + "watchdog_inline_source_fingerprint_verified": true, + "html_verifier": { + "module_entry": "index-CFb6KpZF.js", + "module_entry_matched": true, + "inline_bootstrap_sha256": "c707015e9142e36974b79488aa150772cac63d1b17a2415bdca17c158c4c5f4f", + "inline_bootstrap_matched": true, + "accepted_html_differences": [ + "Cloudflare Insights script", + "closing body newline" + ] + } + } + }, + "oauth_observation": { + "start_status": 200, + "finish_observed": false + } +}