vignette/docs/ops/alliance-pulse-live-integration-evidence-2026-08-06.md
Yun Chan 16e791e044 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 산출물은 커밋에서 제외했다.
2026-08-08 01:30:53 +09:00

121 lines
6.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# G1 동맹 펄스 실통합 증거 — 2026-08-06
## 결론
G1 동맹 펄스의 최신 코드 경로를 별도 API 프로세스에서 실제 HTTP와 PostgreSQL로
끝까지 검증했다. 학습자 자기평가 잠금 전후 공개 순서, 두 독립 에이전트의 3축 측정,
동일 코호트 교수자 열람, 교수자 재평정의 append-only supersession이 모두 통과했다.
## 2026-08-07 실제 pre → mid → post 확장 검증
최신 소스 API `8128`에서 실제 새 회기를 만들고 회기 전·첫 왕복 뒤·종료 뒤 세
checkpoint를 한 흐름으로 검증했다. 기계 판독 증거는
`docs/ops/evidence/alliance-pulse-pre-mid-post-live-2026-08-07.json`에 보존한다.
| checkpoint | 실제 결과 |
|---|---|
| pre | 첫 발화 전 잠금, 축어록 부재를 점수로 추정하지 않고 `degraded / insufficient_transcript`; 학습자 3축은 보존하고 외부 두 관점은 무점수 |
| mid | 실제 counselor/client turn UUID 2개를 근거로 `ready`, 3관점 × 3축 공개 |
| post | DB `ended_at`이 기록된 뒤 생성, `awaiting_agents → ready`, 3관점 × 3축 공개 |
post pulse는 최초 `202 / idempotent_replay=false`, 동일 payload 재전송은 같은 ID와
`idempotent_replay=true`, 변경 payload는 `409`였다. 다른 학습자와 교차 cohort
교수자는 `404`, 동일 cohort 교수자는 열람 가능했고 교수자 2회 평정은 3축 모두
append-only supersession으로 연결됐다. post 원장은 self assessment 1행, ready model-run
2행, measurement event 15행이며 prompt bundle은 `1.2.0`이다.
이 실행 전에 두 실제 경계 결함도 수정하고 회귀를 추가했다.
- 정상적인 pre fail-closed 결과인 `degraded + insufficient_transcript`를 거부하던
`ck_alliance_pulse_terminal_state`와 audit status-event 제약을 바로잡고 실제 dev DB에
재적용했다.
- PostgreSQL `READ COMMITTED`에서 pulse 상태 조회와 event 조회 사이에 agent 커밋이
끼면 한 HTTP 응답 안에서 상태는 `awaiting_agents`인데 외부 관점만 먼저 보일 수 있었다.
첫 pulse 조회에서 공개된 ID 집합을 고정해 같은 응답의 reveal 경계를 일관되게 만들었다.
- 구조화 출력 실패는 성공으로 대체하지 않으며 최대 3회까지 동일 근거·스키마로 재시도하고
각 실패 시도를 model-run provenance로 보존한다.
최신 focused G1 계약 묶음은 `43 passed`, Ruff는 통과했다. 물리 마이크나 실제 사용자
로그인은 사용하지 않았다.
- API: `http://127.0.0.1:8004` — prompt `1.2.0` 최신 코드로 별도 기동
- PostgreSQL: `vignette-dev-db`, host port `55432`
- 엔진: `127.0.0.1:9099`, `claude_cli`
- 표준 persona/cohort: `P1`, `e2e-hanshin`
- 성공 회기: `8854fd64-2e63-45da-a97f-30e7ba8de1f2`
- 성공 pulse: `d85212f3-b9e1-4c73-8809-d34d7b473371`
- fixture 정책: `dev:e2e` 식별자를 삭제하지 않고 내구 저장소에 보존
기존 `8002`·`8003` 프로세스는 최신 prompt 변경 전에 기동됐으므로 최종 증거에서
제외했다. 아래 결과는 `PROMPT_BUNDLE_VERSION=1.2.0` 코드를 로드한 `8004`에서 얻었다.
## 재현 명령
```powershell
$env:PYTHONUTF8='1'
py -3.11 -X utf8 scripts/smoke-alliance-pulse-api.py `
--api-base-url http://127.0.0.1:8004 `
--expected-prompt-version 1.2.0 `
--request-timeout 180 `
--poll-timeout 360
```
스크립트는 쿠키, 이메일, 데이터베이스 접속 문자열, 축어록 원문을 출력하지 않는다.
출력은 회기/pulse 식별자와 상태·개수 증거만 포함한다.
## HTTP 증거
| 게이트 | 실제 결과 |
|---|---|
| health | API `ok`, DB `true`, engine `true` |
| 자기평가 잠금 | `POST .../alliance-pulses``202` |
| 최초 read model | `awaiting_agents`, 외부 관점 0개, 학습자 `goal/task/bond`만 3개 |
| terminal reveal | 25.266초, `ready` |
| 학습자 terminal read | 3관점 × 3축 = 9개 |
| 동일 코호트 교수자 GET | 성공, 학습자 terminal read와 동일 |
| 교수자 평정 1차/2차 | `201`, `201` |
| 교수자 최신 read | 4관점 × 3축 = 12개 |
`awaiting_agents`로 읽히는 모든 poll에서 `client_agent_report`
`independent_observer`가 노출되지 않는 것도 함께 단언했다. 즉 최종 결과가 먼저
계산됐더라도 학습자 자기평가 잠금 이전 또는 비동기 완료 이전에는 외부 점수를 볼 수 없다.
## PostgreSQL 원장 증거
| 원장 계약 | 실제 결과 |
|---|---|
| pulse 상태 이력 | `awaiting_agents → ready` |
| 시간 순서 | `created_at ≤ learner_locked_at ≤ revealed_at ≤ updated_at` |
| self assessment | 1행, `goal/task/bond` 정확히 3축 |
| model run | 총 2행, terminal ready 2행 |
| prompt provenance | 전 행 bundle `1.2.0`, prompt/evidence hash 존재 |
| learner event | 3행 |
| client-agent event | 3행 |
| independent-observer event | 3행 |
| supervisor event | 6행 — 1차 3행 + 2차 3행 |
| supervisor supersedes | 2차 평정 3행이 1차 각 축을 각각 참조 |
| measurement event 합계 | 15행 |
최신 live 실행은 두 관점 모두 첫 시도에 성공했다. 재시도 경계는 별도 실증도 함께 보존한다.
- prompt `1.2.0` 합성 gold calibration에서 `oas-g0-007`의 엔진 오류와
`oas-g0-008`의 필수 rationale 누락이 각각 두 번째 시도에 회복됐고, 이전 실패 model-run id와
error code가 결과 snapshot에 남았다.
- prompt `1.1.0` live 실행(`8003`, 회기 `55389bd3-8ea2-4c9d-a625-a71fbb63d431`)에서도
client 1차 validation error → 2차 ready, evaluator 1차 ready의 3개 model-run 원장을 확인했다.
따라서 정상 첫 시도와 실제 retry 모두에서 terminal run만 측정 이벤트에 연결되고 실패 시도는
덮어쓰지 않는 계약이 검증됐다.
## 자동 단언 범위
재현 스크립트 `scripts/smoke-alliance-pulse-api.py`는 다음 조건 중 하나라도 어긋나면
비정상 종료한다.
- 첫 read가 `awaiting_agents`가 아니거나 외부 관점이 보임
- terminal 상태가 `ready`가 아니거나 3관점 × 3축이 아님
- 교수자가 같은 코호트 회기를 읽지 못함
- 두 번의 교수자 평정 뒤 최신 read가 4관점 × 3축이 아님
- DB 시간 순서, 상태 감사 이력, event 개수, model-run hash/version이 어긋남
- retry attempt가 관점별로 1부터 연속되지 않음
- 두 번째 교수자 평정의 `supersedes_id`가 3축 중 하나라도 빠짐