Menu

#450 fix(storage): make --last 0 return zero rows instead of every row

closed
nobody
None
2026-08-25
2026-08-23
Anonymous
No

Originally created by: slegarraga

Fixes [#430]

Root cause

Every --last flag flows into a storage reader whose LIMIT clause was guarded by truthiness:

query = _SELECT_DECISIONS + (f" LIMIT {int(limit)}" if limit else "")

limit=0 is falsy, so the clause was dropped and "show me zero rows" returned every row. The signature already documents the intended contract (limit: int | None = None, None = unlimited), so the guard now reads if limit is not None.

Changes

  • src/doberman/storage/log.py: read_decisions and read_decisions_since use limit is not None.
  • src/doberman/policy/drift.py: read_policy_changes had the same pattern; fixed there too, which covers policy-history --last 0.
  • tests/unit/test_storage_last_zero.py (new): pins the 0/None/1 contract for all three readers against a real seeded DB. These tests fail on main without the fix.
  • tests/unit/test_cli_log_jsonl.py: log --jsonl --last 0 must print nothing (fails on main without the fix).

No field or schema changes; behavior only changes for limit=0, which previously returned data nobody asked for.

Verification

Reproduced before fixing: doberman demo --fast --path <tmp>, then log --last 0 printed all 8 rows, byte-identical to log --last 100.

With the fix, on this machine:

  • pytest tests/unit/test_storage_last_zero.py tests/unit/test_cli_log_jsonl.py: 10 passed.
  • pytest tests/unit -k "log or decisions or drift or policy or tune": 212 passed, 1 skipped.
  • Full suite: pytest tests/unit = 2713 passed, 3 skipped, excluding test_hosthook_codex.py and test_hosthook_taint_floor.py, which abort natively on this Mac even on a clean checkout of main; CI arbitrates those two.
  • ruff check and ruff format --check clean on all touched files.
  • End-to-end after the fix: doberman log --last 0 --path <seeded tmp> now prints (no decisions recorded yet).

Related

Tickets: #213
Tickets: #430

Discussion

  • Anonymous

    Anonymous - 2026-08-24

    Ticket changed by: fu351

    • status: open --> closed
     
  • Anonymous

    Anonymous - 2026-08-24

    Originally posted by: fu351

    Merged, thanks @slegarraga! Fixing the truthiness guard in all three readers instead of just the log path the issue named is what I was hoping to see, policy-history --last 0 had the same bug and your storage-level contract test now pins the 0/None/1 semantics for all three at once. If you want to stay in storage, [#213] (level-5) adds a configurable prune policy for the decision log and builds directly on the readers you just fixed.

     

    Related

    Tickets: #213

  • Anonymous

    Anonymous - 2026-08-25

    Originally posted by: slegarraga

    Thank you for the thoughtful review and merge, @fu351! I really enjoyed tightening those semantics across all three readers — that contract test felt like the right way to make the fix durable. I'll take a look at [#213] next and follow up with questions or a focused PR soon. :)

     

    Related

    Tickets: #213


Log in to post a comment.