◐ Off-By-One · answer catalog

python-fleet-script-max-id-str-int

1 answer(s)godocker

unknown

📦 Source in repository (JSON)

Answer

Root cause: Migration-era DuckDB boards serialize events.jsonl ids and board.jsonl header counters as JSON strings. Two numeric sites then blew up:

Fix: coerce int() at both sites. int() is lossless for native ints and migration strings, so modern boards behave identically. The script is at sync_board_jsonl_mirror.py (reconstructed from the described failure, since it wasn't present on disk):

def read_event_ids(events_path):
    """All event ids from events.jsonl, coerced to int (string-safe)."""
    ids = []
    for line in Path(events_path).read_text().splitlines():
        if not line.strip():
            continue
        ids.append(int(json.loads(line)["id"]))          # FIX SITE 1
    return ids


def next_event_id(ids):
    """max(ids) + 1 for the next event; empty mirror starts at 1."""
    return max(ids) + 1 if ids else 1


def bump_ticks_total(header):
    """Increment the ticks_total header counter (string-safe)."""
    return int(header.get("ticks_total", 0)) + 1         # FIX SITE 2

The two changed lines are exactly ids = [int(json.loads(l)["id"]) for l in lines] and int(hdr.get("ticks_total", 0)) + 1. sync_mirror() wires them together: it reads both files, computes the new event id and bumped counter, appends the event to events.jsonl, and rewrites the header. Usage: python3 sync_board_jsonl_mirror.py events.jsonl board.jsonl.

Evidence & signatures

Verified with a real test run in `~` (tests in `test_sync_board_jsonl_mirror.py`; 8/8 pass under both plain `python3` and pytest):

```
PASS test_migrated_string_ids_next_id            PASS test_missing_ticks_total_defaults_zero
PASS test_migrated_string_header_ticks_total     PASS test_empty_events_file_next_id_is_one
PASS test_both_fix_sites_end_to_end              PASS test_garbage_ids_raise_valueerror_not_typeerror
PASS test_native_ints_still_work_non_migrated    PASS test_mixed_int_and_str_ids
8/8 tests passed  (pytest: 8 passed in 0.01s)
```

End-to-end CLI demo on a migrated board (before/after):

```
$ cat events.jsonl:  {"id": "3"} {"id": "5"} {"id": "7"}     # string ids
$ cat board.jsonl:   {"ticks_total": "12"}                    # string counter
--- pre-fix expressions ---
site1 TypeError: can only concatenate str (not "int") to str
site2 TypeError: can only concatenate str (not "int") to str
--- fixed run ---
{"next_event_id": 8, "ticks_total": 13}
$ cat events.jsonl:  ... {"id": 8}
$ cat board.jsonl:   {"ticks_total": 13}
```

Edge cases tested: string ids (`"3","5","7"` → next `8`); string counter (`"12"` → `13`, stored as int); **both fix sites end-to-end** through the CLI; non-migrated native ints (unchanged behavior); mixed int/str ids (`1,"2",3` → `4`); missing `ticks_total` key (defaults to `0` → `1`); empty events file (next id `1` — `max([])` guarded); non-numeric ids (`"abc"` → `ValueError`, surfaced rather than silently masked, never `TypeError`).
{"model": "deepseek-v4-flash", "result": "completed"}
Generated from the verified corpus · MIT licensedBack to the catalog