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,7 @@ Dockerfile CMD: uvicorn app.main:app --host 0.0.0.0 --port 8000
|
|||
from __future__ import annotations
|
||||
|
||||
from contextlib import asynccontextmanager
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
|
@ -17,36 +18,169 @@ from fastapi.staticfiles import StaticFiles
|
|||
from . import __version__
|
||||
from .auth_sessions import ensure_runtime_tables
|
||||
from .config import settings
|
||||
from .db import close_pool, healthcheck, init_pool
|
||||
from .db import acquire, close_pool, healthcheck, init_pool
|
||||
from .engine_client import engine_client
|
||||
from .persona_repository import materialize_seed_personas
|
||||
from .session_persistence import ensure_review_tables
|
||||
from .runtime_schema import (
|
||||
CALIBRATION_TRANSFER_SCHEMA_CONTRACT,
|
||||
CONTINUOUS_IMPROVEMENT_SCHEMA_CONTRACT,
|
||||
DELIBERATE_PRACTICE_SCHEMA_CONTRACT,
|
||||
MEASUREMENT_SCHEMA_CONTRACT,
|
||||
MULTIMODAL_ALLIANCE_SCHEMA_CONTRACT,
|
||||
OUTCOME_TRAJECTORY_SCHEMA_CONTRACT,
|
||||
RUPTURE_REPAIR_SCHEMA_CONTRACT,
|
||||
SUPERVISION_RESEARCH_SCHEMA_CONTRACT,
|
||||
runtime_schema_bootstrap_required,
|
||||
schema_contract_ready,
|
||||
)
|
||||
from .routes import auth as auth_routes
|
||||
from .routes import calibration_transfer as calibration_transfer_routes
|
||||
from .routes import continuous_improvement as continuous_improvement_routes
|
||||
from .routes import admin as admin_routes
|
||||
from .routes import client_diagnostics as client_diagnostics_routes
|
||||
from .routes import deliberate_practices as deliberate_practice_routes
|
||||
from .routes import eval as eval_routes
|
||||
from .routes import kb as kb_routes
|
||||
from .routes import multimodal_alliance as multimodal_alliance_routes
|
||||
from .routes import measurements as measurement_routes
|
||||
from .routes import outcome_trajectories as outcome_trajectory_routes
|
||||
from .routes import personas as persona_routes
|
||||
from .routes import rupture_repairs as rupture_repair_routes
|
||||
from .routes import supervision_research as supervision_research_routes
|
||||
from .routes import sessions as session_routes
|
||||
from .routes import share as share_routes
|
||||
from .routes import teacher as teacher_routes
|
||||
from .routes import users as user_routes
|
||||
from .routes import voice as voice_routes
|
||||
from .services.notifications import ensure_notification_tables
|
||||
from .services import (
|
||||
alliance_measurement,
|
||||
continuous_improvement_producer,
|
||||
supervision_research_producer,
|
||||
)
|
||||
from .services.voice import voice_service
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
"""startup: DB 풀 + 엔진 클라이언트 / shutdown: 정리.
|
||||
|
||||
DB 미가용(Docker off / NAS 연결불가)이면 store 인메모리 폴백으로 degraded 기동한다.
|
||||
"""
|
||||
measurement_schema_ready = False
|
||||
outcome_trajectory_schema_ready = False
|
||||
rupture_repair_schema_ready = False
|
||||
deliberate_practice_schema_ready = False
|
||||
calibration_transfer_schema_ready = False
|
||||
supervision_research_schema_ready = False
|
||||
continuous_improvement_schema_ready = False
|
||||
multimodal_alliance_schema_ready = False
|
||||
try:
|
||||
await init_pool()
|
||||
await ensure_runtime_tables()
|
||||
await ensure_review_tables()
|
||||
await ensure_notification_tables()
|
||||
async with acquire(role="admin") as conn:
|
||||
measurement_schema_ready = await schema_contract_ready(
|
||||
conn,
|
||||
MEASUREMENT_SCHEMA_CONTRACT,
|
||||
)
|
||||
outcome_trajectory_schema_ready = await schema_contract_ready(
|
||||
conn,
|
||||
OUTCOME_TRAJECTORY_SCHEMA_CONTRACT,
|
||||
)
|
||||
rupture_repair_schema_ready = await schema_contract_ready(
|
||||
conn,
|
||||
RUPTURE_REPAIR_SCHEMA_CONTRACT,
|
||||
)
|
||||
deliberate_practice_schema_ready = await schema_contract_ready(
|
||||
conn,
|
||||
DELIBERATE_PRACTICE_SCHEMA_CONTRACT,
|
||||
)
|
||||
calibration_transfer_schema_ready = await schema_contract_ready(
|
||||
conn,
|
||||
CALIBRATION_TRANSFER_SCHEMA_CONTRACT,
|
||||
)
|
||||
supervision_research_schema_ready = await schema_contract_ready(
|
||||
conn,
|
||||
SUPERVISION_RESEARCH_SCHEMA_CONTRACT,
|
||||
)
|
||||
continuous_improvement_schema_ready = await schema_contract_ready(
|
||||
conn,
|
||||
CONTINUOUS_IMPROVEMENT_SCHEMA_CONTRACT,
|
||||
)
|
||||
multimodal_alliance_schema_ready = await schema_contract_ready(
|
||||
conn,
|
||||
MULTIMODAL_ALLIANCE_SCHEMA_CONTRACT,
|
||||
)
|
||||
if runtime_schema_bootstrap_required(
|
||||
MEASUREMENT_SCHEMA_CONTRACT,
|
||||
ready=measurement_schema_ready,
|
||||
):
|
||||
logger.warning(
|
||||
"Outcome/Alliance 측정 스키마가 불완전해 측정 경로를 시작하지 않음; "
|
||||
"infra/db/init/07_measurement_foundation.sql 적용 필요"
|
||||
)
|
||||
if runtime_schema_bootstrap_required(
|
||||
OUTCOME_TRAJECTORY_SCHEMA_CONTRACT,
|
||||
ready=outcome_trajectory_schema_ready,
|
||||
):
|
||||
logger.warning(
|
||||
"종단 성과 궤적 스키마가 불완전해 G2 경로가 실패할 수 있음; "
|
||||
"infra/db/init/08_outcome_trajectory.sql 적용 필요"
|
||||
)
|
||||
if runtime_schema_bootstrap_required(
|
||||
RUPTURE_REPAIR_SCHEMA_CONTRACT,
|
||||
ready=rupture_repair_schema_ready,
|
||||
):
|
||||
logger.warning(
|
||||
"파열·수선 원장 스키마가 불완전해 G3 경로가 실패할 수 있음; "
|
||||
"infra/db/init/09_rupture_repair.sql 적용 필요"
|
||||
)
|
||||
if runtime_schema_bootstrap_required(
|
||||
DELIBERATE_PRACTICE_SCHEMA_CONTRACT,
|
||||
ready=deliberate_practice_schema_ready,
|
||||
):
|
||||
logger.warning(
|
||||
"숙의 연습 원장 스키마가 불완전해 G4 경로가 실패할 수 있음; "
|
||||
"infra/db/init/10_deliberate_practice.sql 적용 필요"
|
||||
)
|
||||
if runtime_schema_bootstrap_required(
|
||||
CALIBRATION_TRANSFER_SCHEMA_CONTRACT,
|
||||
ready=calibration_transfer_schema_ready,
|
||||
):
|
||||
logger.warning(
|
||||
"자기보정·전이 원장 스키마가 불완전해 G5 경로가 실패할 수 있음; "
|
||||
"infra/db/init/11_calibration_transfer.sql 적용 필요"
|
||||
)
|
||||
if runtime_schema_bootstrap_required(
|
||||
SUPERVISION_RESEARCH_SCHEMA_CONTRACT,
|
||||
ready=supervision_research_schema_ready,
|
||||
):
|
||||
logger.warning(
|
||||
"감독·연구 원장 스키마가 불완전해 G6 경로가 실패할 수 있음; "
|
||||
"infra/db/init/12_supervision_research.sql 적용 필요"
|
||||
)
|
||||
if runtime_schema_bootstrap_required(
|
||||
CONTINUOUS_IMPROVEMENT_SCHEMA_CONTRACT,
|
||||
ready=continuous_improvement_schema_ready,
|
||||
):
|
||||
logger.warning(
|
||||
"지속 개선 승인 원장 스키마가 불완전해 G8 경로가 실패할 수 있음; "
|
||||
"infra/db/init/14_continuous_improvement.sql 적용 필요"
|
||||
)
|
||||
if runtime_schema_bootstrap_required(
|
||||
MULTIMODAL_ALLIANCE_SCHEMA_CONTRACT,
|
||||
ready=multimodal_alliance_schema_ready,
|
||||
):
|
||||
logger.warning(
|
||||
"멀티모달 동맹 원장 스키마가 불완전해 G7 경로가 실패할 수 있음; "
|
||||
"infra/db/init/13_multimodal_alliance.sql 적용 필요"
|
||||
)
|
||||
if settings.auto_seed_personas:
|
||||
await materialize_seed_personas()
|
||||
await admin_routes.apply_engine_config_from_store()
|
||||
|
|
@ -54,15 +188,31 @@ async def lifespan(app: FastAPI):
|
|||
if settings.environment != "dev":
|
||||
raise
|
||||
import logging
|
||||
|
||||
logging.getLogger("uvicorn.error").warning(
|
||||
"DB 풀 초기화 실패 — store 인메모리 폴백으로 degraded 기동: %s", exc
|
||||
)
|
||||
await engine_client.startup()
|
||||
if measurement_schema_ready:
|
||||
try:
|
||||
recovered = await alliance_measurement.recover_pending_alliance_pulses()
|
||||
if recovered:
|
||||
logger.info("미완료 Alliance Pulse %d건 재예약", recovered)
|
||||
except Exception:
|
||||
if settings.environment != "dev":
|
||||
raise
|
||||
logger.exception("미완료 Alliance Pulse 복구 예약 실패")
|
||||
await voice_service.startup()
|
||||
session_routes.schedule_missing_session_evaluation_recovery()
|
||||
if supervision_research_schema_ready:
|
||||
supervision_research_producer.schedule_supervision_research_producer()
|
||||
if continuous_improvement_schema_ready:
|
||||
continuous_improvement_producer.schedule_continuous_improvement_producer()
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
await continuous_improvement_producer.stop_continuous_improvement_producer()
|
||||
await supervision_research_producer.stop_supervision_research_producer()
|
||||
session_routes.cancel_missing_session_evaluation_recovery()
|
||||
await voice_service.shutdown()
|
||||
await engine_client.shutdown()
|
||||
|
|
@ -97,10 +247,18 @@ _upload_root.mkdir(parents=True, exist_ok=True)
|
|||
app.mount("/uploads", StaticFiles(directory=str(_upload_root)), name="uploads")
|
||||
|
||||
app.include_router(auth_routes.router)
|
||||
app.include_router(calibration_transfer_routes.router)
|
||||
app.include_router(continuous_improvement_routes.router)
|
||||
app.include_router(client_diagnostics_routes.router)
|
||||
app.include_router(admin_routes.router)
|
||||
app.include_router(persona_routes.router)
|
||||
app.include_router(session_routes.router)
|
||||
app.include_router(measurement_routes.router)
|
||||
app.include_router(multimodal_alliance_routes.router)
|
||||
app.include_router(outcome_trajectory_routes.router)
|
||||
app.include_router(rupture_repair_routes.router)
|
||||
app.include_router(deliberate_practice_routes.router)
|
||||
app.include_router(supervision_research_routes.router)
|
||||
app.include_router(share_routes.router)
|
||||
app.include_router(teacher_routes.router)
|
||||
app.include_router(user_routes.router)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue