Repository navigation
Conversation
Huddles decided "is this an agent" from the channel role `bot`. The relay now stores `bot` only for keys with a recorded NIP-OA owner (#8494), so an agent without an owner attestation joins as `member`. Desktop then treated it as a person: its text was not spoken, its voice publisher was refused, and the Huddle did not end while it was still connected. Add one roster owner, `huddle::roster::fetch_huddle_roster`. A member is an agent when it has the `bot` role or when a trusted author published a kind:30177 managed-agent record for it. Desktop publishes that record for every agent it manages, from every machine. Trusted authors are the current user and the Huddle channel's owners; a record from anyone else is only a claim. All Huddle agent and human checks now use this roster. Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Signed-off-by: Logan Johnson <loganj@squareup.com>
Mobile Huddles decided "is this an agent" from the channel role `bot`. The relay now stores `bot` only for keys with a recorded NIP-OA owner (#8494), so an agent without an owner attestation joins as `member`. Mobile then left it out of the participant list after joining, labeled it as a person, did not show its "preparing a response" state, and counted it as a person when deciding whether leaving ends the Huddle. Add one Huddle agent owner, `huddle_agents_provider.dart`. A member is an agent when it has the `bot` role or when a trusted author published a validly signed kind:30177 managed-agent record for it. Trusted authors are the current user and the Huddle channel's owners; a record from anyone else is only a claim. This is the same rule as the Desktop fix (#8544). Signature checks run off the UI isolate. If the records are still loading or cannot be read, the `bot` role still works, and the last-person count fails so leave keeps the Huddle open. Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Signed-off-by: Logan Johnson <loganj@squareup.com>
Mobile Huddles decided "is this an agent" from the channel role `bot`. The relay now stores `bot` only for keys with a recorded NIP-OA owner (#8494), so an agent without an owner attestation joins as `member`. Mobile then left it out of the participant list after joining, labeled it as a person, did not show its "preparing a response" state, and counted it as a person when deciding whether leaving ends the Huddle. Add one Huddle agent owner, `huddle_agents_provider.dart`. A member is an agent when it has the `bot` role or when a trusted author published a validly signed kind:30177 managed-agent record for it. Trusted authors are the current user and the Huddle channel's owners; a record from anyone else is only a claim. This is the same rule as the Desktop fix (#8544). Signature checks run off the UI isolate. If the records are still loading or cannot be read, the `bot` role still works, and the last-person count fails so leave keeps the Huddle open. Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Signed-off-by: Logan Johnson <loganj@squareup.com>
🔐 Codex Security Review
Review SummaryOverall Risk: NONE
FindingsNo concrete security, correctness, or reliability findings were identified. Notes
Generated by Codex Security Review | |
This comment has been minimized.
This comment has been minimized.
When the kind:30177 managed-agent records could not be read, the roster still listed the members proven by role `bot`, but the post-connect and periodic refresh paths dropped the whole incomplete roster. A joiner then had no stored agents: its agents' text was not spoken and their audio was treated as a person's. `HuddleRoster::apply_agents` now owns updating the stored list. A complete roster replaces it. An incomplete roster adds the `bot` agents and keeps stored agents that are still members. An incomplete roster still cannot end the Huddle. Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Signed-off-by: Logan Johnson <loganj@squareup.com>
This comment has been minimized.
This comment has been minimized.
The earlier regression test called HuddleRoster::apply_agents directly, so it stayed green if post-connect setup or the hotstart refresh stopped using it. Move the two roster hydration steps into functions and test them against a fake relay whose managed-agent record read fails: the post-connect read keeps the role-proven bot agent, the hotstart refresh also keeps a still-member agent and drops a departed one, and the same incomplete roster gives no human count for the last-person check. Both tests fail when the call sites accept only complete rosters. Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Signed-off-by: Logan Johnson <loganj@squareup.com>
This comment has been minimized.
This comment has been minimized.
jedwards27
left a comment
There was a problem hiding this comment.
🤖 :bot: Jude's code review agent
Verdict: REQUEST_CHANGES
The source behavior at d58012d32f52c9b5f2460d2d462b14d84fe33626 looks fixed, but the replacement regression still does not bind the production callers this PR needs to protect.
Blocking finding
[P1] Production-caller linkage is still test-unbound.
The new regression tests prove the extracted helper bodies, but not the top-level production wiring:
desktop/src-tauri/src/huddle/roster_hydration_tests.rs:98callshydrate_huddle_roster(...)directly.desktop/src-tauri/src/huddle/roster_hydration_tests.rs:118callsrefresh_huddle_roster(...)directly.- The production seams are
check_pipeline_hotstart -> refresh_huddle_rosteratdesktop/src-tauri/src/huddle/pipeline.rs:119-120andpost_connect_setup -> hydrate_huddle_rosteratdesktop/src-tauri/src/huddle/pipeline.rs:241-242.
I mutation-checked both seams at this exact head:
- Replaced the
post_connect_setupcall tohydrate_huddle_roster(...)with a no-op. - Replaced the
check_pipeline_hotstartcall torefresh_huddle_roster(...)with a no-op.
In both mutants, this command still passed 2/2:
cargo test --manifest-path desktop/src-tauri/Cargo.toml --lib huddle::pipeline::roster_hydration_tests -- --nocaptureThat means a future deletion/bypass of either actual production invocation can go green while joiners or hotstart stop hydrating role-proven bot agents when kind:30177 managed-agent reads fail. That is the seam this PR was meant to lock down; green helper tests are not enough armor. The dungeon eats unguarded seams first.
Author action: add falsifiable production-caller regression coverage such that:
- Removing/bypassing
post_connect_setup -> hydrate_huddle_rostermakes a behavioral assertion fail. - Removing/bypassing
check_pipeline_hotstart -> refresh_huddle_rostermakes a behavioral assertion fail when the Huddle is active and refresh is due.
The existing helper tests can stay, but the missing bite is that deleting pipeline.rs:119-120 or pipeline.rs:241-242 must fail a test.
Validation notes
- Confirmed live GitHub
headRefOidmatchedd58012d32f52c9b5f2460d2d462b14d84fe33626before review. - Clean control test passed at that head:
cargo test --manifest-path desktop/src-tauri/Cargo.toml --lib huddle::pipeline::roster_hydration_tests -- --nocapture(2 passed). - The two mutation runs above also passed, which is the blocker.
- Relevant Desktop/Rust/security/DCO CI checks were green on this head; that is useful evidence, but it does not cover the production-caller seam.
Confidence gaps, not author blockers: I did not run a live multi-user native Huddle/audio session, and I did not run full local just ci.
|
🤖 :bot: Jude’s code review agent — integrated addendum to the existing REQUEST_CHANGES review at exact head The terminal verdict is unchanged, and I am not submitting a duplicate review. Reconciled state: the source behavior is fixed at this head. The production source currently wires Remaining author-actionable defect: the new regression still does not bind the outer production entrypoints. The added tests call Author action remains: add a falsifiable production-caller regression, or an equivalent production-entrypoint spy, such that removing/bypassing Integrated evidence: product/UI review found no separate unresolved user-visible or policy defect: trusted agent/person classification, incomplete-roster fail-closed last-person behavior, visible participant handling, spoken-text gating, voice-publisher authorization, playout/floor behavior, and cleanup all line up with the intended contract in source. Systems/integration review confirmed the production source is currently correct but mutation-checked the missing caller binding described above. Exact-head CI relevant to Desktop/Rust/security/DCO was green. Live/native multi-user Huddle audio remains a confidence gap, not an additional author blocker. |
Chessing234
left a comment
There was a problem hiding this comment.
trusted_record_authors always includes the viewer. a member who is not an owner can sign a kind 30177 and the roster treats that pubkey as an agent, including the count that decides whether leaving ends the huddle.
🤖
Summary
In a Huddle (a voice call in a channel), Buzz Desktop decides which participants are agents. It uses that answer to choose whose text it speaks aloud, which agents can publish voice, and when the last person leaves and the Huddle ends.
Desktop currently treats a participant as an agent only when its channel role is
bot. #8494 changes the relay so that it givesbotonly to agents with a verified owner attestation (NIP-OA). After that change, agents without an attestation join as ordinary members, and Desktop treats them as people:With this PR, Desktop also counts a member as an agent when a trusted person has published a managed-agent record for it. Desktop already publishes such a record for every agent it runs, on every machine. Trusted people are:
Some agents without an attestation still count as people: an agent added by someone who does not own the Huddle, as seen from any machine other than that person's. The only way to recognize those agents is an owner attestation. This PR does not sign one.
Details
huddle/roster.rs(fetch_huddle_roster) is now the only place that decides agent or person for Huddles. A member is an agent if its role isbot, or if the current user or a channelownerpublished a kind:30177 managed-agent record whosedtag is that member's key. Records from other authors are ignored. Records whose signature does not verify are ignored.get_huddle_agent_pubkeys(spoken-text gating and the participant list), the periodic roster refresh, adding an agent, cleanup at the end of the Huddle, and the last-person check.bot.botrole. Spoken text, voice publishing, adding agents and cleanup keep working for those agents. The Huddle does not end automatically, because an agent without an attestation could be counted as a person. When you join, and on each periodic refresh, Desktop adds thebotagents to its stored list and keeps stored agents that are still members.Related issue
Follow-up to #8494 (the relay stores
botonly for attested agents). No existing issue found.Testing
huddle/roster.rs. They do not run the relay query, the pipeline writers or the leave path.botrole, the user's own record and the owner's record each mark a member as an agent;botagents stay agents, the Huddle cannot end automatically, and the next successful read restores the full roster.botagents, an agent known only by its record stays stored, and a stored agent that left drops out.huddle/roster_hydration_tests.rsrun the production roster reads in the post-connect and hotstart paths against a fake relay whose managed-agent record read fails. Post-connect stores thebotagent; the hotstart refresh also keeps a still-member agent known from an earlier record and drops one that left; the same incomplete roster gives no human count for the last-person check. Both tests fail when the two call sites accept only complete rosters.cargo test --lib huddle::(Huddle tests only),cargo clippy --tests -D warningsandcargo fmt --checkpass indesktop/src-tauri.