Root cause analysis of the 2026-07-20 redundancy incident: 1. No single-source-of-truth rule -> same file legitimately lived in 4+ locations, diverging silently 2. Relative path resolution (Path(__file__).parent/'data') -> each hardlinked copy of mofin_db.py pointed to a DIFFERENT database 3. 'Backup habit' left .bak/legacy files in production dirs, which monitoring then scanned and reported as false alarms 4. Half-done migrations: DB tables created but old JSON writers/readers stayed (price_events), old files stayed 5. Dead modules never got buried: xiaoguo 'dead' but bot ran 8 days as root eating 2.5GB 6. Monitoring checked 'does it exist' not 'is it alive' -> stale file mtime reported as 'pipeline stalled 14 days' (false alarm) 7. No 'system hygiene' as a check category at all Prevention implemented: - dev-spec.md v2.0: 五条红线 -> 十条红线 #6 single source of truth (hardlink only, no independent copies) #7 absolute data paths only (no __file__-relative data resolution) #8 no backups/legacy in production data dirs (archive immediately) #9 dead module burial checklist (6 mandatory steps) #10 monitor liveness (DB table freshness) not existence - File Location Constitution: canonical location per content type - NEW system_hygiene_audit.py: weekly Monday 07:30 cron checking diverged copies / broken hardlinks / zombie processes / orphan data files / dead cron scripts / DB freshness -> hygiene_report.json + XMPP - specs/hygiene.json: module spec per red line #1 - Verified: audit found 5 real issues on first run, all fixed, re-run clean
33 lines
1.2 KiB
Python
33 lines
1.2 KiB
Python
import sqlite3
|
|
from datetime import datetime
|
|
|
|
THIRD = '/home/hmo/.hermes/profiles/position-analyst/scripts/data/mofin.db'
|
|
MAIN = '/home/hmo/MoFin/data/mofin.db'
|
|
|
|
t = sqlite3.connect(THIRD, timeout=10)
|
|
m = sqlite3.connect(MAIN, timeout=30)
|
|
m.execute('PRAGMA busy_timeout=30000')
|
|
|
|
for table in ['sector_snapshots', 'market_snapshots', 'todos', 'capital_flow_cache']:
|
|
try:
|
|
tcols = [r[1] for r in t.execute(f"PRAGMA table_info({table})")]
|
|
mcols = [r[1] for r in m.execute(f"PRAGMA table_info({table})")]
|
|
print(f'{table}: third_cols={tcols}')
|
|
print(f' main_cols={mcols}')
|
|
tcnt = t.execute(f"SELECT COUNT(*) FROM {table}").fetchone()[0]
|
|
mcnt = m.execute(f"SELECT COUNT(*) FROM {table}").fetchone()[0]
|
|
print(f' third={tcnt} rows, main={mcnt} rows')
|
|
except Exception as e:
|
|
print(f'{table}: ERR {e}')
|
|
print()
|
|
|
|
# sector_snapshots schema in both
|
|
print('sector_snapshots sample (third):')
|
|
for r in t.execute("SELECT * FROM sector_snapshots ORDER BY rowid DESC LIMIT 2"):
|
|
print(' ', str(r)[:200])
|
|
print('sector_snapshots sample (main):')
|
|
for r in m.execute("SELECT * FROM sector_snapshots ORDER BY rowid DESC LIMIT 2"):
|
|
print(' ', str(r)[:200])
|
|
|
|
t.close()
|
|
m.close() |