44 lines
1.7 KiB
Python
44 lines
1.7 KiB
Python
"""As-of harness (§6.6 look-ahead guard).
|
|
|
|
Every scorer reads the `visible_claims` TEMP VIEW, never `claims` directly: at nomination time only
|
|
claims dated <= as_of are visible, so the backtest can't reward noticing what already happened. The
|
|
view also resolves merged canonical topics (topics.status='merged') to a stable `topic_id`.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import sqlite3
|
|
|
|
|
|
class Scorer:
|
|
"""Context manager that binds a run to an as_of date and exposes `visible_claims`.
|
|
|
|
mode='backtest' enforces strict as-of discipline; 'forward' is the live pilot. as_of is a
|
|
controlled ISO date (YYYY-MM-DD) — safe to inline into the view DDL (views can't take params)."""
|
|
|
|
def __init__(self, conn: sqlite3.Connection, as_of: str, *, mode: str = "backtest") -> None:
|
|
self.conn = conn
|
|
self.as_of = as_of
|
|
self.mode = mode
|
|
|
|
def __enter__(self) -> "Scorer":
|
|
self.conn.executescript(
|
|
f"""
|
|
DROP VIEW IF EXISTS visible_claims;
|
|
CREATE TEMP VIEW visible_claims AS
|
|
SELECT c.*,
|
|
COALESCE((SELECT t.merged_into FROM topics t
|
|
WHERE t.topic_canonical = c.topic_canonical AND t.status='merged'),
|
|
c.topic_canonical) AS topic_id
|
|
FROM claims c
|
|
JOIN documents d ON d.doc_id = c.doc_id
|
|
WHERE c.date IS NOT NULL AND c.date <= '{self.as_of}';
|
|
"""
|
|
)
|
|
return self
|
|
|
|
def __exit__(self, *exc) -> None:
|
|
self.conn.execute("DROP VIEW IF EXISTS visible_claims")
|
|
|
|
def count_visible(self) -> int:
|
|
return self.conn.execute("SELECT COUNT(*) FROM visible_claims").fetchone()[0]
|