diff --git a/lib/substantive_fixer.py b/lib/substantive_fixer.py index 6280e55..c7537b0 100644 --- a/lib/substantive_fixer.py +++ b/lib/substantive_fixer.py @@ -540,6 +540,7 @@ async def substantive_fix_cycle(conn, max_workers=None) -> tuple[int, int]: AND (domain_verdict = 'request_changes' OR leo_verdict = 'request_changes') AND COALESCE(fix_attempts, 0) < ? AND (last_attempt IS NULL OR last_attempt < datetime('now', '-3 minutes')) + AND json_valid(eval_issues) AND EXISTS ( SELECT 1 FROM json_each(eval_issues) WHERE value IN ({placeholders}) @@ -552,10 +553,11 @@ async def substantive_fix_cycle(conn, max_workers=None) -> tuple[int, int]: if not rows: return 0, 0 - # Defense-in-depth: corrupt eval_issues JSON shouldn't reach here (json_each - # would error in the SELECT and SQLite would skip the row), but the WARN log - # stays so we catch any edge case where a row's JSON parses for json_each - # but not for json.loads (different parsers, technically). + # Defense-in-depth: json_valid(eval_issues) in the SELECT already filters + # corrupt JSON before json_each runs, so this WARN should be unreachable. + # Kept anyway: json_valid and json.loads use technically distinct parsers, + # and the journal entry names the failure mode if SQLite ever surfaces a + # row that passes json_valid + json_each but fails json.loads. substantive_rows = [] for row in rows: try: