Skip to content

Fix authoritative status and huddle removal ordering - #7574

Open
klopez4212 wants to merge 1 commit into
mainfrom
princess-donut/pr-7112-followup
Open

Fix authoritative status and huddle removal ordering#7574
klopez4212 wants to merge 1 commit into
mainfrom
princess-donut/pr-7112-followup

Conversation

@klopez4212

Copy link
Copy Markdown
Contributor

Summary

Follow up on the two valid inherited findings from #7112:

  • clear stale cached user statuses when an authoritative relay refetch returns no status, while preserving live cache changes that arrive during the fetch
  • carry the huddle owner's authoritative roster revision back to a remote ingress so same-second JOIN/LEFT lifecycle events order deterministically
  • bound status history requests to four concurrent relay calls

Compatibility

PeerUnregistered is appended to the postcard control enum, preserving every existing discriminant. During a rolling relay deployment, either mixed-version direction falls back to the existing revisionless LEFT behavior without breaking the control stream.

Validation

  • pre-push hook: all enabled lanes passed (Desktop check/typecheck/full tests, Tauri checks, Rust tests, file-size and branch-skew gates)
  • focused Desktop status/huddle tests: 36/36 passed
  • focused relay audio::join: 37/37 passed
  • focused relay audio::handler: 5/5 passed
  • Desktop typecheck and touched-file Biome checks passed
  • independent review found no material findings

A separate broad cargo test -p buzz-relay investigation compiled and passed 1,034 tests; six unrelated media fixture tests failed with Sqlx(PoolTimedOut) against local Postgres. The focused huddle suites and the subsequent pre-push Rust lane passed.

Signed-off-by: Princess Donut <b238ea756dee4d98afa5883fc7f1de61eeabe65bf700e3a5a5a80db5e42e2c2b@buzz.block.builderlab.xyz>
@klopez4212
klopez4212 requested a review from a team as a code owner September 11, 2026 07:16
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 11, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-11T07:22:38.781943Z 2049789 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

Copy link
Copy Markdown

🔐 Codex Security Review

Status: review required for the current range.

The current range is 813bbd14121edacc6cb4733301a3af12131aa10e...2049789959cdf161f51184a1d3472461bf98bb2e.
A new review must complete for this exact range. When manual authorization
is required, a Block organization member must comment exactly
@buzz-security-review 2049789959cdf161f51184a1d3472461bf98bb2e to authorize a new review.
Any previous review applies only to its recorded range.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2049789959

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +260 to +262
lookup[pubkey] = !sameUserStatus(current, cached)
? (current ?? null)
: null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fence authoritative status refetches by generation

When two different useUserStatusQuery keys containing the same pubkey overlap, an older request can return a status after a newer request has returned an authoritative empty result. This value comparison notices the intervening null, but null carries no version, so the subsequent newerUserStatus call accepts the older page and resurrects the deleted status. Use a request generation or versioned absence tombstone so an older fetch cannot overwrite a later authoritative clear.

AGENTS.md reference: AGENTS.md:L176-L180

Useful? React with 👍 / 👎.

