""" Aaron AI ingest_failures helpers — shared by watcher.py and ingest.py. Both modules write structured failure rows so the SettingsPanel "Ingest Health" view sees the same shape regardless of ingest path. Functions take an explicit conn parameter; the caller decides transaction boundaries and exception handling. Both current callers wrap with their own log-and-swallow shims. """ def record_ingest_failure(conn, source: str, filepath, error: str) -> None: """Insert or update an ingest_failures row. Commits.""" cur = conn.cursor() cur.execute(""" INSERT INTO ingest_failures (source, filepath, error, retry_count, first_failed_at, last_failed_at) VALUES (%s, %s, %s, 0, NOW(), NOW()) ON CONFLICT (source) DO UPDATE SET error = EXCLUDED.error, retry_count = ingest_failures.retry_count + 1, last_failed_at = NOW(), resolved = FALSE """, (source, str(filepath), error[:1000])) conn.commit() def resolve_ingest_failure(conn, source: str) -> None: """Mark a previously failed source as resolved. Commits.""" cur = conn.cursor() cur.execute("UPDATE ingest_failures SET resolved = TRUE WHERE source = %s", (source,)) conn.commit()