feat(agent-centric-logging): consolidate CoT infra in shared, close REASON→REFLECT chains

- shared/cot_logger.py is SSOT; backend/cot_logger.py deleted
- elapsed_ms timing in all REFLECT markers
- Frontend: REASON→REFLECT/EXPLORE in all fetch/post/delete/requestApi
- Dynamic src: route.GET.api.plugins instead of hardcoded api.request_handler
- trace_id generated immediately (no 'no-trace'), X-Trace-ID in both directions
- Global error handlers (window error + unhandledrejection + error.svelte)
- Fixed duplicate logging (shared/logger.py double StreamHandler)
- propagate=False in configure_logger (was in ConfigManager = duplicated startup logs)
- belief_scope: 'Coherence OK' → '{anchor}: completed' + elapsed_ms
- Fixed 28 pre-existing test failures (scheduler sig, DB columns, DRAFT validation, etc)
This commit is contained in:
2026-07-12 19:30:57 +03:00
parent 24d3b7d1f9
commit a39a76c87f
58 changed files with 1532 additions and 916 deletions

View File

@@ -65,7 +65,7 @@ from .api.routes import (
)
from .api.routes.validation_tasks import router as validation_tasks
from .core.auth.security import get_password_hash
from .core.cot_logger import get_trace_id, seed_trace_id
from ss_tools.shared.cot_logger import get_trace_id, seed_trace_id
from .core.database import AuthSessionLocal, init_db
from .core.encryption_key import ensure_encryption_key
from .core.logger import belief_scope, logger
@@ -90,11 +90,11 @@ async def lifespan(app: FastAPI):
# Startup
seed_trace_id()
with belief_scope("startup_event"):
logger.reason("Ensuring encryption key")
logger.reason("Ensure encryption subsystem availability")
ensure_encryption_key()
logger.reason("Initializing database tables")
logger.reason("Initialize persistent database tables")
init_db()
logger.reason("Bootstrapping admin user")
logger.reason("Bootstrap initial admin user (idempotent)")
ensure_initial_admin_user()
# Clean up stuck validation runs from previous backend lifetime
# (runs left "running" in DB when the in-memory task queue was lost)
@@ -412,26 +412,27 @@ async def log_requests(request: Request, call_next):
if not get_trace_id():
seed_trace_id()
with belief_scope("log_requests"):
# Avoid spamming logs for polling endpoints
is_polling = request.url.path.endswith("/api/tasks") and request.method == "GET"
# Dynamic src derived from the request route — more informative than hardcoded "api.request_handler"
_route_path = request.url.path.strip("/").replace("/", ".")
_src = f"route.{request.method}.{_route_path}" if _route_path else f"route.{request.method}.root"
is_polling = (
(request.url.path.endswith("/api/tasks") and request.method == "GET")
or request.url.path.endswith("/api/health/summary")
)
if not is_polling:
import json as _json, logging as _lg
if logger.isEnabledFor(_lg.INFO):
logger.reason("Incoming request", payload={"method": request.method, "path": request.url.path})
else:
_json.dump({"ts": __import__("datetime").datetime.now(__import__("datetime").UTC).isoformat(), "level": "INFO", "src": "log_requests", "marker": "REASON", "intent": f"Incoming request: {request.method} {request.url.path}"}, sys.stderr, ensure_ascii=False)
sys.stderr.write("\n")
sys.stderr.flush()
logger.reason(
"Handle API request",
src=_src,
payload={"method": request.method, "path": request.url.path}
)
try:
response = await call_next(request)
if not is_polling:
if logger.isEnabledFor(_lg.INFO):
logger.reflect("Response", payload={"status": response.status_code, "path": request.url.path})
else:
_json.dump({"ts": __import__("datetime").datetime.now(__import__("datetime").UTC).isoformat(), "level": "INFO", "src": "log_requests", "marker": "REFLECT", "intent": f"Response: {response.status_code} for {request.url.path}"}, sys.stderr, ensure_ascii=False)
sys.stderr.write("\n")
sys.stderr.flush()
logger.reflect(
"API request completed",
src=_src,
payload={"status": response.status_code, "path": request.url.path}
)
return response
except NetworkError as e:
logger.explore("Network error caught in middleware", error=str(e))