feat(api): add /api/metrics/manifold-coverage by-category endpoint
CI/CD / build-and-push (push) Successful in 8s

Measure real Manifold coverage per semantic market category counted by UNIQUE
market (not audit rows, which are inflated by repeated re-evaluation). Base table
is manifold_match_audit filtered to v3_outcome_guard; each poly_market_id is
collapsed to one row, LEFT JOIN trades for family_key, category inferred from
family_key when present else from poly_question (gubernatorial / mayoral / senate
/ primary-republican / primary-democrat / big-tech / geopolitics / other).

Per category: unique_evaluated / unique_accepted / unique_rejected /
unique_no_results / coverage_rate, ordered by unique_evaluated DESC. Summary adds
total_unique_evaluated, total_unique_accepted, overall_coverage_rate,
categories_with_coverage. Read-only: new db method + endpoint only; matcher,
scheduler, cooldowns, thresholds and exposure untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
chemavx
2026-06-08 15:41:45 +00:00
co-authored by Claude Opus 4.8
parent 98abd96fd2
commit 823914789d
2 changed files with 133 additions and 0 deletions
+26
View File
@@ -243,6 +243,32 @@ async def get_manifold_matches():
return data
@app.get("/api/metrics/manifold-coverage")
async def get_manifold_coverage():
"""Manifold coverage by semantic market category, counted by UNIQUE market.
Unlike the raw audit counters (which count per-attempt and are inflated by the
trading loop re-evaluating the same markets), this measures real coverage:
how many DISTINCT markets in each category the matcher found an accepted
Manifold counterpart for. Base table is manifold_match_audit filtered to the
current matcher (v3_outcome_guard); category is inferred from trade family_key
when available, otherwise from the question text.
coverage_by_category — one entry per category, ordered by unique_evaluated DESC:
category — gubernatorial | mayoral | senate | primary-republican |
primary-democrat | big-tech | geopolitics | other
unique_evaluated — distinct markets audited in this category
unique_accepted — distinct markets with at least one accepted match
unique_rejected — distinct markets with at least one rejected match
unique_no_results — distinct markets with at least one no_results outcome
coverage_rate — unique_accepted / unique_evaluated (null if evaluated=0)
summary — total_unique_evaluated, total_unique_accepted, overall_coverage_rate
(null if nothing evaluated), categories_with_coverage (categories with
unique_accepted > 0).
"""
return await db.get_manifold_coverage_by_category()
@app.get("/api/summary")
async def get_summary():
"""Dashboard summary card data.