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:
Yun Chan 2026-08-08 01:30:53 +09:00
parent 93dd8f82d7
commit 16e791e044
390 changed files with 243188 additions and 499 deletions

View file

@ -0,0 +1,224 @@
"""Run the real G8 scheduled worker against the configured dev engine and DB."""
from __future__ import annotations
import argparse
import asyncio
import hashlib
import json
import os
from pathlib import Path
import sys
from typing import Any
REPO_ROOT = Path(__file__).resolve().parents[1]
API_ROOT = REPO_ROOT / "apps" / "api"
if str(API_ROOT) not in sys.path:
sys.path.insert(0, str(API_ROOT))
os.chdir(API_ROOT)
from app import db # noqa: E402
from app.engine_client import engine_client # noqa: E402
from app.services import continuous_improvement_agentic as agentic # noqa: E402
from app.services import continuous_improvement_producer as producer # noqa: E402
class SmokeFailure(RuntimeError):
pass
class CountingEngine:
def __init__(self) -> None:
self.call_count = 0
self.stages: list[str] = []
self.responses: list[dict[str, str]] = []
async def generate(self, request: Any) -> Any:
self.call_count += 1
self.stages.append(str(request.metadata.get("agentic_stage", "unknown")))
response = await engine_client.generate(
request,
timeout=producer.settings.continuous_improvement_producer_engine_timeout_seconds,
)
self.responses.append(
{"provider": str(response.provider), "model": str(response.model)}
)
return response
def _sha256_text(value: str) -> str:
return hashlib.sha256(value.encode("utf-8")).hexdigest()
async def _read_evidence_row(job_id: Any) -> dict[str, Any]:
async with db.acquire(ai_view="research", ai_context=True) as conn:
row = await conn.fetchrow(
"""
SELECT j.job_id, j.job_key, j.status, j.attempt_count,
j.data_classification, j.source_fingerprint,
j.last_error_code, j.last_error_message,
j.result_submission_id, j.result_qualification_id,
p.pipeline_id, p.generation_model, p.prompt_version,
p.prompt_sha256, p.payload_sha256, p.state AS pipeline_state,
p.clinical_claim_allowed,
q.gate_state, q.catalog_entry_id,
b.variant_count, b.variant_pass_rate, b.qualified,
(SELECT count(*) FROM app.ci_red_team_review r
WHERE r.pipeline_id = p.pipeline_id) AS reviewer_count,
(SELECT count(*) FROM app.ci_catalog_entry c
WHERE c.qualification_id = q.qualification_id) AS catalog_count,
(SELECT count(*) FROM audit.ci_human_approval_event a
WHERE a.target_kind = 'content_qualification'
AND a.target_id = q.qualification_id) AS approval_count,
(SELECT jsonb_agg(jsonb_build_object(
'source_id', s.source_id,
'version', s.source_version,
'content_sha256', s.content_sha256,
'provenance_uri', s.provenance_uri,
'usage_status', s.usage_status
) ORDER BY s.source_id)
FROM app.ci_source_artifact s
WHERE s.source_record_id = ANY(p.source_record_ids)) AS sources
FROM app.ci_agentic_job j
LEFT JOIN app.ci_content_pipeline p
ON p.submission_id = j.result_submission_id
LEFT JOIN app.ci_content_qualification q
ON q.qualification_id = j.result_qualification_id
LEFT JOIN app.ci_content_benchmark b
ON b.pipeline_id = p.pipeline_id
WHERE j.job_id = $1
""",
job_id,
)
if row is None:
raise SmokeFailure("scheduled agentic job is not visible")
return dict(row)
async def _run(out_path: Path) -> dict[str, Any]:
await db.init_pool()
await engine_client.startup()
try:
readiness = await engine_client.health_detail()
if not readiness.get("ok"):
raise SmokeFailure(f"engine is not ready: {readiness.get('detail')}")
spec = producer.load_repo_approved_job()
job_id = await producer.ensure_repo_approved_job()
claimed = await producer.claim_next_agentic_job(job_id=job_id)
if claimed is None:
raise SmokeFailure("repo-approved job was not available for a fresh model run")
first_engine = CountingEngine()
first = await producer.execute_claimed_agentic_job(
claimed,
engine=first_engine,
)
row = await _read_evidence_row(job_id)
evidence: dict[str, Any] = {
"evidence_version": "g8-agentic-producer-live-v1",
"environment": "dev",
"engine_ready": {
"ok": bool(readiness.get("ok")),
"detail": str(readiness.get("detail", "")),
},
"repo_source": {
"job_key": spec.job_key,
"data_classification": spec.data_classification,
"source_ids": [item.artifact.source_id for item in spec.source_packs],
"usage_statuses": [
item.artifact.usage_status for item in spec.source_packs
],
"content_hashes_verified": all(
_sha256_text(item.content) == item.artifact.content_sha256
for item in spec.source_packs
),
"raw_transcript_included": False,
"pii_included": False,
},
"first_run": {
"status": first.status,
"engine_call_count": first_engine.call_count,
"stages": sorted(first_engine.stages),
"provider_models": first_engine.responses,
"error_code": first.error_code,
},
"durable_db": row,
"safety_boundary": {
"human_approval_required": row.get("gate_state")
== "pending_human_approval",
"catalog_promoted": int(row.get("catalog_count") or 0) > 0,
"human_approval_event_count": int(row.get("approval_count") or 0),
"clinical_claim_allowed": bool(row.get("clinical_claim_allowed")),
},
}
if first.status == "completed":
ids = producer._job_ids(job_id)
replay_engine = CountingEngine()
async with db.acquire(ai_view="research", ai_context=True) as conn:
replay = await agentic.run_agentic_content_pipeline(
conn=conn,
engine=replay_engine,
submission_id=ids["submission"],
pipeline_id=ids["pipeline"],
benchmark_record_id=ids["benchmark_record"],
qualification_id=ids["qualification"],
source_packs=spec.source_packs,
content_kind=spec.content_kind,
difficulty_level=spec.difficulty_level,
variant_count=spec.variant_count,
prompt_version=spec.prompt_version,
trigger_kind=spec.trigger_kind,
)
evidence["idempotent_replay"] = {
"reported": replay.idempotent_replay,
"engine_call_count": replay_engine.call_count,
"same_submission_id": str(replay.submission_id)
== str(row.get("result_submission_id")),
"same_qualification_id": str(replay.qualification_id)
== str(row.get("result_qualification_id")),
}
else:
evidence["storage_rejected"] = {
"pipeline_absent": row.get("pipeline_id") is None,
"qualification_absent": row.get("result_qualification_id") is None,
"catalog_count": int(row.get("catalog_count") or 0),
}
out_path.parent.mkdir(parents=True, exist_ok=True)
out_path.write_text(
json.dumps(evidence, ensure_ascii=False, indent=2, default=str) + "\n",
encoding="utf-8",
)
return evidence
finally:
await engine_client.shutdown()
await db.close_pool()
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument(
"--out",
type=Path,
required=True,
help="JSON evidence path",
)
args = parser.parse_args()
requested_out = args.out
out_path = (
requested_out
if requested_out.is_absolute()
else REPO_ROOT / requested_out
).resolve()
evidence = asyncio.run(_run(out_path))
print(json.dumps(evidence, ensure_ascii=False, indent=2, default=str))
first_status = evidence["first_run"]["status"]
return 0 if first_status == "completed" else 2
if __name__ == "__main__":
raise SystemExit(main())