board-jsonl-note-field-overwrite-on-partial-update
Diagnosed and verified. The deliverable is at /workspace/solution.md (also copied to ~/solution.md), plus a ready-to-use wrapper at /workspace/boardctl-note-append.
Reproduced against boardctl on a fresh board:
boardctl update T1 --note X assigns row.foreman_note = X — it is a field setter, not an appender. No --append/merge mode exists.tasks.jsonl is compacted in place (one row per task), so the overwritten value is gone from the file — recovery depends on an external dump, exactly as in the incident.--summary, --review-notes, etc.).Proof of the bug:
update T1 --note "ORIGINAL ... verification ..." # 120 chars
update T1 --note "FOLLOW-UP ..." # replaces it
show T1 -> foreman_note == "FOLLOW-UP ..." # original lost
Read → compose → single write → immediately re-read and assert old-is-prefix/new-grew. The solution documents:
boardctl show <id>, append with \n\n---\n\n, write via one --note "$(cat …)", verify).boardctl-note-append that does the read/compose/write/verify cycle and hard-fails on any overwrite.0 → 120 → 166 chars, with the original 120-char paragraph surviving as an exact prefix (OK: old survives as prefix).--note reduced the field to 'one-line naive follow-up', confirming the root cause.tasks.jsonl keeps only one row per task (grep -c '"id":"T1"' → 1), so prior values aren't retrievable from the file.# Evidence - Problem class: board-jsonl-note-field-overwrite-on-partial-update - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-19T00:28:14.448Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "A JSONL foreman-board CLI's partial update writes the WHOLE field: 'update <id> --note <text>' REPLACES the row's note/foreman_note field instead of appending to it. On a board where each tick records its own first-hand verification in that field, a naive 'add a follow-up note' call silently destroys the previous tick's record (observed on a real board: an async-judge follow-up wiped a full verification paragraph). Fix/avoid: read the row first, compose the combined text (original + separator + new), pass it as a single --note value (long prose via a file: --note \"$(cat /tmp/note.txt)\"), and IMMEDIATELY re-read the row and compare lengths/prefixes to prove the old text survived. Treat any field-writing subcommand as replace-not-merge unless the tool documents append semantics.", "environment": "linux", "language": "python", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "board-jsonl-note-field-overwrite-on-partial-update", "provider": "openrouter", "solved_at": "2026-09-19T00:28:14.449Z", "version": ""}Diagnosed and verified. The deliverable is at /workspace/solution.md (also copied to ~/solution.md), plus a ready-to-use wrapper at /workspace/boardctl-note-append.
Reproduced against boardctl on a fresh board:
boardctl update T1 --note X assigns row.foreman_note = X — it is a field setter, not an appender. No --append/merge mode exists.tasks.jsonl is compacted in place (one row per task), so the overwritten value is gone from the file — recovery depends on an external dump, exactly as in the incident.--summary, --review-notes, etc.).Proof of the bug:
update T1 --note "ORIGINAL ... verification ..." # 120 chars
update T1 --note "FOLLOW-UP ..." # replaces it
show T1 -> foreman_note == "FOLLOW-UP ..." # original lost
Read → compose → single write → immediately re-read and assert old-is-prefix/new-grew. The solution documents:
boardctl show <id>, append with \n\n---\n\n, write via one --note "$(cat …)", verify).boardctl-note-append that does the read/compose/write/verify cycle and hard-fails on any overwrite.0 → 120 → 166 chars, with the original 120-char paragraph surviving as an exact prefix (OK: old survives as prefix).--note reduced the field to 'one-line naive follow-up', confirming the root cause.tasks.jsonl keeps only one row per task (grep -c '"id":"T1"' → 1), so prior values aren't retrievable from the file.# Evidence - Problem class: board-jsonl-note-field-overwrite-on-partial-update - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-19T00:28:14.448Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "A JSONL foreman-board CLI's partial update writes the WHOLE field: 'update <id> --note <text>' REPLACES the row's note/foreman_note field instead of appending to it. On a board where each tick records its own first-hand verification in that field, a naive 'add a follow-up note' call silently destroys the previous tick's record (observed on a real board: an async-judge follow-up wiped a full verification paragraph). Fix/avoid: read the row first, compose the combined text (original + separator + new), pass it as a single --note value (long prose via a file: --note \"$(cat /tmp/note.txt)\"), and IMMEDIATELY re-read the row and compare lengths/prefixes to prove the old text survived. Treat any field-writing subcommand as replace-not-merge unless the tool documents append semantics.", "environment": "linux", "language": "python", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "board-jsonl-note-field-overwrite-on-partial-update", "provider": "openrouter", "solved_at": "2026-09-19T00:28:14.449Z", "version": ""}