◐ Off-By-One · answer catalog

board-jsonl-worker-status-normalization

2 answer(s)godockergodocker

if row.get("status") != CANONICALCOMPLETE: # "complete"

📦 Source in repository (JSON)

Answer 1

Root cause: 10 board rows had status="complete" but a non-canonical worker_status (pending/done/completed). Contract violated: a row is complete iff status == "complete" AND worker_status == "complete". Some rows also lacked completed_at. Fix is JSONL-first bookkeeping: normalize rows with update_board_task_notes.py, atomically (so the update lands before the benign duckdb sync error), backfill completed_at from the closing tick-116 commit time.

The fixer (~/board-fix/update_board_task_notes.py), core logic:

# Canonical contract: complete row must say "complete" in both fields
def normalize_row(row, backfill_ts):
    if row.get("status") != CANONICAL_COMPLETE:          # "complete"
        return []                                        # never touch non-complete rows
    if row.get("worker_status") != CANONICAL_COMPLETE:   # pending/done/completed/None
        row["worker_status"] = CANONICAL_COMPLETE
    if not row.get("completed_at"):                      # backfill from tick-116 commit
        row["completed_at"] = backfill_ts

def write_board_atomic(path, rows):          # temp file -> fsync -> os.replace
    fd, tmp = tempfile.mkstemp(dir=os.path.dirname(os.path.abspath(path)), ...)
    with os.fdopen(fd, "w") as f:
        for r in rows: f.write(json.dumps(r, sort_keys=True) + "\n")
        f.flush(); os.fsync(f.fileno())      # durable BEFORE sync runs
    os.replace(tmp, path)                    # atomic: sync never sees a half file

The mandated per-row FIELD=VALUE workflow (10 invocations; field allowlist blocks arbitrary key injection):

for t in T-101 T-102 T-103 T-104 T-105 T-106 T-107 T-108 T-109 T-110; do
  python3 update_board_task_notes.py --board board.jsonl \
    --id "$t" --set worker_status=complete
done

Backfill + PASS check (or run --normalize to do all rows in one pass):

python3 update_board_task_notes.py --board board.jsonl \
  --normalize --backfill-ts 2026-08-11T01:59:19Z     # tick-116 closing commit time
python3 update_board_task_notes.py --board board.jsonl --verify   # exit 0 iff PASS
python3 sync_board.py   # runs AFTER fix; duckdb missing -> BENIGN error, exit 0

Evidence & signatures

Reproduced the exact scenario with a deterministic 45-row fixture (10 bad rows: `pending`×3, `done`×4, `completed`×3; 6 of them missing `completed_at`).

| Step | Result |
|---|---|
| Pre-fix `--verify` | **exit 1** — `PASS criterion: 10` (T-101…T-110 listed) |
| 10× per-row `FIELD=VALUE` | all landed atomically: `wrote board.jsonl atomically (45 rows) — landed before duckdb sync` |
| Backfill | 6 rows got `completed_at=2026-08-11T01:59:19Z`; 4 rows kept their real timestamps |
| Post-fix `--verify` | **exit 0** — `status=complete: 20`, `status=complete & worker_status!=complete: 0` ✅ |
| Sync ordering | `sync: BENIGN ERROR — duckdb not available… exit 0` (JSONL source of truth already fixed) |
| Idempotency | re-run → `no changes needed (already normalized)` |

**13 edge-case tests pass** (`python3 test_fix.py`): pre-fix verify fails, per-row edits fix all 10, batch normalize + backfill, idempotency, post-fix verify passes, healthy rows untouched (pending/done/in_progress/already-complete), atomic write leaves no temp residue, dry-run writes nothing, unknown id → exit 2, field allowlist rejects arbitrary keys, malformed `--set` → exit 2, ISO8601 backfill validation, clean-board verify. *(One display quirk: my before/after filter used `startswith('T-10')` which omits `T-110`; grep confirmed T-110 was fixed like the rest — 0 bad rows, not 1.)*

Artifacts: `update_board_task_notes.py`, `make_fixture.py`, `sync_board.py`, `test_fix.py`, `board.jsonl` in `~/board-fix/`.
{"model": "deepseek-v4-flash", "problem_class": "board-jsonl-worker-status-normalization", "result": "passed", "tests": 13}

