diff --git a/diagnostics/app.py b/diagnostics/app.py index dbcf3cc..cbfe507 100644 --- a/diagnostics/app.py +++ b/diagnostics/app.py @@ -25,6 +25,7 @@ from aiohttp import web from review_queue_routes import register_review_queue_routes from daily_digest_routes import register_daily_digest_routes from response_audit_routes import register_response_audit_routes, RESPONSE_AUDIT_PUBLIC_PATHS +from leaderboard_routes import register_leaderboard_routes, LEADERBOARD_PUBLIC_PATHS from lib.search import search as kb_search, embed_query, search_qdrant logger = logging.getLogger("argus") @@ -508,7 +509,7 @@ def _load_secret(path: Path) -> str | None: @web.middleware async def auth_middleware(request, handler): """API key check. Public paths skip auth. Protected paths require X-Api-Key header.""" - if request.path in _PUBLIC_PATHS or request.path in RESPONSE_AUDIT_PUBLIC_PATHS or request.path.startswith("/api/response-audit/"): + if request.path in _PUBLIC_PATHS or request.path in RESPONSE_AUDIT_PUBLIC_PATHS or request.path in LEADERBOARD_PUBLIC_PATHS or request.path.startswith("/api/response-audit/"): return await handler(request) expected = request.app.get("api_key") if not expected: @@ -2361,6 +2362,8 @@ def create_app() -> web.Application: # Response audit - cost tracking + reasoning traces app["db_path"] = str(DB_PATH) register_response_audit_routes(app) + # Event-sourced leaderboard (Phase B — reads contribution_events directly) + register_leaderboard_routes(app) # Timeline activity feed (per-PR + audit_log events for dashboard v2) from activity_endpoint import handle_activity app.router.add_get("/api/activity", handle_activity) diff --git a/diagnostics/leaderboard_routes.py b/diagnostics/leaderboard_routes.py index 433b4a6..bab39d5 100644 --- a/diagnostics/leaderboard_routes.py +++ b/diagnostics/leaderboard_routes.py @@ -49,11 +49,12 @@ def _parse_window(raw): return ("", (), "all_time") n = int(m.group(1)) unit = m.group(2) + # Note: WHERE clause is composed via " AND ".join(...) — do NOT prefix with "AND ". if unit == "d": n = min(n, 365) - return ("AND ce.timestamp >= datetime('now', ?)", (f"-{n} days",), f"{n}d") + return ("ce.timestamp >= datetime('now', ?)", (f"-{n} days",), f"{n}d") n = min(n, 8760) - return ("AND ce.timestamp >= datetime('now', ?)", (f"-{n} hours",), f"{n}h") + return ("ce.timestamp >= datetime('now', ?)", (f"-{n} hours",), f"{n}h") async def handle_leaderboard(request):