本文へ移動
cccskills
無料GitHub で公開

nostr-addressable-event-dual-tag-query

Fix "count shows X but list shows empty" bugs when querying related events (comments, reactions, zaps, reposts) for Nostr addressable events (Kind 30000-39999). Use when: (1) REST API shows engagement count > 0 but WebSocket query returns empty, (2) Comments/reactions exist but app shows "No comments yet" or similar, (3) Working with NIP-22 comments, NIP-25 reactions, or NIP-18 reposts on Kind 34235/34236 video events or other addressable events. Root cause: clients may reference addressable events using either E tag (event ID) or A tag (kind:pubkey:d-tag format), and querying only one tag misses events tagged with the other.

インストール方法を見る

含まれるファイル(1)

  • SKILL.md6.2 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Nostr Addressable Event Dual-Tag Query

Problem

When querying related events (comments, reactions, reposts, zaps) for Nostr addressable events (Kind 30000-39999), the query returns fewer or zero results even though an indexing service shows the correct count. This happens because addressable events can be referenced two ways, and different clients use different methods.

Context / Trigger Conditions

Use this skill when:

  • Video/post shows comment count of 5, but comments modal says "No comments yet"
  • REST API (like Funnelcake) returns correct engagement counts, but WebSocket queries return empty
  • Working with NIP-22 comments (Kind 1111) on addressable events
  • Working with NIP-25 reactions (Kind 7) on addressable events
  • Working with NIP-18 reposts (Kind 6/16) on addressable events
  • Any feature querying events that reference Kind 30000-39999 events

Root Cause

For addressable events (Kind 30000-39999, like Kind 34236 videos), related events can reference the target using either:

  1. E tag: References by event ID (64-character hex)

    ["E", "abc123...def456", "", "author-pubkey"]
    
  2. A tag: References by addressable identifier (kind:pubkey:d-tag)

    ["A", "34236:abc123...def456:my-video-id", "", "author-pubkey"]
    

Different Nostr clients and indexers use different conventions:

  • Some always use E tags (event ID-based)
  • Some prefer A tags for addressable events (following NIP-22 strictly)
  • Some use both tags

If your app only queries by one tag type, you'll miss events tagged with the other.

Solution

1. Update Filter Class (if needed)

Ensure your Filter class supports uppercase A tag queries:

// In Filter class
List<String>? uppercaseA;  // Add this field

// In toJson()
if (uppercaseA != null) {
  data['#A'] = uppercaseA;
}

2. Query by BOTH Tags

When loading related events, run two parallel queries and merge results:

Future<List<Event>> loadRelatedEvents({
  required String eventId,
  required String? addressableId,  // Format: "kind:pubkey:d-tag"
}) async {
  // Query by E tag (event ID)
  final filterByE = Filter(
    kinds: [targetKind],
    uppercaseE: [eventId],
  );

  // If addressable ID available, also query by A tag
  if (addressableId != null && addressableId.isNotEmpty) {
    final filterByA = Filter(
      kinds: [targetKind],
      uppercaseA: [addressableId],
    );

    // Run both queries in parallel
    final results = await Future.wait([
      nostrClient.queryEvents([filterByE]),
      nostrClient.queryEvents([filterByA]),
    ]);

    // Merge and deduplicate by event ID
    final eventMap = <String, Event>{};
    for (final event in results[0]) {
      eventMap[event.id] = event;
    }
    for (final event in results[1]) {
      eventMap[event.id] = event;
    }

    return eventMap.values.toList();
  }

  return nostrClient.queryEvents([filterByE]);
}

3. Post with BOTH Tags

When creating related events, include both E and A tags for maximum compatibility:

final tags = <List<String>>[
  // Always include E tag
  ['E', rootEventId, '', authorPubkey],

  // Include A tag for addressable events
  if (rootAddressableId != null && rootAddressableId.isNotEmpty)
    ['A', rootAddressableId, '', authorPubkey],

  // ... other tags
];

4. Build Addressable ID

Construct the addressable identifier from event metadata:

String? get addressableId {
  if (dTag == null) return null;
  return '$kind:$pubkey:$dTag';  // e.g., "34236:abc123...:my-video-id"
}

Verification

After implementing:

  1. Find an event where REST API shows count > 0 but your app showed empty
  2. Verify the list now shows the expected items
  3. Post a new related event (comment/reaction)
  4. Verify it appears when querying by either E or A tag

