Ambiguous card name handling #4

Open
opened 2026-08-16 11:38:54 -05:00 by pyaniz · 1 comment
Owner

If the name of a card is ambiguous offer back a list of the top 10 cards with that name. Clicking on the name of the card returns the card to the chat.

In the inline chat, wait 2 seconds before starting the search for a card name. Offer the cards in a list inline similar to printings.

If the name of a card is ambiguous offer back a list of the top 10 cards with that name. Clicking on the name of the card returns the card to the chat. In the inline chat, wait 2 seconds before starting the search for a card name. Offer the cards in a list inline similar to printings.
Author
Owner

Implemented in 373baa1, with follow-up fixes in 9165d71.

Ambiguous names offer a choice

[[bolt]] now returns the closest ten as buttons; tapping one posts that card.

Card names reach 141 characters — there is a real card called "Our Market Research Shows That Players Like Really Long Card Names So We Made this Card…" — while callback_data is capped at 64 bytes, so a button cannot carry a name. The candidate list is cached under a short token and each button carries only that token plus an index, about 15 bytes. The cache is in memory and short-lived; an expired token answers with an explanation rather than failing silently.

Worth knowing: Scryfall returns 404 both for an ambiguous name and for one matching nothing, and only the detail text distinguishes them. So [[bolt]] offers choices while [[zzzznotacard]] still just says no card found.

Inline mode is a list

Card search now returns article results, so every mode renders as a readable list rather than a grid of near-identical card images. The art still arrives with the message as a link preview.

Debounce

Inline searches wait INLINE_DEBOUNCE_SECONDS (2 by default) and drop any query the typist has already superseded, so "lightning bolt" costs one search instead of fourteen. Configurable from the environment; set it to 0 to search on every keystroke.

Implementation note: the inline handler had to be registered non-blocking, because python-telegram-bot processes updates sequentially by default and a 2-second wait would otherwise stall every other user's messages behind it.

Follow-ups from testing

Making the results a list exposed two things that a thumbnail grid had hidden.

Non-cards were being returned. Searching lightning resolved to a card literally named "Lightning" — a Jumpstart front card (layout: front_card, set_type: memorabilia) — and it took the top slot. Printings were worse: Lightning Bolt listed 71, of which nine were oversized gold-bordered display pieces. Tokens, emblems, art series, front cards, memorabilia and oversized items are now excluded from search, printings and name lookup alike.

Ordering ignored what was typed. Scryfall sorts alphabetically, so lightning led with Arc Lightning and Ball Lightning while the forty-one cards beginning with the word came later. Results now rank exact name, then starts-with, then a matching face of a split card, then a word match:

lightning  ->  Lightning Angel, Lightning Axe, Lightning Berserker, Lightning Blast
goblin     ->  Goblin Airbrusher, Goblin Anarchomancer, Goblin Archaeologist
sol        ->  Sol Grail, Sol Ring, Sol Talisman, Sol'kanar the Swamp King

Scryfall search syntax is unaffected — t:instant c:r cmc=1 still behaves as a real search, since prefix ranking applies only to plain-name queries.

Left open

Leaving this open until it has been used in the group. The 2-second debounce in particular feels different in real typing than in a test, and it can be retuned from the environment without a rebuild.

Implemented in `373baa1`, with follow-up fixes in `9165d71`. ### Ambiguous names offer a choice `[[bolt]]` now returns the closest ten as buttons; tapping one posts that card. Card names reach 141 characters — there is a real card called *"Our Market Research Shows That Players Like Really Long Card Names So We Made this Card…"* — while `callback_data` is capped at 64 bytes, so a button cannot carry a name. The candidate list is cached under a short token and each button carries only that token plus an index, about 15 bytes. The cache is in memory and short-lived; an expired token answers with an explanation rather than failing silently. Worth knowing: Scryfall returns 404 both for an ambiguous name and for one matching nothing, and only the detail text distinguishes them. So `[[bolt]]` offers choices while `[[zzzznotacard]]` still just says no card found. ### Inline mode is a list Card search now returns article results, so every mode renders as a readable list rather than a grid of near-identical card images. The art still arrives with the message as a link preview. ### Debounce Inline searches wait `INLINE_DEBOUNCE_SECONDS` (2 by default) and drop any query the typist has already superseded, so "lightning bolt" costs one search instead of fourteen. Configurable from the environment; set it to 0 to search on every keystroke. Implementation note: the inline handler had to be registered non-blocking, because python-telegram-bot processes updates sequentially by default and a 2-second wait would otherwise stall every other user's messages behind it. ### Follow-ups from testing Making the results a list exposed two things that a thumbnail grid had hidden. **Non-cards were being returned.** Searching `lightning` resolved to a card literally named "Lightning" — a Jumpstart front card (`layout: front_card`, `set_type: memorabilia`) — and it took the top slot. Printings were worse: Lightning Bolt listed 71, of which nine were oversized gold-bordered display pieces. Tokens, emblems, art series, front cards, memorabilia and oversized items are now excluded from search, printings and name lookup alike. **Ordering ignored what was typed.** Scryfall sorts alphabetically, so `lightning` led with Arc Lightning and Ball Lightning while the forty-one cards beginning with the word came later. Results now rank exact name, then starts-with, then a matching face of a split card, then a word match: ``` lightning -> Lightning Angel, Lightning Axe, Lightning Berserker, Lightning Blast goblin -> Goblin Airbrusher, Goblin Anarchomancer, Goblin Archaeologist sol -> Sol Grail, Sol Ring, Sol Talisman, Sol'kanar the Swamp King ``` Scryfall search syntax is unaffected — `t:instant c:r cmc=1` still behaves as a real search, since prefix ranking applies only to plain-name queries. ### Left open Leaving this open until it has been used in the group. The 2-second debounce in particular feels different in real typing than in a test, and it can be retuned from the environment without a rebuild.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
pyaniz/mtg-bot#4
No description provided.