"""Was das Ähnlichkeits-Gate von Jikan wirklich durchlässt — gemessen. Hintergrund (26.07.2026): Der SAVEPOINT v3.16 vermutete, das Gate 0,55 sei „großzügig" und Jikan stehe in der Metadaten-Kette zu früh (vor OMDb). Beides war nachrechenbar, weil `titel_aehnlichkeit` eine reine Funktion ist — und die Rechnung ergab ein anderes Bild als die Vermutung: - Für kurze Kinofilm-Titel ist das Gate WIRKLICH zu locker (Alien → 0,83). - Für den Fall, für den Jikan eingebaut wurde, ist es sogar zu STRENG („Evangelion 2.22" gegen den MAL-Titel → 0,51, fällt durch). Eine einzelne Zahl kann also beides nicht leisten. Die Folge steht in prescan._scan_video: „exakt schlägt unscharf" statt „erster gewinnt". Die Anime-Titel unten existieren auf MyAnimeList; die Zahlen sind ausgerechnet, nicht geschätzt. MyAnimeList selbst war bei dieser Messung nicht erreichbar (Jikan antwortete durchweg HTTP 504) — die Live-Abfrage steht damit weiter aus, die Arithmetik des Gates ist davon aber unberührt. """ from clients.jikan import JikanClient, titel_aehnlichkeit def test_kurze_kinofilm_titel_reissen_das_gate_0_55(): """Diese vier würden ohne die Änderung Anime-Metadaten bekommen, obwohl OMDb die Filme kennt — es wurde nur nie gefragt.""" faelle = [ ("Alien", "Alien 9", 0.83), ("Inception", "Deception", 0.78), ("Hero", "Heroman", 0.73), ("The Dark Knight", "Dark Knight Rises", 0.69), ] for disc, anime, erwartet in faelle: score = titel_aehnlichkeit(disc, anime) assert round(score, 2) == erwartet, f"{disc} vs {anime}: {score}" # ... liegt über dem Gate (Jikan gibt also einen Treffer zurück) ... assert score >= JikanClient.MINDEST_AEHNLICHKEIT # ... aber unter „sicher", darf die Kette also nicht beenden. assert score < JikanClient.SICHER_AEHNLICHKEIT def test_echter_treffer_gilt_weiter_als_sicher(): """Exakter Titel → 1,0. Der Normalfall eines echten Anime-Fundes darf durch die Verschärfung NICHT verlorengehen (AGENTS Regel B).""" assert titel_aehnlichkeit("Monster", "Monster") == 1.0 assert titel_aehnlichkeit("Cowboy Bebop", "COWBOY BEBOP") == 1.0 # Interpunktion und Kleinschreibung sind egal — norm() wirft sie weg assert titel_aehnlichkeit("Akira", "AKIRA!") == 1.0 for a, b in (("Monster", "Monster"), ("Akira", "AKIRA!")): assert titel_aehnlichkeit(a, b) >= JikanClient.SICHER_AEHNLICHKEIT def test_untertitel_zaehlt_noch_als_sicher_genug(): """Discs tragen oft den Kurztitel, MAL den vollen. Das muss ein sicherer Treffer bleiben, sonst hilft die Quelle bei Anime nicht mehr.""" assert titel_aehnlichkeit("Steins Gate", "Steins;Gate") >= JikanClient.SICHER_AEHNLICHKEIT def test_der_fall_fuer_den_jikan_gebaut_wurde_faellt_heute_durch(): """Gegenbeweis zur Vermutung „das Gate ist zu großzügig": Für Evangelion 2.22 ist es zu STRENG. Der Wert ist dokumentiert, damit ein späteres Anheben des Gates nicht unbemerkt auch diesen Fall killt.""" score = titel_aehnlichkeit( "Evangelion 2.22", "Evangelion: 2.0 You Can (Not) Advance" ) assert round(score, 2) == 0.51 assert score < JikanClient.MINDEST_AEHNLICHKEIT def test_voellig_anderer_titel_wird_verworfen(): score = titel_aehnlichkeit("Blade", "Blade of the Immortal") assert score < JikanClient.MINDEST_AEHNLICHKEIT def test_leere_titel_geben_null(): assert titel_aehnlichkeit("", "Monster") == 0.0 assert titel_aehnlichkeit("Monster", "") == 0.0 assert titel_aehnlichkeit("!!!", "???") == 0.0