Comment on lines +161 to +165
participantEvent({
id: "a",
kind: 48102,
admissionId: "remote",
rosterRevision: 2,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Test the remote leave revision through handler cleanup

This regression test supplies rosterRevision: 2 directly, while the added Rust tests stop at producing/receiving PeerUnregistered; none exercises the production handoff through handle_active_audio_connection into the emitted kind-48102 event. Removing the new remote_removal_revision propagation from the handler leaves every added test green, so add a handler-level test that asserts the persisted or broadcast LEFT event contains the owner's revision.

AGENTS.md reference: AGENTS.md:L188-L192

Useful? React with 👍 / 👎.

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Carl, an automated reviewer, commenting via Wes’s GitHub account.

Changes requested: two P2 correctness findings

Reviewed exact head 2049789959cdf161f51184a1d3472461bf98bb2e against base 813bbd14121edacc6cb4733301a3af12131aa10e. Scope: authoritative status absence without losing live ordering, and owner-revision propagation for remote clean departure while retaining rolling-relay compatibility.

1. P2: Clear the status display without discarding its version fence

hooks.ts:260–267 converts an unchanged cached entry to bare null, including an already-hidden clear/expired version. A supported NIP-09 coordinate deletion of 30315:<pubkey>:general legitimately makes history empty (deletion producer). A subsequently delivered older kind-30315 live event now passes the version check against null and resurrects the status. Previously the retained hidden version rejected it; the existing regression explicitly establishes that ordering contract, but does not cross a refetch.

Source-derived reproduction: cache hidden version (101, idB); delete the coordinate and settle an unchanged empty authoritative refetch; deliver a delayed visible status (100, idA). The older text becomes visible instead of staying cleared.

Exit criterion: preserve (updatedAt,eventId) as a versioned hidden entry when clearing authoritative absence, while retaining the concurrent-live merge. Add production-cache coverage for empty refetch → older delayed live event → genuinely newer event, asserting the status stays hidden until the newer event.

2. P2: Preserve receive framing across the close-time reader handoff

handler.rs:780–792 drops read_owner_control on cancellation, then the new send_clean_close receive loop reads the same stream again. Production IrohRecvHalf::recv_frame stores its length/body buffers inside the cancellable future. If cancellation lands after consuming the four-byte length but before completing a roster frame body, the fresh receive interprets body bytes as the next length and can return a framing/decode error immediately. The valid owner acknowledgement behind it is lost and cleanup emits LEFT without a revision.

This is new read-after-cancel behavior: base teardown did not receive again. On a healthy new/new relay connection, a same-second JOIN/leave with this fragmented-frame interleaving and LEFT ID sorting below JOIN still reproduces the ghost participant this PR targets. Revisionless fallback for old owners or broken links is an intentional compatibility limitation; losing an available acknowledgement because our own handoff corrupts framing is not merely teardown latency.

Exit criterion: keep the receiver/framing state alive across cancellation, or make the frame reader cancellation-safe before reusing it. Add a byte-fragmented receive regression that cancels after header/partial-body consumption, then supplies the remaining frame and removal acknowledgement and verifies the owner revision reaches LEFT. Current tests use whole-frame ChanRecv and cannot expose this handoff failure.

Scope and validation

Source/metadata-only review on Wes’s Mac Studio (BLKD2G9MWNRWY.local), with independent desktop, relay, and consumer lanes. No checkout, build, test, or PR-code execution; the reproductions above are source-derived, not runtime test claims. Successful acknowledgement propagation, unchanged wire discriminants, per-stream unregister ownership, bounded status fetches and failure propagation were traced.

The unchanged HuddleIndicator/HuddleAttachment same-second LEFT→reconnect-JOIN reducers are a separate pre-existing inconsistency, not another blocker for this JOIN→LEFT repair. No new requirement to consolidate them here.

@jedwards27 jedwards27 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:bot: Jude’s code review agent

Verdict: REQUEST CHANGES
Reviewed: 813bbd14121edacc6cb4733301a3af12131aa10e..2049789959cdf161f51184a1d3472461bf98bb2e (exact live head)
Risk: high — status ordering and relay huddle departure ordering cross live delivery, authoritative snapshots, community/session ownership, and user-visible truthfulness.

Blocking finding

[P2] Preserve the status version fence across authoritative absence

desktop/src/features/user-status/hooks.ts:255-263 maps an unchanged cached status to bare null when authoritative history returns no event. applyUserStatusEventToQueries at :167-205 then has no (updatedAt,eventId) fence, so a delayed older live event is accepted and can resurrect a status that another client cleared, expired, or deleted.

Both independent lanes reproduced this through the production cache seam at the clean exact head: seed hidden/versioned (updatedAt=101,eventId=b), settle an empty authoritative refetch, then deliver visible (100,a). The cache moved from null to visible "STALE RESURRECTED". The added helper test at desktop/src/features/user-status/hooks.test.mjs:114-132 asserts only bare null, thereby preserving the provenance loss rather than protecting the live-event merge.

Author action: retain a hidden/versioned tombstone across authoritative absence while preserving genuinely concurrent newer cache state. Add a causal production-cache regression proving: versioned visible/hidden state → empty authoritative refetch → delayed older event remains hidden → genuinely newer event becomes visible.

Verification owner: author for the fix and regression; reviewer/A Team for exact-new-head mutation and full-gate rerun.

Huddle ordering trace

No second concrete defect was established in the changed huddle path. Owner removal is community/session/generation scoped; removal captures the owner-monotonic revision before LEFT broadcast and PeerUnregistered, ingress waits boundedly for the matching pubkey acknowledgment, and the handler joins that reader before kind 48102 emission (crates/buzz-relay/src/handlers/join.rs:1131-1187,1346-1368,1883-1924; handler.rs:859-889,914-927). QUIC control frames use write_all/read_exact, so fragmented length/payload delivery is reconstructed before decode (crates/buzz-relay-mesh/src/peer.rs:138-190). The appended enum variant degrades boundedly with older peers without renumbering existing discriminants.

A single production-seam fragmented/reconnect journey from remote disconnect through emitted revisioned kind 48102 was not run. That remains a reviewer/relay/native confidence gap, not additional author rework.

Exact-head validation

  • Full cargo test -p buzz-relay: lib 1,041 passed / 93 ignored, main 13 passed / 1 ignored, lifecycle 9 passed; exit 0.
  • Full Desktop pnpm test: 6,494 passed; exit 0.
  • Desktop typecheck and focused status/huddle suites (40/40) passed.
  • Production-cache stale-resurrection probe reproduced the defect independently in both lanes.
  • git diff --check: passed; final lane trees clean at the exact live head.
  • Required CI is broadly green across Rust/PostgreSQL/relay E2E/Desktop core/integration/macOS/Windows/security/DCO. Desktop Smoke shard 4 has an unrelated unchanged video-playback failure; no changed file touches that surface, so CI/tooling owns its disposition rather than this author-actionable verdict.
  • No native Desktop/iOS huddle journey was run.

Any new head invalidates this verdict until its delta is reviewed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants