feat: watch-to-post reciprocity pacing (replaces clout)#182
Merged
Conversation
groups gains reciprocity_seed/cap/ratio and drops daily_share_limit, share_pacing_mode, share_burst, share_cooldown_minutes, clout_enabled. users gains post_credits and drops the clout_* columns. clip_queue drops position/scheduled_at (the queue is now an unscheduled holding area).
New credits.ts owns the atomic earn/spend primitives, group config lookup, and ratio-gated watch crediting. New members are seeded with the group's configured starting credits at all four user-creation sites.
Rewrites queue.ts into an unlimited holding area: enqueue, publishQueuedClip (now async + notifies), postQueuedClips (multi-select, spends a credit each), and setClipReady (direct-post spends at publish, degrades to queue if drained). Adds POST /api/queue/post, paginates GET /api/queue, and removes the reorder + move-to-top routes. Deletes the 30s auto-publish scheduler timer so nothing leaves the queue except a deliberate credit spend. Failed downloads clean up their orphan queue row.
POST /api/clips and /api/clips/share post directly when the uploader has a credit and an empty queue, else enqueue (credit spent at publish). The watched handler earns a credit on the first watch of another member's clip and returns the new balance.
Adds groups.reciprocity_started_at: only clips created at/after the cutoff earn watch credits. Pre-cutoff backlog clips stay fully watchable but pay out zero, so rolling out reciprocity over an existing feed can't convert the backlog into a flood of posting credits. The cutoff is stamped at group creation and backfilled to deploy time for the existing group on first boot after migration. grantWatchCredit gates on the clip's created_at and only advances the ratio counter on eligible (post-cutoff, non-self) watches. Self-watches and rewatches still earn nothing.
Deletes the clout module/API/components/tests, the share-limit module, and the share-pacing + daily-share-limit endpoints and their pickers. Settings now uses ReciprocityPicker; the root layout drops CloutChangeModal; the app layout drops the clout-tier poll and seeds the credit store + queue count; the me header shows credit dots instead of a rank badge. Adds the credit store and the CreditDots/CreditInfoModal primitives.
markClipWatched syncs the returned credit balance into the store. The feed blocks forward advance (scrollToIndex, wheel, keyboard, native momentum via a scroll-lock class) once the user is at the credit cap with a non-empty queue, opening the post sheet instead. An empty queue never gates.
QueueSheet becomes a multi-select post surface (sort/reverse, lazy-load, tap-to-explain credits pill, Post N) using SvelteSet for selection state. AddVideo/AddVideoModal show the credit dots and a posts-now-vs-queued hint and sync the returned balance. The share landing page is simplified to posted/queued states. UploadStatus drops the daily-limit dots and timed copy.
Adds the reciprocity settings endpoint and its API test; rewrites the queue unit/API tests for the holding-queue model + post endpoint; adds clips direct-vs-queue and watch-to-earn cases; drops the clout/pacing test blocks. Updates api.md + architecture.md, e2e fixtures (reciprocity seed/cap/ratio), the queue-interactions spec (multi-select post), and adds the reciprocity credit-lifecycle e2e spec.
Adds groups.daily_post_limit (null = unlimited, default off): a rolling-24h ceiling on posts per member, layered on top of credits. Enforced at the share decision, at publish (setClipReady degrades over-cap posts to the queue), and when posting from the queue. Configurable via the reciprocity settings picker and PATCH /api/group/reciprocity.
The requestfailed filter checked for capital 'Cancelled' but WebKit reports lowercase 'Load request cancelled', so navigation-cancelled video/font loads leaked through and flaked back-gestures on mobile-ios only. Match case-insensitively and on both spellings.
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.
What & why
The feed could be flooded by one prolific poster while everyone else fell behind. This replaces all prior pacing (clout reputation, daily-cap, and the burst/cooldown queue timer) with a single watch-to-post credit economy:
Anti-flood guards
reciprocity_started_at): only clips created at/after rollout earn credits, so the existing backlog stays watchable but can't be farmed into a flood of credits. Backfilled to deploy time on first boot.daily_post_limit, default off): optional rolling-24h hard ceiling on top of credits; over-cap posts are held in the queue rather than rejected.Host config
seed/cap/ratio/dailyPostLimitare tunable per group via Settings → Share Pacing andPATCH /api/group/reciprocity.Removed
The clout system (module,
/api/clout, tier modals/components, columns), thedaily_cap/queuepacing modes and their endpoints/pickers, the burst/cooldown machinery, and the 30s auto-publish scheduler timer.Test plan
npm run check— 0 errorsnpm test— 478 unit/API tests passnpm run test:e2e(desktop) — reciprocity credit-lifecycle, multi-select post, queue, group-host all green