Example

Before fix - only queries by E tag:

final filter = Filter(
  kinds: [1111],  // Comments
  uppercaseE: [videoEventId],  // Only E tag!
);
// Returns 0 comments even though 5 exist (tagged with A)

After fix - queries both tags:

final filterByE = Filter(kinds: [1111], uppercaseE: [videoEventId]);
final filterByA = Filter(kinds: [1111], uppercaseA: [addressableId]);

final results = await Future.wait([
  client.queryEvents([filterByE]),
  client.queryEvents([filterByA]),
]);
// Returns all 5 comments regardless of how they were tagged

Notes

  • This pattern applies to ANY feature that queries events referencing addressable events
  • The d-tag may contain colons, so parse addressable IDs carefully: parts.sublist(2).join(':')
  • For count queries (NIP-45), take the maximum of both counts (may over-count if events have both tags)
  • Some relays may not support #A filter queries yet - test with your target relays
  • This is especially important for interoperability between different Nostr clients

Affected NIPs

  • NIP-22: Comments (Kind 1111) - uses E/A tags for root scope
  • NIP-25: Reactions (Kind 7) - references target event
  • NIP-18: Reposts (Kind 6/16) - references reposted event
  • NIP-33: Parameterized Replaceable Events (Kind 30000-39999) - defines addressable format
  • NIP-71: Video Events (Kind 34235/34236) - common use case for this pattern

References

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Fix ArgoCD ExternalSecret deployment failing with "namespace X is not permitted in project Y". Use when: (1) ExternalSecret shows OutOfSync in ArgoCD but won't sync, (2) ArgoCD application status shows "namespace X is not permitted in project 'infrastructure'", (3) ExternalSecret targets a namespace managed by a different ArgoCD project, (4) Using apps-of-apps pattern with separate infrastructure and application projects.

日本語の概要は準備中です。原文の説明を表示しています。

divinevideo/divine-mobile2662026年10月13日 更新

Art direction for any content — reads text, PDF, Word, HTML, PPT, then proposes 2-3 creative directions with photography style, mood, and visual language. After selection, generates AI image prompts and visual briefs section-by-section. Use when the user shares content and needs visual direction, image sourcing, or creative direction for any material.

日本語の概要は準備中です。原文の説明を表示しています。

divinevideo/divine-mobile2662026年10月13日 更新

Fix "Null check operator used on a null value" errors when an object is set to null during an async await. Use when: (1) Object reference is nullified while awaiting, (2) Code accesses object with ! after await returns, (3) Cancel/dispose operations run concurrently with async operations on same object. Solution: capture local reference before await.

日本語の概要は準備中です。原文の説明を表示しています。

divinevideo/divine-mobile2662026年10月13日 更新

Add custom metadata headers (x-amz-meta-*) to AWS v4 signed requests for GCS S3-compatible API. Use when: (1) Adding custom metadata to GCS uploads via S3 API, (2) Getting signature mismatch errors after adding new headers, (3) x-amz-meta-* headers being ignored or causing 403 errors. Custom headers MUST be included in canonical headers and signed headers list.

日本語の概要は準備中です。原文の説明を表示しています。

divinevideo/divine-mobile2662026年10月13日 更新

Fix password/secret authentication failures caused by trailing newlines when creating Google Cloud secrets (or similar) with bash here-strings. Use when: (1) Password authentication fails with correct password, (2) Secret created with `<<< "value"` syntax, (3) Error like "password authentication failed" or "invalid token" despite correct value. Bash here-strings (`<<<`) add a trailing newline that corrupts secrets.

日本語の概要は準備中です。原文の説明を表示しています。

divinevideo/divine-mobile2662026年10月13日 更新

Fix silent video/media processing failures caused by URL extraction code that filters on file extensions (.mp4, .webm, .webp). Use when: (1) Media moderation, transcoding, or analysis silently skips files from Blossom or content-addressed storage servers, (2) URL extraction from Nostr event tags (imeta, r tags) drops URLs without recognized extensions, (3) CDN fallback URLs append .mp4 but the actual server uses extensionless content-addressed paths like /{sha256}. Common in Nostr video events (kind 34236) where different clients use different URL formats.

日本語の概要は準備中です。原文の説明を表示しています。

divinevideo/divine-mobile2662026年10月13日 更新

divinevideo のスキルをすべて見る

このスキルの問題を報告する