PROTECTED CORE — local_fallback.py (extract_artist_name/_ILLUS_RE) is in the file list at docs/upstreaming/license-provenance.md §2. This issue is a finding + sizing only; any actual pattern-derived fix needs the absorption-protocol read/sign-off that doc requires before local_fallback.py is touched.
Finding (read-only investigation, 2026-07-23). extract_artist_name (called by both Stage C's artist_ocr extractor and the general narrowing fallback below) only recognizes an explicit "Illus."/"illus:" anchor before a name (_ILLUS_RE = re.compile(r"[il1]llus[.:]?\s*(...)")). That's the pre-8th-edition old-border credit-line convention. Modern-frame cards print the artist's bare name on the credit line with no anchor word at all — extract_artist_name structurally cannot match that shape, regardless of OCR quality.
Concrete case: card 83867 (Garruk, Caller of Beasts Emblem) — the owner independently read "Karl Kopinski" off the card face. Stage C's own artist_ocr_raw_text for this card is ':| battlefield, then shuffle your library.\nTe Kalk Kopinski* "AEE a! Ce gee\n' — the OCR genuinely captured the (garbled but recognizable) credit line — but artist_ocr_name is empty because no "Illus." anchor is present, so extract_artist_name returns None. Same story for card 151634 (Mirror Strike, artist Dave Dorman) except that card's Stage C extraction never ran at all (separate fetch_ok=False issue, not filed here) so it's unconfirmed whether the anchor gap alone would have blocked it too.
This cascades into a second, already-built consumer. local_calculate_verdicts.py's general-purpose fallback narrowing calculator (stage-d-fallback-v1, not lands-specific — it intersects border/artist/symbol sub-check survivors against a card's own name-narrowed candidate set, already running in production as of the 2026-07-23 pilot write) reads evidence.artist_ocr_name as one of its three sub-checks. When artist_ocr_name is empty, that sub-check contributes nothing. For all six of the owner's sample cards, stage-d-fallback-v1 ran and logged no-sub-check-evidence — border and symbol also came back empty for these six, but the artist sub-check was guaranteed empty by construction because none of these are old-border cards. The artist-OCR-to-identification wiring the owner asked about already exists and already runs — the gap is entirely upstream, in what extract_artist_name is even capable of recognizing.
Scale. Catalog-wide: 13,588 cards have a non-empty artist_ocr_name (out of 218k+ ImageEvidence rows) — almost certainly concentrated in old-border cards given the anchor requirement. Cheap to verify by cross-referencing against CanonicalPrintingMetadata.border_color/frame era in a follow-up, not done here to stay read-only/cheap.
Ask (scoping only, not built): a second, non-anchored bare-name recognition mode for artist_ocr — e.g. matching the credit-line crop's OCR text directly against the candidate set's own known artist names (fuzzy, same threshold discipline match_artist already uses) rather than requiring a textual anchor first. Needs the license-provenance read before landing since it touches protected core.
PROTECTED CORE —
local_fallback.py(extract_artist_name/_ILLUS_RE) is in the file list atdocs/upstreaming/license-provenance.md§2. This issue is a finding + sizing only; any actual pattern-derived fix needs the absorption-protocol read/sign-off that doc requires beforelocal_fallback.pyis touched.Finding (read-only investigation, 2026-07-23).
extract_artist_name(called by both Stage C'sartist_ocrextractor and the general narrowing fallback below) only recognizes an explicit"Illus."/"illus:"anchor before a name (_ILLUS_RE = re.compile(r"[il1]llus[.:]?\s*(...)")). That's the pre-8th-edition old-border credit-line convention. Modern-frame cards print the artist's bare name on the credit line with no anchor word at all —extract_artist_namestructurally cannot match that shape, regardless of OCR quality.Concrete case: card 83867 (Garruk, Caller of Beasts Emblem) — the owner independently read "Karl Kopinski" off the card face. Stage C's own
artist_ocr_raw_textfor this card is':| battlefield, then shuffle your library.\nTe Kalk Kopinski* "AEE a! Ce gee\n'— the OCR genuinely captured the (garbled but recognizable) credit line — butartist_ocr_nameis empty because no"Illus."anchor is present, soextract_artist_namereturnsNone. Same story for card 151634 (Mirror Strike, artist Dave Dorman) except that card's Stage C extraction never ran at all (separatefetch_ok=Falseissue, not filed here) so it's unconfirmed whether the anchor gap alone would have blocked it too.This cascades into a second, already-built consumer.
local_calculate_verdicts.py's general-purpose fallback narrowing calculator (stage-d-fallback-v1, not lands-specific — it intersects border/artist/symbol sub-check survivors against a card's own name-narrowed candidate set, already running in production as of the 2026-07-23 pilot write) readsevidence.artist_ocr_nameas one of its three sub-checks. Whenartist_ocr_nameis empty, that sub-check contributes nothing. For all six of the owner's sample cards,stage-d-fallback-v1ran and loggedno-sub-check-evidence— border and symbol also came back empty for these six, but the artist sub-check was guaranteed empty by construction because none of these are old-border cards. The artist-OCR-to-identification wiring the owner asked about already exists and already runs — the gap is entirely upstream, in whatextract_artist_nameis even capable of recognizing.Scale. Catalog-wide: 13,588 cards have a non-empty
artist_ocr_name(out of 218k+ImageEvidencerows) — almost certainly concentrated in old-border cards given the anchor requirement. Cheap to verify by cross-referencing againstCanonicalPrintingMetadata.border_color/frame era in a follow-up, not done here to stay read-only/cheap.Ask (scoping only, not built): a second, non-anchored bare-name recognition mode for
artist_ocr— e.g. matching the credit-line crop's OCR text directly against the candidate set's own known artist names (fuzzy, same threshold disciplinematch_artistalready uses) rather than requiring a textual anchor first. Needs the license-provenance read before landing since it touches protected core.