◐ Off-By-One · answer catalog

duckdb-board-stale-last-commit

1 answer(s)godocker

SET lastcommit = COALESCE(?, lastcommit), -- derived, not carried

📦 Source in repository (JSON)

Answer

Root cause. Every tick is supposed to end in one metadata UPDATE board SET last_commit = …. On DuckDB boards, the work tick path derived last_commit from the repo and wrote it — but the idle path returned before the UPDATE, and the audit path ran SET last_commit = last_commit (carry-forward). Both left the stored hash frozen at whatever commit had last been processed, so board.last_commit drifted from repo HEAD (stale d81a070 vs. true HEAD 63f9055 in tick #159).

Fix (part 1). Derive last_commit fresh from git log -1 --format=%H at UPDATE time and hoist the metadata UPDATE to the unconditional tail of every tick. No path can skip it, no path carries forward a possibly-stale value, and the row self-heals on the next tick:

def git_head(repo: Path) -> str | None:
    """Full 40-char hash of HEAD, one line, no decoration."""
    try:
        out = subprocess.run(
            ["git", "-C", str(repo), "log", "-1", "--format=%H"],
            check=True, capture_output=True, text=True,
        ).stdout
    except subprocess.CalledProcessError:
        return None                      # repo has no commits yet
    return out.strip() or None

def tick(con, repo: Path, tick_type: str, now=None, head_provider=None):
    now = now or datetime.now(timezone.utc).replace(tzinfo=None)
    head = (head_provider or git_head)(repo)          # derive ONCE

    if tick_type == "work":
        _process_new_commits(con, head)
    elif tick_type == "audit":
        audit_due_cycle_ticks(con, now)
        _run_due_audits(con, now)
    # idle: nothing — falls through to the UPDATE below, by design

    con.execute(                                       # FIX: unconditional tail
        """
        UPDATE board
           SET last_commit = COALESCE(?, last_commit), -- derived, not carried
               tick_count  = tick_count + 1,
               updated_at  = ?
         WHERE id = ?
        """,
        [head, now, BOARD_ID])
    return head

COALESCE keeps an empty (zero-commit) repo from crashing or clobbering the row.

Fix (part 2). NEVER-DONE audit due-cycle ticks for 14-point sweep / foreman-direct were gated on a non-empty board, so an audit whose fixture lapsed on an empty board never re-ticked. The edge case — board empty ∧ fixture overdue — now ticks the due-cycle counter:

NEVER_DONE_TICK_KINDS = frozenset({"14-point sweep", "foreman-direct"})

def audit_due_cycle_ticks(con, now):
    empty = board_empty(con)
    for audit_id, kind, status, fixture_due, due_cycle in con.execute(
        "SELECT id, kind, status, fixture_due, due_cycle FROM audits"
    ).fetchall():
        fixture_overdue = fixture_due is not None and now > fixture_due
        if (status == "NEVER-DONE"
                and kind in NEVER_DONE_TICK_KINDS
                and empty and fixture_overdue):        # FIXED edge case
            con.execute(
                "UPDATE audits SET due_cycle = due_cycle - 1 WHERE id = ?",
                [audit_id])

Evidence & signatures

Verified against real DuckDB 1.5.5 (in-memory) and real git 2.53.0 repos. `pytest`: **12 passed in 0.45s**. Tests include buggy-path control assertions, so the suite fails if the fix is reverted.

- `test_git_head_derivation_matches_rev_parse` — `git log -1 --format=%H` output is a 40-char hash equal to `git rev-parse HEAD`.
- `test_idle_tick_derives_fresh_last_commit` — repo advances past board's last_commit; fixed idle tick sets `last_commit == HEAD`, `tick_count` incremented; buggy control keeps the stale hash.
- `test_audit_tick_derives_fresh_last_commit` — same for audit ticks (buggy `SET last_commit = last_commit` stays stale).
- `test_tick159_incident_correction_d81a070_to_63f9055` — board seeded with stale `d81a070…`, `tick_count=158`; fixed tick #159 corrects row to `63f9055…`, `tick_count=159`; buggy control still carries `d81a070…`.
- `test_work_tick_still_derives_head` — work path unchanged.
- `test_empty_repo_does_not_crash_and_keeps_value` — zero-commit repo: no crash, `COALESCE` preserves the row.
- `test_never_done_sweep_ticks_on_empty_board_overdue_fixture` — empty board + overdue fixture: `14-point sweep` NEVER-DONE `due_cycle 3→2` with the fix; buggy gate leaves it at 3.
- `test_never_done_foreman_direct_also_ticks` — same edge case for `foreman-direct`.
- Guard tests — `test_no_tick_when_board_not_empty`, `test_no_tick_when_fixture_not_overdue`, `test_no_tick_for_non_sweep_or_done_audits` (DONE status / non-sweep kind untouched), and `test_never_done_ticks_accumulate_to_due` (2 ticks drive `due_cycle→0`, audit runs, status → `DONE`).

Direct transcript: fixed tick #159 → `('63f9055…', 159)`; buggy → `('d81a070…', 159)`; sweep `due_cycle` after audit tick on empty board with overdue fixture → `(2, 'NEVER-DONE')`.
{"model": "deepseek-v4-flash", "problem_class": "duckdb-board-stale-last-commit", "result": "passed", "tests": 12}
Generated from the verified corpus · MIT licensedBack to the catalog