Baida07 commited on
Commit
2d2f7f5
Β·
verified Β·
1 Parent(s): e340385

sync: 194 file da Baida98/AI@7d89d62a (2026-08-30 06:05 UTC)

Browse files
api/public_snapshot.py CHANGED
@@ -62,9 +62,11 @@ async def write_public_dashboard_snapshot() -> bool:
62
  if attempt < 3:
63
  await asyncio.sleep(2)
64
 
 
65
  _logger.warning(
66
- "BOOT: public snapshot upsert failed after retries (%s); public status remains degraded",
67
  type(last_error).__name__ if last_error else "unknown",
 
68
  )
69
  return False
70
 
 
62
  if attempt < 3:
63
  await asyncio.sleep(2)
64
 
65
+ error_code = getattr(last_error, "code", None) or getattr(last_error, "status_code", None)
66
  _logger.warning(
67
+ "BOOT: public snapshot upsert failed after retries type=%s code=%s; public status remains degraded",
68
  type(last_error).__name__ if last_error else "unknown",
69
+ str(error_code)[:32] if error_code is not None else "unknown",
70
  )
71
  return False
72
 
api/public_snapshot_diagnostics.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Protected diagnostics for the public dashboard snapshot.
2
+
3
+ The route is MACHINE-only and returns a sanitized Supabase error code so an
4
+ operator can distinguish missing schema, permissions, and connectivity without
5
+ exposing URLs, keys, SQL, or row contents.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import re
10
+ from typing import Any, Optional
11
+
12
+ from fastapi import APIRouter, Depends
13
+
14
+ from .auth_guard import AuthRole, require_role
15
+ from .state import sb
16
+
17
+ router = APIRouter(
18
+ prefix="/api/diagnostics/public-snapshot",
19
+ tags=["diagnostics"],
20
+ dependencies=[Depends(require_role(AuthRole.MACHINE))],
21
+ )
22
+
23
+ _PUBLIC_FIELDS = "singleton,service_status,active_sessions,queued_tasks,in_progress_tasks,app_version,updated_at"
24
+
25
+
26
+ def _safe_error(exc: Exception) -> dict[str, Optional[str]]:
27
+ code = getattr(exc, "code", None) or getattr(exc, "status_code", None)
28
+ raw = str(getattr(exc, "message", None) or exc)
29
+ # Keep useful PostgreSQL/Supabase codes, remove URLs, credentials and long SQL.
30
+ message = re.sub(r"https?://\S+", "[url]", raw)
31
+ message = re.sub(r"(?i)(authorization|apikey|api[_-]?key|token|password)=?\s*\S+", r"\1=[redacted]", message)
32
+ message = re.sub(r"\s+", " ", message).strip()[:240]
33
+ return {
34
+ "code": str(code) if code is not None else None,
35
+ "type": type(exc).__name__,
36
+ "message": message,
37
+ }
38
+
39
+
40
+ @router.get("")
41
+ async def public_snapshot_diagnostics() -> dict[str, Any]:
42
+ """Return snapshot presence and a sanitized exact Supabase error, if any."""
43
+ client = sb()
44
+ if client is None:
45
+ return {
46
+ "ok": False,
47
+ "client_available": False,
48
+ "row_present": False,
49
+ "error": {"code": None, "type": "SupabaseClientUnavailable", "message": "client unavailable"},
50
+ }
51
+
52
+ try:
53
+ result = client.table("public_dashboard_snapshot").select(_PUBLIC_FIELDS).eq("singleton", True).limit(1).execute()
54
+ rows = result.data or []
55
+ return {
56
+ "ok": True,
57
+ "client_available": True,
58
+ "row_present": bool(rows),
59
+ "snapshot": rows[0] if rows else None,
60
+ "error": None,
61
+ }
62
+ except Exception as exc:
63
+ return {
64
+ "ok": False,
65
+ "client_available": True,
66
+ "row_present": False,
67
+ "error": _safe_error(exc),
68
+ }
main.py CHANGED
@@ -165,6 +165,7 @@ _ROUTER_MAP = {
165
  "private_state": "private_state",
166
  "auth": "auth_managed",
167
  "public_status": "public_status",
 
168
  "me_tasks": "me_tasks",
169
  "admin_state": "admin_state",
170
  # ── Aggiunti ROUTER-COMPLETE (29 moduli orfani rimontati) ─────────────────
 
165
  "private_state": "private_state",
166
  "auth": "auth_managed",
167
  "public_status": "public_status",
168
+ "public_snapshot_diagnostics": "public_snapshot_diagnostics",
169
  "me_tasks": "me_tasks",
170
  "admin_state": "admin_state",
171
  # ── Aggiunti ROUTER-COMPLETE (29 moduli orfani rimontati) ─────────────────