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
|
|
@ -8,6 +8,9 @@
|
|||
[string]$CloudflaredConfig = "$env:USERPROFILE\.cloudflared\vignette-config.yml",
|
||||
[string]$PublicHealthUrl = "https://api-vignette.chanpaca.net/health",
|
||||
[string[]]$AdditionalPublicHealthUrls = @(),
|
||||
# 게이트웨이가 shared secret으로 떠 있으면 /ready는 인증이 필요하다(/health만 면제).
|
||||
# 토큰이 없으면 401을 장애로 오판해 재시작 폭풍이 난다.
|
||||
[string]$EngineToken = $env:ENGINE_GATEWAY_SHARED_SECRET,
|
||||
[string]$LogPath = "",
|
||||
[int]$FailuresBeforeRestart = 3,
|
||||
[switch]$CheckOnly,
|
||||
|
|
@ -51,11 +54,16 @@ function Test-JsonHealth {
|
|||
[string]$Name,
|
||||
[string]$Uri,
|
||||
[scriptblock]$IsHealthy,
|
||||
[int]$TimeoutSec = 30
|
||||
[int]$TimeoutSec = 30,
|
||||
[hashtable]$Headers = $null
|
||||
)
|
||||
|
||||
try {
|
||||
$response = Invoke-RestMethod -Uri $Uri -TimeoutSec $TimeoutSec
|
||||
if ($Headers) {
|
||||
$response = Invoke-RestMethod -Uri $Uri -TimeoutSec $TimeoutSec -Headers $Headers
|
||||
} else {
|
||||
$response = Invoke-RestMethod -Uri $Uri -TimeoutSec $TimeoutSec
|
||||
}
|
||||
$ok = [bool](& $IsHealthy $response)
|
||||
$detail = $response | ConvertTo-Json -Compress -Depth 5
|
||||
[pscustomobject]@{
|
||||
|
|
@ -64,14 +72,39 @@ function Test-JsonHealth {
|
|||
Detail = $detail
|
||||
}
|
||||
} catch {
|
||||
# 게이트웨이 /ready는 실패를 503 + JSON 본문으로 알린다. 본문을 버리면 로그에
|
||||
# "(503)"만 남아 원인(만료 인증·플래그 오류)을 잃는다.
|
||||
$detail = $_.Exception.Message
|
||||
$body = ""
|
||||
if ($_.ErrorDetails -and $_.ErrorDetails.Message) {
|
||||
$body = $_.ErrorDetails.Message
|
||||
} elseif ($_.Exception.Response) {
|
||||
try {
|
||||
$reader = New-Object System.IO.StreamReader($_.Exception.Response.GetResponseStream())
|
||||
$body = $reader.ReadToEnd()
|
||||
$reader.Dispose()
|
||||
} catch {
|
||||
$body = ""
|
||||
}
|
||||
}
|
||||
if ($body) {
|
||||
$detail = "$detail :: $body"
|
||||
}
|
||||
[pscustomobject]@{
|
||||
Name = $Name
|
||||
Ok = $false
|
||||
Detail = $_.Exception.Message
|
||||
Detail = $detail
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Get-EngineHeaders {
|
||||
if ($EngineToken) {
|
||||
return @{ "X-Vignette-Engine-Token" = $EngineToken }
|
||||
}
|
||||
return $null
|
||||
}
|
||||
|
||||
function Test-CloudflaredProcess {
|
||||
if ($SkipCloudflaredRestart) {
|
||||
return [pscustomobject]@{
|
||||
|
|
@ -102,15 +135,23 @@ if (!(Test-Path $startScript)) {
|
|||
throw "Start script not found at $startScript"
|
||||
}
|
||||
|
||||
# engine 판정은 /health(프로세스 liveness)가 아니라 /ready(실제 claude -p 생성)로 한다.
|
||||
# /health는 ok:true만 보므로 "프로세스는 살아 있고 그 프로세스의 claude 세션만 죽은"
|
||||
# 상태를 통과시킨다(2026-08-07 공개 런타임: engine=false인데 워치독 lastResult=0).
|
||||
# /ready는 게이트웨이 readiness 캐시(ENGINE_READY_TTL_SECONDS)를 그대로 쓰므로
|
||||
# 매 주기 LLM 호출로 이어지지 않는다. 콜드 스폰 여유로 타임아웃만 넉넉히 준다.
|
||||
$checks = @(
|
||||
(Test-JsonHealth `
|
||||
-Name "engine" `
|
||||
-Uri "http://127.0.0.1:$EnginePort/health" `
|
||||
-IsHealthy { param($health) $health.ok -eq $true }),
|
||||
-Uri "http://127.0.0.1:$EnginePort/ready" `
|
||||
-IsHealthy { param($health) $health.ok -eq $true } `
|
||||
-TimeoutSec 45 `
|
||||
-Headers (Get-EngineHeaders)),
|
||||
(Test-JsonHealth `
|
||||
-Name "api" `
|
||||
-Uri "http://127.0.0.1:$ApiPort/health" `
|
||||
-IsHealthy { param($health) $health.environment -eq "prod" -and $health.db }),
|
||||
-IsHealthy { param($health) $health.environment -eq "prod" -and $health.db -and $health.engine } `
|
||||
-TimeoutSec 60),
|
||||
(Test-JsonHealth `
|
||||
-Name "web-preview" `
|
||||
-Uri "http://127.0.0.1:$WebPort/" `
|
||||
|
|
@ -180,11 +221,12 @@ try {
|
|||
throw
|
||||
}
|
||||
|
||||
# 재시작 직후 첫 health는 readiness 콜드 스폰(10~20초)을 포함하므로 여유를 준다.
|
||||
$apiAfter = Test-JsonHealth `
|
||||
-Name "api" `
|
||||
-Uri "http://127.0.0.1:$ApiPort/health" `
|
||||
-IsHealthy { param($health) $health.environment -eq "prod" -and $health.db } `
|
||||
-TimeoutSec 20
|
||||
-IsHealthy { param($health) $health.environment -eq "prod" -and $health.db -and $health.engine } `
|
||||
-TimeoutSec 90
|
||||
if (!$apiAfter.Ok) {
|
||||
throw "Public API still unhealthy after restart: $($apiAfter.Detail)"
|
||||
}
|
||||
|
|
@ -200,9 +242,10 @@ if (!$webAfter.Ok) {
|
|||
|
||||
$engineAfter = Test-JsonHealth `
|
||||
-Name "engine" `
|
||||
-Uri "http://127.0.0.1:$EnginePort/health" `
|
||||
-Uri "http://127.0.0.1:$EnginePort/ready" `
|
||||
-IsHealthy { param($health) $health.ok -eq $true } `
|
||||
-TimeoutSec 20
|
||||
-TimeoutSec 60 `
|
||||
-Headers (Get-EngineHeaders)
|
||||
if (!$engineAfter.Ok) {
|
||||
throw "Engine gateway still unhealthy after isolated restart: $($engineAfter.Detail)"
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue