From d93eb6f1cfb47af224f2be03354ea1ea86863ca2 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 23 Jul 2026 17:39:05 +0000 Subject: [PATCH] Fix retweet/reply author mismatch: name and handle now describe the same person MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit authorName came from fxtwitter's enrichment (keyed by the tweet ID, which for a retweet/reply resolves to the original tweet) while authorHandle was hardcoded to the RSS feed's dc:creator — which is actually whichever list member's retweet or reply surfaced the item, not the original author. The card ended up showing one person's display name next to another person's @handle. Both fields now come from the same enrichment response, falling back together to the RSS-derived handle only when enrichment fails. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_014c1L8ghNBFjfiH64UMViP8 --- backend/src/ingestion/adapters/nitter.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/backend/src/ingestion/adapters/nitter.ts b/backend/src/ingestion/adapters/nitter.ts index f249b6b..8e1060f 100644 --- a/backend/src/ingestion/adapters/nitter.ts +++ b/backend/src/ingestion/adapters/nitter.ts @@ -116,16 +116,21 @@ export const nitterAdapter: SourceAdapter = { continue; } - // dc:creator is reliably the author of this item's own tweet text (rss-parser - // maps it to item.creator) — for a retweet, that's the original tweet's author, - // not whichever list member's retweet surfaced it in this feed. - const handle = (item.creator ?? '').replace(/^@/, '') || 'unknown'; + // dc:creator (rss-parser maps it to item.creator) is actually whichever list + // member's retweet/reply surfaced this item in the feed — NOT the original + // tweet's author for a retweet. It's only used here to look up the fxtwitter + // enrichment (fxtwitter needs *a* handle + the tweet ID, and any handle works + // for that lookup); the author identity actually displayed always comes from + // the enrichment response below, keyed consistently off the same tweet — so + // name and handle never end up describing two different people. + const rssHandle = (item.creator ?? '').replace(/^@/, '') || 'unknown'; const ownHtml = ownContentHtml(item.content ?? ''); const rssImageUrl = extractImageUrl(ownHtml); - const enrichment = await fetchFxTwitter(handle, tweetId); + const enrichment = await fetchFxTwitter(rssHandle, tweetId); - const authorName = enrichment?.author?.name ?? handle; + const authorName = enrichment?.author?.name ?? rssHandle; + const handle = enrichment?.author?.screen_name ?? rssHandle; const avatarUrl = enrichment?.author?.avatar_url ?? null; const text = enrichment?.text ?? ownHtml; // Enrichment failed (or came back with no media) — fall back to the RSS