mirror of
https://github.com/block/buzz.git
synced 2026-10-28 21:11:48 +00:00
fix(mobile): resolve removal-aware roster heads for discovery
Signed-off-by: Logan Johnson <loganj@squareup.com>
This commit is contained in:
@@ -22,13 +22,37 @@ Future<List<AgentDirectoryEntry>> readAgentAuthorization(
|
||||
}
|
||||
final authority = await session.fetchRelaySelf();
|
||||
check();
|
||||
final membership = await _membershipPages(
|
||||
var membership = await _membershipPages(
|
||||
session,
|
||||
authority,
|
||||
viewer,
|
||||
channelId,
|
||||
check,
|
||||
);
|
||||
if (channelId == null) {
|
||||
// #p discovers destinations, not authority: a replacement removing the
|
||||
// viewer cannot match that filter. Re-read each exact coordinate without
|
||||
// #p, and never retain a discovery snapshot if its head is absent.
|
||||
final destinations = membership
|
||||
.where((e) => e.kind == 39002 && e.pubkey == authority)
|
||||
.map((e) => e.getTagValue('d'))
|
||||
.whereType<String>()
|
||||
.toSet();
|
||||
if (destinations.length > 1000) {
|
||||
throw StateError('Membership destination budget exceeded');
|
||||
}
|
||||
membership = await _queryAgentFilters(session, [
|
||||
for (final destination in destinations)
|
||||
NostrFilter(
|
||||
kinds: const [39002],
|
||||
authors: [authority],
|
||||
tags: {
|
||||
'#d': [destination],
|
||||
},
|
||||
limit: 1,
|
||||
),
|
||||
], checkCurrent: check);
|
||||
}
|
||||
check();
|
||||
final runtime = await _queryAgentFilters(session, [
|
||||
for (final key in requestedKeys)
|
||||
|
||||
@@ -19,6 +19,8 @@ part 'agent_authorization.dart';
|
||||
class AgentDirectoryEntry {
|
||||
final String pubkey;
|
||||
final String? displayName;
|
||||
/// Owner authenticated by the agent's verified NIP-OA kind:0 attestation,
|
||||
/// not a runtime ownership claim. Null means no authenticated owner here.
|
||||
final String? ownerPubkey;
|
||||
final String? respondTo;
|
||||
final List<String> respondToAllowlist;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:buzz/shared/mentions/agent_identity_provider.dart';
|
||||
import 'package:buzz/features/channels/mentions/mention_candidates.dart';
|
||||
import 'package:buzz/shared/relay/relay.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
@@ -149,6 +150,57 @@ void main() {
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
'global discovery re-reads removal heads without viewer filter',
|
||||
() async {
|
||||
final old = signed(
|
||||
relay,
|
||||
39002,
|
||||
'',
|
||||
tags: [
|
||||
['d', 'room'],
|
||||
['p', owner.public],
|
||||
['p', agent.public, '', 'bot'],
|
||||
],
|
||||
);
|
||||
final removed = members(time: 101, includeViewer: false);
|
||||
final session = _ReadSession([runtime], relay.public);
|
||||
var removedNow = false;
|
||||
session.page = (filters) {
|
||||
final filter = filters.single;
|
||||
expect(filter.authors, [relay.public]);
|
||||
if (filter.tags.containsKey('#p')) {
|
||||
expect(filter.tags['#p'], [owner.public]);
|
||||
return [old]; // The removed head cannot match #p=viewer.
|
||||
}
|
||||
expect(filter.tags, {
|
||||
'#d': ['room'],
|
||||
});
|
||||
expect(filter.limit, 1);
|
||||
return [removedNow ? removed : old];
|
||||
};
|
||||
final before = await read(session, destination: null);
|
||||
expect(before.single.channelIds, ['room']);
|
||||
removedNow = true;
|
||||
final after = await read(
|
||||
_ReadSession([runtime], relay.public)..page = session.page,
|
||||
destination: null,
|
||||
);
|
||||
expect(after, isEmpty);
|
||||
expect(
|
||||
buildMentionCandidates(
|
||||
members: [],
|
||||
relayAgents: after,
|
||||
sharedChannelIds: {'room'},
|
||||
userCache: {},
|
||||
ownerByAgentPubkey: {},
|
||||
currentPubkey: owner.public,
|
||||
),
|
||||
isEmpty,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
test('same-second membership tie is deterministic', () async {
|
||||
final yes = members();
|
||||
final no = members(includeAgent: false);
|
||||
@@ -197,6 +249,7 @@ void main() {
|
||||
final session = _ReadSession([owned, policy], relay.public);
|
||||
var calls = 0;
|
||||
session.page = (filters) {
|
||||
if (filters.first.tags.containsKey('#d')) return [first, last];
|
||||
calls++;
|
||||
if (calls == 1) return List.filled(500, first);
|
||||
expect(filters.single.until, first.createdAt);
|
||||
|
||||
Reference in New Issue
Block a user