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)
- 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.
- 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.
Repro (2026.10.5, fresh workspace)
The
migration_hintsin 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)
--output-limit 50). Replay verifies the cursor against the original producer collection, so the fingerprints never match when both ceilings remove rows.--limitplus--output-limit/--output-budget, the rebasedafter_indexsubtracts 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_replayandcombined_ceilings_match_published_deleted_identity_fallbackintests/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.