- npm start / watch:telegram: add --env-file=env so TELEGRAM_* and HTTPS_PROXY from nv reach process.env
- watcher: import CONFIG.candleWindowMinutes from src/config.js so the per-window latch stays in sync with the bot
- watcher: replace prevSide/cooldown latch with lastSentWindowId keyed on floor(ts/WINDOW_MS); one alert per window, NO_TRADE rows no longer reset state
Outputs: file info, time span, recommendation breakdown, max edges,
phase distribution, max model probabilities per phase, would-be ENTER
breakdown by regime, recent rows, and PM2 error tails.
Use when no pushes arrive to distinguish 'no signals' from 'signals
being swallowed' — see DEPLOYMENT.md pitfall #7.
After 8 hours of silent signal swallowing, document:
- Root cause: watcher expected "ENTER:" prefix but bot writes "side:phase:strength"
- Discovery method: analyze.sh recommendation distribution shows signals vs pushes
- Fix commit reference: 08560d0
- Three concrete lessons for cross-process data contracts
Also:
- Reference analyze.sh in cheat sheet (信号诊断 command)
- Fix manual test format in cheat sheet (no more ENTER: prefix)
- Add file structure entry for analyze.sh
- Add security checklist item: check real field formats before editing parsers
The bot writes recommendation as "side:phase:strength" (e.g. "UP:MID:STRONG")
without an "ENTER:" prefix per src/index.js:721. The watcher checked
startsWith("ENTER"), so all real signals were treated as NO_TRADE.
Only manual test rows (which I had user write with ENTER: prefix for clarity)
ever triggered. 7,460 real signals over 8 hours were silently ignored.
Detection now uses rec.includes(":") as the ENTER marker, parses side from
split[0] and phase/strength from [1]/[2].
Two fs.watch callbacks can fire for the same row within the 300ms debounce
window. Both enter the setTimeout, both read prevSide=null before either
sets it, both call send(). Result: duplicate push within ~20ms.
Fix: track lastSentTs. Same row timestamp = skip. Only a NEW row from
the bot (or a new manual append) can trigger another push.
Also log the slug before each push so we can diagnose the missing link.