ADR-003: Sync Score Decay with Quadratic Vulnerability¶
Status: Accepted Date: 2026-02-03 Context: Sync scores need to reflect ongoing alignment, not just historical accuracy. A player who stops playing should see their score decay, but the decay shouldn't punish consistency or brief absences.
Decision¶
Daily decay formula:
Where:
- vulnerability = max(0.1, 1 - (score/100)^2) — high scores are protected. A 95% score has 0.10 vulnerability; a 30% score has 0.91.
- durability = 1 + ln(1 + games_played/20) — more games = more decay resistance. 200 games gives ~3.4x resistance.
- inactivity_factor = (days_inactive - 7) / 14 — 7-day grace period, then gentle acceleration over 14 days.
- Score floor: 10 (functionally zero for governance).
Runs as a daily pg_cron job at 04:00 UTC.
Rationale¶
High sync scores should be hard to lose. The quadratic vulnerability curve means consistency is rewarded — a player who earned 95% through hundreds of games shouldn't lose it to a vacation. The logarithmic durability scaling means early games matter most for building resistance, with diminishing returns preventing gaming via mass low-quality games.
Alternatives Considered¶
- Linear decay: Equal decay regardless of score level. Rejected because it punishes high-performing members the same as low-performing ones.
- No decay, just recency weighting: Only consider last N games. Rejected because it doesn't create urgency for inactive members to return.
- Cliff decay (score resets after N days): Too harsh; would discourage members from taking breaks.
Consequences¶
- All config parameters are tunable via
sync_decay_configtable without code changes. - Decay has a kill switch (
decay_enabled = 0) for pausing during events or migrations. - The 7-day grace period means weekly players never experience decay.
- Members with 200+ games and high scores are nearly immune to short absences, which aligns with rewarding sustained commitment.
How We Got Here¶
The sync score was originally static — it went up or down based on game outcomes but never changed when a player was inactive. This created a problem: a player could achieve a high sync score in January, stop playing entirely, and still hold governance authority in March based on stale alignment data.
The first instinct was simple time-based decay: lose X points per day inactive. But this felt wrong for high-performing members. Someone who had played 200 games and maintained 95% alignment shouldn't be punished the same as someone who played 5 games and hit 30%.
The design drew from the Diablo-style difficulty curve concept already in the codebase (increment_sync_score_v2) — the idea that the game should get harder as you improve. The decay system inverted this: the game gets more forgiving as you improve. High scores earned through sustained play become durable because the player has demonstrated genuine alignment.
The quadratic vulnerability curve was chosen specifically because it creates a steep cliff at low scores and a gentle plateau at high scores. A 30% score (0.91 vulnerability) decays almost at full rate — this player hasn't demonstrated alignment, so their score should return to baseline quickly. A 95% score (0.10 vulnerability) barely decays — this player has proven alignment over many games, and a vacation shouldn't erase that.
The 7-day grace period came from a practical insight: most engaged members play at least weekly. The decay system should only activate for genuinely inactive members, not punish someone who plays every Saturday. The 14-day acceleration scale means it takes 3 weeks of total inactivity to reach full decay rate — giving members a reasonable window to return before their score erodes meaningfully.
The score floor of 10 (not 0) was chosen because a score of 0 could be confused with "never played." A floor of 10 signals "this player existed but their alignment data has expired."
Key files:
- src/lib/decay/decay-service.ts — TypeScript decay functions
- migrations/007_sync_score_decay.sql — pg_cron setup and SQL functions
- src/app/api/admin/decay/route.ts — admin config management