The Reinforcement Loop Machine
Step through the algorithmic feedback loop that causes your interests to drift, even when you don't change your behavior.
What Is The Reinforcement Loop?
The algorithm creates a self-reinforcing feedback loop: Your profile determines what you see. What you see determines what you engage with. What you engage with updates your profile. Round and round, amplifying imbalances week after week.
The Six Steps of the Loop
1. Your Profile: 60% AI, 40% Cooking
2. Fetch Candidates: Algorithm fetches more AI tweets (60%) than Cooking (40%)
3. Score Tweets: AI tweets score higher (0.9 × 0.60 vs 0.9 × 0.40)
4. Build Feed: You see 60% AI, 40% Cooking (matches your profile)
5. You Engage: You engage with what you see (60% AI, 40% Cooking)
6. Update Profile: Next week, your profile becomes 62% AI, 38% Cooking
→ Return to Step 1 with NEW profile (loop repeats)
Why This Matters
- Mathematical inevitability: Any imbalance (even 51/49) will drift over time
- Zero-sum dynamics: L2 normalization means one interest growing forces others to shrink
- Weekly compounding: Each cycle amplifies the previous imbalance
- No equilibrium: The system has no rebalancing mechanism—it only concentrates
The Shape of the Drift
The drift follows a logistic curve: Fast growth initially (60 → 70% in 12 weeks), then slowing as you approach saturation (~80% is typical plateau). This isn't about your behavior changing—it's pure mathematics from multiplicative scoring + L2 normalization + weekly batch updates.
Step Through The Loop
Configure Your Starting Profile
Set your initial cluster interests. Watch how even a small imbalance (60/40) compounds over time.
Total: 100%
The Technical Details
Why This Loop Creates Drift
1. Multiplicative Scoring Amplifies Advantages
At the scoring stage, tweets get multiplied by your cluster interest:
AI tweet (quality 0.9): 0.9 × 0.60 = 0.54
Cooking tweet (quality 0.9): 0.9 × 0.40 = 0.36
50% score advantage for AI despite equal quality!
2. You Engage With What You See
Because AI content ranks higher, you see more of it. Your engagement naturally matches what's visible:
Feed composition: 60% AI, 40% Cooking
Your engagement: 60% AI, 40% Cooking
You didn't change your preferences - you engaged with what was shown!
3. L2 Normalization Creates Zero-Sum Dynamics
Cluster interests must sum to 1.0 (100%). When AI increases, Cooking MUST decrease:
Before: 60% AI, 40% Cooking (sum = 100%)
After: 62% AI, 38% Cooking (sum = 100%)
AI gained 2%, Cooking lost 2% - it's zero-sum!
4. Weekly Batch Updates Lock In Changes
InterestedIn updates weekly via batch jobs. Each week's drift becomes the new baseline:
Week 0: 60% AI, 40% Cooking
Week 1: 62% AI, 38% Cooking ← New baseline
Week 4: 64% AI, 36% Cooking ← Compounds
Week 12: 70% AI, 30% Cooking ← Accelerates
Week 24: 76% AI, 24% Cooking ← Lock-in
5. The Loop Feeds Itself
The output becomes the input:
- Week 0: 60/40 profile → see 60/40 feed → engage 60/40
- Week 1: 62/38 profile → see 62/38 feed → engage 62/38
- Week 4: 64/36 profile → see 64/36 feed → engage 64/36
- Result: Each iteration amplifies the imbalance
Mathematical Inevitability
This isn't about user behavior. It's pure math:
The Drift Formula
New_AI_Interest = Old_AI_Interest + (drift_rate × advantage × slowdown)
Where:
- drift_rate = engagement intensity (0.008 to 0.025)
- advantage = AI_interest / Cooking_interest (e.g., 0.60 / 0.40 = 1.5)
- slowdown = 1 - (imbalance × 0.5) (slows as approaching extremes)
Example (Week 0 → Week 1):
New_AI = 0.60 + (0.015 × 1.5 × 0.9) = 0.60 + 0.02025 ≈ 0.62
Key insight: As long as there's ANY imbalance (not perfect 50/50), drift will occur. The stronger interest always wins.
The Only Ways to Prevent Drift
- Start perfectly balanced (50/50) - But even 51/49 will drift over time
- Use additive scoring - Instead of multiplication, use addition (but this eliminates personalization)
- Disable cluster scoring - Don't multiply by interest (but then why have clusters?)
- Active counterbalancing - Manually over-engage with minority interest (exhausting)
In the current design, drift is inevitable for any user with unequal interests.
Code References
Multiplicative scoring: ApproximateCosineSimilarity.scala:84-94
Weekly batch updates: InterestedInFromKnownFor.scala:59 - val batchIncrement: Duration = Days(7)
L2 normalization: SimClustersEmbedding.scala:59-72
InterestedIn calculation: InterestedInFromKnownFor.scala:88-95 - Follows who you follow, what you engage with