From be9036f2b2c66604b606081375c14955211ec79c Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Thu, 22 Oct 2026 05:46:09 +0200 Subject: [PATCH] feat: document the category of every entry Held entries carry their category and readers too, not only missing ones, so each platform page says which cores read every file it lists and where the code does it. Severity still applies to firmware gaps only. --- scripts/generate_site.py | 14 +++++++------- scripts/verify.py | 17 +++++++++-------- wiki/testing-guide.md | 2 +- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/scripts/generate_site.py b/scripts/generate_site.py index c8fd7e14..b474a54a 100644 --- a/scripts/generate_site.py +++ b/scripts/generate_site.py @@ -1993,14 +1993,14 @@ def _render_platform_systems( status_display = f"untested: {reason}" if reason else "untested" elif status == "missing": status_display = "**missing**" - # Not every missing entry is firmware: the platform may list a - # game's data or a file no core it runs opens. - kind = {"game_data": "game data", - "unread": "no core the platform runs opens it"}.get(f.get("category", "")) - if kind: - status_display += f", {kind}" else: status_display = status + # Not every entry is firmware: the platform may list a game's data + # or a file no core it runs opens. + kind = {"game_data": "game data", + "unread": "no core the platform runs opens it"}.get(f.get("category", "")) + if kind: + status_display += f", {kind}" size_str = _fmt_size(size) if size else "" details = [status_display] @@ -2033,7 +2033,7 @@ def _render_platform_systems( if sha256: hash_parts.append(f"SHA256: `{sha256}`") lines.append(f"{pad} {' | '.join(hash_parts)}") - if status == "missing" and f.get("category_evidence"): + if f.get("category_evidence"): lines.append(f"{pad} {_category_evidence_md(f['category_evidence'])}") lines.append("") diff --git a/scripts/verify.py b/scripts/verify.py index b34cdc62..97f6d06e 100644 --- a/scripts/verify.py +++ b/scripts/verify.py @@ -1192,8 +1192,8 @@ def verify_platform( file_status: dict[str, str] = {} file_required: dict[str, bool] = {} file_severity: dict[str, str] = {} - # What a missing entry is: firmware, a game's data, or a name no core - # the platform runs opens. Only firmware gaps carry a severity. + # What each entry is: firmware, a game's data, or a name no core the + # platform runs opens. Only firmware gaps carry a severity. file_category: dict[str, str] = {} categories = EntryCategories(config, profiles, data_dir_registry) @@ -1356,13 +1356,14 @@ def verify_platform( prev = file_status.get(dest) hle = hle_index.get(file_entry.get("name", ""), False) sev = compute_severity(cur, required, mode, hle) - if cur == Status.MISSING: - explained = categories.explain(file_entry, destination, sys_id) - category = explained.pop("category") - result["category_evidence"] = explained - else: - category = BIOS + explained = categories.explain(file_entry, destination, sys_id) + category = explained.pop("category") result["category"] = category + result["category_evidence"] = explained + if cur != Status.MISSING: + # A held entry is firmware for the counts: its category only + # documents it. + category = BIOS if file_category.get(dest, category) == BIOS: category = BIOS file_category[dest] = category diff --git a/wiki/testing-guide.md b/wiki/testing-guide.md index 61aeecdf..d5bfa9c6 100644 --- a/wiki/testing-guide.md +++ b/wiki/testing-guide.md @@ -39,7 +39,7 @@ Every module in `tests/`, by the area it guards. |------|----------|---------| | Core regression suites | synthetic | `test_e2e`, `test_audit_regressions`, `test_tool_messages` | | File resolution and identity | synthetic + collection | `test_adler32_resolution`, `test_agnostic_scan`, `test_agnostic_scan_mode`, `test_agnostic_scope`, `test_agnostic_substitute`, `test_archive_choice`, `test_bios_companions`, `test_bundled_identity`, `test_casefold_cache`, `test_db_aliases`, `test_declared_names`, `test_derivations`, `test_directory_entries`, `test_extra_identity`, `test_foreign_tree`, `test_foreign_tree_names`, `test_frontend_digest`, `test_game_data_homonyms`, `test_hashing`, `test_identity`, `test_md5_pack_context`, `test_name_tiebreak`, `test_nec_filing`, `test_owner_resolution`, `test_path_suffix`, `test_resolution_evidence`, `test_sega_filing`, `test_shipped_content`, `test_twin_declarations`, `test_validated_choice`, `test_variant_choice`, `test_variant_identity`, `test_zipped_member` | -| Verification, cross-reference and profile checks | synthetic + profiles | `test_case_insensitive_platforms`, `test_checks_have_values`, `test_core_file_fills_declaration`, `test_core_size_refusal`, `test_cross_reference_sources`, `test_crypto_aes`, `test_crypto_unique_data`, `test_crypto_verify`, `test_file_consumers`, `test_fileless_audit`, `test_flycast_layout`, `test_gap_settlement`, `test_hidden_extras`, `test_launcher_aliases`, `test_launcher_layer`, `test_native_mode`, `test_no_case_collisions`, `test_path_conflict_status`, `test_path_null_copies`, `test_profile_checks`, `test_profile_repositories`, `test_romm_hash_rule`, `test_shared_groups`, `test_standalone_links`, `test_standalone_mode`, `test_undeclared_dedup`, `test_unplaced_extras`, `test_validation_scope`, `test_verify_all_dir`, `test_verify_emulator_evidence`, `test_verify_listing`, `test_verify_pack_choice`, `test_verify_release_asset` | +| Verification, cross-reference and profile checks | synthetic + profiles | `test_case_insensitive_platforms`, `test_checks_have_values`, `test_core_file_fills_declaration`, `test_core_size_refusal`, `test_cross_reference_sources`, `test_crypto_aes`, `test_crypto_unique_data`, `test_crypto_verify`, `test_entry_categories`, `test_file_consumers`, `test_fileless_audit`, `test_flycast_layout`, `test_gap_settlement`, `test_hidden_extras`, `test_launcher_aliases`, `test_launcher_layer`, `test_native_mode`, `test_no_case_collisions`, `test_path_conflict_status`, `test_path_null_copies`, `test_profile_checks`, `test_profile_repositories`, `test_romm_hash_rule`, `test_shared_groups`, `test_standalone_links`, `test_standalone_mode`, `test_undeclared_dedup`, `test_unplaced_extras`, `test_validation_scope`, `test_verify_all_dir`, `test_verify_emulator_evidence`, `test_verify_listing`, `test_verify_pack_choice`, `test_verify_release_asset` | | Packs and manifests | synthetic + real packs | `test_artifact_lock`, `test_atomic_artifacts`, `test_batocera_cores`, `test_deterministic_zip`, `test_emulator_pack_counts`, `test_finalize_pack_names`, `test_large_file_cache`, `test_libretro_layout`, `test_manifest_entry`, `test_minui_platform`, `test_pack_conformance_dirs`, `test_pack_core_extras`, `test_pack_counts`, `test_pack_destinations`, `test_pack_failures`, `test_pack_file_names`, `test_pack_grouping`, `test_pack_integrity`, `test_pack_member_identity`, `test_pack_readme`, `test_platform_inheritance`, `test_platform_keys`, `test_required_only_archives`, `test_required_only_twins`, `test_split_extras`, `test_split_names`, `test_split_pack`, `test_system_pack_extras`, `test_system_pack_parity`, `test_torrentzip`, `test_which_pack` | | Slots and regions | synthetic + profiles | `test_region`, `test_region_agnostic_scan`, `test_region_groups`, `test_region_held`, `test_region_platform_index`, `test_region_required_only`, `test_slot`, `test_slots`, `test_slots_shipped_file` | | Hardware targets and systems | synthetic + target files | `test_extract_targets`, `test_lakka_targets`, `test_libretro_slugs`, `test_system_ids`, `test_system_selection`, `test_target_names`, `test_target_scrapers`, `test_target_systems`, `test_target_verify` |