feat: import Chinese-localized Buzz source snapshot
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled
Signed-off-by: cls_宁波本机 <908705107@qq.com>
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
# Bridge `/query` Extension: Channel Window
|
||||
|
||||
> **Normative spec:** [NIP-CW](nips/NIP-CW.md) is the canonical, standalone
|
||||
> specification of the channel window (kinds 39005/39006, filter extension,
|
||||
> cursor and trust semantics). This document remains as the ratified
|
||||
> engineering contract and internal design record; where wording differs,
|
||||
> NIP-CW governs.
|
||||
|
||||
Status: frozen contract v2 (2026-07-03) — GUI read-model overhaul.
|
||||
Reviewed by: Mari (relay ground truth), Wren (client core), Quinn (spec
|
||||
guardian), Perci (NIP landscape). Ratified in
|
||||
`#buzz-gui-formal-relay-interaction-spec`, thread `a7c68013`.
|
||||
|
||||
The channel window is how Buzz clients page a channel timeline by
|
||||
**top-level rows** instead of raw events. It is a raw-filter extension on
|
||||
the existing HTTP bridge `POST /query` — the same extension family as
|
||||
`before_id` and `thread_cursor`. There is no new endpoint, and the wire
|
||||
carries only signed nostr events.
|
||||
|
||||
Vanilla NIP-01 cannot express "messages with no reply e-tag" (filters have
|
||||
no negation), which is why generic nostr clients page raw events and
|
||||
reassemble threads client-side. This relay computes `thread_metadata`
|
||||
(depth, root, reply counts) at ingest, so it can serve the top-level view
|
||||
directly. The WS REQ path ignores all fields below via `nostr::Filter`'s
|
||||
unknown-field behavior — generic clients degrade gracefully to a normal
|
||||
full-event query; they never see a wrong-but-plausible timeline.
|
||||
|
||||
## Request
|
||||
|
||||
A standard bridge filter plus extension fields:
|
||||
|
||||
```json
|
||||
{
|
||||
"kinds": [9],
|
||||
"#h": ["<channel-uuid>"],
|
||||
"limit": 50,
|
||||
"top_level": true,
|
||||
"include_summaries": true,
|
||||
"include_aux": true,
|
||||
"until": 1751500000,
|
||||
"before_id": "<64-hex event id>"
|
||||
}
|
||||
```
|
||||
|
||||
- `top_level: true` — routes this filter to the top-level SQL view.
|
||||
Requires exactly one `#h` channel the caller can access.
|
||||
- `limit` — row budget. Counts **row events only**; summaries, aux, and
|
||||
bounds overlays never consume it.
|
||||
- `until` + `before_id` — the composite request cursor `(created_at, id)`
|
||||
of the last retained row from the previous page. **Both or neither.**
|
||||
`top_level` with `until` but no `before_id` is rejected (`400`): the
|
||||
window path has no timestamp-only fallback, ever. Neither = head request.
|
||||
- `include_summaries` / `include_aux` — opt-in overlay/closure appends.
|
||||
|
||||
`page`/OFFSET is not honored on the window path.
|
||||
|
||||
## Top-level predicate
|
||||
|
||||
A row is top-level iff `depth IS NULL OR depth = 0 OR (depth = 1 AND
|
||||
broadcast = true)` in `thread_metadata` (v1 ruling: `NULL` — an event
|
||||
ingested before thread metadata existed — counts as top-level; the harness
|
||||
`legacyReply` scenario decides whether a backfill migration is needed).
|
||||
Deleted rows (`deleted_at IS NOT NULL`) are excluded before the limit.
|
||||
|
||||
## Ordering and cursor
|
||||
|
||||
Rows are ordered `(created_at DESC, id ASC)` — the same composite every
|
||||
other read path uses. The next-page cursor is the `(created_at, id)` of the
|
||||
**last retained row**; the server echoes it in the `39006` bounds overlay
|
||||
as `next_cursor`. Keyset comparison is
|
||||
`created_at < $ts OR (created_at = $ts AND id > $id)`; dense seconds
|
||||
paginate without loss or duplication by construction.
|
||||
|
||||
`has_more` is a **server fact**: the relay probes `limit + 1` rows after
|
||||
all predicates (access, deletion, top-level, kinds), returns at most
|
||||
`limit`, and reports the probe result in `39006`. The sentinel row never
|
||||
reaches the wire, and no closure is computed for it. Clients must not
|
||||
infer exhaustion from row count (`rows < limit` does not imply anything on
|
||||
an exact-multiple final page) — `39006.has_more` is the only authority.
|
||||
|
||||
## Response
|
||||
|
||||
The existing flat bridge shape: a JSON array of signed nostr events.
|
||||
Clients **partition by kind before any cursor math**:
|
||||
|
||||
1. **Rows** — the top-level events, in keyset order.
|
||||
2. **Aux closure** (`include_aux`) — reactions (7), deletions (5, 9005),
|
||||
and edits (40003) targeting the retained rows by `#e`, **plus**
|
||||
deletions targeting those aux events (the transitive second hop, e.g.
|
||||
a delete-of-a-reaction). One round trip; no client `#e` fan-out.
|
||||
3. **Thread summaries** (`include_summaries`) — one relay-signed
|
||||
`kind:39005` per row that has replies.
|
||||
4. **Window bounds** — exactly one relay-signed `kind:39006` per window
|
||||
response.
|
||||
|
||||
### `kind:39005` — thread summary overlay
|
||||
|
||||
- tags: `["e", <root-id>]`, `["d", <root-id>]`, `["h", <channel-id>]`
|
||||
- content: `{"reply_count":n,"descendant_count":n,"last_reply_at":ts|null,"participants":["<hex-pubkey>",...]}`
|
||||
(participants: up to 10, most recent first)
|
||||
- Signed by the relay keypair. Synthesized at query time, **never stored**.
|
||||
Clients treat it as replace-by-target metadata keyed by the `e`/`d` tag
|
||||
(the `d` tag gives parameterized-replaceable semantics natively); it is
|
||||
never a row, never a cursor input, never durable timeline history.
|
||||
|
||||
### `kind:39006` — window bounds overlay
|
||||
|
||||
- tags: `["d", "<channel_id>:<request-cursor-or-head>"]`, `["h", "<channel_id>"]`
|
||||
- content: `{"has_more": bool, "next_cursor": {"created_at": ts, "id": "<hex>"} | null}`
|
||||
- `next_cursor = null ⇔ has_more = false`.
|
||||
- `d`-tag suffix serialization (canonical): `head` for a head request,
|
||||
else `<created_at>:<event_id>` — decimal unix seconds, then the full
|
||||
64-char lowercase hex id, colon-delimited. Clients must verify the
|
||||
suffix equals the cursor they sent and reject the overlay on mismatch.
|
||||
- Reserved field: `oldest_retained` (retention gap), added without a wire
|
||||
break if needed.
|
||||
- Same overlay rules as 39005: relay-signed, query-time, never stored,
|
||||
never a row or cursor input.
|
||||
|
||||
Both kinds are relay-only: client submission is rejected at ingest.
|
||||
|
||||
## Client obligations (frozen)
|
||||
|
||||
- Pages are immutable authoritative history chained cursor→cursor; live
|
||||
events land in a separate overlay, never spliced into pages.
|
||||
- Reconnect refetches page 0 and re-arms the live subscription
|
||||
(`since: now`); deeper pages need no repair path.
|
||||
- Replies never enter the channel timeline; the thread panel uses the
|
||||
existing `thread_cursor` surface (#1418).
|
||||
|
||||
## Siblings
|
||||
|
||||
`before_id` (requires `until`), `thread_cursor`/`thread_cursor_id`,
|
||||
`depth_limit`, `feed_types` — see `bridge.rs`. All are bridge-only raw
|
||||
filter extensions invisible to vanilla relays and clients.
|
||||
Reference in New Issue
Block a user