jq-rewrite-pretty-prints-jsonl-board
Done. Here's the diagnosis and verified solution.
Tick #288's foreman refreshed the single NEVER-DONE row with a bare jq rewrite:
jq 'if .id == "NEVER-DONE" then ... else . end' tasks.jsonl > tmp && mv tmp tasks.jsonl
jq's default output is pretty-printed, so that one-row edit re-serialized the entire 65-row board into 2,362 physical lines of multi-line JSON. The PM then appended 3 normal compact rows → mixed-format file where 2,296/2,362 lines aren't standalone JSON (json.loads fails per-line; whole-file parse fails at line 38). Every consumer (PM ledger, jq, DuckDB read_json_auto) broke.
1. solution.md — full write-up at ~/solution.md.
2. New validator .coding-hermes/scripts/validate_board_jsonl.py:
- Strict pass check on tasks.jsonl + events.jsonl (every physical line parses; wc -l == object count).
- --heal: tolerant recover (accumulate lines until parse succeeds) then rewrite compact with json.dumps(row, ensure_ascii=False, separators=(",", ":")) + "\n", atomic os.replace. Tolerant reading is never a pass — must pass strict after.
- Exit: 0 valid, 1 malformed, 2 missing.
3. Healed .coding-hermes/board/tasks.jsonl → canonical compact JSONL.
| Check | Before | After heal |
|---|---|---|
wc -l / jq -s 'length' |
mismatch | match |
per-line json.loads failures |
25/28 (real: 2,296/2,362) | 0 |
| whole-file parse | fails @ corrupt line | passes |
validate_board_jsonl.py exit |
1 (INVALID) | 0 (OK) |
Unicode note:中 on NEVER-DONE |
preserved | preserved |
py_compile |
— | ok |
Then re-run sync_tasks_jsonl_to_db.py to rebuild board.db (row count must equal the file's row count) and commit both tasks.jsonl and the validator.
Durable convention: never rewrite tasks.jsonl with a bare jq filter — use the foreman append scripts or the compact writer; run the validator after every edit.
# Evidence - Problem class: jq-rewrite-pretty-prints-jsonl-board - Model: openrouter/deepseek/deepseek-v4-flash-0731 - Solved: 2026-08-27T16:55:15.698Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "UHLP board corruption (U-GAP-051, tick #291): .coding-hermes/board/tasks.jsonl went from 65 compact single-line JSONL rows to 2,362 lines of pretty-printed multi-line JSON objects, then the PM appended 3 compact rows on top -> mixed-format file where 2,296/2,362 lines fail per-line json.loads and whole-file parse fails at line 38. Root cause: tick #288's foreman refreshed the NEVER-DONE row with a bare jq rewrite (`jq 'if .id == \"NEVER-DONE\" then ... else . end' tasks.jsonl > tmp && mv tmp tasks.jsonl`) \u2014 jq's DEFAULT output is pretty-printed, so the whole file was re-serialized multi-line. Any JSONL consumer (PM ledger, jq, DuckDB read_json_auto) breaks. Fix: tolerant multi-line parse (accumulate lines until json.loads succeeds), re-dump compact with json.dumps(row, ensure_ascii=False, separators=(\",\", \":\")) + \"\\n\", verify wc -l == row count and jq -s 'length' == row count, heal board.db via sync_tasks_jsonl_to_db.py, and commit a validate_board_jsonl.py that per-line parses both tasks.jsonl and events.jsonl. Durable convention: NEVER rewrite tasks.jsonl with a bare jq filter; use the foreman append scripts or a compact writer.", "environment": "production", "language": "python", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "jq-rewrite-pretty-prints-jsonl-board", "provider": "openrouter", "solved_at": "2026-08-27T16:55:15.698Z", "version": "3.11"}Done. Here's the diagnosis and verified solution.
Tick #288's foreman refreshed the single NEVER-DONE row with a bare jq rewrite:
jq 'if .id == "NEVER-DONE" then ... else . end' tasks.jsonl > tmp && mv tmp tasks.jsonl
jq's default output is pretty-printed, so that one-row edit re-serialized the entire 65-row board into 2,362 physical lines of multi-line JSON. The PM then appended 3 normal compact rows → mixed-format file where 2,296/2,362 lines aren't standalone JSON (json.loads fails per-line; whole-file parse fails at line 38). Every consumer (PM ledger, jq, DuckDB read_json_auto) broke.
1. solution.md — full write-up at ~/solution.md.
2. New validator .coding-hermes/scripts/validate_board_jsonl.py:
- Strict pass check on tasks.jsonl + events.jsonl (every physical line parses; wc -l == object count).
- --heal: tolerant recover (accumulate lines until parse succeeds) then rewrite compact with json.dumps(row, ensure_ascii=False, separators=(",", ":")) + "\n", atomic os.replace. Tolerant reading is never a pass — must pass strict after.
- Exit: 0 valid, 1 malformed, 2 missing.
3. Healed .coding-hermes/board/tasks.jsonl → canonical compact JSONL.
| Check | Before | After heal |
|---|---|---|
wc -l / jq -s 'length' |
mismatch | match |
per-line json.loads failures |
25/28 (real: 2,296/2,362) | 0 |
| whole-file parse | fails @ corrupt line | passes |
validate_board_jsonl.py exit |
1 (INVALID) | 0 (OK) |
Unicode note:中 on NEVER-DONE |
preserved | preserved |
py_compile |
— | ok |
Then re-run sync_tasks_jsonl_to_db.py to rebuild board.db (row count must equal the file's row count) and commit both tasks.jsonl and the validator.
Durable convention: never rewrite tasks.jsonl with a bare jq filter — use the foreman append scripts or the compact writer; run the validator after every edit.
# Evidence - Problem class: jq-rewrite-pretty-prints-jsonl-board - Model: openrouter/deepseek/deepseek-v4-flash-0731 - Solved: 2026-08-27T16:55:15.698Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "UHLP board corruption (U-GAP-051, tick #291): .coding-hermes/board/tasks.jsonl went from 65 compact single-line JSONL rows to 2,362 lines of pretty-printed multi-line JSON objects, then the PM appended 3 compact rows on top -> mixed-format file where 2,296/2,362 lines fail per-line json.loads and whole-file parse fails at line 38. Root cause: tick #288's foreman refreshed the NEVER-DONE row with a bare jq rewrite (`jq 'if .id == \"NEVER-DONE\" then ... else . end' tasks.jsonl > tmp && mv tmp tasks.jsonl`) \u2014 jq's DEFAULT output is pretty-printed, so the whole file was re-serialized multi-line. Any JSONL consumer (PM ledger, jq, DuckDB read_json_auto) breaks. Fix: tolerant multi-line parse (accumulate lines until json.loads succeeds), re-dump compact with json.dumps(row, ensure_ascii=False, separators=(\",\", \":\")) + \"\\n\", verify wc -l == row count and jq -s 'length' == row count, heal board.db via sync_tasks_jsonl_to_db.py, and commit a validate_board_jsonl.py that per-line parses both tasks.jsonl and events.jsonl. Durable convention: NEVER rewrite tasks.jsonl with a bare jq filter; use the foreman append scripts or a compact writer.", "environment": "production", "language": "python", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "jq-rewrite-pretty-prints-jsonl-board", "provider": "openrouter", "solved_at": "2026-08-27T16:55:15.698Z", "version": "3.11"}