news corpus for a local scorer + agent panel v2 + dashboard read-only (2026-09-17); books byte-identical
Agent panel v2: personas return p_win anchored to the book base rates with a code-computed decision context; verdict = equal-weight mean (verdict_source "mean"); only the macro persona runs live (agent_panel.personas ["macro"]); prompt version and exact payloads logged; offline replay harness scripts/panel_replay.py; base-rate table agent_panel_base_rates.json (scripts/build_panel_base_rates.py). Backtester `strategy` column now carries the generator's own stamp (label-only; five reference books re-pinned, all 62 other columns identical). News corpus (after evaluating the owner's ML-NEWS scikit model against DeepSeek: golden set 39/78 vs 78/78, out-of-sample agreement 64% against a 90% self-agreement ceiling; verdict: fallback only, not a replacement): - NewsSentiment.xau_score + archive column xau_score keep DeepSeek's gold score for every headline (930 of the first 1,546 DeepSeek rows had none); an existing newsdata.db gains the column in place on first open - headlines naming no tracked currency are scored and archived (currencies_json []) but never returned to the platform - _apply_llm_sentiment sends every new headline in its cycle, 25 per call; a failed call ends the cycle's sending Dashboard publisher never writes a database: main() calls app_config.set_db_writes_for_process(False), honoured by signal_log_enabled() and news_archive_enabled() (owner decision: the bot is the single writer). Test suite: the hermetic app config now points both writers at a suite-private temp dir — the RSS fixture tests were writing fixture headlines into the real logs/newsdata.db — with a Module 32 test pinning it. 529 tests.
This commit is contained in:
+45
-3
@@ -152,7 +152,12 @@ CREATE TABLE IF NOT EXISTS signals (
|
||||
panel_payload_hash TEXT,
|
||||
advisory_outcome_status TEXT,
|
||||
advisory_r_multiple REAL,
|
||||
advisory_outcome_json TEXT
|
||||
advisory_outcome_json TEXT,
|
||||
panel_prompt_version TEXT,
|
||||
panel_probability REAL,
|
||||
panel_probs_json TEXT,
|
||||
panel_payloads_json TEXT,
|
||||
panel_context_json TEXT
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_signals_sym_tf_ts
|
||||
ON signals (symbol, timeframe, logged_at);
|
||||
@@ -225,6 +230,16 @@ _ADDITIVE_SIGNAL_COLS = (
|
||||
("watch_level", "TEXT"),
|
||||
("watch_kinds", "TEXT"),
|
||||
("watch_line", "TEXT"),
|
||||
# 2026-09-17 agent-panel v2 (see agent_panel.py): prompt era, the mean
|
||||
# persona probability, per-persona probabilities + reasons, the exact
|
||||
# per-persona payloads and the shared context — written post-hoc by
|
||||
# update_panel so scripts/panel_replay.py can re-score any prompt
|
||||
# version on the same evidence.
|
||||
("panel_prompt_version", "TEXT"),
|
||||
("panel_probability", "REAL"),
|
||||
("panel_probs_json", "TEXT"),
|
||||
("panel_payloads_json", "TEXT"),
|
||||
("panel_context_json", "TEXT"),
|
||||
)
|
||||
|
||||
# Read-side compatibility view `signals_with_news`: legacy rows keep
|
||||
@@ -1025,6 +1040,11 @@ class SignalLogger:
|
||||
cache_status: Optional[str] = None,
|
||||
payload_hash: Optional[str] = None,
|
||||
verdict_source: Optional[str] = None,
|
||||
prompt_version: Optional[str] = None,
|
||||
probability: Optional[float] = None,
|
||||
probs_json: Optional[str] = None,
|
||||
payloads_json: Optional[str] = None,
|
||||
context_json: Optional[str] = None,
|
||||
) -> None:
|
||||
"""Fill panel provenance; seeds an outcome only for rows that
|
||||
log() did not already seed (rows written by an older process)."""
|
||||
@@ -1051,11 +1071,18 @@ class SignalLogger:
|
||||
" panel_cache_status=COALESCE(?, panel_cache_status),"
|
||||
" panel_payload_hash=COALESCE(?, panel_payload_hash),"
|
||||
" panel_verdict_source=COALESCE(?, panel_verdict_source),"
|
||||
" panel_prompt_version=COALESCE(?, panel_prompt_version),"
|
||||
" panel_probability=COALESCE(?, panel_probability),"
|
||||
" panel_probs_json=COALESCE(?, panel_probs_json),"
|
||||
" panel_payloads_json=COALESCE(?, panel_payloads_json),"
|
||||
" panel_context_json=COALESCE(?, panel_context_json),"
|
||||
" advisory_outcome_status=COALESCE(advisory_outcome_status, ?),"
|
||||
" advisory_outcome_json=COALESCE(advisory_outcome_json, ?)"
|
||||
" WHERE id=?",
|
||||
(verdict, confidence, rationale, takes_json,
|
||||
created_at, cache_status, payload_hash, verdict_source,
|
||||
prompt_version, probability, probs_json, payloads_json,
|
||||
context_json,
|
||||
advisory_status, advisory_json, rowid))
|
||||
self._conn.commit()
|
||||
|
||||
@@ -1592,15 +1619,30 @@ def log_panel_update(report: Any) -> None:
|
||||
lg = _loggers.get(path)
|
||||
if lg is None:
|
||||
return
|
||||
takes = getattr(report, "panel_takes", None) or []
|
||||
probs = [{"persona": t.get("persona"), "p_win": _finite(t.get("p_win")),
|
||||
"stance": t.get("stance"),
|
||||
"confidence": _finite(t.get("confidence")),
|
||||
"reason_for": t.get("reason_for") or "",
|
||||
"reason_against": t.get("reason_against") or ""}
|
||||
for t in takes if isinstance(t, dict)]
|
||||
payloads = getattr(report, "panel_payloads", None) or {}
|
||||
context = getattr(report, "panel_context", None) or {}
|
||||
probability = _finite(getattr(report, "panel_probability", None))
|
||||
lg.update_panel(
|
||||
int(rowid), verdict,
|
||||
_finite(getattr(report, "panel_confidence", None)),
|
||||
getattr(report, "panel_rationale", "") or "",
|
||||
_dumps(getattr(report, "panel_takes", None) or []),
|
||||
_dumps(takes),
|
||||
created_at=getattr(report, "panel_created_at", "") or None,
|
||||
cache_status=getattr(report, "panel_cache_status", "") or None,
|
||||
payload_hash=getattr(report, "panel_payload_hash", "") or None,
|
||||
verdict_source=getattr(report, "panel_verdict_source", "") or None)
|
||||
verdict_source=getattr(report, "panel_verdict_source", "") or None,
|
||||
prompt_version=getattr(report, "panel_prompt_version", "") or None,
|
||||
probability=probability if probability else None,
|
||||
probs_json=_dumps(probs) if probs else None,
|
||||
payloads_json=_dumps(payloads) if payloads else None,
|
||||
context_json=_dumps(context) if context else None)
|
||||
except Exception:
|
||||
logger.warning("signal_log: failed to persist panel verdict",
|
||||
exc_info=True)
|
||||
|
||||
Reference in New Issue
Block a user