diff --git a/README.md b/README.md index a6399648..2c4390b4 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ The RetroDECK pack already contains its own `bios/` folder, so it extracts into BIOS, firmware, and system files for consoles from Atari to PlayStation 3. Every file passes its platform's own verification; where an emulator profile exists, the expected hashes and sizes are read from the emulator's source code (the Source-backed column below). -- **142 files** the platforms' emulators load are not in the collection yet, named in the [gap analysis](https://abdess.github.io/retrobios/gaps/) +- **77 files** the platforms' emulators load are not in the collection yet, named in the [gap analysis](https://abdess.github.io/retrobios/gaps/) - **12 platforms** supported with platform-specific verification - **328 emulators** profiled from source (RetroArch cores + standalone) - **409 systems** covered (NES, SNES, PlayStation, Saturn, Dreamcast, ...) @@ -72,22 +72,23 @@ Full list with per-file details: **[https://abdess.github.io/retrobios/](https:/ ## Coverage -| Platform | Platform list | Its emulators need | Verified by | -|----------|--------------:|-------------------:|-------------| -| Batocera | 353/353 | 1,145/1,216 | MD5 hash | -| BizHawk | 118/118 | 366/366 | SHA1 hash | +| Platform | Platform list | Read from emulator code | Verified by | +|----------|--------------:|------------------------:|-------------| +| Batocera | 353/353 | 1,145/1,222 | MD5 hash | +| BizHawk | 118/118 | 366/367 | SHA1 hash | | EmuDeck | 161/161 | 404/404 | MD5 hash | -| Lakka | 530/530 | 1,148/1,148 | file presence | +| Lakka | 530/530 | 1,148/1,153 | file presence | | MiSTer FPGA | 65/65 | - | MD5 hash | -| ROCKNIX | 38/38 | 1,483/1,483 | MD5 hash | -| Recalbox | 346/346 | 714/714 | MD5 hash | -| RetroArch | 530/530 | 1,148/1,148 | file presence | -| RetroBat | 341/341 | 808/879 | MD5 hash | -| RetroDECK | 2,008/2,008 | 1,182/1,182 | MD5 hash | -| RetroPie * | 530/530 | 1,148/1,148 | file presence | -| RomM | 374/374 | 266/266 | MD5 hash | +| ROCKNIX | 38/38 | 1,483/1,488 | MD5 hash | +| Recalbox | 346/346 | 714/719 | MD5 hash | +| RetroArch | 530/530 | 1,148/1,153 | file presence | +| RetroBat | 341/341 | 808/884 | MD5 hash | +| RetroDECK | 2,008/2,008 | 1,182/1,188 | MD5 hash | +| RetroPie * | 530/530 | 1,148/1,153 | file presence | +| RomM | 374/374 | 266/269 | MD5 hash | -Each fraction reads collected over needed. Platform list is the BIOS list the platform publishes. Its emulators need counts what the cores it ships actually load, read from their source code, that the list never mentions: routinely several times the list itself. Both go in the pack, so a full pair means nothing is missing. Verified by is the check the platform itself runs. +Each fraction reads collected over needed, required and optional files alike, since both go in the pack. Platform list is the BIOS list the platform publishes. Read from emulator code counts the files the cores it ships load that the list never mentions, traced in their source: routinely several times the list itself, and it includes the files documented as impossible to source. +It is a floor, not a ceiling: a core that accepts any file handed to it declares nothing to count, so what such an emulator can load is not enumerable from its code. The [gap analysis](https://abdess.github.io/retrobios/gaps/) page names those missing files and details how far each platform's files are corroborated against emulator source code. ## Build your own pack @@ -161,4 +162,4 @@ The scripts and tooling are released under the [MIT License](LICENSE). The BIOS and firmware files are not covered by that license: they are third-party system software, preserved and provided for personal backup, archival, and interoperability with emulation software. The legal reasoning is laid out in the [FAQ](https://abdess.github.io/retrobios/wiki/faq/#is-this-legal). -*Auto-generated on 2026-08-08T06:45:48Z* +*Auto-generated on 2026-08-08T07:00:03Z* diff --git a/scripts/generate_readme.py b/scripts/generate_readme.py index 9d907f3a..2caf0e70 100644 --- a/scripts/generate_readme.py +++ b/scripts/generate_readme.py @@ -24,6 +24,7 @@ from common import ( load_emulator_profiles, load_platform_config, load_platform_registry, + resolve_platform_cores, unique_emulator_profiles, write_if_changed, ) @@ -54,6 +55,19 @@ def compute_coverage( undeclared = result.get("undeclared_files", []) core_present = sum(1 for u in undeclared if u.get("in_repo")) core_missing = len(undeclared) - core_present + # Files a profile marks unsourceable never reach the undeclared list, so + # the gap they represent has to be counted back in. + profiles = load_emulator_profiles("emulators") + unsourceable_names = { + f.get("name", "") + for emu in resolve_platform_cores(config, profiles) + for f in (profiles.get(emu) or {}).get("files", []) or [] + if f.get("unsourceable") + } + core_unsourceable = len(unsourceable_names) + missing_names = unsourceable_names | { + u.get("name", "") for u in undeclared if not u.get("in_repo") + } return { "platform": config.get("platform", platform_name), "total": total, @@ -64,6 +78,8 @@ def compute_coverage( "percentage": pct, "core_present": core_present, "core_missing": core_missing, + "core_unsourceable": core_unsourceable, + "missing_names": missing_names, "pack_files": present + core_present, "total_missing": missing + core_missing, "mode": config.get("verification_mode", "existence"), @@ -180,7 +196,7 @@ def generate_readme(db: dict, platforms_dir: str) -> str: ) emulator_count = len(profiles) comp = compute_composition(db) - missing_total = sum(c["total_missing"] for c in coverages.values()) + missing_total = len(set().union(*(c["missing_names"] for c in coverages.values()))) system_ids: set[str] = set() for p in profiles.values(): @@ -359,8 +375,8 @@ def generate_readme(db: dict, platforms_dir: str) -> str: "", "## Coverage", "", - "| Platform | Platform list | Its emulators need | Verified by |", - "|----------|--------------:|-------------------:|-------------|", + "| Platform | Platform list | Read from emulator code | Verified by |", + "|----------|--------------:|------------------------:|-------------|", ] ) @@ -373,7 +389,9 @@ def generate_readme(db: dict, platforms_dir: str) -> str: for name, cov in sorted(coverages.items(), key=lambda x: x[1]["platform"]): display = f"{cov['platform']} *" if name in archived else cov["platform"] checked = mode_labels.get(cov["mode"], cov["mode"]) - core_total = cov["core_present"] + cov["core_missing"] + core_total = ( + cov["core_present"] + cov["core_missing"] + cov["core_unsourceable"] + ) core_cell = f"{cov['core_present']:,}/{core_total:,}" if core_total else "-" lines.append( f"| {display} | {cov['present']:,}/{cov['total']:,} |" @@ -383,12 +401,15 @@ def generate_readme(db: dict, platforms_dir: str) -> str: lines.extend( [ "", - "Each fraction reads collected over needed. Platform list is the" - " BIOS list the platform publishes. Its emulators need counts what" - " the cores it ships actually load, read from their source code," - " that the list never mentions: routinely several times the list" - " itself. Both go in the pack, so a full pair means nothing is" - " missing. Verified by is the check the platform itself runs.", + "Each fraction reads collected over needed, required and optional" + " files alike, since both go in the pack. Platform list is the BIOS" + " list the platform publishes. Read from emulator code counts the" + " files the cores it ships load that the list never mentions," + " traced in their source: routinely several times the list itself," + " and it includes the files documented as impossible to source.", + "It is a floor, not a ceiling: a core that accepts any file handed" + " to it declares nothing to count, so what such an emulator can" + " load is not enumerable from its code.", f"The [gap analysis]({SITE_URL}gaps/) page names those missing files" " and details how far each platform's files are corroborated against" " emulator source code.", diff --git a/scripts/generate_site.py b/scripts/generate_site.py index cc0b0e55..28ce704c 100644 --- a/scripts/generate_site.py +++ b/scripts/generate_site.py @@ -1734,8 +1734,8 @@ def generate_gap_analysis( lines.extend([ "## What Each Pack Contains", "", - "| Platform | Platform list | Its emulators need | Verified by |", - "|----------|--------------:|-------------------:|-------------|", + "| Platform | Platform list | Read from emulator code | Verified by |", + "|----------|--------------:|------------------------:|-------------|", ]) mode_labels = { @@ -1755,7 +1755,9 @@ def generate_gap_analysis( for pname, cov in sorted(coverages.items(), key=lambda x: x[1]["platform"]): display = cov["platform"] - core_total = cov["core_present"] + cov["core_missing"] + core_total = ( + cov["core_present"] + cov["core_missing"] + cov["core_unsourceable"] + ) lines.append( f"| [{display}](platforms/{pname}.md) " f"| {_ratio(cov['present'], cov['total'])} " @@ -1764,13 +1766,16 @@ def generate_gap_analysis( ) lines.extend([ "", - "Each fraction reads collected over needed. Platform list is the BIOS " - "list the platform publishes. Its emulators need counts what the cores " - "it ships actually load, read from their source code, that the list " - "never mentions: routinely several times the list itself. Both go in " - "the pack, so a full pair means nothing is missing; a short one is " - "flagged and named in the sections below. Verified by is the check the " - "platform runs at runtime, replicated here " + "Each fraction reads collected over needed, required and optional " + "files alike, since both go in the pack. Platform list is the BIOS " + "list the platform publishes. Read from emulator code counts the files " + "the cores it ships load that the list never mentions, traced in their " + "source: routinely several times the list itself, and it includes the " + "files documented as impossible to source. A short fraction is flagged " + "and named in the sections below. It is a floor, not a ceiling: a core " + "that accepts any file handed to it declares nothing to count, so what " + "such an emulator can load is not enumerable from its code. Verified " + "by is the check the platform runs at runtime, replicated here " "([how each mode works](wiki/verification-modes.md)).", "", "## Corroboration Against Emulator Source",