feat(apify): scrape alerts fire only on genuinely new posts (diff against stored posts)#759
feat(apify): scrape alerts fire only on genuinely new posts (diff against stored posts)#759sweetmantech wants to merge 1 commit into
Conversation
… posts first The Instagram scrape alert fired whenever a scrape returned posts, with no comparison against posts already stored — every scrape re-announced the profile's recent feed as new (observed: 6 of 7 alerts in one day announced posts up to 10 days old). New reusable filterNewPostUrls diffs candidate URLs against posts BEFORE upsert; the alert is gated on a non-empty result. Persistence unchanged (recoupable/chat#1855, PR #3 of 6). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
|
Warning Review limit reached
Next review available in: 24 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (2)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
No issues found across 4 files
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Architecture diagram
sequenceDiagram
participant ApifyCloud as Apify Cloud Webhook
participant Handler as handleInstagramProfileScraperResults
participant Filter as filterNewPostUrls (NEW)
participant DB as Supabase (posts table)
participant Upsert as upsertPosts / upsertSocials / upsertSocialPosts
participant Email as sendApifyWebhookEmail
participant FollowUp as handleInstagramProfileFollowUpRuns
Note over ApifyCloud,FollowUp: Instragram scrape alert — NEW: only notify on genuinely new posts
ApifyCloud->>Handler: POST /apify/instagram (scrape result)
Handler->>Handler: Extract post URLs from latestPosts
Note over Handler,Filter: Must run BEFORE upsert (chat#1855)
Handler->>Filter: filterNewPostUrls(postUrls)
Filter->>DB: getPosts({ postUrls })
DB-->>Filter: existing posts (post_urls)
Filter-->>Handler: newPostUrls (URLs not in DB)
Handler->>Upsert: upsertPosts(postRows) (all scraped URLs)
Handler->>Handler: getPosts() to fetch upserted records
alt newPostUrls.length > 0
Handler->>Email: sendApifyWebhookEmail(firstResult, emails)
Email-->>Handler: sentEmails
else newPostUrls.length === 0
Note over Handler: NEW: skip email — all posts already stored
end
Handler->>FollowUp: handleInstagramProfileFollowUpRuns(...)
FollowUp-->>Handler: follow-up runs
Handler-->>ApifyCloud: response (social, posts, etc.)
Auto-approved: Adds filterNewPostUrls to diff scraped URLs against stored posts, gating alert emails on genuinely new posts only. Tests pass for both the helper and the handler's no-email path.
Re-trigger cubic
Summary
Kills the alert false positives: the notifier sent "new posts" whenever a scrape returned any posts — no diff against what's stored — so every scrape re-announced the profile's recent feed. Evidence on recoupable/chat#1855: 6 of 7 alerts to one customer in one day announced posts that were 2–10 days old and already in the database.
Tracking issue: recoupable/chat#1855 (PR #3 of 6 — independent; biggest notification-volume win).
What changed
lib/socials/filterNewPostUrls.ts(new, reusable across platforms): given candidate post URLs, returns those with no existingpostsrow. Documented constraint: must run before the upsert (afterwards nothing is distinguishable as new).lib/apify/instagram/handleInstagramProfileScraperResults.ts: computes the diff pre-upsert and only sends the alert when ≥1 URL is genuinely new. Persistence is unaffected — posts/socials/social_posts/follow-up scrapes run exactly as before; only the notification is gated.Tests (RED→GREEN)
filterNewPostUrls: known-vs-new partition, all-new passthrough, empty-input short-circuit (no query).vitest run lib/socials lib/apify/instagram→ 13 files, 63 tests passed; eslint clean.Relationship to the digest PRs
The digest aggregation (PR #4) consumes this same helper per platform. This PR is deliberately shippable alone for immediate relief on the current per-platform email.
🤖 Generated with Claude Code
Summary by cubic
Stop Instagram scrape alerts from re-announcing old posts by diffing scraped URLs against stored
postsbefore upsert. This eliminates false-positive “new post” emails (recoupable/chat#1855).filterNewPostUrlsand used it in the Instagram handler before upsert to identify genuinely new URLs.Written for commit 360268b. Summary will update on new commits.