diff --git a/tests/test_doc_pages.py b/tests/test_doc_pages.py index 57a285f1..27487bbf 100644 --- a/tests/test_doc_pages.py +++ b/tests/test_doc_pages.py @@ -559,5 +559,27 @@ class RegistryKeysDocumented(unittest.TestCase): self.assertNotIn("belongs to the platform\nYAML", section) +class ResolutionSkipsNamesForUnheldFiles(unittest.TestCase): + """The resolution table promised name_exact to any entry without a hash, + while an unsourceable entry, or one whose indexed path is absent from + disk, skips every step that answers by name and returns not_found.""" + + def test_the_page_names_both_cases_the_code_guards(self): + import common + + source = inspect.getsource(common.resolve_local_file) + self.assertIn('unsourceable = bool(file_entry.get("unsourceable")) or own_file_absent', source) + for guard in ( + "if not has_strong_hash and not unsourceable:", + "elif not unsourceable:", + "if _depth < 3 and not has_strong_hash and not unsourceable:", + "if data_dir_registry and (has_strong_hash or not unsourceable):", + ): + self.assertIn(guard, source) + section = _section(_page("verification-modes.md"), "File resolution chain") + self.assertIn("`unsourceable:`", section) + self.assertIn("restore_large_files.py", section) + + if __name__ == "__main__": unittest.main() diff --git a/wiki/verification-modes.md b/wiki/verification-modes.md index 3990eda5..efaee1fe 100644 --- a/wiki/verification-modes.md +++ b/wiki/verification-modes.md @@ -274,6 +274,20 @@ evidence-compatible match: If no step matches, the result is `(None, "not_found")`. +Two kinds of entry skip every answer given by a name alone: steps 6 and 9, the +`hash_mismatch` of step 7, and the name lookup of step 10 when no hash is declared. + +- An entry whose profile carries `unsourceable:`. The collection cannot hold that + file, so a file answering to its name belongs to something else: `kanji.rom` + names an FPseNG font, an openMSX font and a 3DO ROM. +- An entry whose full destination path is in the `by_path_suffix` index while no + indexed copy is on disk. That file is a release asset the checkout has not + restored (`scripts/restore_large_files.py`), and another file of the same name + is not it. + +The content steps still apply to both, so collecting the real bytes, or restoring +the asset, makes the entry resolve. + The `hash_mismatch` status means a file with the right name or path exists but its hash does not match. This still resolves to a local path (the file is present), but verification will report it as UNTESTED with a reason string showing the expected vs actual hash prefix.