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:
+17
-1
@@ -471,7 +471,23 @@ function detailHTML(tf) {
|
||||
${esc(r.news_summary || "")}</div>`);
|
||||
}
|
||||
|
||||
if (r.panel_verdict) {
|
||||
if (r.panel_verdict && r.panel_verdict_source === "mean") {
|
||||
// v2 panel: a probability anchored to the setup class's base rate,
|
||||
// one reason each way per persona. Advisory only; no verdict colour.
|
||||
const base = (r.panel_context && r.panel_context.base_rate) || {};
|
||||
const usual = base.win_rate != null ? ` (usual for this kind of setup: ${Math.round(base.win_rate)}%)` : "";
|
||||
const takes = (r.panel_takes || []).map(t =>
|
||||
`<tr><td class="ind-k">${esc(t.persona)}</td>
|
||||
<td class="num text-end">${t.p_win != null ? Math.round(t.p_win) + "%" : "—"}</td>
|
||||
<td class="small text-secondary">${esc(t.reason_for || "")}</td>
|
||||
<td class="small text-secondary">${esc(t.reason_against || "")}</td></tr>`).join("");
|
||||
out += sec("AI estimate (advisory, still being tested)", `<div class="text-secondary small mb-2">
|
||||
About a <strong>${Math.round(r.panel_probability || 0)}%</strong> chance this trade pays off${esc(usual)}.<br>
|
||||
${esc(r.panel_rationale || "")}</div>
|
||||
${takes ? `<div class="detail-table"><table class="table table-sm d-table">
|
||||
<thead><tr><th></th><th class="text-end">chance</th><th>for</th><th>against</th></tr></thead>
|
||||
<tbody>${takes}</tbody></table></div>` : ""}`);
|
||||
} else if (r.panel_verdict) {
|
||||
const vcls = r.panel_verdict === "AGREE" ? "text-success"
|
||||
: r.panel_verdict === "OPPOSE" ? "text-danger" : "text-secondary";
|
||||
const takes = (r.panel_takes || []).map(t =>
|
||||
|
||||
Reference in New Issue
Block a user