main.py: --panel runs the agent panel on demand (force bypasses
enabled/surface/quality toggles; daily budget + LLM cap still apply),
prints the verdict + persona takes, and report_to_dict carries the four
panel keys — which auto-propagates them into the dashboard's
snapshot.json via report_to_webapp_dict. dashboard_publisher attaches
in scan_tf gated by agent_panel.dashboard (default off); dashboard.html
renders an "AI panel (advisory)" section in the TF detail dialog.
Claude-Session: https://claude.ai/code/session_01SisdfkxnXNL9iZsXxN3T15
Three display-side fixes, no signal-logic changes:
- run_cycle publishes snapshot.json BEFORE the news refresh — news I/O
(FF + 4 RSS + possible DeepSeek calls) took 20-30 s on TTL-expired
cycles and kept fresh signals off the page (publish_all split into
publish_snapshot/publish_news, kept for boot)
- page polls every 5 s (was 20 s) using conditional GETs: dropped the
?t= cache-buster + no-store so Apache answers unchanged files with
bodyless 304s
- boundary refetch sniper re-armed: fires 2 s after next_scan_epoch
regardless of distance (the old delay<POLL_MS guard would have been
dead code at 5 s polling)
New Module 20 test locks the snapshot-before-news ordering. 352 tests.
Claude-Session: https://claude.ai/code/session_017mbXs9HRawZhD1uZ3ze7zQ
2026-08-04 Fable 5 QA audit, final code batch.
- Boundary math: removed the provably-dead `remaining <= buffer` guard
from all three scheduler copies (518,400-instant frozen-clock sweep:
never fired) and documented the exact-boundary-instant semantics.
- websockets/websockets.client loggers pinned to INFO so a DEBUG run
can never write the TD key (connect URI) or Tiingo auth frame into
the 30-day rotating log. (.env also chmod 600, untracked.)
- Cooldown pass factored into _apply_cooldown (pure, testable) — the
only sequential replay rule finally has direct tests.
- New simulator behavior tests (previously ZERO coverage of the trade
resolver): same-bar SL+TP tie → SL-first, gap-through-SL fills at
the open, TIMEOUT pricing + round-trip spread charging, trailing
ratchet arms at bar close and fills next-bar-only, cooldown ordering.
- CLAUDE.md synced to verified reality: 338 tests/21 modules; three
weekend-implementation copies caveat; throttle claim corrected
(single-flight, TD-only throttle); daemon trail/cooldown parity
caveats (once-per-OBSERVED-bar, wall-clock cooldown) + OPEN_ONLY and
reconcile notes; CP-path gate semantics documented as validated
behavior; new "known open items" section for the owner-decision
findings (weekend DST constant, spread-in-trigger rule-6 item, H4
seeding divergence, FB2_EMA_LO).
Gates: suite 338/338 green; pinned M15 book and M5 HEAD baseline both
reproduced identically after the cooldown refactor.
Claude-Session: https://claude.ai/code/session_01UnZkzeFcTu9agFg8BDh2tn
- dashboard_publisher.py: standalone candle-close daemon that atomically
writes snapshot.json/news.json/dashboard.html to an Apache-served dir
(DASHBOARD_OUT_DIR). Fully independent of telegram_bot/oanda_daemon —
local confirmation map + boundary math, no imports either way, no new
deps, no open port. Due-TF classification from the RAW wake time.
- static/dashboard.html: self-contained dark page — hero rail, four TF
cards (score bar, 3x3 indicator grid, MTF, setup, reasons), DeepSeek
market context, week economic calendar, scored newswire. Clock offset
from the HTTP Date header (publish-time epoch is stale between closes).
- news_engine.get_week_events(): additive read-only accessor over the
cached FF week; no signal path calls it.
- deploy/: systemd unit + live-server (LAMP/SELinux) checklist.
- test_all.py: Module 20 (9 tests) + get_week_events test; 296 green.
Claude-Session: https://claude.ai/code/session_01Wc9ZoqKLYBT2QJcpRWKoGm