Same hourly tick. On a named hour from POST_HOURS_UTC the slot posts MATCHUPS_PER_SLOT matchups together — three, at 9am — and then refuses until they close. A matchup closes when the next posting hour comes round rather than a fixed span after it went up, so with one hour a day that is a full day of voting, and a post made off-schedule still hands its slot back on time. The cap counts what is open rather than what went out, so a batch that failed to close is topped back up rather than stacked on. Pair selection:
- 01Any dish with
first_matchup_id IS NULL jumps the queue, oldest first, so new dishes are guaranteed a slot. - 02Otherwise take the least-played dish, ties broken randomly.
- 03Opponent comes from a 150-point Elo band, excluding any pair seen in the last 20 matchups. Close matchups are tense matchups.
- 04Every fifth matchup is a deliberate wide-gap pair. Upsets make the best results.
- 05Fall back to the nearest rating, then to any dish, rather than skipping a day.
The row is inserted first so the matchup id can go in the image URL path — that is what makes Discord's proxy treat each card as a new image instead of serving a stale one.
The batch lives in two threads. Five cards in the morning and five results the next morning is ten bot posts a day in a channel that exists for people to post their dinner in, so the batch goes out as one message — "Cooking — Thu 3 Sep", with when voting closes — that opens a thread with the cards inside, and the results open "Results — Thu 3 Sep" the same way a day later. The channel sees two posts a day. Bonuses, ranking rounds and the caption contest are one post each and stay on the channel floor.
Sides are randomized, and the post never pings. A ping would correlate with new dishes entering the pool, and position 1 would otherwise always be the newer plate.
The morning's posts are cooking and nothing else. Drinks used to share them, and because both halves of a pair have to match category, that meant the 9am post was a food matchup only when the draw happened to land on food — at a rate nobody chose. Drinks, places and people each got a slot of their own instead.
Three a morning rather than two a day is a decision about the backlog. 577 food photographs, 539 never on the board, refilling at about one a day — and the Wednesday five comes out of the same pool. Two matchups a day spends 4.7 photographs and gains one, so the unplayed pile lasts about five months; three spends 6.7 and makes it three. Worth paying — at two a day a photograph gets 1.9 outings a year and a rating built on that is noise. Nothing runs out either way, because the draw orders by play count and an empty backlog just means a second lap.
Thursday is the placement round: up to five photographs from the last fortnight that nobody has voted on, ranked on one card. The rotation does put unplayed photographs first, which is not the same as putting new ones first — 539 of them are unplayed and the pick among them is random, so something posted on Tuesday joins the back of a queue three months deep. This does not change how fast the pool is spent, only the order, and the order is the point. Below three new photographs it posts a pair instead; below one it posts nothing and leaves the slot for the next tick.
How often the drink slot fires is computed rather than configured, because a fixed weekly day is wrong in both directions — six drinks and it shows the same two every month, eighty and it never gets through them. It aims at a constant sweep: the time for every drink to reach the board once. Two drinks a matchup, a four-week sweep, so about one post a week per eight drinks, clamped between weekly and daily.