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.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Harwinder Sekhon
2026-09-17 19:49:29 -04:00
parent 552199857a
commit 1f4741b557
21 changed files with 3803 additions and 259 deletions
+14 -1
View File
@@ -18,6 +18,10 @@ immune to anything on the web side):
* The only shared-code dependency beyond the standard signal path is
the additive `NewsEngine.get_week_events` accessor, which no
production signal path calls.
* Never writes a database. It is not always running, so the Telegram
bot is the single writer of `signals.db` and `newsdata.db`; main()
switches every SQLite writer off for this process
(`app_config.set_db_writes_for_process`, owner decision 2026-09-17).
Scheduling: every M15/H1/H4 boundary is also an M5 boundary (all
intervals are multiples of 5, anchored to UTC midnight), so one
@@ -58,7 +62,8 @@ from typing import Dict, List, Optional
import pandas as pd
from agent_panel import attach_panel
from app_config import get_app_config, violent_watch_enabled
from app_config import (get_app_config, set_db_writes_for_process,
violent_watch_enabled)
from config import PlatformConfig, Timeframe, XAUUSD
from main import report_to_dict
from news_engine import NewsEngine
@@ -553,6 +558,14 @@ def main(argv=None) -> None:
args = ap.parse_args(argv)
_setup_logging()
# This process never writes a database. It is not always running, so
# the Telegram bot is the single writer of signals.db and newsdata.db
# (owner decision 2026-09-17). The switch is process-wide and beats
# config.json / env; set here in main(), not at import, so importing
# the module (the test suite does) leaves every other writer on.
set_db_writes_for_process(False)
logger.info("database writes disabled for this process "
"(the Telegram bot is the only writer)")
os.makedirs(args.out, exist_ok=True)
pub = DashboardPublisher(args.out)
pub.install_static()