fix(mobile): honor authenticated owner policy in agent candidates - #7392
fix(mobile): honor authenticated owner policy in agent candidates#7392loganj wants to merge 2 commits into
Conversation
Signed-off-by: Logan Johnson <loganj@squareup.com>
Signed-off-by: Logan Johnson <loganj@squareup.com>
Independent policy readiness evidence — 2026-09-07Verified current stacked range:
|
jedwards27
left a comment
There was a problem hiding this comment.
:bot: Jude’s code review agent reviewed exact head 804c07f016b7f73504b614d1bf81ef6f0120d83d against base b2253ce1aa5fd2e05e6a51b67c8edae112364308.
Blocking findings
-
Policy loading/error fails open at the production candidate consumer.
mentionCandidatesProviderturns bothAsyncLoadingandAsyncErrorfromagentDirectoryProviderinto an empty directory (mobile/lib/features/channels/mentions/mention_candidates_provider.dart:80-83). Candidate assembly then applies owner policy only when an entry exists, so authenticated-owned channel members and owned search results can be admitted through the legacy paths (mobile/lib/shared/mentions/mention_candidates.dart:64-88,121-143). Initial loading, timeout, or failed policy reads can therefore visibly restore an agent that the authenticated owner denied. A temporary production-seam probe at this head reproduced one candidate where zero were expected; the current provider test only proves the underlying future throws.Author action: preserve policy readiness/error as explicit authorization state and fail closed for authenticated-owned identities until exact policy resolution succeeds, while retaining intentional headless compatibility. Add production-consumer regressions for loading and failed reads across member and owned-search paths, including successful retry recovery.
-
A successful policy snapshot does not refresh when a newer owner policy is published. Policy is queried only when the directory provider builds (
mobile/lib/shared/mentions/agent_identity_provider.dart:67-75;mobile/lib/shared/mentions/agent_policy.dart:25-60). In the reviewed mobile production paths, the live directory invalidation listens to kinds0and10100, not policy kind30177(mobile/lib/features/channels/pages/channel_detail_page.dart:150-171), and short foreground resume does not reconnect (mobile/lib/shared/relay/relay_session.dart:451-465). A connected app can consequently retain a permissive snapshot indefinitely after the owner publishesnobodyor a restrictive allowlist; the send path does not re-read policy.Author action: add lifecycle-owned exact-coordinate policy refresh—live subscription with backfill/live overlap, reconnect recovery, and generation fencing, or a bounded foreground/interaction refresh that cannot retain stale authorization. Regress permissive initial state → newer deny → candidate disappears without an unrelated kind-10100 event, plus resume/reconnect recovery.
-
Repository-required public API documentation is missing. The new public
AgentDirectoryEntry.ownerPubkeyfield atmobile/lib/shared/mentions/agent_identity_provider.dart:21lacks the doc comment required byAGENTS.md:147-150.Author action: document the field and its authenticated-owner semantics.
Verification
- Live PR head and remote head matched
804c07f016b7f73504b614d1bf81ef6f0120d83d; reviewer identity wasjedwards27, distinct from authorloganj; no prior reviews existed. - Full exact-head
./bin/just mobile-test: 2,086 passed, exit 0, clean tree and unchanged HEAD afterward. git diff --checkpassed; DCO passed; all reported GitHub checks were green or intentionally skipped.- Signed owner envelope validation, exact owner-coordinate queries, latest/tie handling, malformed-latest deny behavior, revocation, and batching otherwise traced consistently.
Confidence gap
No native iOS/simulator journey was run. That is not separate author rework, but native observation should follow the repairs. The source-level production seam and lifecycle defects above are sufficient to block this head.
|
Documentation callout is covered by descendant #7393 at c73ff57: AgentDirectoryEntry.ownerPubkey now documents verified NIP-OA kind:0 owner authority, not runtime claims, and null semantics. This is cross-PR coverage, not a backport. Loading/error picker eligibility and live policy lifecycle findings remain open; this comment does not claim those fixed. |
|
Followup #7530 (a6d7298, based on published #7395) completes the remaining picker-readiness callout without backporting it here: Latest-policy delivery is supplied by #7395 at 1eabb04: filter-faithful kind:30177/kind:5 deletion/replay and bounded generation-fenced establishment recovery (see its existing exact-head response). #7530 additionally shares ordered snapshot/live profile authority, preventing stale owner snapshots from defeating policy resolution. The ownerPubkey docs already acknowledged in the earlier response remain in #7393's current df61d54 (only a blank-line change from tested c73ff57). These are explicit descendant dependencies, not fixes present in unchanged #7392 at 804c07f. Publication guards are not counted as discovery/picker coverage; repository-wide CI/native-device completion is not claimed. |
jedwards27
left a comment
There was a problem hiding this comment.
:bot: Jude’s code review agent — REQUEST CHANGES remains after reconsidering response IC_kwDORgXb2s8AAAABTiOW8Q on exact head 804c07f016b7f73504b614d1bf81ef6f0120d83d.
The response accurately identifies descendant repairs; those repairs are not in this merge object. This head still collapses directory loading/error to [] (mobile/lib/features/channels/mentions/mention_candidates_provider.dart:80-83), after which authenticated-owned member/search paths admit identities without authoritative policy (mention_candidates.dart:64-74,121-143). Its directory remains a one-shot policy fetch (agent_identity_provider.dart:67-75), so a newer deny can remain stale. Public AgentDirectoryEntry.ownerPubkey also remains undocumented (agent_identity_provider.dart:18-23), contrary to AGENTS.md:147-150.
The current descendant chain is not an atomic safety gate: #7392 itself remains independently mergeable, while child reviews/checks and heads moved during reconsideration. A prose graph does not prevent ancestor-first deployment. #7530’s readiness work also does not by itself establish the selected-before-revocation send seam.
Author action: backport fail-closed readiness/error handling, live policy freshness/recovery, regression coverage, and docs here; or keep this PR blocked and provide one immutable integration head containing the complete picker and send-time revocation fences with encoded ancestry and green child checks.
Verification owner: author for coherent integrated head and causal loading/error + permissive→deny + selected-before-revocation/send regressions; reviewer for exact-head mutation and topology validation.
Evidence: remote head/base rechecked unchanged; immutable source confirms all three defects; prior exact-head full 2,086-test pass did not exercise these production transitions. Native picker observation remains a separate confidence gap.
9b39d90 to
24035e2
Compare
🤖
Summary
Which agents mobile suggested could ignore their owner's latest decision: the picker trusted the permissions an agent's running instance advertised, so an owner's newer policy — revoking an agent's mention access, or publishing a broken latest policy — didn't reliably remove that agent from suggestions. This PR makes the owner's latest signed policy the authority for candidate eligibility: it overlays exact, authenticated policy reads on the existing runtime directory, so an agent the owner has denied no longer appears as a mention candidate.
Desktop reference:
desktop/src-tauri/src/nostr_convert/agent_directory.rs,commands/agent_discovery/relay_directory.rs,agentAutocompleteEligibility.ts.Related issue
Testing
just mobile-check, the full mobile test suite, and full localjust ciall pass — receipts in the exact-head evidence comment.Screenshots
Flutter production-widget test renders — not native-device screenshots or acceptance captures.
Capture provenance
Rendered by the Flutter widget engine in a
flutter testrun (production widgets, production theme; no device or simulator). Before: this PR's declared baseb2253ce1aa5fd2e05e6a51b67c8edae112364308. After: its head804c07f016b7f73504b614d1bf81ef6f0120d83d.