-
normalize_series — Lowercase, strip volume suffixes, collapse non-alphanumeric runs.
-
s_series — Series-name similarity via rapidfuzz
WRatio, normalized. -
s_issue — Issue number match. Integer-equal first; fall back to string-equal.
-
s_year — Year match with smooth decay beyond the original 1.0/0.7/0.4 anchors.
-
s_publisher — Score publisher equality after normalization.
-
s_pages — Page-count match: 1 if equal, 0.7 within 10%, 0.3 within 25%, else 0.
comicbox.formats.base.online.signals¶
source module comicbox.formats.base.online.signals
Per-signal scoring functions for the matcher.
Each s_* returns a value in [0, 1]. Missing inputs are treated as “uncertain, partial credit” rather than “definitely wrong” so a candidate isn’t penalised for the comic being thin on metadata.
The cover-hash signal lives in cover_hash.py (M4); this module only covers metadata signals.
Functions
source normalize_series(name: str) → str
Lowercase, strip volume suffixes, collapse non-alphanumeric runs.
source s_series(profile: ComicProfile, candidate: Candidate) → float
Series-name similarity via rapidfuzz WRatio, normalized.
source s_issue(profile: ComicProfile, candidate: Candidate) → float
Issue number match. Integer-equal first; fall back to string-equal.
source s_year(profile: ComicProfile, candidate: Candidate) → float
Year match with smooth decay beyond the original 1.0/0.7/0.4 anchors.
- 1.0 on exact match
- 0.7 at ±1 year
- 0.4 at ±2 years
- Linear decay from 0.4 (diff=2) to 0.0 (diff=7) — Phase F
- 0.0 for diff ≥ 7
Missing-data handling distinguishes two cases
- both missing: 0.5 (weak agnostic prior — we have no signal)
- asymmetric (one side has year, other doesn’t): 0.3 (the previous 0.6 over-credited unknown candidates and let wrong-volume picks coast through the auto-write band when CV’s BasicIssue lacked a cover_date)
Phase F (2026-05-14) replaced the original cliff (0.0 for any diff ≥ 3) with linear decay. The cliff treated modern reissues of older series as having no year signal at all — fine for the common case where year discriminates between volumes, but bad when the right candidate IS the same series at a different year (e.g. The Boys 2009 fixture’s expected vol was at year=2006, gap of 3 years). Smooth decay gives the older candidate ~75% of the one-year-off signal, enough to compete with cover-hash signal when present. Beyond 7 years, the score still hits zero — the long tail of 20+ year reissues (Conan 1973 vs 2025) shouldn’t benefit from year signal.
See tasks/online-tagging/calibration-notes/2026-05-14-bigmedia-247.md for the failure-mode analysis that motivated this change.
source s_publisher(profile: ComicProfile, candidate: Candidate) → float
Score publisher equality after normalization.
source s_pages(profile: ComicProfile, candidate: Candidate) → float
Page-count match: 1 if equal, 0.7 within 10%, 0.3 within 25%, else 0.