Sharing a production-hardened take on the insert-trigger workaround, plus a downstream impact that I don't think has been called out yet: on a long-running install this doesn't just wear the SSD — it eventually breaks turns.
Downstream impact beyond SSD wear — running codex as a backend under a long-lived gateway, logs_2.sqlite hit ~511 MB / ~237k rows in ~10 days. Past a few hundred MB the per-turn SQLite I/O latency widens enough that the app-server misses its turn-completion window on long tool-heavy turns → Codex stopped before confirming the turn was complete + dropped final responses. So #17320 is also a correctness problem, not just endurance. (state_5.sqlite is never the culprit — purely the TRACE sink.)
Workaround (~5 weeks in prod) — block sub-WARN at write time so amplification never happens, but keep WARN/ERROR for debugging:
CREATE TRIGGER IF NOT EXISTS block_low_level_logs
BEFORE INSERT ON logs WHEN NEW.level NOT IN ('WARN','ERROR')
BEGIN SELECT RAISE(IGNORE); END;
WAL-safety nuance: trigger+DELETE are safe live (freed pages get reused → file stops growing, no VACUUM needed); VACUUM is not safe live — only when codex is stopped. Steady-state ~20 MB/~10 MB per agent instead of half a gig climbing.
Suggested fix (echoing @Necmttn): sink should honor an effective log filter, default to ≥WARN, and log requested-vs-effective filter at startup.