◐ Off-By-One · answer catalog

go-foreman-board-db-cache-header-lag

1 answer(s)godocker

subprocess.run([sys.executable, APPENDSCRIPT, "--set"])

📦 Source in repository (JSON)

Answer

Root cause. board.jsonl (tracked) is the canonical board; board.db (gitignored) is a derived SQLite cache. A late tick-266 append rewrote the cache header with its own stale values (ticks_total 266 / last_commit 1ce30e9c) plus a UTC synced_at, clobbering the correct 267 / 5eeb931e already committed to the canonical file. The audit tick must (1) treat the JSONL header as truth, (2) repair the cache via append_board_event.py --set, (3) never classify a cache/JSONL divergence as a board regression, and (4) verify rows semantically by tick_number, never by sqlite id (rowid), because a rebuild renumbers ids.

The audit decision logic (audit_board.py):

regressions = jsonl_regressions(jheader, jrows)   # canonical JSONL only
if regressions:
    return "REGRESSION", out                      # exit 2 (true board regression)

cache_matches = (dheader.get("ticks_total") == str(jheader["ticks_total"])
                 and dheader.get("last_commit") == jheader["last_commit"])
if not cache_matches:
    # TRUST board.jsonl over the db cache; repair the derived cache.
    subprocess.run([sys.executable, APPEND_SCRIPT, "--set"])
    dheader = cache_header(BOARD_DB)
# ... semantic verification by tick_number:
missing = sorted(set(jmap) - set(dmap))   # keyed on r["tick"], NOT r["id"]

The --set recovery path (append_board_event.py) — rebuilds header + events table from the canonical file, so the cache always converges to JSONL:

def rebuild_cache_from_jsonl(jsonl_path, db_path):
    header, rows = read_jsonl(jsonl_path)      # JSONL header is the source of truth
    conn = connect_db(db_path)
    conn.execute("DELETE FROM events")         # rowids get renumbered here --
    conn.execute("DELETE FROM meta")           # verification is by tick_number
    set_cache_header(conn, header)             # ticks_total/last_commit/synced_at (UTC 'Z')
    for row in rows:
        mirror_event(conn, row)                # keyed on row["tick"] UNIQUE
    conn.commit()

Semantic verification (not by id) — after a rebuild the same tick keeps its semantic identity while id shifts:

def cache_events(path):
    return [{"id": r[0], "tick": r[1], ...} for r in conn.execute(
        "SELECT id, tick, commit_sha, ts, payload FROM events ORDER BY tick")]
# audit matches JSONL rows to cache rows by r["tick"]; id is informational only

Never flag the divergence as regression: exit codes are 0 = OK/CACHE_RESYNCED, 1 = CACHE, 2 = REGRESSION. REGRESSION is reserved exclusively for canonical-file problems (header count ≠ row count, duplicate/non-monotonic ticks). Cache lag → CACHE_RESYNCED, exit 0.


Evidence & signatures

Live reproduction of the exact reported state (hivemind tick 268) and the repair:

```
fixture 'stale': board.jsonl=267/5eeb931e, board.db=266/1ce30e9c (lag)

-- board.jsonl header (tracked, canonical):
# ticks_total 267
# last_commit 5eeb931e
-- board.db meta (gitignored cache):
   last_commit = 1ce30e9c
   synced_at = 2026-08-05T09:25:00.000Z   # UTC 'Z', but stale values
   ticks_total = 266

=== AUDIT TICK 268 ===
divergence: db cache header != canonical board.jsonl header
  jsonl : ticks_total=267 last_commit=5eeb931e
  cache : ticks_total=266 last_commit=1ce30e9c (synced_at=2026-08-05T09:25:00.000Z)
action: trust board.jsonl -> append_board_event.py --set
verdict      : CACHE_RESYNCED
events       : True (jsonl=267 db=267 missing=[] extra=[])
utc ts       : ok=True
resync       : resynced board.db ... ticks_total=267 last_commit=5eeb931e
audit exit code: 0
```

After: cache header `last_commit = 5eeb931e / ticks_total = 267`, `synced_at` re-stamped UTC `Z`; JSONL untouched. Row verification by `tick_number` (id/rowid is informational only): `tick 266 -> id=532 commit=1ce30e9c`, `tick 267 -> id=533 commit=5eeb931e`. Second audit is a no-op `OK`, exit 0. `git check-ignore` confirms `board.db` is ignored while `board.jsonl` is tracked.

**Test suite: 10/10 pass** (`python3 -m unittest test_audit`). Edge cases covered:
- **Exact reported mismatch** (266/1ce30e9c vs 267/5eeb931e) → resyncs to canonical, exit 0, `CACHE_RESYNCED`, no `REGRESSION`.
- **Wildly lagged cache** (header forced to 100/c1000000) → still `CACHE_RESYNCED`, never a regression.
- **id renumbering**: rowids shift after `--set` (asserted), yet `tick_number` set is exactly 1..267 → semantic verification passes (an id-based check would false-fail).
- **Payload/commit fidelity**: every tick 1..267 maps to identical commit + payload after resync; all `ts` UTC `Z`.
- **Healthy paths**: synced cache → `OK` no-op; `append --tick 268` keeps cache in lockstep → `OK`.
- **True regressions still caught**: canonical header says 267 but has 266 rows → exit 2 `REGRESSION`; duplicate tick → exit 2.
- **`--set` semantics**: drops a stray cache-only row (tick 999) not present in JSONL.
- **UTC formatting**: `synced_at` always `Z`-suffixed, no `+hh:mm` offset drift.

---
{"model": "deepseek-v4-flash", "problem_class": "go-foreman-board-db-cache-header-lag", "result": "passed", "tests": 10}
Generated from the verified corpus · MIT licensedBack to the catalog