[Unit] Description=Fold client-reported outcomes into proficiency twice a day [Timer] OnBootSec=30min OnUnitActiveSec=12h # 12h, which is neither the poller's 2h nor the seed sweep's 6h, because the # quantity being tracked moves differently. The fold is exactly additive -- # add_outcome keeps a running mean and recompute_category re-derives each row # from the stored components -- so ten folds of five samples land on the same # numbers as one fold of fifty. Cadence therefore cannot change WHERE the # scores end up, only how long routing spends on stale ones and how large each # irreversible batch is. # # Measured on the live DB (2026-09-15): attributable client outcomes arrive at # 50-300/day (bursty; 1/day idle, 324/day under heavy dogfooding). At 12h a run # folds roughly 25-150 samples -- the same order as the 404-sample backlog that # prompted this unit, so a run stays a reviewable batch rather than a stream of # micro-updates, while staleness is capped at half a day instead of the 5 days # observed with no timer at all. # # No Persistent=true. It reads as catch-up insurance but systemd.timer(5) is # explicit that it "only has an effect on timers configured with OnCalendar=", # and this timer is monotonic. OnBootSec above is the actual catch-up: a machine # that was off through a scheduled window folds 30 minutes after it comes back. # The sibling poller and seed timers carry the same inert line -- left alone # here rather than fixed in passing, but it buys them nothing either. [Install] WantedBy=timers.target