mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
docs(cli): the depth-limited path answers a different question
`--depth-limit` was documented as selecting which server code path serves
the request. True, and incomplete in the direction that loses rows: the
two paths return different SETS, not the same set at different speeds.
The depth-limited path (buzz-db/src/thread.rs:422 `tm.root_event_id = $2`)
returns descendants by thread ANCESTRY, from `thread_metadata` rows the
relay writes at ingest only when an event clears two gates -- kind
(handlers/ingest.rs:612 `requires_h_channel_scope`) AND a NIP-10 marked
`e` tag (handlers/ingest.rs:745, `root_hex.is_none() && reply_hex.is_none()
-> Ok(None)`). The path without a depth bound matches on `#e` containment:
any event referencing the id, ancestry or not.
Measured on the built binary against the live relay, one channel:
- All 18 kind-40003 edits carry a 2-element bare `e` tag: kind gate
passes, marker gate fails, no ancestry row. 16 of 16 edit-carrying
roots diverge; the depth path loses all 18 edits and gains nothing.
e.g. root 3b341dac: no depth bound n=9 {9:7, 40003:2};
`--after 0` n=7 {9:7}.
- A thread requested on a mid-thread event returns that event ALONE on
the depth path (04e40378: n=4 without a depth bound -- itself plus its
3 direct children -- n=1 with any depth bound), because no ancestry
row names it as a root.
This matters for this crate specifically because `--after` implies the
depth sentinel, so the forward-paging idiom this help text recommends
switches every caller onto the ancestry path. Documenting the mechanism
rather than the observation: the two sets are not nested in either
direction by construction, since the ancestry path ignores the filter's
kinds entirely, so a kind outside the documented reply list can come back
on it and the documented list can be silently narrowed on it.
Strict subset is what this corpus shows, not an invariant: no marked
event of a kind outside the CLI's reply list exists here (only 9000
appears, 0 marked), so the gain column is empty by corpus, not by rule.
Doc-only. No behaviour change: two builds, hashes 975a2e1c vs 63542b39,
identical output over an 8-command probe (forward walks, both hazard
cells, the mid-thread event, garbage `--kinds`, a half cursor), with
`thread --help` as the positive control reporting DIFFERS so the oracle
is known to discriminate. 370 tests / 0 failed, clippy -D warnings clean.
Reported by Quinn (R119) and required before merge by Eva (R121).
Co-authored-by: Sami <f4a42a97e594b77bdbd8ee35191c8b28a94a4cb871d96f32921558275421fb68@buzz.block.builderlab.xyz>
Signed-off-by: Sami <f4a42a97e594b77bdbd8ee35191c8b28a94a4cb871d96f32921558275421fb68@buzz.block.builderlab.xyz>
This commit is contained in:
@@ -488,7 +488,7 @@ pub enum MessagesCmd {
|
||||
},
|
||||
/// Get a message thread (replies to a root message)
|
||||
#[command(
|
||||
after_help = "Pagination:\n Returns up to --limit replies (default 100, max 500) plus the root event.\n Replies without a cursor and without --depth-limit are NEWEST-first; either\n one selects the OLDEST-first walk, so the cursor picks which end you see.\n\n To page a thread larger than the cap, walk FORWARD from the oldest reply.\n Seed with --after 0, then pass the newest reply of each page back in:\n\n buzz messages thread --channel <UUID> --event <ID> --limit 500 --after 0\n buzz messages thread --channel <UUID> --event <ID> --limit 500 \\\n --after <created_at of newest reply seen> --after-id <its event id>\n\n Always pass --after-id. The timestamp-only cursor is STRICTLY greater-than,\n so a page boundary landing inside a second shared by several replies skips\n the rest of that second silently (rc=0). --after-id carries the tiebreak, so\n no reply is skipped regardless of where the boundary lands.\n\nServer path and counts:\n The cursor is honoured only on the depth-limited server path; a filter\n without a depth bound routes to a generic query that has no cursor. So\n --depth-limit selects WHICH server code path serves the request, which\n its name does not suggest. Passing --after implies a depth bound meaning\n \"no effective limit\" so the cursor is always reached.\n\n The root event is fetched by a SECOND filter that carries no cursor, no\n depth bound and its own limit of 1. It therefore reappears on every page\n and does not consume a reply slot: expect --limit + 1 events per page,\n and dedupe the root when concatenating pages.\n\nKind scope:\n Replies are limited to kinds 9,40002,40003,40008,45003 (message, message\n v2, edit, diff, forum comment) and NOTHING ELSE. Notably EXCLUDED:\n reactions (7) and deletions (5) — on a busy thread these outnumber the\n replies, and no flag here surfaces them, so a reply count is not a thread\n event count. This list intentionally differs from `messages get`, which\n omits edits (40003) and includes forum posts (45001)."
|
||||
after_help = "Pagination:\n Returns up to --limit replies (default 100, max 500) plus the root event.\n Replies without a cursor and without --depth-limit are NEWEST-first; either\n one selects the OLDEST-first walk, so the cursor picks which end you see.\n\n To page a thread larger than the cap, walk FORWARD from the oldest reply.\n Seed with --after 0, then pass the newest reply of each page back in:\n\n buzz messages thread --channel <UUID> --event <ID> --limit 500 --after 0\n buzz messages thread --channel <UUID> --event <ID> --limit 500 \\\n --after <created_at of newest reply seen> --after-id <its event id>\n\n Always pass --after-id. The timestamp-only cursor is STRICTLY greater-than,\n so a page boundary landing inside a second shared by several replies skips\n the rest of that second silently (rc=0). --after-id carries the tiebreak, so\n no reply is skipped regardless of where the boundary lands.\n\nServer path and counts:\n The cursor is honoured only on the depth-limited server path; a filter\n without a depth bound routes to a generic query that has no cursor. So\n --depth-limit selects WHICH server code path serves the request, which\n its name does not suggest. Passing --after implies a depth bound meaning\n \"no effective limit\" so the cursor is always reached.\n\n Those two paths answer DIFFERENT QUESTIONS, not the same question at\n different speeds. The depth-limited path returns DESCENDANTS BY THREAD\n ANCESTRY, built from rows the relay writes at ingest only for events that\n carry a NIP-10 MARKED e tag (root/reply). The path without a depth bound\n returns every event that REFERENCES the id by any e tag. Two measured\n consequences: message edits (40003) carry a bare e tag, get no ancestry\n row, and are ABSENT from the depth-limited path; and a thread requested on\n a MID-THREAD event returns that event ALONE there, because no ancestry row\n names it as a root. Since --after implies a depth bound, a forward walk\n pays both. The ancestry path also ignores the filter kinds, so the two\n result sets are not nested in either direction by construction.\n\n The root event is fetched by a SECOND filter that carries no cursor, no\n depth bound and its own limit of 1. It therefore reappears on every page\n and does not consume a reply slot: expect --limit + 1 events per page,\n and dedupe the root when concatenating pages.\n\nKind scope:\n Replies are limited to kinds 9,40002,40003,40008,45003 (message, message\n v2, edit, diff, forum comment) and NOTHING ELSE. Notably EXCLUDED:\n reactions (7) and deletions (5) — on a busy thread these outnumber the\n replies, and no flag here surfaces them, so a reply count is not a thread\n event count. This list intentionally differs from `messages get`, which\n omits edits (40003) and includes forum posts (45001).\n This list is applied on the path WITHOUT a depth bound; the ancestry path\n ignores it, so --depth-limit and --after change the kind mix too."
|
||||
)]
|
||||
Thread {
|
||||
/// Channel UUID
|
||||
@@ -503,7 +503,8 @@ pub enum MessagesCmd {
|
||||
#[arg(long)]
|
||||
limit: Option<u32>,
|
||||
/// Maximum reply nesting depth to include. Also selects the
|
||||
/// oldest-first reply ordering and the cursor-capable server path
|
||||
/// oldest-first reply ordering, the cursor-capable server path, and a
|
||||
/// result set defined by thread ancestry rather than e-tag reference
|
||||
/// (see Pagination below)
|
||||
#[arg(long)]
|
||||
depth_limit: Option<u32>,
|
||||
|
||||
Reference in New Issue
Block a user