Issuance Explorer¶
The page at /admin/issuance-explorer is a read-only inspect tool. Pick a
match, filter by status (published / blocked / all) and period / phase,
then click a published issuance to see why that definition issued, the
At play settings and pinned definition snapshot, and how it later
resolved — or a blocked attempt to see which gate stopped a trigger that
did not publish.
It does not show live league / group / definition settings. Use Question Inheritance for the current inheritance model (live-only). At play and the pinned snapshot are the historical settings path.
This page does not write.
Data source¶
The admin page is a thin HTML shell. Alpine.js loads:
- Matches via
GET /api/matches(any status for the selected local day) - Inspect payload via
GET /api/matches/{id}/question-inheritance - In-game operational fields via
GET /api/matches/{id}/question-issuances(joined by issuance id) - Blocked in-game attempts via
GET /api/matches/{id}/question-issuance-denials(joined by denial id) - Match questions via
GET /api/matches/{id}(match_question_issuances, joined by issuance id)
Optional query on the inspect API: kind=in_game|match. The inspect API still
accepts definition_id (filters traces); the admin UI does not send it.
Deep-link: ?league=&day=&match_id=&kind=&status=&period=&issuance_id=&denial_id=.
period= is a stamped label. Omit it for All.
Match detail links here with match only (league, day, match_id — no
issuance_id). /admin/question-inheritance?issuance_id= redirects here.
How to read it¶
| Panel | Meaning |
|---|---|
| Event timeline | Optional. Collapsed until Show timeline. Scatter of stream events, correctives, blocked attempts, and issue / resolve markers (named Y lanes + legend). Subtle vertical lines mark period / phase changes (from stream events when ingested, otherwise from issuances / blocked rows). Hover a marker for event type, period / phase, situation, and clock (extracted stamps; not the full payload). Drag a time range to zoom; slider / wheel to pan; reset icon for the full match. Times use the browser timezone. Stream / corrective dots need ingest. Hide timeline collapses without refetching. Changing match resets the panel. |
| Match issuances | Starting point. Left list is play order after Published / Blocked / All (in-game) and period / phase filters. # is the match’s published issuance sequence (blocked rows have no number). Published rows show the winning definition and its question group. Blocked titles are event + closed gate + how many definitions triggered (for example atbat · Group · 14 triggered), or the picked definition when probability / pending stopped a selection. A pivotal badge marks in-game issuances whose pinned snapshot is a pivotal moment. Click a published row for identity, At play, snapshot, selection, other definitions, and resolution. Click a blocked row for the stored short-circuit path (no At play / resolution). |
| Identity | Short issuance id (copy full UUID), question sponsor pill when the issuance claimed a slot (Match questions use the match sponsor), issued/resolved times, P/R period labels, situation / clock when stamped, per-issuance answer metrics (in-game only). Resolved opens the resolution modal. Eye icon opens the current definition editor. |
| At play | In-game question_settings_snapshot frozen at issue time (effective / override / league default). Historical — not live Question inheritance. |
| Definition snapshot | Pinned definition_snapshot at issue time as a Setting / Value table (copy JSON for the Question Definitions editor). Legacy rows without a snapshot do not fall back to the live definition body. |
| Selection path + table | Same listener check order, compact on desktop. passed kept this definition in; blocked would have stopped it; skipped did not apply. Caps show as used / cap. Each Check has a ? for what that gate does; Detail is this issuance’s replay. |
Match issuances¶
Published traces are DB-only. They do not replay S3 listener archives.
Blocked attempts are compact listener rows (question_issuance_denials)
written going forward when a definition trigger matched and nothing
published. Matches whose listener ran before this shipped have none.
- Winner (accurate): trigger match on the stored issuance event; listener
gate order using the pinned
definition_snapshotand play-timequestion_settings_snapshot; resolution reason and correct choices from the stored issuance (snapshot conditions, not the live definition if they later diverged). - Resolution is later: the question already published; resolution is how it closed. A blocked replay check does not retract it. Resolved opens condition evaluations and event fields (same chrome as History).
- Published vs replay: the list is published questions. If Selection shows blocked on that winner, replay of stored caps/history would have stopped it (for example a second pivotal in the same period after one already used the slot). That is not “it never issued.”
- Other definitions (approximate): same event and prior-issuance history. Prefer that definition’s latest earlier snapshot on this match; otherwise the live row (labeled as such). First failing step only.
- Not reconstructed on published rows: probability roll, false-streak / dynamic-weight in-memory counters, exact weighted winner among a pool. After eligibility the copy is “in the selection pool; this issuance is the one that published.” Probability skips are stored on blocked attempts.
- Blocked attempts: one row per event where at least one trigger matched
and nothing published (caps, group, match-wide subject uniqueness, probability skip,
pending slot occupied). Silent “no trigger matched” events are not stored.
The list name is event + gate + trigger count unless the listener had
already picked a definition (
probability/pending_occupied) — then it shows that definition. Do not read a group-blockedatbatrow as “this one question definition kept retrying”; many defs can trigger on the same event. The detail pane lists Triggered definitions for those no-pick rows (fulltriggeredlist). The Selection path stays the same gates; Group / Pivotal / cap / Subject Detail and Used name the sub-check and numbers whendetailsis present (for example waited 97s of 300s, or subject id + period). Older rows keep a generic reason. The listener also writes one compactBlocked attemptINFO line with that same reason. - Legacy rows without a snapshot fall back to the live definition for selection replay only; the identity pane does not reconstruct name/text from the live row.
Match questions use a thinner trace (Beat/API issued + lock/resolve). No listener selection pool, At play table, or in-game answer metrics.
The eye icon next to the winning definition name opens the current QD / MQD editor row. The pinned snapshot below is historical (Setting / Value table, same chrome as At play) and is not that live editor. This page does not deeplink a selected issuance into Question inheritance (that tool is live config, not this issuance’s play-time settings).
Workflow¶
- Open Manage → Issuance Explorer, or Issuance Explorer on match detail (metrics column).
- Pick a league, local day (defaults to yesterday), and match.
The match option uses
AdminMatches.optionLabel(aliases, local scheduled time, TEST whenis_test, then shortcode — notsr_id). - Optionally open Event timeline (Show timeline) for stream / issuance markers on the selected match (on demand; not loaded with the page).
- On Match issuances, toggle In-game vs Match Questions. For in-game, filter Published / Blocked / All. Filter period / phase with All (default) or a stamped label.
- Click a published issuance (the list shows which definition won) to read identity, At play / snapshot, the selection path, other definitions, and resolution. Click a blocked row for the gate that stopped the pass. A group / cap miss lists who triggered; a probability / pending miss names the picked definition. Group / Pivotal / cap / Subject Detail names the sub-check and numbers when stored; older rows stay generic.
Code map¶
| Concern | Location |
|---|---|
| REST inspect | GET /api/matches/{id}/question-inheritance |
| Blocked attempts | GET /api/matches/{id}/question-issuance-denials |
| In-game issuances | GET /api/matches/{id}/question-issuances |
| Match questions | GET /api/matches/{id} (match_question_issuances) |
| Ops + schemas | src/lib/question_inheritance/ |
| Admin HTML shell | src/api/admin/routes/issuance_explorer.py |
| Template | src/api/admin/templates/issuance_explorer/index.jinja2 |
| Alpine app | src/api/admin/static/js/issuance_explorer_app.js |
| Timeline chart | src/api/admin/static/js/issuance_explorer_timeline.js (ECharts on demand) |
| Timeline JSON | GET /api/matches/{id}/event-timeline |
| CSS | src/api/admin/static/css/question_inheritance.css |
| Tests | src/api/tests/admin/test_issuance_explorer.py, src/api/tests/test_match_event_timeline.py |