Fork-Actions entruempeln + Upstream-Sync: der Actions-Tab wird wieder ein Signal (#113) - #117
Merged
Conversation
…#4012) ## Problem Threaded replies "disappeared" from archived Buzz channels: the **"N replies →"** summary row and the huddle-started **"View thread"** button vanished, so existing threads were unreachable from the channel timeline. The thread data was intact — this was a UI gate, not data loss. ## Root cause A single `onReply` prop drove two distinct affordances: - the **compose** affordances (hover "Reply" button, inline reply target), and - the **view** affordances ("N replies →" summary row, huddle "View thread"). `ChannelPane` nulls `onReply` on archived channels to keep them read-only. That correctly hid composing — but also hid the view affordances, since they keyed off the same prop. ## Fix Two independent props, one per concern: - **`onReply`** drives the compose affordances and is gated on `archivedAt` — nulled on archived channels, so no new replies can be started. - **`onOpenThread`** drives the view affordances and is passed regardless of archived state, threaded `ChannelPane → MessageTimeline → TimelineMessageList → MessageRow`. Opening a thread on an archived channel is read-only: the thread panel's composer is independently gated via `isComposerDisabled` (includes `archivedAt !== null`, `ChannelPane.tsx:318`). ### Before <img width="811" height="794" alt="Screenshot 2026-07-31 at 20 26 00" src="https://github.com/user-attachments/assets/670d9db4-30da-4c6d-97dc-275b5dbebca8" /> ### After <img width="873" height="791" alt="Screenshot 2026-07-31 at 20 28 04" src="https://github.com/user-attachments/assets/88525231-2539-4eb3-8117-8e58a0cb3855" /> ## Validation - `pnpm typecheck` clean - biome lint clean on touched files - full `pnpm test` suite green (3885 tests) - pre-push `branch-skew` / `desktop-check` / `desktop-test` hooks passed Signed-off-by: Trey Wood <treyw@squareup.com> Co-authored-by: npub14h0tw3uj7jm77qfxcwn6um2s5h55l0klrt2w9srzp3m3yvjc0mpsjsuk6e <addeb74792f4b7ef0126c3a7ae6d50a5e94fbedf1ad4e2c0620c771232587ec3@buzz.block.builderlab.xyz>
…Reading (block#2613) ## Problem Three small documentation defects, each verified against the code at 06e3d82: 1. **ARCHITECTURE.md (Event Kinds section)** says `buzz-core` defines "all 81 kinds". The registry has grown: `ALL_KINDS` in `crates/buzz-core/src/kind.rs` now has **127** entries (all unique values). The sentence also says every kind is `pub const KIND_*`, but registry entries such as `RELAY_ADMIN_ADD_MEMBER` do not use that prefix. 2. **NOSTR.md Quick Start** numbers its steps 1, 2, 3, 5 — there is no step 4. PR block#797 (2a03851) collapsed the old steps 1-4 (dropping the separate "Start infrastructure" step) into 1-3, but the final "Connect any NIP-29 + NIP-42 client" comment kept its old number 5. 3. **NOSTR.md "Further Reading"** is an empty heading — the section's only content (a link to `crates/buzz-proxy/README.md`) was removed in PR block#1321 (14fba21) along with the proxy crate itself, leaving a dangling header as the last line of the file. ## Fix 1. Reworded the ARCHITECTURE.md sentence to defer to `crates/buzz-core/src/kind.rs` as the source of truth, with the current count (127) as an explicit "at the time of writing" snapshot, so the sentence stays truthful as kinds are added. Also removed the incorrect `KIND_*`-naming claim. 2. Renumbered the final quick-start step 5 → 4. 3. Populated Further Reading with three durable links: the upstream nostr-protocol/nips repo, this repo's `docs/nips/` extension documents, and `ARCHITECTURE.md`. Docs-only; no code changes, no build impact. ## Verification (each claim ~30 seconds) - Kind count: `python3 -c "import re; s=open('crates/buzz-core/src/kind.rs').read(); m=re.search(r'ALL_KINDS: &\[u32\] = &\[(.*?)\];', s, re.S); print(len([e for e in m.group(1).split(',') if e.strip()]))"` → 127. All 127 values are distinct. Non-`KIND_*` entry example: `RELAY_ADMIN_ADD_MEMBER` (kind.rs, in `ALL_KINDS`). - Missing step: `grep -n '^# [0-9]' NOSTR.md` on main shows `# 1.`, `# 2.`, `# 3.`, `# 5.` in the Quick Start block; `git show 2a03851 -- NOSTR.md` shows the renumbering that orphaned step 5. - Empty section: `tail -1 NOSTR.md` on main is `## Further Reading` with nothing after it; `git log -S'buzz-proxy/README' --oneline -- NOSTR.md` shows the content removal in 14fba21 (block#1321). ## Links - `crates/buzz-core/src/kind.rs` — `ALL_KINDS` registry (source of truth for the count) - PR block#797 / 2a03851 — introduced the step-numbering gap - PR block#1321 / 14fba21 — emptied the Further Reading section Signed-off-by: Sean Gearin <sgearin@gmail.com> Co-authored-by: Sean Gearin <sgearin@gmail.com>
) The channel scoping note in `AGENTS.md` reads as universal: > **Channel scoping**: Channels use `h` tags (NIP-29 group tag), not `e` tags. > Filters and queries must scope to `h` tags when operating within a channel. It holds for events inside a channel, but not for the addressable events that describe one. kind:39000, kind:39001 and kind:39002 carry the channel id in their `d` tag, which is what `get_channels` already reads. Taking the existing wording at face value while working on kind:39002 produces an empty result rather than an error, since those events do carry `h` tags in other flows, so the mistake is quiet and costs a debugging cycle. Came up while working on block#4023. Four lines, no behaviour change. Signed-off-by: Szymon Tanski <szymontanski8@gmail.com>
…d:9033) (block#3998) ## Problem The desktop deliberately shows the workspace icon editor on open relays (block#2640, gate: `canEditIcon` in `desktop/src/features/communities/ui/EditCommunityDialog.tsx`) and defers to the relay-side kind:9033 check — which required an admin/owner row in `relay_members`. For a community with **no admin/owner row at all** (the `ensure_configured_community` path, which never writes an owner), every 9033 was refused and the icon was permanently unsettable. **Correction from review (thanks @dawn):** the original version of this PR claimed nobody holds a role on an open relay. That's false — `main.rs` bootstraps `RELAY_OWNER_PUBKEY` as owner regardless of `BUZZ_REQUIRE_RELAY_MEMBERSHIP`, so a production open relay like bb-block *does* have an owner row, and the old gate was refusing everyone except that owner. The first revision of this diff would have silently widened that owner-only control to any NIP-42-authenticated sender. ## Fix — steward-wins `may_set_workspace_profile(sender_role, membership_enforced, community_has_steward)`: | Relay mode | Community has admin/owner row? | Who may set the icon | |---|---|---| | Closed (`require_relay_membership=true`) | any | admin or owner (unchanged) | | Open | yes (e.g. bb-block) | admin or owner (unchanged posture) | | Open | no (genuinely rosterless) | any NIP-42-authenticated sender | - New DB helper `has_admin_or_owner(community)` (`crates/buzz-db/src/relay_members.rs`); the call site only queries it on open relays. - The rosterless admit logs a `warn!` with the sender pubkey — 9033 writes no audit row and publishes no announcement event (unlike 9030/9031), so this is the only durable attribution. - Kinds 9030–9032, NIP-42 auth, `AdminUsers` scope, ban gate, and icon validation are all untouched. - Doc comment fixed: cited nonexistent `canEditCommunityProfile`; real symbol is `canEditIcon`. ## Test coverage — closing the mutation gap Dawn's mutation testing showed the original unit tests pinned only the helper's truth table: inverting the flag at the call site or deleting the gate entirely survived the full suite. - Unit tests now cover the 3-arg truth table (closed steward-independent, open-with-steward stays steward-only, rosterless-open admits). - Two `#[ignore]`d Postgres integration tests drive `handle_relay_admin_event` with a real `AppState` (open rosterless admit → steward appears → roleless refused again; closed relay member refused). Wired into the Backend Integration CI job as a dedicated nextest step. - **Both of Dawn's mutants verified killed** at this head: flag inversion fails 1 unit test; gate deletion fails both integration tests (`Ok(())` where `Rejected` expected). ## CI wrinkle found and fixed: pre-existing schema drift The first Backend Integration run of the new 9033 tests failed with `column "icon" of relation "communities" does not exist` — migration `0003_community_icon.sql` added the column, but `schema/schema.sql` (the desired-state file that CI job applies via pgschema) was never updated. Pre-existing drift, invisible until a test in that job actually wrote the column. Fixed in `297148f62` (3-line addition to `schema/schema.sql`). ## Receipts (at `1b4b52db8` code / `297148f62` head) - `cargo test -p buzz-relay`: 835 pass, 1 fail — `api::mesh_demo::tests::demo_join_forwarded_arm_round_trips_echo`, pre-existing (fails identically at the old base and on clean main); `telemetry::trace_context_lookup_does_not_enable_callsites` is a known order-dependent flake, passes in isolation. - `cargo test -p buzz-db`: 94 pass. - Both ignored integration tests pass live against local Postgres. - `cargo fmt --all -- --check`: clean. - Live-local pass per TESTING.md at this head (release build, relay on :3199, real WS + NIP-42 via nak): - open rosterless: roleless key sets icon → NIP-11 serves it; `warn!` with sender pubkey in the relay log - open + owner row inserted: fresh roleless key refused ("must be admin or owner"); owner sets icon - closed relay (owner bootstrapped, `BUZZ_RELAY_PRIVATE_KEY` set): plain member refused, owner sets icon, `javascript:` URL rejected, empty icon clears (NIP-11 → null) --------- Signed-off-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz> Co-authored-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz>
…lock#3481) ## Summary The "I just want to try the app" section names platforms generically (macOS `.dmg`, Linux `.AppImage` / `.deb`, Windows `.exe`), but the release publishes five assets, including two separate macOS builds. A first-time user on a Mac has no way to tell whether they need `aarch64` or `x64`, and nothing sets expectations for the SmartScreen warning on the unsigned Windows build. This replaces that sentence with a platform-to-filename table, a one-line note on how to check which Mac you have, and a note that the Windows build is unsigned and what the warning looks like. Filenames use `<version>` rather than `0.5.0` so the table doesn't go stale each release. ### Related issue None found. Searched open issues and PRs for README/download/install topics. ### Testing Docs-only change, no code paths touched. Verified the table and paragraph breaks render correctly in GitHub's markdown preview. --------- Signed-off-by: Dan Sheehan <dannysheehan90@gmail.com> Signed-off-by: npub12gtutshhh76rx0jx697f32f9tffd4hhp3hx58fp4x6u4uemkm7sqf8f757 <5217c5c2f7bfb4333e46d17c98a9255a52dadee18dcd43a43536b95e6776dfa0@buzz.block.builderlab.xyz> Co-authored-by: npub12gtutshhh76rx0jx697f32f9tffd4hhp3hx58fp4x6u4uemkm7sqf8f757 <5217c5c2f7bfb4333e46d17c98a9255a52dadee18dcd43a43536b95e6776dfa0@buzz.block.builderlab.xyz>
… repoURL + path) (block#3426) ## Problem `examples/argocd-app.yaml` uses the split form: ```yaml repoURL: oci://ghcr.io/block/buzz/charts chart: buzz targetRevision: 0.1.0 ``` On ArgoCD >= 3.0 (native OCI sources), the `chart` field is **ignored** for `oci://` repoURLs, so ArgoCD tries to pull the `charts` path itself and fails with `403 … repository:block/buzz/charts:pull denied` — a misleading error that reads like an auth problem. Additionally, spec validation rejects the Application without a `path` (`spec.source.repoURL and either spec.source.path or spec.source.chart are required`), since `chart` isn't recognized for OCI. Hit both on ArgoCD 3.4.4 following the example verbatim. ## Fix Use the full chart artifact path as `repoURL`, add `path: "."`, bump the pinned example version to the latest published chart (0.1.6), and leave a comment explaining both traps: ```yaml repoURL: oci://ghcr.io/block/buzz/charts/buzz path: . targetRevision: 0.1.6 ``` Verified working in production (ArgoCD 3.4.4, anonymous GHCR pull, chart 0.1.6). Related open PRs/issues: none found. --------- Signed-off-by: Kampe <blindside328@gmail.com> Signed-off-by: npub1t2tgm7d8f995uqvmnm8h88sg3wnpp9a5xysjf6dg3tjmgt3ltulqdp8ehr <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@buzz.block.builderlab.xyz> Co-authored-by: Kampe <blindside328@gmail.com> Co-authored-by: npub1t2tgm7d8f995uqvmnm8h88sg3wnpp9a5xysjf6dg3tjmgt3ltulqdp8ehr <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@buzz.block.builderlab.xyz>
…lock#3487) ## What this fixes `fan_out_scoped` (`crates/buzz-relay/src/subscription.rs:278-394`) enforces a deliberate, symmetric scoping invariant — documented in the code itself: > Global subscriptions (channel_id = None) do NOT receive channel-scoped events. Channel-scoped subscriptions do NOT receive global events. The relay derives a reaction's stored channel from its `#e` target at ingest — client-supplied `#h` is ignored for channel determination (`NOSTR.md:50` documents this for *writing*). The consequence for *reading* is that every reaction is a channel-scoped event, so a live subscription `{"kinds":[7]}` without `#h` is a global subscription and **silently receives no reactions at all** — no error, no CLOSED, just nothing. The working form is `{"kinds":[7],"#h":["<channel-uuid>"]}`, and it works regardless of how the reaction was signed: explicit `h` tags on the event are matched directly, and tagless reactions match via the stored channel fallback (`crates/buzz-core/src/filter.rs:78-91` — fallback applies only when the event has no `h` tags; explicit tags are authoritative). `NOSTR.md` already documents this exact pitfall for group-metadata events: > **Note:** Channel-scoped storage means live global subscriptions (`{kinds:[39000]}`) won't receive these via fan-out. (`NOSTR.md:124-126`) …but has no equivalent note for reactions, which is the case a bot/integration author is far more likely to hit: any client that wants to observe approvals/reactions live (workflow reaction-triggers make this a first-class pattern in Buzz) will naturally try a kinds-only REQ first and conclude reactions are broken. We lost real debugging time to exactly this while building a headless integration (https://github.com/OriginTrail/buzz-dkg-integration); the behavior is by design, only the docs are missing. ## What this PR changes Docs only (`NOSTR.md`): a subscribe-to-reactions example in "Sending Messages", plus one note mirroring the existing 39000 note. No code changes. ## How to verify - Behavior: with the relay running, open a live REQ `{"kinds":[7]}` (no `#h`) and react to a channel message from another client → nothing is delivered; re-subscribe with `{"kinds":[7],"#h":["<channel-uuid>"]}` → the reaction arrives. - Claims against code (verified at `485d03a`): scoping invariant `crates/buzz-relay/src/subscription.rs:386-393`; channel derivation `derive_reaction_channel()` in `crates/buzz-relay/src/handlers/ingest.rs`; `#h` fallback `crates/buzz-core/src/filter.rs:78-91` and its test `h_tag_fallback_uses_stored_channel_id`. Duplicate search: no existing issue/PR found for `reactions subscription`, `fan-out kinds` (searched 2026-07-29). DCO signed-off. --------- Signed-off-by: Žiga Drev <ziga.drev@gmail.com> Signed-off-by: npub1jh9wn95s0472h86ahapupaf7m6kx4v9sx2n0atj2hltcfer8k06s5n3pyf <95cae996907d7cab9f5dbf43c0f53edeac6ab0b032a6feae4abfd784e467b3f5@buzz.block.builderlab.xyz> Co-authored-by: Žiga Drev <ziga.drev@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: npub1jh9wn95s0472h86ahapupaf7m6kx4v9sx2n0atj2hltcfer8k06s5n3pyf <95cae996907d7cab9f5dbf43c0f53edeac6ab0b032a6feae4abfd784e467b3f5@buzz.block.builderlab.xyz>
Bump `nostr-relay-pool` from 0.44.1 to 0.44.2 to clear [RUSTSEC-2026-0224](https://rustsec.org/advisories/RUSTSEC-2026-0224), which addresses verification-cache poisoning that could let forged Nostr events bypass signature validation on redelivery. The dependency is transitive through `nostr-sdk`; this PR updates only the corresponding package version and checksum in `Cargo.lock`. The advisory currently marks every open PR red until this fix merges. - `cargo test -p buzz-sdk -p buzz-cli` passes: 271 + 241 tests - `cargo deny check advisories` passes - `just fmt-check` passes Signed-off-by: Will Pfleger <pfleger.will@gmail.com> Co-authored-by: npub16v54tttfqacx9ycvc3k0ut0npj564ahcuajzy6qjvh57ntmsf4uq4806j2 <d32955ad69077062930cc46cfe2df30ca9aaf6f8e76422681265e9e9af704d78@buzz.block.builderlab.xyz>
…ck#4124) ## Summary Route `Db::is_relay_member` — the membership check that runs on every authenticated HTTP request and WS AUTH — through the standard `route_read` machinery on the bounded arm, instead of adding a bespoke cache (replaces block#3844). - `crates/buzz-db/src/relay_members.rs`: add `is_relay_member_on(&mut PgConnection, ...)` executor seam; the pool version delegates to it. - `crates/buzz-db/src/lib.rs`: `Db::is_relay_member` now routes via `route_read("relay_membership", RoutePredicate::Bounded)` — replica only on a proved fresh session, writer on any route rejection, writer re-run on replica query error. Exactly the shape of every other routed read. This is the one permission read served from the replica, by explicit product decision (Tyler accepted ≤1s bounded staleness on reads we choose): the fleet-wide fence guarantee (`BUZZ_REPLICA_READ_MAX_AGE_MS`, deploy target 1s) is an order of magnitude tighter than the 10s TTL proposed in block#3844 and needs no invalidation machinery. Staleness is symmetric for admits and revokes. `BUZZ_REPLICA_READ_MAX_AGE_MS` unset = writer-only = kill switch. It is not precedent for routing other permission reads. ## Validation At this exact commit (`git rev-parse HEAD` confirmed in the same shell, rustc 1.95): - `cargo test -p buzz-db` — 94 passed, 0 failed - PG-gated suite single-threaded — **151 passed, 2 failed**; the 2 failures are the per-owner-limit tests broken on main by block#3829 (limit 3→5, tests still seed 3) — they fail identically at base `19d57b0d4` in a pristine control checkout; separate trivial fix to follow - New PG-gated test `is_relay_member_is_bounded_routed_and_fails_closed` — divergent writer/replica fixtures prove: budget unset ⇒ writer; budget set + fresh proof ⇒ replica; over-budget entry ⇒ writer - clippy `-D warnings` + fmt clean; pre-push hooks green (desktop check/test, rust tests, tauri checks) - **Live-local pass** (TESTING.md, release binary, `BUZZ_REQUIRE_RELAY_MEMBERSHIP=true`, fresh DB): - writer-only (no `READ_DATABASE_URL`): member accepted, outsider 403 `relay_membership_required`; metrics `route_decision{path="relay_membership",decision="writer",reason="disabled"}` - replica configured + `BUZZ_REPLICA_READ_MAX_AGE_MS=1000`: member accepted / outsider denied via `decision="replica",reason="fresh"`; admit visible to the routed check within ~1.2s; revoke enforced within ~1.2s - reader outage mid-flight (TCP proxy killed): member send still succeeds in <200ms via `decision="writer",reason="reader_acquire_timeout"`; outsider still denied — fails closed, no availability loss Reviewed by Wren: 9/10 minimalness, 9/10 elegance, 9.5/10 correctness at this SHA. Supersedes the 10s-cache approach in PR 3844, which should be closed unmerged once this lands. Signed-off-by: Tyler <109685178+tlongwell-block@users.noreply.github.com> Co-authored-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz>
# Conflicts: # .empire/BUILD.md
Closed
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Der Actions-Tab ist nur ein Signal, wenn Rot etwas bedeutet. CI scheitert auf jedem main-Push im Job Security an cargo-deny: RUSTSEC-2026-0224 (nostr-relay-pool). Upstream hat das mit block#4139 behoben — der Fork war 9 Commits hinterher.
Echter Merge-Commit (kein Squash), damit die Upstream-Ahnenreihe erhalten bleibt und der naechste Sync nicht dieselben Commits nochmal sieht.
Teil von #113.