mirror of
https://github.com/block/buzz.git
synced 2026-11-01 06:51:17 +00:00
`buzz messages thread` and `buzz messages get` are both capped (500 and
200) with no way to page past the ceiling, so any thread or channel
larger than its cap is unreadable from the CLI. Both relay-side cursors
already exist and are fully implemented; neither flag was ever added.
## messages thread: --after / --after-id
`get_thread_replies` takes a composite `(created_at, event_id)` keyset
cursor (buzz-db/src/thread.rs:334-343) and the bridge parses it from
`thread_cursor`/`thread_cursor_id` (bridge.rs:1183) — the CLI never sent
the field, so a 265-reply thread ends at the 500-reply wall with no
escape. The wire names are unchanged; the flags are spelled `--after`
because this cursor pages FORWARD (`event_created_at > $n`), so the
house `--before` spelling from `social notes` would name the wrong
direction. Shape and both-or-neither grammar follow that precedent.
The relay reads the cursor only on the depth-limited code path — a
filter without `depth_limit` routes to the generic catch-all, which has
no cursor. Rather than touch that routing guard (removing it would
silently re-anchor every existing caller), a cursor supplied without
`--depth-limit` sends a depth sentinel meaning "no effective bound".
The sentinel is `i32::MAX`, not `u32::MAX`: buzz-db binds depth as i32
(thread.rs:459), so anything above `i32::MAX` wraps negative and matches
zero replies. Measured live: `--depth-limit 2147483648` returns the root
alone, `2147483647` returns the full thread.
## messages get: --before-id
`--before` maps to `until`, which is INCLUSIVE (`created_at <= $u`,
event.rs:505). `before_id` upgrades it to the exclusive keyset branch
(event.rs:493-499) and the bridge has parsed it, with a both-or-neither
grammar and a BAD_REQUEST on malformed input, since bridge.rs:263 — the
doc comment at :424 names the dense-second bug it exists to kill. The
flag did not exist.
## Why the tiebreak is not optional
The two paths have OPPOSITE cursor polarity, so they fail differently
and no timestamp-only rule covers both:
backward (get) `created_at <= $u` INCLUSIVE event.rs:505
forward (thread) `event_created_at > $n` STRICT thread.rs:443
Measured at this base. Backward, a cap binding inside a second shared by
several messages stalls or drops depending on loop shape. Forward, a page
boundary landing inside a shared second skips the rest of that second
outright: on a 44-reply thread with one 2-multiplicity second, the
timestamp-only walk drops a reply at caps {1, 2, 11, 22} and succeeds at
the other twenty — non-monotonic, because the hazard is where the
boundary lands, not the cap's size. Both failures are silent, rc=0.
With `(ts, id)` the tiebreak travels in the cursor: recovery no longer
depends on loop shape at all. That is what these flags buy — not just a
higher ceiling.
## Tests and help
15 new unit tests over two extracted pure filter builders, covering the
sentinel, its i32 representability, explicit-depth precedence, the
zero-cursor seed, and both-or-neither on each surface. Mutation-checked:
dropping the `before_id` write kills two of them and degrades the live
composite arm to the same drop as timestamp-only paging.
`--help` on both commands now states the default and cap, which end of
the range you get, that the thread cursor is strictly-after and needs
`--after 0` to seed a forward walk, and why to always pass the tiebreak.
Co-authored-by: Sami <f4a42a97e594b77bdbd8ee35191c8b28a94a4cb871d96f32921558275421fb68@buzz.block.builderlab.xyz>
Signed-off-by: Sami <f4a42a97e594b77bdbd8ee35191c8b28a94a4cb871d96f32921558275421fb68@buzz.block.builderlab.xyz>