User directive: daily not weekly; clear responsibilities per layer with no
overlap; functional criteria (does the function WORK) not process liveness;
problems get FIXED via LLM with file-and-report discipline (act first,
report after); plus a meta-layer watching the watchers; deeply integrated
into F健康.
Architecture (responsibility matrix in dev-spec.md):
- L0 agents_health_check (5min): port/HTTP/DB liveness + auto_heal executor
- L1 functional_health_check (15min trading): per-module FUNCTIONAL
criteria — output freshness/validity per REGISTRY (live_prices/market_
snapshots/mtf_cache/macro_context/bot/LLM/cron engine), not process alive
- L2 system_hygiene_audit (daily 08:20, was weekly): divergence/hardlink/
zombie/orphan/dead-cron/db-freshness
- L3 self_repair (30min): reads L1/L2 failures -> LLM diagnoses -> executes
WHITELISTED repair actions directly (rerun_script/restart_service/
sync_links/switch_llm_key/none) -> repair_log.jsonl + XMPP report.
Max 2 repairs/module/day anti-loop. LLM unavailable -> rule fallback.
- L4 meta_watchdog (hourly): checks L0-L3 output freshness + L3 cron
registration + XMPP bridge; direct XMPP alert as last resort
Retired (overlap): Cron监护-高频 (cron_watchdog -> L3), 全局cron健康监控
(cron_health_monitor -> L1).
Dashboard: mofin_health.py now emits self_check section (functional/meta/
hygiene/recent_repairs); mofin_health.html new '🩺 自检体系' tab rendering
L4 layers, L1 module checks, L2 issues, L3 repair history.
E2E verified: stopped xmpp bot -> L1 flagged fail -> systemd recovered ->
L3 LLM correctly diagnosed 'none needed' and logged; rerun_script whitelist
path executes real scripts successfully; meta_watchdog all-green after fix.
15 lines
569 B
Python
15 lines
569 B
Python
import json, shutil
|
|
jf = '/home/hmo/.hermes/cron/jobs.json'
|
|
shutil.copy(jf, jf + '.bak-20260720-l134')
|
|
d = json.load(open(jf))
|
|
is_list = isinstance(d, list)
|
|
jobs = d if is_list else d.get('jobs', [])
|
|
REMOVE = {'Cron监护-高频'}
|
|
removed = [j.get('name') for j in jobs if j.get('name') in REMOVE]
|
|
jobs = [j for j in jobs if j.get('name') not in REMOVE]
|
|
if is_list:
|
|
json.dump(jobs, open(jf, 'w'), ensure_ascii=False, indent=2)
|
|
else:
|
|
d['jobs'] = jobs
|
|
json.dump(d, open(jf, 'w'), ensure_ascii=False, indent=2)
|
|
print('removed:', removed, '| total:', len(jobs)) |