feat(jobs/challenges): Phase 2 — 7 more poll-based processors#841
Open
raymondjacobson wants to merge 3 commits into
Open
feat(jobs/challenges): Phase 2 — 7 more poll-based processors#841raymondjacobson wants to merge 3 commits into
raymondjacobson wants to merge 3 commits into
Conversation
Adds 7 more challenge processors to api/jobs/challenges/ following the
same poll-based reconciliation pattern from Phase 1. No new infra; all
source tables already exist.
Processors:
c first_weekly_comment one row per (user, ISO-week)
cp comment_pin commenter earns when verified track owner
pins their comment (skips self-pin)
cs cosign verified parent owner saves/reposts a remix;
remixer earns; cap 5 cosigns per parent-owner
per rolling 30 days; currently inactive in catalog
t tastemaker earliest 10 reposters + earliest 10 savers
of each top-10 trending track
w remix_contest_winner winners of verified-host remix contest; max
5 winners per contest, max 5 winner rewards
per host per rolling week
b audio_matching_buyer per USDC purchase; amount = 1 × dollars
s audio_matching_seller same purchase; amount = 5 × dollars; gated
on seller verification
Audio matching reads from v_usdc_purchases (filtered to is_valid = TRUE);
checkpoint by sol_purchases.slot for incremental scanning.
Migration 0204 seeds the catalog rows from challenges.json with ON
CONFLICT DO UPDATE.
Tastemaker top-N bumped to 10 per direction (apps' historical value was
5). Per-track threshold of 10 reposters/savers kept as apps.
All 7 new processors registered in IndexChallengesJob (now 18 total).
Tests: 11 new DB-backed tests covering each processor's happy path and
its main gates (verified/unverified, cap enforcement, invalid purchases).
All passing against test_jobs template DB.
7 tasks
Closes the notification side of the tastemaker (t) and trending
(tt/tut/tp) challenge ports. Phase 1+2 processors mint user_challenges
rows but only handle_user_challenges.sql's generic claimable_reward /
challenge_reward notifications fired — the type-specific tastemaker /
trending / trending_underground / trending_playlist notifications
that apps' index_tastemaker.py and index_trending.py created had no
Go equivalent.
Both new triggers fire AFTER INSERT on user_challenges with a WHEN
clause filtered to their challenge_id. Re-runs hit UpsertUserChallenge's
ON CONFLICT DO UPDATE branch (no AFTER INSERT) so each row's
notification mints exactly once.
handle_tastemaker.sql (challenge_id='t')
- Parses track_id from the processor's specifier "<hex_uid>:t:<hex_tid>"
- Looks up tracks.owner_id and infers repost-vs-save action (repost
wins, matching apps' dedupe_notifications_by_group_id)
- Emits notification with group_id
"tastemaker_user_id:<uid>:tastemaker_item_id:<tid>", specifier=tid,
and data { tastemaker_item_id, tastemaker_item_type:'track',
tastemaker_item_owner_id, action, tastemaker_user_id } — verbatim
apps' Notification(type='tastemaker') shape
handle_trending.sql (challenge_id in 'tt','tut','tp')
- Parses week + rank from "<YYYY-MM-DD>:<rank>"
- Looks up entity_id from trending_results (same processor wrote it
earlier in the same transaction)
- Routes to 'trending' / 'trending_underground' / 'trending_playlist',
swapping the track_id/playlist_id label in group_id and data —
matches apps' index_trending_notifications, ditto for underground +
playlist variants
- Idempotency comes from the AFTER INSERT (not UPDATE) gate plus
the unique (group_id, specifier) constraint on notification
Schema dump regeneration follows in a separate commit (cf. 4da78ab
for the handle_comment_remix_contest_update precedent).
Tests:
- TestTastemaker_EmitsNotification — verifies notification row shape;
asserts repost wins when a user has both a repost and a save
- TestTrending_EmitsNotification — Friday-gated; asserts the rank-1
notification carries track_id, rank=1, and the expected group_id
- TestTrendingPlaylist_EmitsNotification — playlist variant carries
playlist_id (not track_id) in data and group_id
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Member
Author
|
Adding the tastemaker + trending notification side that the processors didn't cover (closes the parity gap with apps' Pushed Notes
cc @raymondjacobson — flagging since you authored the parent PRs. |
The trending playlist reward (challenge_id 'tp') is being removed as a product feature, so handle_trending no longer needs to emit `trending_playlist` notifications. Scope: just this PR's trigger. PR #835's NewTrendingPlaylistProcessor + 'tp' catalog seed are still in place — harmless if the upstream feature stays inactive, can be torn out separately if desired. Changes: - handle_trending.sql: drop the 'tp' case from the type switch, WHEN clause, and data_jsonb branch. Trigger now only handles 'tt' and 'tut' (both tracks), so the entity_label variable goes away too. - trending_test.go: remove TestTrendingPlaylist_EmitsNotification. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Stacked on #835 (Phase 1). Adds 7 more challenge processors. No new infra — all source tables already exist.
Confirmations folded in
Stack
```
#834 parity jobs
└─ #835 phase 1 challenges
└─ this PR — phase 2 challenges
```
Test plan
11 DB-backed tests in addition to the 12 from Phase 1:
Next
PR B (signals endpoint + 5 Phase 3 processors) follows.
🤖 Generated with Claude Code