Skip to content

pm list: with --output-limit and --output-budget both cutting rows, the advertised continuation is refused as stale on an unchanged workspace (and the rebased cursor can skip rows) #1411

Description

@unbraind

Repro (2026.10.5, fresh workspace)

git init && pm init --yes
body=$(printf 'x%.0s' $(seq 1 400))
for i in $(seq 1 75); do pm create --title "Item $i" --type Task -d "$body"; done
pm list --output-limit 50 --output-budget 1500 --json > first.json   # count 33, truncated, has_more
C=$(jq -r .next_cursor first.json)                                     # also output_budget_truncation.recovery.cursor
pm list --output-limit 50 --output-budget 1500 --output-cursor "$C" --json
# -> code: read_output_cursor_stale   (nothing changed between the two reads)

The migration_hints in the first response say to page with --output-cursor. Following that hint fails on the very next read.

Why (from differential testing in the pm-rust reimplementation)

  1. Stale replay: the snapshot fingerprint is computed over the collection after the amount cap (--output-limit 50). Replay verifies the cursor against the original producer collection, so the fingerprints never match when both ceilings remove rows.
  2. Skipped rows after a deletion: with a producer --limit plus --output-limit/--output-budget, the rebased after_index subtracts using the capped count (state.count - retained) instead of the original producer page count. If the last delivered item is deleted before the next read, the position fallback lands too far ahead, and undisplayed rows are skipped silently, which is worse than a refusal.

Both reproduce byte-identically in pm 2026.10.5 and in the native Rust port, which currently pins this behaviour for parity: unbraind/pm-rust#60, tests combined_output_ceilings_match_published_stale_replay and combined_ceilings_match_published_deleted_identity_fallback in tests/pagination_differential.rs.

Expected

Capture the original collection's count and fingerprint before applying either ceiling, and rebase producer cursors with the original page count. Then a continuation the CLI advertises is accepted on an unchanged workspace, and a deletion between reads never skips rows.

Related: #1373, #1401 (output budgets), #1408.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions