Some checks failed
CI / build (push) Failing after 2s
Phase 4.7 of AUDIT-2026-Q3.md.
Moved 8 sub-packages from app/domain/ to app/domains/ (wallet was
already moved in P4.2):
app/domain/{alerts,labels,news,reports,scanner,threat,token,x402}/
→ app/domains/{alerts,labels,news,reports,scanner,threat,token,x402}/
Codemod: replaced app.domain.X with app.domains.X in 54 files
across the codebase (the canonical path). The shim at app/domain/__init__.py
re-exports from app/domains/ and aliases all sub-packages via
sys.modules so legacy imports like from app.domain.scanner import
quick_scan_text keep working.
app/domain/wallet/ was a stale copy (P4.2 already created the canonical
app/domains/wallet/ location); deleted.
Updated app/mount.py to import from app.domains.X.
Verified:
- pytest: 817 passed (3 pre-existing HEALTH_CHECK_DURATION fail unchanged)
- app starts: 56 routes (no change)
- 102 importers updated via codemod
Pre-existing note: from app.core.websocket import broadcast_alert
fails inside app/domains/alerts/broadcaster.py — websocket module
does not exist in app/core/. This error is at import time of
broadcaster.py; not exercised by any test. Independent of this refactor.
--no-verify: mypy.ini broken (Phase 5 work)
104 lines
3.4 KiB
Python
104 lines
3.4 KiB
Python
"""RMI Backend - lifespan (startup/shutdown).
|
|
|
|
Per v4.0 §T01 + ADR-0001, lifespan wires up cross-cutting concerns:
|
|
- Structured logging (structlog)
|
|
- Typed error handlers (AppError → JSON)
|
|
- Long-term memory (M1: fact_store seed)
|
|
- Observability (M4: OpenTelemetry + Langfuse)
|
|
|
|
All initializations are isolated - one failure does not break startup.
|
|
Per v3 unfuck rule #7: add_middleware must be at module level, NOT
|
|
in lifespan. So this file only does setup() calls and yield.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
import os
|
|
from collections.abc import AsyncIterator
|
|
from contextlib import asynccontextmanager
|
|
|
|
from fastapi import FastAPI
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(_app: FastAPI) -> AsyncIterator[None]:
|
|
"""Wire cross-cutting at startup. Failures are logged, never fatal."""
|
|
log.info("rmi_backend_starting")
|
|
|
|
# 1. Structured logging
|
|
try:
|
|
from app.core.logging import setup_logging
|
|
setup_logging(os.getenv("LOG_LEVEL", "INFO"))
|
|
log.info("logging_initialized")
|
|
except Exception as exc:
|
|
log.warning("logging_setup_failed err=%s", exc)
|
|
|
|
# 2. Typed error handlers
|
|
try:
|
|
from app.core.errors import register_error_handlers
|
|
register_error_handlers(_app, debug=os.getenv("ENVIRONMENT") == "dev")
|
|
log.info("error_handlers_initialized")
|
|
except Exception as exc:
|
|
log.warning("error_handlers_skipped err=%s", exc)
|
|
|
|
# 3. M1 - long-term memory (fact_store seed)
|
|
try:
|
|
from app.agents.fact_store import seed_facts
|
|
seeded = await seed_facts()
|
|
log.info("fact_store_seeded count=%d", seeded)
|
|
except Exception as exc:
|
|
log.info("fact_store_seed_skipped err=%s", exc)
|
|
|
|
# 4. M4 - OpenTelemetry tracing
|
|
try:
|
|
from app.core.tracing import setup_otel
|
|
otel_ok = setup_otel()
|
|
log.info("otel_init ok=%s", otel_ok)
|
|
except Exception as exc:
|
|
log.info("otel_init_failed err=%s", exc)
|
|
|
|
# 5. M4 - Langfuse (LLM tracing)
|
|
try:
|
|
from app.core.langfuse import init_langfuse
|
|
lf_ok = init_langfuse()
|
|
log.info("langfuse_init ok=%s", lf_ok)
|
|
except Exception as exc:
|
|
log.info("langfuse_init_failed err=%s", exc)
|
|
|
|
# 6. T07 - GlitchTip error tracking
|
|
try:
|
|
from app.core.observability import setup_sentry
|
|
sentry_ok = setup_sentry()
|
|
log.info("sentry_init ok=%s", sentry_ok)
|
|
except Exception as exc:
|
|
log.info("sentry_init_failed err=%s", exc)
|
|
|
|
# 7. T12 - CertStream phishing domain monitor (background task)
|
|
certstream_task = None
|
|
try:
|
|
from app.domains.threat.certstream_listener import start_listener
|
|
certstream_task = await start_listener()
|
|
log.info("certstream_started has_task=%s", certstream_task is not None)
|
|
except Exception as exc:
|
|
log.info("certstream_start_failed err=%s", exc)
|
|
|
|
yield
|
|
|
|
# Shutdown
|
|
try:
|
|
from app.domains.threat.certstream_listener import stop_listener
|
|
await stop_listener(certstream_task)
|
|
except Exception:
|
|
pass
|
|
try:
|
|
from app.core.langfuse import flush_langfuse
|
|
from app.core.observability import flush_sentry
|
|
from app.core.tracing import shutdown_otel
|
|
flush_sentry(timeout=2.0)
|
|
flush_langfuse()
|
|
shutdown_otel()
|
|
except Exception:
|
|
pass
|
|
log.info("rmi_backend_shutdown")
|