Menu

#430 storage: `--last 0` returns every row instead of none

closed
nobody
2026-08-24
2026-08-20
Anonymous
No

Originally created by: fu351
Originally owned by: slegarraga

doberman log --last 0 (and policy-history --last 0, tune --last 0) prints the whole table. The CLI passes limit=max(0, last) through (src/doberman/cli/main.py:1311, :1627, :1200), and read_decisions builds its query with (f" LIMIT {int(limit)}" if limit else "") (src/doberman/storage/log.py:287). limit=0 is falsy, so the LIMIT clause is dropped and "show me zero rows" becomes "show me everything". The signature already says what was meant: limit: int | None = None, where None means unlimited.

Reproduce: seed with doberman demo --fast --path <tmp>, then doberman log --last 0 --path <tmp> prints all eight rows.

What to do

  1. Make the check if limit is not None at log.py:287 and the same shape in read_decisions_since (:310). Check read_policy_changes in the same module for the same pattern and fix it too if it has it.
  2. Add a test next to the existing read_decisions tests: with N rows stored, limit=0 returns [], limit=None returns all N, limit=1 returns one. Then one CLI-level test beside tests/unit/test_cli_log_jsonl.py: log --last 0 prints no rows.
  3. pytest tests/unit -k "log or decisions" green.

One-token fix at the root, so all three callers are fixed at once. Don't patch it in the CLI instead; the storage helper is where the meaning lives.

Related

Tickets: #450

Discussion

  • Anonymous

    Anonymous - 2026-08-23

    Originally posted by: slegarraga

    Claiming this one. Reproduced first on a clean tree: doberman demo --fast --path <tmp> seeds 8 decisions, and doberman log --last 0 printed all of them, identical to --last 100.

    Root cause is exactly where you pointed: the truthiness guard on the LIMIT clause (if limit) treats limit=0 as "no limit". Since the signature already documents None as unlimited, the fix is the one-token change to limit is not None in all three readers:

    • read_decisions (storage/log.py)
    • read_decisions_since (storage/log.py)
    • read_policy_changes (policy/drift.py, same pattern, so policy-history --last 0 was affected too)

    All three --last callers go through these helpers, so nothing needed patching at the CLI layer.

    Verification on my machine:

    • New storage-level contract tests fail on main without the fix and pass with it: for N seeded rows, limit=0 -> [], limit=None -> all N, limit=1 -> one.
    • CLI-level test beside test_cli_log_jsonl.py: log --jsonl --last 0 prints no rows.
    • Full unit suite green locally (2713 passed, 3 skipped), minus test_hosthook_codex.py / test_hosthook_taint_floor.py which abort natively on this Mac even on clean main; CI arbitrates those.
    • ruff check and ruff format --check clean on touched files.

    PR incoming.

     
  • Anonymous

    Anonymous - 2026-08-24
     
  • Anonymous

    Anonymous - 2026-08-24

    Ticket changed by: fu351

    • status: open --> closed
     

Log in to post a comment.