Answer 2

Root cause: 10 board rows had status="complete" but a non-canonical worker_status (pending/done/completed). Contract violated: a row is complete iff status == "complete" AND worker_status == "complete". Some rows also lacked completed_at. Fix is JSONL-first bookkeeping: normalize rows with update_board_task_notes.py, atomically (so the update lands before the benign duckdb sync error), backfill completed_at from the closing tick-116 commit time.

The fixer (~/board-fix/update_board_task_notes.py), core logic:

# Canonical contract: complete row must say "complete" in both fields
def normalize_row(row, backfill_ts):
    if row.get("status") != CANONICAL_COMPLETE:          # "complete"
        return []                                        # never touch non-complete rows
    if row.get("worker_status") != CANONICAL_COMPLETE:   # pending/done/completed/None
        row["worker_status"] = CANONICAL_COMPLETE
    if not row.get("completed_at"):                      # backfill from tick-116 commit
        row["completed_at"] = backfill_ts

def write_board_atomic(path, rows):          # temp file -> fsync -> os.replace
    fd, tmp = tempfile.mkstemp(dir=os.path.dirname(os.path.abspath(path)), ...)
    with os.fdopen(fd, "w") as f:
        for r in rows: f.write(json.dumps(r, sort_keys=True) + "\n")
        f.flush(); os.fsync(f.fileno())      # durable BEFORE sync runs
    os.replace(tmp, path)                    # atomic: sync never sees a half file

The mandated per-row FIELD=VALUE workflow (10 invocations; field allowlist blocks arbitrary key injection):

for t in T-101 T-102 T-103 T-104 T-105 T-106 T-107 T-108 T-109 T-110; do
  python3 update_board_task_notes.py --board board.jsonl \
    --id "$t" --set worker_status=complete
done

Backfill + PASS check (or run --normalize to do all rows in one pass):

python3 update_board_task_notes.py --board board.jsonl \
  --normalize --backfill-ts 2026-08-11T01:59:19Z     # tick-116 closing commit time
python3 update_board_task_notes.py --board board.jsonl --verify   # exit 0 iff PASS
python3 sync_board.py   # runs AFTER fix; duckdb missing -> BENIGN error, exit 0

Evidence & signatures

Reproduced the exact scenario with a deterministic 45-row fixture (10 bad rows: `pending`×3, `done`×4, `completed`×3; 6 of them missing `completed_at`).

| Step | Result |
|---|---|
| Pre-fix `--verify` | **exit 1** — `PASS criterion: 10` (T-101…T-110 listed) |
| 10× per-row `FIELD=VALUE` | all landed atomically: `wrote board.jsonl atomically (45 rows) — landed before duckdb sync` |
| Backfill | 6 rows got `completed_at=2026-08-11T01:59:19Z`; 4 rows kept their real timestamps |
| Post-fix `--verify` | **exit 0** — `status=complete: 20`, `status=complete & worker_status!=complete: 0` ✅ |
| Sync ordering | `sync: BENIGN ERROR — duckdb not available… exit 0` (JSONL source of truth already fixed) |
| Idempotency | re-run → `no changes needed (already normalized)` |

**13 edge-case tests pass** (`python3 test_fix.py`): pre-fix verify fails, per-row edits fix all 10, batch normalize + backfill, idempotency, post-fix verify passes, healthy rows untouched (pending/done/in_progress/already-complete), atomic write leaves no temp residue, dry-run writes nothing, unknown id → exit 2, field allowlist rejects arbitrary keys, malformed `--set` → exit 2, ISO8601 backfill validation, clean-board verify. *(One display quirk: my before/after filter used `startswith('T-10')` which omits `T-110`; grep confirmed T-110 was fixed like the rest — 0 bad rows, not 1.)*

Artifacts: `update_board_task_notes.py`, `make_fixture.py`, `sync_board.py`, `test_fix.py`, `board.jsonl` in `~/board-fix/`.
{"model": "deepseek-v4-flash", "problem_class": "board-jsonl-worker-status-normalization", "result": "passed", "tests": 13}
Generated from the verified corpus · MIT licensedBack to the catalog