mirror of
https://github.com/block/buzz.git
synced 2026-10-27 04:30:52 +00:00
fix(desktop): discover authenticated owned relay agents (#7122)
🤖 ## Summary An agent you own could be missing from **New message → To:** and **Channel members → Add people and agents** on a machine that has never managed it. This PR lets those existing lists find your agent without requiring a shared channel first. Desktop now checks records proving you own it, rather than looking only at agents in channels you've already joined. **No new screen or control is added.** For example, an agent with verified ownership and **Who can send instructions → Only me (default)** can now appear even with no shared channels. Each screen still applies its existing access rules; this does not make every discovered agent selectable everywhere. | Screen / control | Before | After this PR alone | | --- | --- | --- | | **New message → To:** recipient picker | An owned agent absent from this machine and shared-channel bot lists could be missing. | Its named **agent** row can appear; selecting it adds a recipient chip. This is recipient selection, not a guarantee that a later message will reach or wake the agent. | | **Channel members → Add people and agents** | The same agent could be missing from **Not in this channel** search results. | Its row can appear with the existing **Add** button. If you can add members, that button submits the existing channel-membership request; finding the row alone changes no membership. | | **Stream / forum composer → @ suggestions** | An owned agent already in the channel under an ordinary member role could be missing from agent suggestions. | Its actual membership is recognized without requiring the bot role. Agents not managed on this device still need membership in that channel. | | **Pulse → Agents** | An agent absent from both local management and the server's agent list was omitted from the count and author lookup. | The count and feed's author lookup can include it; notes appear only if it has published them. | Being listed does **not** mean the agent is online, add it to a channel, or grant local Start/Edit controls. For agents not managed on this device, global **Search** still excludes those configured for “Only me”, and DM @ selection is not added here. DM @ selection and message-driven nonmember invitation are addressed in [#7124](https://github.com/block/buzz/pull/7124); the standalone forum **Invite / Cancel** flow is in [#7125](https://github.com/block/buzz/pull/7125). <details> <summary>Ownership and membership checks</summary> A discovery lead is not proof: the latest agent profile must have a valid signature and exactly one valid ownership attestation—the owner's signed link to that agent. Its response policy must be signed by that verified owner; an invalid latest policy cannot restore an older permission. Membership comes separately from the latest server-signed roster, including removals. Existing profile cards, owner labels and agent-avatar shapes also use this stricter verification: malformed or forged evidence must not supply ownership/agent classification on its own. Valid ownership was already recognized; no profile-picture or badge design changes. Attestation time conditions apply to the signed event's timestamp, not a live expiry timer. Existing legacy compatibility and builds requiring verified owner policy retain their respective rules. Discovery and sending remain separate operations, not an atomic permission check. </details> ### Review corrections - When runtime and owner policy overlap, **explicit online/away/offline from the verified latest runtime is retained**. Policy still supplies ownership/permissions; claimed runtime membership is not restored. Missing/unrecognized status stays unknown, and invalid latest policy cannot revive runtime permissions. - Discovery without runtime evidence is now **unknown**, not offline: native conversion, both IPC adapters, Pulse, Projects and profile/session consumers preserve that distinction. Unknown has no status dot and is not promoted to a deployed/running agent. - Both relay-only picker paths retain the authenticated owner, including the existing **managed by you** label. The analogous global Search projection is fixed without changing its existing “anyone” filter. - Authorized stored profile activity remains visible when liveness becomes unknown/absent or the active turn ends. History reads do not start a live subscription, grant access, or imply current availability. ### Related issue Independent base: `main`. Child: [#7124](https://github.com/block/buzz/pull/7124), then [#7125](https://github.com/block/buzz/pull/7125). Extracted from [#7114](https://github.com/block/buzz/pull/7114), retained as historical source (`98fe33ec`). [Behavior contract](3a56d17824/docs/owned-agent-discovery.md). Originating [Buzz discussion](buzz://message?channel=f7a9536a-1738-4bad-a888-b3ea25010ef1&id=7aa1f0ab23dce514bd8a0221441cf005bf428914621171472b79747c50820848) · channel `f7a9536a-1738-4bad-a888-b3ea25010ef1`. ### Testing Current candidate: `3a56d17824522580fe04cae463b54f4c7ba66021`, a four-file native/test/doc runtime-status repair atop published `ae23c1c9680a881cee7eed94e259bf15bf8ce3f7`. Branch ancestry is main `1c8321cd08feb597f8bcff5195c21148fb3e98ed`; refreshed main `0e878664b08cdf7fb2d89d940bc2aa92cdc485f7` adds only the independent CI-workflow split. Read-only mergeability succeeds; this is not a tested merged-tree claim. **Local CI attempt and continuation (not an uninterrupted green run):** the new exact-head `just ci` passed formatting/static checks, workspace and Tauri clippy, workspace Rust tests, **5,910 desktop tests**, desktop production build and Tauri check. Its native main target finished **3,073 passed / 1 failed / 19 ignored** (exit 101): `cheap_discovery_reports_absent_before_any_forced_probe` saw a process-global login-shell counter of 2 instead of 0. The counter includes unrelated version/adapter probes whose tests do not hold the failed test's PATH mutex; no managed-agent discovery implementation changed in the runtime repair. The unchanged failing test then passed **three isolated invocations**. Only the failed native workspace lane was retried with `RUST_TEST_THREADS=1 just desktop-tauri-test`: **3,074 main-target tests passed / 19 ignored**, all additional workspace targets passed (exit 0). The previously unrun `just web-build mobile-test` tail then passed (exit 0; **2,019 mobile tests**). Earlier successful lanes were reused; no source/guard changes or blanket CI rerun. The original failure and all diagnostic/retry logs are retained. - **71 native `nostr_convert` tests pass**, including seven new production merge regressions: online/away/offline, missing/invalid status, policy-only, status-less latest replacement and forged latest replacement. Before production repair, those seven yielded **4 failures / 3 passing controls**. - Reused frontend evidence from `ae23c1c9` (frontend is unchanged): Desktop TypeScript and isolated E2E build pass; **9 browser tests / 0 retries**, covering both relay-only picker journeys and seven adjacent stop-control regressions. Real UI with mock Tauri IPC, not live relay/native webview. - Earlier `ae23c1c9` local `just ci` passed without failures, including 3,067 native main-target tests / 19 ignored and 2,019 mobile tests; not substituted for the new source gate above. - Reused unchanged repair evidence: **17 real-store/hook history regressions**, **161 focused tests**, and independent **9 mounted owner/bot/identity revocation/regrant transitions** with zero hook-phase native calls. The regression was falsified before repair (14 failures, 3 controls). - Signed local-server fixtures cover discovery with no local/shared record, ordinary-role membership, forged ownership, invalid signatures, duplicate authentication, wrong-owner/latest-invalid policy, revoked membership and wrong destinations. These establish native data checks, not a live agent response. GitHub checks and renewed technical/security review must apply to the current published head; earlier-head green checks are not replacement-head proof. Local source review is not formal code-owner/latest-push approval or exact-range security authorization. A green security workflow with substantive review skipped is not security clearance. ### Screenshots #### Relay-only picker evidence — `ae23c1c9680a881cee7eed94e259bf15bf8ce3f7` These cropped rows come from the two real production picker journeys in [`owned-agent-discovery.spec.ts`](ae23c1c968/desktop/tests/e2e/owned-agent-discovery.spec.ts), using mock Tauri IPC with **no local agents and no user-search duplicate**. The fixture supplies verified-owner data and unknown availability; the browser test checks its presentation, not native signature verification. Both exact-tip journeys pass without retries. No live relay, native webview, invitation, delivery or wakeup is claimed. Before the repair, both relay-only candidate constructors discarded the owner, so the existing “managed by you” label was absent. These are after-repair captures; no before image was captured. #### New Message → To The relay-only agent retains its authenticated owner label.  #### Channel members → Add people and agents The matching result retains “managed by you” beside the existing Add action; the test does not click Add or claim membership changed.  --------- Signed-off-by: Logan Johnson <loganj@squareup.com> Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
This commit is contained in:
58
docs/owned-agent-discovery.md
Normal file
58
docs/owned-agent-discovery.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# Authenticated owned-agent discovery
|
||||
|
||||
An owner-authored kind 30177 coordinate seeds discovery independently of local
|
||||
runtime inventory and shared-channel membership. It is not ownership proof. The
|
||||
latest agent kind 0 profile must have a valid envelope and exactly one valid
|
||||
NIP-OA auth tag. Every signed condition is evaluated against event time, never
|
||||
wall-clock time. The owner remains provenance, not the agent's author identity.
|
||||
|
||||
Owner policy coordinates must match that verified owner and have valid signed
|
||||
envelopes. Invalid latest policy reserves the coordinate and fails closed: it
|
||||
cannot revive a legacy permission. Missing policy retains existing OSS legacy
|
||||
compatibility; marked builds require verified owner policy. This change does not
|
||||
invent a missing-policy default or broaden policy audiences.
|
||||
|
||||
Membership comes from the latest relay-signed kind 39002 snapshot for each
|
||||
channel. Known owned agents need not carry the cosmetic bot role. Ownership does
|
||||
not fabricate membership: a nonmember may be discovered with empty channel_ids.
|
||||
Selection queries constrain exact requested keys and destination. Relay authority
|
||||
is obtained through the existing community-bound relay admission boundary.
|
||||
|
||||
This native change expands discovery only. Preparing an invitation and freshly
|
||||
authorizing publication to its exact destination belong to the subsequent
|
||||
mention-routing change; discovery alone does not authorize a message.
|
||||
|
||||
## Regression gates
|
||||
|
||||
- `commands/agent_discovery/relay_directory/owned_tests.rs`: signed loopback
|
||||
discovery with no local record, forged ownership exclusion, ordinary-role
|
||||
membership, wrong destination, revocation and unsupported latest policy.
|
||||
- `nostr_convert/oa_profile_tests.rs`: signed envelope, duplicate/malformed auth,
|
||||
canonical conditions and signed-event time, wrong-owner policy, invalid latest
|
||||
policy, forged and stale membership.
|
||||
- `nostr_convert/tests.rs`: signed conversion fixtures and OSS compatibility.
|
||||
- `nostr_convert/runtime_policy_tests.rs`: known signed runtime status survives
|
||||
policy overlay; absent/unrecognized status, policy-only discovery, and an
|
||||
invalid or status-less latest runtime cannot fabricate or revive availability.
|
||||
|
||||
NIP-OA time conditions are not wall-clock expiry (see `docs/nips/NIP-OA.md`). Relay
|
||||
membership and policy reads remain separate snapshots, not an atomic publication
|
||||
transaction. Independent security review is required before landing.
|
||||
|
||||
## Presentation preserves evidence
|
||||
|
||||
Policy-only agents carry `status: "unknown"` through IPC. When the same agent has
|
||||
an independently verified latest kind 10100 runtime record, its explicit
|
||||
`online`, `away`, or `offline` status survives the owner-policy overlay. Missing
|
||||
or unrecognized runtime status remains unknown, not the generic converter's
|
||||
legacy offline default. Policy still controls ownership and permissions; claimed
|
||||
runtime membership is not restored. An invalid latest policy still excludes the
|
||||
agent rather than falling back to runtime permissions.
|
||||
|
||||
Discovery alone supplies no liveness evidence: Pulse and Projects omit the status
|
||||
dot rather than inventing offline or active presence, and active-agent lookups
|
||||
require positive evidence.
|
||||
Channel and profile activity projections preserve unknown rather than claiming a
|
||||
deployed observer; local managed runtime status still takes precedence.
|
||||
Authenticated `ownerPubkey` is retained by New Message, member-add, and search
|
||||
candidates even when no user-search profile duplicates the relay result.
|
||||
Reference in New Issue
Block a user