Match question issuance & resolution¶
Match questions are the pre-game pick — usually “Who will win the match?” They are not the in-game props the listener fires during play.
Players see them on Live (/play) with a Match question badge. There is
no 60-second countdown. They do not count toward in-game max / period
caps.
Author templates in Manage → Match Questions (folders are organization
only; they do not change issuance). Cap, allowlist, earliest
issue, and resolution grace live on League Defaults
and per-match on Matches. A match null allowlist
inherits the league list; a non-null list is pinned. Editor walkthrough:
Match question definition editor.
In-game props: Question definitions.
flowchart LR
issue[Appear before first play] --> lock[Lock when play starts]
lock --> pending[Pending in Recent answers]
pending --> official[Official result]
official --> scored[Scored]
official --> stale[Award-all if still stuck]
What players see¶
- Open — the question shows in the main Live column. The player can change their pick until play starts.
- Locked — first live play (or the match going in-progress) freezes the answer. Live drops it from the open column and, if they answered, it shows under Recent answers as Pending.
- Scored — after the game is official, the pick is marked right or wrong and points land. If we never get a usable official result, everyone who answered still gets the points for their choice, without a correct/incorrect mark.
Following a match does not create a second copy. One question is shared; follow only controls who can see and answer it.
When it appears on a match¶
A background job (every minute) plus match refresh, follow, clone, and settings saves all try to put Match questions on upcoming games.
They appear when all of these are true:
- The match is still pre-start (not locked, not already showing in-game questions).
- Scheduled start is within the earliest-issue window (league default
15 minutes before
scheduled;0means as soon as the match exists). - There is an active definition allowed by the league/match allowlist, and the match is under Match Questions max (default 1).
They will not appear on a game that already has in-game questions — that means play started, even if status is still messy. A listener starting ~10 minutes before first pitch does not block them by itself.
Rain delay before first play: they can still issue. Rain delay after first play: already locked; no new ones.
Editing a definition later does not rewrite questions already on a match. Lowering the cap later does not retract ones already issued.
Lock¶
Answers lock once, when any of these happen:
- Match status is in-progress or the game is over
- A live stream event arrives (pitch, at-bat, period start, goal, …)
- In-game questions already exist on the match
Delayed pre-start stays unlocked. After lock, changing the pick returns an error (HTTP 410).
How it resolves¶
Most definitions (including Who will win) wait until the game is over. They do not conclude from a mid-game event — a 5–2 score in the 7th is not official.
When the match first looks finished, we fetch the named resolution source (default game summary) and check each choice’s “this option is correct when…” condition. For a winner question that is “did home win?” / “did away win?” using the official home/away scores.
If the payload is missing or still unclear, we keep waiting for
resolution grace (default 15 minutes), then award-all: everyone
who answered gets their choice’s points, is_correct left blank.
Postpone / cancel / unnecessary skip the wait and award-all immediately,
stamping resolution_reason to that match status (postponed, cancelled,
or unnecessary). A makeup game is a new match with its own Match
questions. Complete/closed leftovers after grace stay stale.
A definition can close early from the live stream if you add stream triggers. The stock winner question does not. We do not keep running totals in listener memory for these.
MLB fetches Sportradar Game Summary / Game Boxscore. NFL fetches
Game Boxscore for both game_summary and game_boxscore source keys (NFL
Official has no Game Summary feed; scores are summary.home.points /
summary.away.points). Other leagues still issue and lock; at game end they
sit through grace and then award-all until those fetchers exist.
Sponsorship is the match’s brand only (no per-question slots). Live
WebSocket still notifies. Issuance and resolve push notifications use the same
device cooldown and per-match caps as in-game questions (pivotal_only
does not suppress Match question issuance). Resolve push goes to
followers who answered, only when the close reason is resolved (not
stale / postpone / cancel).
What you configure¶
| Setting | Where | Typical |
|---|---|---|
| Which templates exist | Manage → Match Questions | One active “Who will win” |
| How many per match | League Defaults / match override | 1 |
| Which templates are allowed | Same (null = all active, [] = none) |
All active |
| How early they may appear | Earliest issue (seconds before start) | 900 (15 min) |
| How long to wait after the game for an official result | Resolution grace | 900 (15 min) |
| Points | Same hierarchy as in-game: definition override → match → league default 5. A choice can further override. |
Points are whole numbers only. Award-all still pays the stamped points for the selected choice.
Who will win (the usual case)¶
Player copy is “Who will win the match?” Choices are the two team names (filled in from the match’s home/away teams). Correct when the official summary says that side won. No mid-game close.
Until summary scores are conclusive, the row stays Pending through grace, then award-all.
If something looks wrong¶
| What you see | Likely cause |
|---|---|
| No Match question on a future game | Outside the 15-minute window, allowlist empty, definition archived, or already at cap |
| No Match question on a live game | Expected — we do not issue after play has started |
| Question still in the Live open column after first play | Refresh Live; locked questions belong under Recent answers |
| Pending forever after the game | Official fetch failed or scores not in the payload yet; after grace it should award-all. Beat retries about every 5 minutes |
| Everyone got points, nobody right/wrong | Award-all (grace elapsed → stale; postpone/cancel/unnecessary → that status as reason; or no matching official result) |
Old scheduled games getting new Match questions |
Should not happen once play has started (in-game questions exist). Refresh will also refuse to reopen a finished or in-progress game as scheduled |
| NHL winner never “resolves,” then award-all | Official REST is MLB and NFL today; NHL still award-alls after grace |
Issued rows are on the match detail page (match_question_issuances).
For developers¶
Play kind is "match" (in-game is "in_game"). Tables are
match_question_*. GET /api/question-answers/open still includes locked
Match questions (answer_locked=true) so other clients can show a frozen
pick; /play hides them from the open column.
Issue: src/lib/match_question_issuances/ops.py (Beat
ensure_upcoming_match_questions, 1 min). Lock:
lock.py. Official fetch: official_result.py. End-of-game / award-all:
stale_settlement.py (also from sweep_stale_issuances, 5 min). Scoring:
src/listener/lib/stages/match_question_evaluation.py.