Root cause: holding_strategies.shares field got set to literal string
'write_holding_strategy' for 6 records, causing TypeError at
price_monitor.py line 611 ('>' not supported between str and int).
Fixes:
1. price_monitor.py: Replace set comprehension with safe loop that
checks isinstance before comparison. Non-numeric shares treated
as holdings for safety.
2. mofin_db.py write_holding_strategy: Add type guard that resets
non-numeric shares to 0 with warning.
3. Data fix: Updated 5 corrupted holding_strategies records from
holdings table (300035/300308/300750/518880/00700).
Set 002594 (watchlist) shares=0.
Three issues from zhiwei's strategy report:
1. '37 reassess all timed out (subprocess 60s)': real cause is per-call LLM
latency exceeding the 60s per-subprocess limit during the key5-dead/
gateway-unstable window. NOT 'no concurrency control' as reported (60s
is per stock, not for the batch). Fixes: per-call timeout 60->240s
(LLM cold-start is 20-100s), and cap AUTO_REASSESS batch to 5 stocks
per run with remainder continuing next run (was unbounded serial calls
that also blew the 120s cron script window).
2. '15 stocks entry-zone center wrongly 97.0': quality gates had no
zone-sanity-vs-price check, so bad data (bad quote or LLM template
output) could be written freely. New GATE_ZONE_SANITY (CRITICAL):
zone center must be within 0.3x-3x of current price. Verified: rejects
the exact 97-center-vs-5.69-price corruption, passes legit zones.
3. 'reassess overwrites manual SQL fixes': true by design; with
GATE_ZONE_SANITY at write time, reassess can no longer overwrite good
values with garbage - invalid writes get rejected + flagged instead.
Root causes of the screenshot 404 incident:
1. RACE: client uploads image AND sends message concurrently; bot received
the message before the upload finished writing, so its GET hit a 404
error page (<100B treated as failure). FIX: _download_image now retries
3x with 2s backoff.
2. Zhiwei mentioned tesseract/小果 because the failure text never told her
the pipeline IS SenseNova. FIX: failure messages now name SenseNova
explicitly and ask for resend.
3. log_xmpp never worked for the bot: sys.path used relative '../..' from
a symlinked __file__ which resolved to '/' instead of MoFin root. This
is why the '最近对话' panel never had bot chat data (only cron script
entries). FIX: absolute path per red line #7. Verified: test message
now lands in xmpp_messages.jsonl.
4. My PowerShell -replace corrupted the file encoding (UnicodeDecodeError
crash loop on restart). Restored from git HEAD and re-applied edits with
the edit tool. Lesson: never use PowerShell string replace on UTF-8
source files with Chinese content.
5. functional_health: new sense_ocr module (OCR config presence +
SenseNova API TCP reachability), no token cost.
Zhiwei flagged: '十条红线' but she counted 14. Real issues found:
- duplicate section numbers: two '三、' (验证闭环 + 自检体系矩阵),
two '四、' (开发流程 + 部署环境) -> renumbered 一~七 sequentially
- doc index said '含五条红线' (stale from v1) -> '含十条红线'
- F 小节 still used old Tier1/Tier2 framing -> aligned to L0/L1-L2
with pointer to the L0-L4 matrix section
- version bump v2.0 -> v2.1
Minimal edit: no content changes beyond numbering/consistency.
Gateway看门狗-知微 was erroring (exit -15): its check_session_health did a
live LLM ping with 25s timeout. Cold-start LLM latency is 20-100s so the
ping always timed out -> false '不健康' verdict -> false gateway restart
-> and each 10-min run burned 22k tokens.
Now uses xmpp_logger._scan_agent_log (zero cost, reads real call results):
- ok if last real call succeeded
- unhealthy only if last call explicitly failed
- idle (no recent calls) counts as healthy
Verified: watchdog job now status=ok.
Also: triggered all 6 weekend 'Blocked' jobs via hermes cron run — all
now status=ok, proving the hardlink fix holds.