Initial commit: Ten31 Signal Engine (ingest, scoring brain, corpus seeds)
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
"""Scoring orchestrator. For Job B / the §7.1 backtest: march as_of dates, score every conviction +
|
||||
fan-out derivative, gate, log the denominator, promote nodes.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from ..extract.backends import from_config as backend_from_config
|
||||
from . import bar, under_acted
|
||||
from .asof import Scorer
|
||||
from .ledger_writer import log_candidate, record_candidate_score
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _nodes_for(conn, as_of, mode, conviction_ids):
|
||||
nodes = []
|
||||
where, params = "", []
|
||||
if conviction_ids:
|
||||
ph = ",".join("?" * len(conviction_ids))
|
||||
where = f" WHERE conviction_id IN ({ph})"
|
||||
params = list(conviction_ids)
|
||||
for c in conn.execute(
|
||||
f"SELECT conviction_id, thematic_proposition, conviction_level, current_exposure, is_thesis_breaker "
|
||||
f"FROM conviction_log{where}", params,
|
||||
):
|
||||
nodes.append({"conviction_id": c[0], "node_id": None, "derivative": c[1],
|
||||
"level": c[2], "exposure": c[3], "breaker": bool(c[4])})
|
||||
fq = ("SELECT f.node_id, f.parent_conviction_id, f.derivative_proposition, c.conviction_level, "
|
||||
"c.current_exposure, c.is_thesis_breaker FROM fanout_nodes f "
|
||||
"JOIN conviction_log c ON c.conviction_id = f.parent_conviction_id")
|
||||
conds, fparams = [], []
|
||||
if conviction_ids:
|
||||
conds.append(f"f.parent_conviction_id IN ({','.join('?' * len(conviction_ids))})")
|
||||
fparams += list(conviction_ids)
|
||||
if mode == "forward": # backtest uses the seeded tree as the as-of-2023 hypothesis (no created_at leak)
|
||||
conds.append("f.created_at <= ?")
|
||||
fparams.append(as_of)
|
||||
if conds:
|
||||
fq += " WHERE " + " AND ".join(conds)
|
||||
for f in conn.execute(fq, fparams):
|
||||
nodes.append({"conviction_id": f[1], "node_id": f[0], "derivative": f[2],
|
||||
"level": f[3], "exposure": f[4], "breaker": bool(f[5])})
|
||||
return nodes
|
||||
|
||||
|
||||
def run_under_acted(conn, sc, cfg, *, as_of, mode="backtest", conviction_ids=None, window_days=28) -> list[dict]:
|
||||
backend = backend_from_config(cfg, sc)
|
||||
out = []
|
||||
with Scorer(conn, as_of, mode=mode):
|
||||
for nd in _nodes_for(conn, as_of, mode, conviction_ids):
|
||||
r = under_acted.score_node(
|
||||
conn, sc, backend, as_of=as_of, derivative=nd["derivative"],
|
||||
conviction_id=nd["conviction_id"], node_id=nd["node_id"],
|
||||
conviction_level=nd["level"], exposure=nd["exposure"], is_breaker=nd["breaker"],
|
||||
window_days=window_days,
|
||||
)
|
||||
ev, pr = bar.evaluate("under_acted", r, conn=conn)
|
||||
record_candidate_score(conn, r, as_of, ev, pr)
|
||||
if ev:
|
||||
log_candidate(conn, scorer="under_acted", as_of=as_of,
|
||||
ledger_type="under_acted_conviction", proposition=nd["derivative"],
|
||||
discourse_metric=r["inputs"], origin_conviction_id=nd["conviction_id"],
|
||||
origin_node_id=nd["node_id"])
|
||||
if nd["node_id"]:
|
||||
conn.execute("UPDATE fanout_nodes SET status=? WHERE node_id=?",
|
||||
("signal" if pr else "corroborated", nd["node_id"]))
|
||||
conn.commit()
|
||||
out.append({"node": nd, "result": r, "evidence": ev, "promotion": pr})
|
||||
return out
|
||||
|
||||
|
||||
def run_backtest(conn, sc, cfg, *, conviction_id, dates, window_days=90) -> list[tuple]:
|
||||
timeline = []
|
||||
for as_of in dates:
|
||||
res = run_under_acted(conn, sc, cfg, as_of=as_of, mode="backtest",
|
||||
conviction_ids=[conviction_id], window_days=window_days)
|
||||
timeline.append((as_of, res))
|
||||
fired = [r for r in res if r["evidence"]]
|
||||
log.info("as_of %s: %d/%d nodes cleared evidence bar", as_of, len(fired), len(res))
|
||||
return timeline
|
||||
Reference in New Issue
Block a user