G0~G8 성과·동맹 측정 OS 작업 일괄 고정
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 산출물은 커밋에서 제외했다.
This commit is contained in:
parent
93dd8f82d7
commit
16e791e044
390 changed files with 243188 additions and 499 deletions
|
|
@ -33,13 +33,27 @@ powershell -NoProfile -ExecutionPolicy Bypass -File scripts\dev-up.ps1 -UseHiggs
|
|||
```
|
||||
|
||||
- 진입점 **http://localhost:5173** → 로그인 페이지에서 **dev-login**(아무 `@hs.ac.kr`, role learner/teacher/admin).
|
||||
- Docker가 있으면 기본적으로 `127.0.0.1:55432` DB 컨테이너를 사용한다. 새 컨테이너 생성 시 `POSTGRES_USER=vignette_owner`, API용 앱 role은 `DATABASE_URL` 사용자로 분리해 RLS 검증 기반을 보존한다. Docker가 없거나 `-NoDb`를 쓰면 in-memory degraded로 뜬다.
|
||||
- Docker가 있으면 기본적으로 `127.0.0.1:55432` DB 컨테이너를 사용한다. 정지된 기존
|
||||
`vignette-dev-db`는 제거·재생성하지 않고 그대로 시작하며, 새 컨테이너만 고정 named volume
|
||||
`vignette-dev-db-pgdata`를 사용한다. 시작이나 readiness가 실패하면 container/volume을 보존한 채
|
||||
fail closed한다. 새 컨테이너 생성 시 `POSTGRES_USER=vignette_owner`, API용 앱 role은
|
||||
`DATABASE_URL` 사용자로 분리해 RLS 검증 기반을 보존한다. Docker가 없거나 `-NoDb`를 쓰면
|
||||
in-memory degraded로 뜬다.
|
||||
- 로그는 `.devlogs/`(gitignore). 코드 수정 후에는 dev-up을 다시 실행해 재기동(reload 미사용).
|
||||
- 옵션: `-NoGateway`(기존 gateway 보존), `-NoWeb`(기존 web 보존, API만 재기동), `-NoDb`(DB 컨테이너 보장 건너뜀),
|
||||
`-UseHiggsVoice`(설치된 `higgs-audio-v3-tts-4b`를 127.0.0.1:9881에 상주시켜 P1 TTS로 연결).
|
||||
- `-NoGateway`/`-NoWeb`를 쓰면 해당 컴포넌트의 stale 정리도 건너뛰고, API 정리는 지정한 `-ApiPort` listener만 대상으로 한다. public `8001`, Tailnet `8010`, local `8000`을 나눠 띄운 상태에서 API-only 재기동할 때 다른 포트를 건드리지 않는다.
|
||||
- `dev-down.ps1`은 기본적으로 DB 컨테이너를 보존한다. 컨테이너도 멈추려면 `-Db`를 명시한다.
|
||||
|
||||
DB나 배포 경로를 바꾸기 전에는 custom-format dump와 SHA-256 manifest를 먼저 만든다. 스크립트는
|
||||
DB 내용을 stdout에 흘리지 않고 container 내부 임시 파일을 `pg_restore --list`로 검증한 뒤에만
|
||||
로컬 백업을 원자 게시한다. 기존 container나 volume을 제거하는 경로는 없다.
|
||||
|
||||
```powershell
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\backup-vignette-db.ps1
|
||||
# 기본 위치: D:\workspace\vignette-backups\*.dump + 같은 이름의 .json manifest
|
||||
```
|
||||
|
||||
> 스크립트는 uvicorn이 설치된 python을 자동 해석한다(시스템에 복수 python 공존 시 'python' 별칭이
|
||||
> uvicorn 없는 인터프리터를 가리킬 수 있음 — 이 함정 때문에 명시 해석함).
|
||||
|
||||
|
|
@ -137,6 +151,7 @@ npm install
|
|||
| `DATABASE_URL` | `postgresql://...@127.0.0.1:55432/vignette` | 미연결 시 degraded 폴백(dev 한정) |
|
||||
| `ENGINE_URL` | `http://127.0.0.1:9099` | 엔진 게이트웨이 베이스 URL |
|
||||
| `ENGINE_MODE` | `claude_cli` | `claude_cli` / `claude_api` / `codex_cli` / `agy_cli` 공급자 라우팅. 실제 운영 변경은 관리자 드롭다운이 DB에 저장 |
|
||||
| `ENGINE_GATEWAY_SHARED_SECRET` | 빈 값 | 선택 인증. NAS/원격 preview에서는 API와 gateway에 동일한 32자 이상 비-placeholder 값을 설정. 빈 값은 기존 로컬 9099 호환 |
|
||||
| `VIGNETTE_LIVE_CLIENT_PROVIDER` | `claude_cli` | 실시간 내담자 AI 전용 lane. 관리자에서 선택한 evaluator/review 공급자와 분리해 회기별 Claude 상주 세션을 재사용 |
|
||||
| `AUTH_DEV_LOGIN_ENABLED` | `true` | dev-login 엔드포인트 활성화 |
|
||||
| `AUTH_ALLOWED_EMAIL_DOMAINS` | `["hs.ac.kr","twentyoz.kr"]` | 기본 로그인 허용 이메일 도메인(dev-login 포함 검증). `/admin/users`에 미리 등록된 정확한 이메일은 도메인 밖이어도 예외로 로그인 가능 |
|
||||
|
|
@ -145,8 +160,14 @@ npm install
|
|||
| `AUTH_NEW_USER_DEFAULT_STATUS` | `pending` | Google/SAML 신규 사용자의 기본 승인 상태. `dev:` 로그인은 로컬/E2E 편의를 위해 자동 승인 |
|
||||
| `AUTH_EMAIL_COHORT_MAP` | `{}` | 특정 이메일을 cohort id로 매핑한다. 값은 comma-separated 문자열도 허용 |
|
||||
| `AUTH_DOMAIN_COHORT_MAP` | `{}` | 이메일/Google hosted domain을 cohort id로 매핑한다. Google/SAML/dev-login 세션 `cohort_ids`에 반영 |
|
||||
| `VIGNETTE_VOICE_POC_SAMPLE_TTS` | `false` | P1 무참조 샘플 음성을 `/voice/ws` TTS에 연결하는 개발 전용 플래그. 마이크/STT는 `OPENAI_API_KEY` 필요, 프로덕션 금지 |
|
||||
| `VIGNETTE_VOICE_TTS_PROVIDER` | `openai` 또는 `higgs` | TTS 공급자. `higgs`는 dev + P1에서만 허용하며 다른 환경은 설정 검증에서 차단 |
|
||||
| `VIGNETTE_VOICE_STT_PROVIDER` | `openai` 또는 `deepgram` | STT 공급자. `deepgram`은 streaming interim/final 경로, `openai`는 batch 경로 |
|
||||
| `DEEPGRAM_API_KEY` | 비밀값 | Deepgram streaming credential. key 없이 `deepgram`을 고르면 `OPENAI_API_KEY`가 있을 때만 `openai-batch-fallback`; live Deepgram 증거가 아님 |
|
||||
| `DEEPGRAM_STT_URL` / `DEEPGRAM_STT_MODEL` / `DEEPGRAM_STT_LANGUAGE` | `wss://api.deepgram.com/v1/listen` / `nova-3` / `ko` | Deepgram endpoint와 provider/model metadata 계약 |
|
||||
| `DEEPGRAM_ENDPOINTING_MS` / `DEEPGRAM_UTTERANCE_END_MS` | `300` / `1200` | streaming EOT 경계. utterance end 최솟값은 1000ms |
|
||||
| `DEEPGRAM_KEEPALIVE_SECONDS` / `DEEPGRAM_FINALIZE_TIMEOUT_SECONDS` | `4` / `15` | streaming keepalive와 final 대기 상한 |
|
||||
| `DEEPGRAM_MIP_OPT_OUT` | `true` | Deepgram model improvement program opt-out query 기본값 |
|
||||
| `VIGNETTE_VOICE_POC_SAMPLE_TTS` | `false` | P1 무참조 샘플 음성을 `/voice/ws` TTS에 연결하는 개발 전용 플래그. 마이크/STT는 선택한 STT provider credential 필요, 프로덕션 금지 |
|
||||
| `VIGNETTE_VOICE_TTS_PROVIDER` | `openai` 또는 `higgs` | TTS 공급자. `higgs`는 dev + P1에서만 허용하며 다른 환경은 설정 검증에서 차단. 동작 자체는 운영 상업 이용권 증거를 대신하지 않음 |
|
||||
| `VIGNETTE_HIGGS_TTS_URL` | `http://127.0.0.1:9881` | 로컬 Higgs 상주 서버. 저장소의 무참조 synthetic seed만 화자 참조로 사용 |
|
||||
| `EVALUATOR_SEMANTIC_CACHE_ENABLED` | `true` | fast/deep evaluator structured 결과 인메모리 캐시 활성화. 원문 prompt/completion은 저장하지 않음 |
|
||||
| `EVALUATOR_SEMANTIC_CACHE_TTL_SECONDS` | `900` | evaluator cache TTL(초). 0 이하면 비활성 |
|
||||
|
|
@ -209,7 +230,40 @@ py -3.11 scripts\run-session-digest-worker.py --session-id <session_uuid> --appl
|
|||
- scheduler도 DB load/apply 구간만 connection을 잡고, engine 호출은 DB transaction 밖에서 수행한다.
|
||||
- 장시간 provider 운영, 임상 골든셋 품질평가, 재압축 정책은 별도 gate다.
|
||||
|
||||
### 2.5 DB 없이 degraded 기동 (정상 동작)
|
||||
### 2.5 G8 scheduled agentic producer
|
||||
|
||||
G8 scheduler는 한 job에 generator·독립 reviewer·variant judge 모델 호출이 여러 번 발생하므로 기본값이
|
||||
`false`다. `infra/db/init/14_continuous_improvement.sql`의 runtime contract가 준비된 경우에만 API lifespan이
|
||||
producer를 시작한다. 활성화하면 저장소의 승인된 비식별 synthetic source pack을 immutable
|
||||
`app.ci_agentic_job`으로 멱등 등록하고, lease·`FOR UPDATE SKIP LOCKED`로 제한된 batch를 처리한다.
|
||||
|
||||
```powershell
|
||||
$env:VIGNETTE_CONTINUOUS_IMPROVEMENT_PRODUCER_ENABLED = "true"
|
||||
$env:VIGNETTE_CONTINUOUS_IMPROVEMENT_PRODUCER_INTERVAL_SECONDS = "3600"
|
||||
$env:VIGNETTE_CONTINUOUS_IMPROVEMENT_PRODUCER_STARTUP_DELAY_SECONDS = "30"
|
||||
$env:VIGNETTE_CONTINUOUS_IMPROVEMENT_PRODUCER_RETRY_DELAY_SECONDS = "300"
|
||||
$env:VIGNETTE_CONTINUOUS_IMPROVEMENT_PRODUCER_LEASE_TIMEOUT_SECONDS = "1800"
|
||||
$env:VIGNETTE_CONTINUOUS_IMPROVEMENT_PRODUCER_ENGINE_TIMEOUT_SECONDS = "300"
|
||||
$env:VIGNETTE_CONTINUOUS_IMPROVEMENT_PRODUCER_BATCH_SIZE = "1"
|
||||
$env:VIGNETTE_CONTINUOUS_IMPROVEMENT_DRIFT_TRIGGER_ENABLED = "true"
|
||||
```
|
||||
|
||||
- source usage가 `approved`가 아니거나 classification·본문 SHA-256·PII 검사가 실패하면 engine을 호출하지 않는다.
|
||||
- engine/structured-output 실패는 candidate를 저장하지 않고 `retry_wait`로 남긴다. 한 job 실패는 다음 job을 막지 않는다.
|
||||
- 안전 gate 실패는 `rejected`, 전 gate 통과 결과는 `completed` job과 `pending_human_approval` candidate로만 저장한다.
|
||||
- producer는 사람 승인 event나 catalog entry를 만들지 않는다. 동일 submission recovery는 model call 0으로 재생한다.
|
||||
- drift trigger는 producer와 별도 opt-in이다. 켜면 G6 합성 drift 원장의 canonical 임계값·subgroup 근거를
|
||||
재검증해 metadata-only incident·4-node DAG·`scheduled_incident` job만 원자적으로 enqueue한다. 두 설정 중
|
||||
하나라도 false면 운영 drift 자동 기동은 없다.
|
||||
|
||||
실제 configured engine과 dev PostgreSQL을 일회 검증할 때는 로그인 없이 아래 runner를 사용한다.
|
||||
|
||||
```powershell
|
||||
py -3.11 -X utf8 scripts\smoke-continuous-improvement-agentic-producer.py `
|
||||
--out docs\ops\evidence\continuous-improvement-agentic-producer-live-2026-08-07.json
|
||||
```
|
||||
|
||||
### 2.6 DB 없이 degraded 기동 (정상 동작)
|
||||
|
||||
DB 연결이 안 되어도 dev에서는 그대로 기동한다. `main.py` lifespan이 풀 초기화 예외를 잡고
|
||||
`store` 인메모리 폴백으로 degraded 기동하며, 다음 경고를 남긴다.
|
||||
|
|
@ -434,6 +488,9 @@ python -m uvicorn engine_gateway.gateway:app --host 127.0.0.1 --port 9099
|
|||
```
|
||||
|
||||
관련 환경변수(`gateway.py`):
|
||||
- `ENGINE_GATEWAY_SHARED_SECRET` — 선택 shared secret. 설정하면 `/health`를 제외한 모든 경로가
|
||||
`X-Vignette-Engine-Token`을 constant-time으로 검증한다. API의 `EngineClient`에도 같은 값을 설정한다.
|
||||
값 자체는 로그나 OpenAPI 스키마에 노출하지 않는다. 빈 값은 기존 로컬 9099 호출을 그대로 허용한다.
|
||||
- `CLAUDE_BIN` — claude 실행 파일 경로(기본 `claude`). PATH에 없으면 절대경로 지정.
|
||||
- `CODEX_BIN`, `AGY_BIN` — 각 CLI 경로. Windows Codex는 npm shim 아래 native exe를 자동 탐색한다.
|
||||
- `ANTHROPIC_API_KEY`, `ANTHROPIC_API_BASE` — Anthropic 모델 목록·Messages API.
|
||||
|
|
@ -451,8 +508,9 @@ python -m uvicorn engine_gateway.gateway:app --host 127.0.0.1 --port 9099
|
|||
|
||||
```powershell
|
||||
Invoke-RestMethod http://127.0.0.1:9099/health
|
||||
Invoke-RestMethod 'http://127.0.0.1:9099/v1/capabilities?provider=codex_cli&force=true'
|
||||
Invoke-RestMethod 'http://127.0.0.1:9099/ready?provider=codex_cli&model=gpt-5.6-terra&reasoning_effort=medium'
|
||||
$headers = @{ 'X-Vignette-Engine-Token' = $env:ENGINE_GATEWAY_SHARED_SECRET }
|
||||
Invoke-RestMethod 'http://127.0.0.1:9099/ready?provider=codex_cli&model=gpt-5.6-terra&reasoning_effort=medium' -Headers $headers
|
||||
Invoke-RestMethod 'http://127.0.0.1:9099/v1/capabilities?provider=codex_cli&force=true' -Headers $headers
|
||||
```
|
||||
|
||||
API의 `/health`는 현재 DB 설정의 provider/model/reasoning_effort를 게이트웨이 `/ready`에 전달하고
|
||||
|
|
@ -496,6 +554,18 @@ python scripts\check-deploy-preflight.py --env-file infra\.env
|
|||
python scripts\check-deploy-preflight.py --env-file infra\.env --database-url $env:DATABASE_URL --require-app-role
|
||||
```
|
||||
|
||||
현재 Windows public runtime처럼 `apps/api/.env`의 `DATABASE_URL`로 직접 Uvicorn을 띄우는 경로는 Compose
|
||||
패키징 비밀번호를 요구하지 않는 전용 profile을 쓴다. G3~G8 내부 토큰 값은 명령행이나 로그에 출력하지 않는다.
|
||||
|
||||
```powershell
|
||||
python scripts\provision-outcome-os-runtime-secrets.py --env-file apps\api\.env
|
||||
python scripts\check-deploy-preflight.py --env-file apps\api\.env --deployment-profile direct-runtime --require-app-role
|
||||
```
|
||||
|
||||
운영·스테이징 env는 G3~G8 내부 ingestion 경계별로 서로 다른 32자 이상 토큰 6개를 가져야 한다.
|
||||
프리플라이트는 누락·짧은 값·예시 값·재사용 값을 배포 전에 거부하며, Compose도 같은 키를 필수로 전달한다.
|
||||
DB 검사를 켜면 G0~G8 migration별 대표 원장 테이블도 전부 확인하므로 하나라도 빠진 스키마에는 배포하지 않는다.
|
||||
|
||||
엔진 게이트웨이(9099)는 컴포즈 밖 호스트에서 돌리고, api 컨테이너는
|
||||
`ENGINE_URL=http://host.docker.internal:9099`로 호출한다(compose 기본값).
|
||||
RAG 임베딩/리랭커 의존성은 기본 이미지에 설치하지 않는다. 모델까지 포함한 API 이미지를 만들 때만
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue