From e97c1fbbcc00a8e1dd8430ed468d18835fddb107 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Tue, 11 Aug 2026 14:40:33 +0200 Subject: [PATCH] fix: keep unsourceable files from matching homonyms --- scripts/common.py | 15 ++++++++++++--- tests/test_e2e.py | 26 ++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/scripts/common.py b/scripts/common.py index 26502c7e..32405737 100644 --- a/scripts/common.py +++ b/scripts/common.py @@ -680,7 +680,16 @@ def resolve_local_file( file_entry, files_db.get(match_sha1, {}).get("size") ) - if not has_strong_hash: + # An entry the profile documents as unsourceable is one the collection + # cannot hold: a font that only exists inside a paid package, cheat codes + # written per title. A file answering to its name is therefore a homonym + # from another system, not a stale dump of the same file - kanji.rom names + # an FPseNG font, an openMSX one and a 3DO ROM. Content still decides: the + # hash and path steps above run first, so collecting the real bytes makes + # the entry resolve. + unsourceable = bool(file_entry.get("unsourceable")) + + if not has_strong_hash and not unsourceable: candidates = [] for try_name in names_to_try: for match_sha1 in by_name.get(try_name, []): @@ -751,7 +760,7 @@ def resolve_local_file( primary = [p for p, _ in valid if "/.variants/" not in p] return (primary[0] if primary else valid[0][0]), "hash_mismatch" # No candidate contains the zipped_file -fall through to step 5 - else: + elif not unsourceable: primary = [p for p, _ in candidates if "/.variants/" not in p] return (primary[0] if primary else candidates[0][0]), "hash_mismatch" @@ -853,7 +862,7 @@ def resolve_local_file( return candidate, status data_dir_mismatch = data_dir_mismatch or candidate - if data_dir_mismatch: + if data_dir_mismatch and not unsourceable: return data_dir_mismatch, "hash_mismatch" # Agnostic fallback: for filename-agnostic files, find any DB file diff --git a/tests/test_e2e.py b/tests/test_e2e.py index caa6efaf..85d23e64 100644 --- a/tests/test_e2e.py +++ b/tests/test_e2e.py @@ -793,6 +793,32 @@ class TestE2E(unittest.TestCase): path, status = resolve_local_file(entry, self.db) self.assertEqual(status, "hash_mismatch") + def test_07b_resolve_unsourceable_ignores_homonym(self): + """An unsourceable entry takes content, never a file of the same name.""" + entry = { + "name": "wrong_hash.bin", + "md5": "ffffffffffffffffffffffffffffffff", + "unsourceable": "ships inside a paid application package", + } + path, status = resolve_local_file(entry, self.db) + self.assertIsNone(path) + self.assertEqual(status, "not_found") + + entry = {"name": "no_md5.bin", "unsourceable": "written per title"} + path, status = resolve_local_file(entry, self.db) + self.assertIsNone(path) + self.assertEqual(status, "not_found") + + # Collecting the real bytes still resolves it. + entry = { + "name": "present_req.bin", + "sha1": self.files["present_req.bin"]["sha1"], + "unsourceable": "ships inside a paid application package", + } + path, status = resolve_local_file(entry, self.db) + self.assertEqual(status, "sha1_exact") + self.assertIn("present_req.bin", path) + def test_08_resolve_variants_deprioritized(self): entry = {"name": "present_req.bin"} path, status = resolve_local_file(entry, self.db)