아바타 저장소 승격 계약을 완성
This commit is contained in:
parent
ac9b702688
commit
ccdcfcd2f5
36 changed files with 14734 additions and 222 deletions
|
|
@ -9,17 +9,16 @@ from __future__ import annotations
|
|||
|
||||
from contextlib import asynccontextmanager
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from dataclasses import asdict
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
|
||||
from . import __version__
|
||||
from .access_logging import install_uvicorn_access_log_redaction
|
||||
from .auth_sessions import ensure_runtime_tables
|
||||
from .config import settings
|
||||
from .db import acquire, close_pool, healthcheck, init_pool
|
||||
from .db import acquire, close_pool, get_pool, healthcheck, init_pool
|
||||
from .engine_client import engine_client
|
||||
from .persona_repository import materialize_seed_personas
|
||||
from .session_persistence import ensure_review_tables
|
||||
|
|
@ -63,6 +62,13 @@ from .services import (
|
|||
supervision_research_producer,
|
||||
)
|
||||
from .services.voice import voice_service
|
||||
from .upload_runtime import (
|
||||
FlatPublicAvatarStaticFiles,
|
||||
public_avatar_root,
|
||||
upload_manifest_proof,
|
||||
upload_write_freeze_gate,
|
||||
validate_runtime_upload_database_state,
|
||||
)
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
@ -83,8 +89,13 @@ async def lifespan(app: FastAPI):
|
|||
supervision_research_schema_ready = False
|
||||
continuous_improvement_schema_ready = False
|
||||
multimodal_alliance_schema_ready = False
|
||||
app.state.upload_database_proof = None
|
||||
try:
|
||||
await init_pool()
|
||||
if upload_manifest_proof is not None:
|
||||
app.state.upload_database_proof = (
|
||||
await validate_runtime_upload_database_state(get_pool())
|
||||
)
|
||||
await ensure_runtime_tables()
|
||||
await ensure_review_tables()
|
||||
await ensure_notification_tables()
|
||||
|
|
@ -190,7 +201,7 @@ async def lifespan(app: FastAPI):
|
|||
await materialize_seed_personas()
|
||||
await admin_routes.apply_engine_config_from_store()
|
||||
except Exception as exc: # DB 없어도 store 폴백으로 1턴 동작 (dev/로컬)
|
||||
if settings.environment != "dev":
|
||||
if settings.environment != "dev" or upload_manifest_proof is not None:
|
||||
raise
|
||||
import logging
|
||||
|
||||
|
|
@ -245,11 +256,11 @@ app.add_middleware(
|
|||
|
||||
# TODO: Presidio PII 마스킹 미들웨어 (외부 LLM 경로 진입 전 하드 게이트, R7/F-03)
|
||||
|
||||
_upload_root = Path(settings.user_upload_dir)
|
||||
if not _upload_root.is_absolute():
|
||||
_upload_root = Path.cwd() / _upload_root
|
||||
_upload_root.mkdir(parents=True, exist_ok=True)
|
||||
app.mount("/uploads", StaticFiles(directory=str(_upload_root)), name="uploads")
|
||||
app.mount(
|
||||
"/uploads/profile-avatars",
|
||||
FlatPublicAvatarStaticFiles(directory=str(public_avatar_root)),
|
||||
name="profile-avatars",
|
||||
)
|
||||
|
||||
app.include_router(auth_routes.router)
|
||||
app.include_router(calibration_transfer_routes.router)
|
||||
|
|
@ -280,8 +291,25 @@ async def health() -> dict[str, object]:
|
|||
db_ok = await healthcheck()
|
||||
engine = await engine_client.health_detail()
|
||||
engine_ok = bool(engine.get("ok"))
|
||||
upload_freeze = asdict(upload_write_freeze_gate.status())
|
||||
upload_database_proof = getattr(app.state, "upload_database_proof", None)
|
||||
upload_write_gate_ok = (
|
||||
not bool(upload_freeze["capable"]) or bool(upload_freeze["valid"])
|
||||
)
|
||||
upload_database_ok = (
|
||||
upload_manifest_proof is None
|
||||
or (
|
||||
upload_database_proof is not None
|
||||
and upload_database_proof.database_target_sha256
|
||||
== upload_manifest_proof.database_target_sha256
|
||||
)
|
||||
)
|
||||
return {
|
||||
"status": "ok" if db_ok and engine_ok else "degraded",
|
||||
"status": (
|
||||
"ok"
|
||||
if db_ok and engine_ok and upload_write_gate_ok and upload_database_ok
|
||||
else "degraded"
|
||||
),
|
||||
"version": __version__,
|
||||
"environment": settings.environment,
|
||||
"db": db_ok,
|
||||
|
|
@ -293,4 +321,75 @@ async def health() -> dict[str, object]:
|
|||
),
|
||||
"default_engine": engine.get("default_engine"),
|
||||
"live_client_engine": engine.get("live_client_engine"),
|
||||
"upload_write_freeze": upload_freeze,
|
||||
"upload_manifest": (
|
||||
{
|
||||
"required": True,
|
||||
"validated": True,
|
||||
"manifest_sha256": upload_manifest_proof.manifest_sha256,
|
||||
"database_target_sha256": (
|
||||
upload_manifest_proof.database_target_sha256
|
||||
),
|
||||
"preserved_object_count": (
|
||||
upload_manifest_proof.preserved_object_count
|
||||
),
|
||||
"preserved_total_size_bytes": (
|
||||
upload_manifest_proof.preserved_total_size_bytes
|
||||
),
|
||||
"preserved_decode_valid_count": (
|
||||
upload_manifest_proof.preserved_decode_valid_count
|
||||
),
|
||||
"preserved_decode_invalid_count": (
|
||||
upload_manifest_proof.preserved_decode_invalid_count
|
||||
),
|
||||
"required_decode_invalid_object_count": (
|
||||
upload_manifest_proof.required_decode_invalid_object_count
|
||||
),
|
||||
"required_decode_invalid_reference_count": (
|
||||
upload_manifest_proof.required_decode_invalid_reference_count
|
||||
),
|
||||
"forensic_fallback_active": (
|
||||
upload_manifest_proof.required_decode_invalid_reference_count
|
||||
> 0
|
||||
or (
|
||||
upload_database_proof is not None
|
||||
and upload_database_proof.current_references.decode_invalid_reference_count
|
||||
> 0
|
||||
)
|
||||
),
|
||||
"preserved_object_set_sha256": (
|
||||
upload_manifest_proof.preserved_object_set_sha256
|
||||
),
|
||||
"required_object_count": upload_manifest_proof.required_object_count,
|
||||
"reference_set_sha256": upload_manifest_proof.reference_set_sha256,
|
||||
"runtime_database_validated": upload_database_ok,
|
||||
"current_object_count": (
|
||||
upload_database_proof.current_references.object_count
|
||||
if upload_database_proof is not None
|
||||
else None
|
||||
),
|
||||
"current_reference_count": (
|
||||
upload_database_proof.current_references.reference_count
|
||||
if upload_database_proof is not None
|
||||
else None
|
||||
),
|
||||
"current_reference_set_sha256": (
|
||||
upload_database_proof.current_references.reference_set_sha256
|
||||
if upload_database_proof is not None
|
||||
else None
|
||||
),
|
||||
"current_decode_invalid_object_count": (
|
||||
upload_database_proof.current_references.decode_invalid_object_count
|
||||
if upload_database_proof is not None
|
||||
else None
|
||||
),
|
||||
"current_decode_invalid_reference_count": (
|
||||
upload_database_proof.current_references.decode_invalid_reference_count
|
||||
if upload_database_proof is not None
|
||||
else None
|
||||
),
|
||||
}
|
||||
if upload_manifest_proof is not None
|
||||
else {"required": False, "validated": False}
|
||||
),
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue