fix(diagnostics): wire /api/leaderboard into app.py + fix rolling-window SQL
Some checks are pending
CI / lint-and-test (push) Waiting to run
Some checks are pending
CI / lint-and-test (push) Waiting to run
de7e5ec landed leaderboard_routes.py + the route file's register fn but
the import + register_leaderboard_routes(app) call + auth-middleware
allowlist were never added to app.py — endpoint returned 404 in production.
Three minimal edits to app.py mirror the existing register_*_routes pattern
(import at line 28, allowlist OR-clause at line 512, register call at 2365).
Plus a SQL bug in _parse_window: rolling-window clauses prefixed "AND "
but the WHERE composition uses " AND ".join(...), producing
"WHERE 1=1 AND AND ce.timestamp..." → sqlite3.OperationalError on every
window=Nd / window=Nh request. Stripped the prefix and added a comment so
the asymmetry doesn't bite again.
Verified on VPS:
GET /api/leaderboard?window=all_time&kind=person → 200, 11 rows
GET /api/leaderboard?window=7d&kind=person → 200, 2 rows
GET /api/leaderboard?window=30d&kind=person → 200, 9 rows
GET /api/leaderboard?domain=internet-finance → 200, 3 rows
GET /api/leaderboard?kind=agent → 200, leo/rio/clay/astra/vida
Unblocks: Argus dashboard cutover, Oberon column reorder, Leo's CI
taxonomy broadcast.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
de7e5ec709
commit
42d35d4e15
2 changed files with 7 additions and 3 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
Loading…
Reference in a new issue