chore: merge site fixes

This commit is contained in:
Abdessamad Derraz committed 2026-11-06 18:17:24 +01:00
commit 5b6feef785
286 files changed
+2851 -285

No files matched your search

+16
View File
@@ -32,6 +32,9 @@ on:
- "retired.json"
- "measurements/**"
- "website/**"
# The type check's configuration and baseline.
- "pyproject.toml"
- "mypy-baseline.txt"
# Spelled out twice because the workflow parser reads no YAML anchor. A test
# holds the two lists equal.
push:
@@ -58,6 +61,8 @@ on:
- "retired.json"
- "measurements/**"
- "website/**"
- "pyproject.toml"
- "mypy-baseline.txt"
permissions:
contents: read
@@ -163,6 +168,17 @@ jobs:
- name: Validate platform configs and emulator profiles
run: python scripts/validate_schemas.py --source-only
# The annotations are checked against mypy-baseline.txt, the errors the
# code carried when the check started: a new error fails, and so does
# an entry that no longer occurs until the baseline is synced. mypy
# reads no installed package (no_site_packages in pyproject.toml), so
# what this job has installed does not change the result.
- name: Type-check the scripts and the installer
run: |
pip install "mypy==1.18.2" "mypy-baseline==0.7.4"
mypy > "$RUNNER_TEMP/mypy.txt" || true
mypy-baseline filter --no-colors < "$RUNNER_TEMP/mypy.txt"
# A profile written from a clone can cite lines that do not hold the value
# it declares, and schemas and tests pass it. Each profile a change adds is
# confronted with its upstream, both roads into main. An edited profile is
-3
View File
@@ -342,7 +342,6 @@
"freechaf",
"freeintv",
"frodo",
"fsuae",
"fuse",
"galaksija",
"gam4980",
@@ -424,7 +423,6 @@
"nxengine",
"o2em",
"oberon",
"omicron",
"openlara",
"opera",
"panda3ds",
@@ -505,7 +503,6 @@
"vice_xplus4",
"vice_xscpu64",
"vice_xvic",
"video_processor",
"vircon32",
"virtualjaguar",
"virtualxt",
+25 -25
View File
@@ -13,20 +13,20 @@
{"content":{"catalog":"redump","label":"Bust-A-Move 2 - Arcade Edition (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/mednafen_psx_hw_libretro.so.zip","file":"mednafen_psx_hw_libretro.so","last_modified":"Tue, 27 Oct 2026 05:06:00 GMT","sha256":"d16c889c9f12bd3265edc3c9d4b0e6e24c1f244d1d8d475235f6a74e65e5b10b"},"emulator":"beetle_psx","error":null,"files_opened":[{"created":false,"entry":"scph5501.bin","path":"scph5501.bin","sha1":"0555c6fae8906f3f09baf5988f00e55f88e9f30b"}],"findings":[],"id":"2026-10-27-7117d9fe809f","install":"pack","platform":"retroarch","platform_system":"sony-playstation","platform_version":"v1.22.2","probed_at":"2026-10-27T14:54:23+00:00","records":["2026-10-27-436b1708ef9b"],"rounds":1,"schema_version":1,"source":{"manifest":null,"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2"},"staged":24,"system":"sony-playstation","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Bust-A-Move 2 - Arcade Edition (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/pcsx_rearmed_libretro.so.zip","file":"pcsx_rearmed_libretro.so","last_modified":"Sun, 25 Oct 2026 06:43:04 GMT","sha256":"bfda3f667f8ea8c2f5cc939b970628174b6f491ad32d7f6b143728322df46af6"},"emulator":"pcsx_rearmed","error":null,"files_opened":[{"created":false,"entry":"scph5500.bin","path":"scph5500.bin","sha1":"b05def971d8ec59f346f2d9ac21fb742e3eb6917"},{"created":false,"entry":"scph5501.bin","path":"scph5501.bin","sha1":"0555c6fae8906f3f09baf5988f00e55f88e9f30b"},{"created":false,"entry":"scph5502.bin","path":"scph5502.bin","sha1":"f6bc2d1f5eb6593de7d089c425ac681d6fffd3f0"}],"findings":[],"id":"2026-10-27-f215251f1fbe","install":"pack","platform":"retroarch","platform_system":"sony-playstation","platform_version":"v1.22.2","probed_at":"2026-10-27T14:55:00+00:00","records":["2026-10-27-dcc3253dd29c"],"rounds":1,"schema_version":1,"source":{"manifest":null,"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2"},"staged":22,"system":"sony-playstation","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Bust-A-Move 2 - Arcade Edition (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/swanstation_libretro.so.zip","file":"swanstation_libretro.so","last_modified":"Tue, 27 Oct 2026 05:20:50 GMT","sha256":"fc65bb2d662c3ad762b611a62ac578f78efd260431d3b8c090f0eb40887a77ea"},"emulator":"swanstation","error":null,"files_opened":[{"created":false,"entry":"scph5501.bin","path":"scph5501.bin","sha1":"0555c6fae8906f3f09baf5988f00e55f88e9f30b"}],"findings":[],"id":"2026-10-27-e0de25b19c5d","install":"pack","platform":"retroarch","platform_system":"sony-playstation","platform_version":"v1.22.2","probed_at":"2026-10-27T14:55:04+00:00","records":["2026-10-27-4b1fae82aa24"],"rounds":1,"schema_version":1,"source":{"manifest":null,"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2"},"staged":160,"system":"sony-playstation","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"After Burner III (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/blastem_libretro.so.zip","file":"blastem_libretro.so","last_modified":"Tue, 27 Oct 2026 06:40:24 GMT","sha256":"1901fcbccef88c088328a18e680e11f3626175ea4cc36ba31674286afdc7ac9f"},"emulator":"blastem","error":null,"files_opened":[{"created":false,"entry":"files:bios_MD.bin","path":"bios_MD.bin","sha1":"3f50b76b0529db7f79c396b5e808cc0786ffc311"},{"created":false,"entry":"files:bios_CD_U.bin","path":"bios_CD_U.bin","sha1":"f4f315adcef9b8feb0364c21ab7f0eaf5457f3ed"}],"findings":[{"declared_by":["tmss.md"],"kind":"missing_declared","path":"tmss.md","paths":[]}],"id":"2026-10-27-999ee89554ae","install":"installer","platform":"retroarch","platform_system":"sega-mega-cd","platform_version":"v1.22.2","probed_at":"2026-10-27T14:55:53+00:00","records":["2026-10-27-20cd02176c4b"],"rounds":1,"schema_version":1,"source":{"installer_summary":"-af6705283a8fc4932/tmp/pack_probe/retroarch/installer/system 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2","save_dir_files":106},"staged":9,"system":"sega-mega-cd","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"After Burner III (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/clownmdemu_libretro.so.zip","file":"clownmdemu_libretro.so","last_modified":"Mon, 26 Oct 2026 05:34:34 GMT","sha256":"0d85101878d347a420cf67bf35d9fa339ac8bbe0a636064a5a66af43eb9cec2a"},"emulator":"clownmdemu","error":null,"files_opened":[],"findings":[],"id":"2026-10-27-401e733ca21d","install":"installer","platform":"retroarch","platform_system":"sega-mega-cd","platform_version":"v1.22.2","probed_at":"2026-10-27T14:56:45+00:00","records":["2026-10-27-1642d5598a5b"],"rounds":1,"schema_version":1,"source":{"installer_summary":"-af6705283a8fc4932/tmp/pack_probe/retroarch/installer/system 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2","save_dir_files":106},"staged":3,"system":"sega-mega-cd","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"After Burner III (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/genesis_plus_gx_libretro.so.zip","file":"genesis_plus_gx_libretro.so","last_modified":"Sat, 24 Oct 2026 07:22:46 GMT","sha256":"90b3b66fa998b7769e0c56c6aa288f891eec33c3cd1cf328ccbddb2d628a1522"},"emulator":"genesis_plus_gx","error":null,"files_opened":[{"created":false,"entry":"files:bios_CD_U.bin","path":"bios_CD_U.bin","sha1":"f4f315adcef9b8feb0364c21ab7f0eaf5457f3ed"}],"findings":[],"id":"2026-10-27-ac147338e3a8","install":"installer","platform":"retroarch","platform_system":"sega-mega-cd","platform_version":"v1.22.2","probed_at":"2026-10-27T14:57:17+00:00","records":["2026-10-27-1510af952e4f"],"rounds":1,"schema_version":1,"source":{"installer_summary":"-af6705283a8fc4932/tmp/pack_probe/retroarch/installer/system 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2","save_dir_files":106},"staged":12,"system":"sega-mega-cd","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"After Burner III (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/genesis_plus_gx_wide_libretro.so.zip","file":"genesis_plus_gx_wide_libretro.so","last_modified":"Sun, 25 Oct 2026 06:32:50 GMT","sha256":"03e157b15bd9faadab5a79dde1986c90ba7da9c11b5b44d4243b60c931e23d78"},"emulator":"genesis_plus_gx_wide","error":null,"files_opened":[{"created":false,"entry":"files:bios_CD_U.bin","path":"bios_CD_U.bin","sha1":"f4f315adcef9b8feb0364c21ab7f0eaf5457f3ed"}],"findings":[],"id":"2026-10-27-7b9744e164c6","install":"installer","platform":"retroarch","platform_system":"sega-mega-cd","platform_version":"v1.22.2","probed_at":"2026-10-27T14:57:19+00:00","records":["2026-10-27-d192c31e4bbc"],"rounds":1,"schema_version":1,"source":{"installer_summary":"-af6705283a8fc4932/tmp/pack_probe/retroarch/installer/system 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2","save_dir_files":106},"staged":12,"system":"sega-mega-cd","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"After Burner III (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/picodrive_libretro.so.zip","file":"picodrive_libretro.so","last_modified":"Sun, 25 Oct 2026 05:53:32 GMT","sha256":"fd4010afa91f69d3c61be49c95e14a5c37117c4d0899d3e593ccc4339c1417d5"},"emulator":"picodrive","error":null,"files_opened":[{"created":false,"entry":"files:us_scd2_9306.bin","path":"us_scd2_9306.bin","sha1":"5adb6c3af218c60868e6b723ec47e36bbdf5e6f0"},{"created":false,"entry":"files:carthw.cfg","path":"carthw.cfg","sha1":"d3fe0b958705e4cb5eeb7822e60d474204df4bd3"}],"findings":[],"id":"2026-10-27-019d891b68e9","install":"installer","platform":"retroarch","platform_system":"sega-mega-cd","platform_version":"v1.22.2","probed_at":"2026-10-27T14:57:20+00:00","records":["2026-10-27-568e6ae9560c"],"rounds":1,"schema_version":1,"source":{"installer_summary":"-af6705283a8fc4932/tmp/pack_probe/retroarch/installer/system 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2","save_dir_files":106},"staged":16,"system":"sega-mega-cd","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/mednafen_saturn_libretro.so.zip","file":"mednafen_saturn_libretro.so","last_modified":"Tue, 27 Oct 2026 07:34:40 GMT","sha256":"2cef16a3444d45032ad0ae0d523cbff0e5655f4bc15eb33406c81212f54dc9c1"},"emulator":"beetle_saturn","error":null,"files_opened":[{"created":false,"entry":"files:sega_101.bin","path":"sega_101.bin","sha1":"df94c5b4d47eb3cc404d88b33a8fda237eaf4720"}],"findings":[],"id":"2026-10-27-6207be7f6fa2","install":"installer","platform":"retroarch","platform_system":"sega-saturn","platform_version":"v1.22.2","probed_at":"2026-10-27T14:57:31+00:00","records":["2026-10-27-323214feeed8"],"rounds":1,"schema_version":1,"source":{"installer_summary":"-af6705283a8fc4932/tmp/pack_probe/retroarch/installer/system 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2","save_dir_files":106},"staged":19,"system":"sega-saturn","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/kronos_libretro.so.zip","file":"kronos_libretro.so","last_modified":"Tue, 27 Oct 2026 06:30:48 GMT","sha256":"ca7d0655cb4283b1749ddd2751450d2ec0fd2ea3a3686bde5c4b626cb99e06ac"},"emulator":"kronos","error":null,"files_opened":[],"findings":[],"id":"2026-10-27-c2f209b271ee","install":"installer","platform":"retroarch","platform_system":"sega-saturn","platform_version":"v1.22.2","probed_at":"2026-10-27T14:57:32+00:00","records":["2026-10-27-f9b964643090"],"rounds":1,"schema_version":1,"source":{"installer_summary":"-af6705283a8fc4932/tmp/pack_probe/retroarch/installer/system 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2","save_dir_files":106},"staged":18,"system":"sega-saturn","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: retro_load_game returned false and no error pattern matched","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/yabasanshiro_libretro.so.zip","file":"yabasanshiro_libretro.so","last_modified":"Tue, 27 Oct 2026 06:26:02 GMT","sha256":"d75ae811201373f0b3db69b4258f5d19ee42bfb81231af8abeb6a8389a8417ec"},"emulator":"yabasanshiro","error":null,"files_opened":[],"findings":[],"id":"2026-10-27-f39c67d20831","install":"installer","platform":"retroarch","platform_system":"sega-saturn","platform_version":"v1.22.2","probed_at":"2026-10-27T14:57:32+00:00","records":["2026-10-27-a9e89d04a77f"],"rounds":1,"schema_version":1,"source":{"installer_summary":"-af6705283a8fc4932/tmp/pack_probe/retroarch/installer/system 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2","save_dir_files":106},"staged":13,"system":"sega-saturn","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: retro_load_game returned false and no error pattern matched","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/yabause_libretro.so.zip","file":"yabause_libretro.so","last_modified":"Tue, 27 Oct 2026 06:42:50 GMT","sha256":"974a4cc700ed7eef80b8a33abd33ed07ab317f2123a1014b78c57e043b923296"},"emulator":"yabause","error":null,"files_opened":[{"created":false,"entry":"files:saturn_bios.bin","path":"saturn_bios.bin","sha1":"2b8cb4f87580683eb4d760e4ed210813d667f0a2"}],"findings":[],"id":"2026-10-27-00c60e795b5f","install":"installer","platform":"retroarch","platform_system":"sega-saturn","platform_version":"v1.22.2","probed_at":"2026-10-27T14:57:39+00:00","records":["2026-10-27-6ca3d0d1f0ec"],"rounds":1,"schema_version":1,"source":{"installer_summary":"-af6705283a8fc4932/tmp/pack_probe/retroarch/installer/system 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2","save_dir_files":106},"staged":13,"system":"sega-saturn","target":"linux-x86_64","verdict":"hang","verdict_evidence":{"detail":"1 of 1 repetitions: the last 183 sampled frames are one colour each","repetitions":["hang"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/ymir_libretro.so.zip","file":"ymir_libretro.so","last_modified":"Tue, 27 Oct 2026 05:34:56 GMT","sha256":"237d154fa6ef5caccc1d2899e0a2444947e4391a81bd241803932d1319832712"},"emulator":"ymir","error":null,"files_opened":[{"created":false,"entry":"files:sega_101.bin","path":"sega_101.bin","sha1":"df94c5b4d47eb3cc404d88b33a8fda237eaf4720"},{"created":false,"entry":"files:mpr-17933.bin","path":"mpr-17933.bin","sha1":"faa8ea183a6d7bbe5d4e03bb1332519800d3fbc3"},{"created":false,"entry":"files:saturn_bios.bin","path":"saturn_bios.bin","sha1":"2b8cb4f87580683eb4d760e4ed210813d667f0a2"},{"created":false,"entry":"files:cdb/cdb_rom.bin","path":"cdb/cdb_rom.bin","sha1":"b3c20fbe57cd2eb595e9edac86817e5948dccae4"}],"findings":[],"id":"2026-10-27-da1992edf668","install":"installer","platform":"retroarch","platform_system":"sega-saturn","platform_version":"v1.22.2","probed_at":"2026-10-27T14:57:51+00:00","records":["2026-10-27-0cfeae5767b2"],"rounds":1,"schema_version":1,"source":{"installer_summary":"-af6705283a8fc4932/tmp/pack_probe/retroarch/installer/system 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2","save_dir_files":106},"staged":14,"system":"sega-saturn","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Bust-A-Move 2 - Arcade Edition (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/mednafen_psx_libretro.so.zip","file":"mednafen_psx_libretro.so","last_modified":"Tue, 27 Oct 2026 05:05:54 GMT","sha256":"a89200443c0afa594e85e5e77630921d5e5b04ebf9c499597f3e6f1c947b0c87"},"emulator":"beetle_psx","error":null,"files_opened":[{"created":false,"entry":"files:scph5501.bin","path":"scph5501.bin","sha1":"0555c6fae8906f3f09baf5988f00e55f88e9f30b"}],"findings":[],"id":"2026-10-27-400f6875c7b5","install":"installer","platform":"retroarch","platform_system":"sony-playstation","platform_version":"v1.22.2","probed_at":"2026-10-27T14:57:59+00:00","records":["2026-10-27-953506afe46d"],"rounds":1,"schema_version":1,"source":{"installer_summary":"-af6705283a8fc4932/tmp/pack_probe/retroarch/installer/system 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2","save_dir_files":106},"staged":24,"system":"sony-playstation","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Bust-A-Move 2 - Arcade Edition (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/mednafen_psx_hw_libretro.so.zip","file":"mednafen_psx_hw_libretro.so","last_modified":"Tue, 27 Oct 2026 05:06:00 GMT","sha256":"d16c889c9f12bd3265edc3c9d4b0e6e24c1f244d1d8d475235f6a74e65e5b10b"},"emulator":"beetle_psx","error":null,"files_opened":[{"created":false,"entry":"files:scph5501.bin","path":"scph5501.bin","sha1":"0555c6fae8906f3f09baf5988f00e55f88e9f30b"}],"findings":[],"id":"2026-10-27-3ac99e860c4f","install":"installer","platform":"retroarch","platform_system":"sony-playstation","platform_version":"v1.22.2","probed_at":"2026-10-27T14:58:05+00:00","records":["2026-10-27-01ee781f441e"],"rounds":1,"schema_version":1,"source":{"installer_summary":"-af6705283a8fc4932/tmp/pack_probe/retroarch/installer/system 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2","save_dir_files":106},"staged":24,"system":"sony-playstation","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Bust-A-Move 2 - Arcade Edition (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/pcsx_rearmed_libretro.so.zip","file":"pcsx_rearmed_libretro.so","last_modified":"Sun, 25 Oct 2026 06:43:04 GMT","sha256":"bfda3f667f8ea8c2f5cc939b970628174b6f491ad32d7f6b143728322df46af6"},"emulator":"pcsx_rearmed","error":null,"files_opened":[{"created":false,"entry":"files:scph5500.bin","path":"scph5500.bin","sha1":"b05def971d8ec59f346f2d9ac21fb742e3eb6917"},{"created":false,"entry":"files:scph5501.bin","path":"scph5501.bin","sha1":"0555c6fae8906f3f09baf5988f00e55f88e9f30b"},{"created":false,"entry":"files:scph5502.bin","path":"scph5502.bin","sha1":"f6bc2d1f5eb6593de7d089c425ac681d6fffd3f0"}],"findings":[],"id":"2026-10-27-5305f9a96888","install":"installer","platform":"retroarch","platform_system":"sony-playstation","platform_version":"v1.22.2","probed_at":"2026-10-27T14:58:13+00:00","records":["2026-10-27-ebaf456445fd"],"rounds":1,"schema_version":1,"source":{"installer_summary":"-af6705283a8fc4932/tmp/pack_probe/retroarch/installer/system 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2","save_dir_files":106},"staged":22,"system":"sony-playstation","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Bust-A-Move 2 - Arcade Edition (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/swanstation_libretro.so.zip","file":"swanstation_libretro.so","last_modified":"Tue, 27 Oct 2026 05:20:50 GMT","sha256":"fc65bb2d662c3ad762b611a62ac578f78efd260431d3b8c090f0eb40887a77ea"},"emulator":"swanstation","error":null,"files_opened":[{"created":false,"entry":"files:scph5501.bin","path":"scph5501.bin","sha1":"0555c6fae8906f3f09baf5988f00e55f88e9f30b"}],"findings":[],"id":"2026-10-27-5bd8c6d9541c","install":"installer","platform":"retroarch","platform_system":"sony-playstation","platform_version":"v1.22.2","probed_at":"2026-10-27T14:58:16+00:00","records":["2026-10-27-9165bec33048"],"rounds":1,"schema_version":1,"source":{"installer_summary":"-af6705283a8fc4932/tmp/pack_probe/retroarch/installer/system 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2","save_dir_files":106},"staged":160,"system":"sony-playstation","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"After Burner III (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/blastem_libretro.so.zip","file":"blastem_libretro.so","last_modified":"Tue, 27 Oct 2026 06:40:24 GMT","sha256":"1901fcbccef88c088328a18e680e11f3626175ea4cc36ba31674286afdc7ac9f"},"emulator":"blastem","error":null,"files_opened":[{"created":false,"entry":"files:bios_MD.bin","path":"bios_MD.bin","sha1":"3f50b76b0529db7f79c396b5e808cc0786ffc311"},{"created":false,"entry":"files:bios_CD_U.bin","path":"bios_CD_U.bin","sha1":"f4f315adcef9b8feb0364c21ab7f0eaf5457f3ed"}],"findings":[{"declared_by":["tmss.md"],"kind":"missing_declared","path":"tmss.md","paths":[]}],"id":"2026-10-27-6d9bf0105e6b","install":"installer","platform":"retroarch","platform_system":"sega-mega-cd","platform_version":"v1.22.2","probed_at":"2026-10-27T14:55:53+00:00","records":["2026-10-27-20cd02176c4b"],"rounds":1,"schema_version":1,"source":{"installer_summary":"<dest> 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2","save_dir_files":106},"staged":9,"system":"sega-mega-cd","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"After Burner III (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/clownmdemu_libretro.so.zip","file":"clownmdemu_libretro.so","last_modified":"Mon, 26 Oct 2026 05:34:34 GMT","sha256":"0d85101878d347a420cf67bf35d9fa339ac8bbe0a636064a5a66af43eb9cec2a"},"emulator":"clownmdemu","error":null,"files_opened":[],"findings":[],"id":"2026-10-27-57ca2c364da2","install":"installer","platform":"retroarch","platform_system":"sega-mega-cd","platform_version":"v1.22.2","probed_at":"2026-10-27T14:56:45+00:00","records":["2026-10-27-1642d5598a5b"],"rounds":1,"schema_version":1,"source":{"installer_summary":"<dest> 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2","save_dir_files":106},"staged":3,"system":"sega-mega-cd","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"After Burner III (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/genesis_plus_gx_libretro.so.zip","file":"genesis_plus_gx_libretro.so","last_modified":"Sat, 24 Oct 2026 07:22:46 GMT","sha256":"90b3b66fa998b7769e0c56c6aa288f891eec33c3cd1cf328ccbddb2d628a1522"},"emulator":"genesis_plus_gx","error":null,"files_opened":[{"created":false,"entry":"files:bios_CD_U.bin","path":"bios_CD_U.bin","sha1":"f4f315adcef9b8feb0364c21ab7f0eaf5457f3ed"}],"findings":[],"id":"2026-10-27-7fdea1d8d23a","install":"installer","platform":"retroarch","platform_system":"sega-mega-cd","platform_version":"v1.22.2","probed_at":"2026-10-27T14:57:17+00:00","records":["2026-10-27-1510af952e4f"],"rounds":1,"schema_version":1,"source":{"installer_summary":"<dest> 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2","save_dir_files":106},"staged":12,"system":"sega-mega-cd","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"After Burner III (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/genesis_plus_gx_wide_libretro.so.zip","file":"genesis_plus_gx_wide_libretro.so","last_modified":"Sun, 25 Oct 2026 06:32:50 GMT","sha256":"03e157b15bd9faadab5a79dde1986c90ba7da9c11b5b44d4243b60c931e23d78"},"emulator":"genesis_plus_gx_wide","error":null,"files_opened":[{"created":false,"entry":"files:bios_CD_U.bin","path":"bios_CD_U.bin","sha1":"f4f315adcef9b8feb0364c21ab7f0eaf5457f3ed"}],"findings":[],"id":"2026-10-27-63b36da4e56d","install":"installer","platform":"retroarch","platform_system":"sega-mega-cd","platform_version":"v1.22.2","probed_at":"2026-10-27T14:57:19+00:00","records":["2026-10-27-d192c31e4bbc"],"rounds":1,"schema_version":1,"source":{"installer_summary":"<dest> 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2","save_dir_files":106},"staged":12,"system":"sega-mega-cd","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"After Burner III (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/picodrive_libretro.so.zip","file":"picodrive_libretro.so","last_modified":"Sun, 25 Oct 2026 05:53:32 GMT","sha256":"fd4010afa91f69d3c61be49c95e14a5c37117c4d0899d3e593ccc4339c1417d5"},"emulator":"picodrive","error":null,"files_opened":[{"created":false,"entry":"files:us_scd2_9306.bin","path":"us_scd2_9306.bin","sha1":"5adb6c3af218c60868e6b723ec47e36bbdf5e6f0"},{"created":false,"entry":"files:carthw.cfg","path":"carthw.cfg","sha1":"d3fe0b958705e4cb5eeb7822e60d474204df4bd3"}],"findings":[],"id":"2026-10-27-fff0117b43b1","install":"installer","platform":"retroarch","platform_system":"sega-mega-cd","platform_version":"v1.22.2","probed_at":"2026-10-27T14:57:20+00:00","records":["2026-10-27-568e6ae9560c"],"rounds":1,"schema_version":1,"source":{"installer_summary":"<dest> 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2","save_dir_files":106},"staged":16,"system":"sega-mega-cd","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/mednafen_saturn_libretro.so.zip","file":"mednafen_saturn_libretro.so","last_modified":"Tue, 27 Oct 2026 07:34:40 GMT","sha256":"2cef16a3444d45032ad0ae0d523cbff0e5655f4bc15eb33406c81212f54dc9c1"},"emulator":"beetle_saturn","error":null,"files_opened":[{"created":false,"entry":"files:sega_101.bin","path":"sega_101.bin","sha1":"df94c5b4d47eb3cc404d88b33a8fda237eaf4720"}],"findings":[],"id":"2026-10-27-cba4ec471283","install":"installer","platform":"retroarch","platform_system":"sega-saturn","platform_version":"v1.22.2","probed_at":"2026-10-27T14:57:31+00:00","records":["2026-10-27-323214feeed8"],"rounds":1,"schema_version":1,"source":{"installer_summary":"<dest> 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2","save_dir_files":106},"staged":19,"system":"sega-saturn","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/kronos_libretro.so.zip","file":"kronos_libretro.so","last_modified":"Tue, 27 Oct 2026 06:30:48 GMT","sha256":"ca7d0655cb4283b1749ddd2751450d2ec0fd2ea3a3686bde5c4b626cb99e06ac"},"emulator":"kronos","error":null,"files_opened":[],"findings":[],"id":"2026-10-27-52f7110f988c","install":"installer","platform":"retroarch","platform_system":"sega-saturn","platform_version":"v1.22.2","probed_at":"2026-10-27T14:57:32+00:00","records":["2026-10-27-f9b964643090"],"rounds":1,"schema_version":1,"source":{"installer_summary":"<dest> 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2","save_dir_files":106},"staged":18,"system":"sega-saturn","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: retro_load_game returned false and no error pattern matched","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/yabasanshiro_libretro.so.zip","file":"yabasanshiro_libretro.so","last_modified":"Tue, 27 Oct 2026 06:26:02 GMT","sha256":"d75ae811201373f0b3db69b4258f5d19ee42bfb81231af8abeb6a8389a8417ec"},"emulator":"yabasanshiro","error":null,"files_opened":[],"findings":[],"id":"2026-10-27-4801da4eab2a","install":"installer","platform":"retroarch","platform_system":"sega-saturn","platform_version":"v1.22.2","probed_at":"2026-10-27T14:57:32+00:00","records":["2026-10-27-a9e89d04a77f"],"rounds":1,"schema_version":1,"source":{"installer_summary":"<dest> 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2","save_dir_files":106},"staged":13,"system":"sega-saturn","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: retro_load_game returned false and no error pattern matched","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/yabause_libretro.so.zip","file":"yabause_libretro.so","last_modified":"Tue, 27 Oct 2026 06:42:50 GMT","sha256":"974a4cc700ed7eef80b8a33abd33ed07ab317f2123a1014b78c57e043b923296"},"emulator":"yabause","error":null,"files_opened":[{"created":false,"entry":"files:saturn_bios.bin","path":"saturn_bios.bin","sha1":"2b8cb4f87580683eb4d760e4ed210813d667f0a2"}],"findings":[],"id":"2026-10-27-1f998c82b1ae","install":"installer","platform":"retroarch","platform_system":"sega-saturn","platform_version":"v1.22.2","probed_at":"2026-10-27T14:57:39+00:00","records":["2026-10-27-6ca3d0d1f0ec"],"rounds":1,"schema_version":1,"source":{"installer_summary":"<dest> 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2","save_dir_files":106},"staged":13,"system":"sega-saturn","target":"linux-x86_64","verdict":"hang","verdict_evidence":{"detail":"1 of 1 repetitions: the last 183 sampled frames are one colour each","repetitions":["hang"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/ymir_libretro.so.zip","file":"ymir_libretro.so","last_modified":"Tue, 27 Oct 2026 05:34:56 GMT","sha256":"237d154fa6ef5caccc1d2899e0a2444947e4391a81bd241803932d1319832712"},"emulator":"ymir","error":null,"files_opened":[{"created":false,"entry":"files:sega_101.bin","path":"sega_101.bin","sha1":"df94c5b4d47eb3cc404d88b33a8fda237eaf4720"},{"created":false,"entry":"files:mpr-17933.bin","path":"mpr-17933.bin","sha1":"faa8ea183a6d7bbe5d4e03bb1332519800d3fbc3"},{"created":false,"entry":"files:saturn_bios.bin","path":"saturn_bios.bin","sha1":"2b8cb4f87580683eb4d760e4ed210813d667f0a2"},{"created":false,"entry":"files:cdb/cdb_rom.bin","path":"cdb/cdb_rom.bin","sha1":"b3c20fbe57cd2eb595e9edac86817e5948dccae4"}],"findings":[],"id":"2026-10-27-b2819fb679eb","install":"installer","platform":"retroarch","platform_system":"sega-saturn","platform_version":"v1.22.2","probed_at":"2026-10-27T14:57:51+00:00","records":["2026-10-27-0cfeae5767b2"],"rounds":1,"schema_version":1,"source":{"installer_summary":"<dest> 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2","save_dir_files":106},"staged":14,"system":"sega-saturn","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Bust-A-Move 2 - Arcade Edition (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/mednafen_psx_libretro.so.zip","file":"mednafen_psx_libretro.so","last_modified":"Tue, 27 Oct 2026 05:05:54 GMT","sha256":"a89200443c0afa594e85e5e77630921d5e5b04ebf9c499597f3e6f1c947b0c87"},"emulator":"beetle_psx","error":null,"files_opened":[{"created":false,"entry":"files:scph5501.bin","path":"scph5501.bin","sha1":"0555c6fae8906f3f09baf5988f00e55f88e9f30b"}],"findings":[],"id":"2026-10-27-65efad62e33f","install":"installer","platform":"retroarch","platform_system":"sony-playstation","platform_version":"v1.22.2","probed_at":"2026-10-27T14:57:59+00:00","records":["2026-10-27-953506afe46d"],"rounds":1,"schema_version":1,"source":{"installer_summary":"<dest> 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2","save_dir_files":106},"staged":24,"system":"sony-playstation","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Bust-A-Move 2 - Arcade Edition (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/mednafen_psx_hw_libretro.so.zip","file":"mednafen_psx_hw_libretro.so","last_modified":"Tue, 27 Oct 2026 05:06:00 GMT","sha256":"d16c889c9f12bd3265edc3c9d4b0e6e24c1f244d1d8d475235f6a74e65e5b10b"},"emulator":"beetle_psx","error":null,"files_opened":[{"created":false,"entry":"files:scph5501.bin","path":"scph5501.bin","sha1":"0555c6fae8906f3f09baf5988f00e55f88e9f30b"}],"findings":[],"id":"2026-10-27-fc5fd143e6e9","install":"installer","platform":"retroarch","platform_system":"sony-playstation","platform_version":"v1.22.2","probed_at":"2026-10-27T14:58:05+00:00","records":["2026-10-27-01ee781f441e"],"rounds":1,"schema_version":1,"source":{"installer_summary":"<dest> 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2","save_dir_files":106},"staged":24,"system":"sony-playstation","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Bust-A-Move 2 - Arcade Edition (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/pcsx_rearmed_libretro.so.zip","file":"pcsx_rearmed_libretro.so","last_modified":"Sun, 25 Oct 2026 06:43:04 GMT","sha256":"bfda3f667f8ea8c2f5cc939b970628174b6f491ad32d7f6b143728322df46af6"},"emulator":"pcsx_rearmed","error":null,"files_opened":[{"created":false,"entry":"files:scph5500.bin","path":"scph5500.bin","sha1":"b05def971d8ec59f346f2d9ac21fb742e3eb6917"},{"created":false,"entry":"files:scph5501.bin","path":"scph5501.bin","sha1":"0555c6fae8906f3f09baf5988f00e55f88e9f30b"},{"created":false,"entry":"files:scph5502.bin","path":"scph5502.bin","sha1":"f6bc2d1f5eb6593de7d089c425ac681d6fffd3f0"}],"findings":[],"id":"2026-10-27-500d09e316a3","install":"installer","platform":"retroarch","platform_system":"sony-playstation","platform_version":"v1.22.2","probed_at":"2026-10-27T14:58:13+00:00","records":["2026-10-27-ebaf456445fd"],"rounds":1,"schema_version":1,"source":{"installer_summary":"<dest> 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2","save_dir_files":106},"staged":22,"system":"sony-playstation","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Bust-A-Move 2 - Arcade Edition (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/swanstation_libretro.so.zip","file":"swanstation_libretro.so","last_modified":"Tue, 27 Oct 2026 05:20:50 GMT","sha256":"fc65bb2d662c3ad762b611a62ac578f78efd260431d3b8c090f0eb40887a77ea"},"emulator":"swanstation","error":null,"files_opened":[{"created":false,"entry":"files:scph5501.bin","path":"scph5501.bin","sha1":"0555c6fae8906f3f09baf5988f00e55f88e9f30b"}],"findings":[],"id":"2026-10-27-b5d57c2a3d85","install":"installer","platform":"retroarch","platform_system":"sony-playstation","platform_version":"v1.22.2","probed_at":"2026-10-27T14:58:16+00:00","records":["2026-10-27-9165bec33048"],"rounds":1,"schema_version":1,"source":{"installer_summary":"<dest> 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"49b47355b9504dbefcb0261513b18e9f15dc20a2","save_dir_files":106},"staged":160,"system":"sony-playstation","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"After Burner III (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/blastem_libretro.so.zip","file":"blastem_libretro.so","last_modified":"Tue, 27 Oct 2026 06:40:24 GMT","sha256":"1901fcbccef88c088328a18e680e11f3626175ea4cc36ba31674286afdc7ac9f"},"emulator":"blastem","error":null,"files_opened":[{"created":false,"entry":"tmss.md","path":"tmss.md","sha1":"3f50b76b0529db7f79c396b5e808cc0786ffc311"},{"created":false,"entry":"bios_CD_U.bin","path":"bios_CD_U.bin","sha1":"5adb6c3af218c60868e6b723ec47e36bbdf5e6f0"}],"findings":[],"id":"2026-10-27-2b3b2b6e67b7","install":"pack","platform":"batocera","platform_system":"sega-mega-cd","platform_version":"43.1","probed_at":"2026-10-27T17:07:16+00:00","records":["2026-10-27-788859c63e16"],"rounds":1,"schema_version":1,"source":{"manifest":null,"pack":{"file":"Batocera_43.1_BIOS_Pack.zip","members":14725,"sha256":"494c82fe9aff94e0ad6bc1cad0e14f00719ca5dccf057293009659572988806a","size":6969317213},"repo_commit":"052986c92351077a88cba47b5314727cb3984f82"},"staged":10,"system":"sega-mega-cd","target":"x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"After Burner III (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/genesis_plus_gx_libretro.so.zip","file":"genesis_plus_gx_libretro.so","last_modified":"Sat, 24 Oct 2026 07:22:46 GMT","sha256":"90b3b66fa998b7769e0c56c6aa288f891eec33c3cd1cf328ccbddb2d628a1522"},"emulator":"genesis_plus_gx","error":null,"files_opened":[{"created":false,"entry":"bios_CD_U.bin","path":"bios_CD_U.bin","sha1":"5adb6c3af218c60868e6b723ec47e36bbdf5e6f0"}],"findings":[],"id":"2026-10-27-2745e259a3bd","install":"pack","platform":"batocera","platform_system":"sega-mega-cd","platform_version":"43.1","probed_at":"2026-10-27T17:07:18+00:00","records":["2026-10-27-34ef09cf10e7"],"rounds":1,"schema_version":1,"source":{"manifest":null,"pack":{"file":"Batocera_43.1_BIOS_Pack.zip","members":14725,"sha256":"494c82fe9aff94e0ad6bc1cad0e14f00719ca5dccf057293009659572988806a","size":6969317213},"repo_commit":"052986c92351077a88cba47b5314727cb3984f82"},"staged":12,"system":"sega-mega-cd","target":"x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"After Burner III (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/genesis_plus_gx_wide_libretro.so.zip","file":"genesis_plus_gx_wide_libretro.so","last_modified":"Sun, 25 Oct 2026 06:32:50 GMT","sha256":"03e157b15bd9faadab5a79dde1986c90ba7da9c11b5b44d4243b60c931e23d78"},"emulator":"genesis_plus_gx_wide","error":null,"files_opened":[{"created":false,"entry":"bios_CD_U.bin","path":"bios_CD_U.bin","sha1":"5adb6c3af218c60868e6b723ec47e36bbdf5e6f0"}],"findings":[],"id":"2026-10-27-6275db21bd63","install":"pack","platform":"batocera","platform_system":"sega-mega-cd","platform_version":"43.1","probed_at":"2026-10-27T17:07:20+00:00","records":["2026-10-27-e63bf0cea0fa"],"rounds":1,"schema_version":1,"source":{"manifest":null,"pack":{"file":"Batocera_43.1_BIOS_Pack.zip","members":14725,"sha256":"494c82fe9aff94e0ad6bc1cad0e14f00719ca5dccf057293009659572988806a","size":6969317213},"repo_commit":"052986c92351077a88cba47b5314727cb3984f82"},"staged":12,"system":"sega-mega-cd","target":"x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
@@ -68,7 +68,7 @@
{"content":{"catalog":"redump","label":"Bust-A-Move 2 - Arcade Edition (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/pcsx_rearmed_libretro.so.zip","file":"pcsx_rearmed_libretro.so","last_modified":"Sun, 25 Oct 2026 06:43:04 GMT","sha256":"bfda3f667f8ea8c2f5cc939b970628174b6f491ad32d7f6b143728322df46af6"},"emulator":"pcsx_rearmed","error":null,"files_opened":[{"created":false,"entry":"files:scph5500.bin","path":"scph5500.bin","sha1":"b05def971d8ec59f346f2d9ac21fb742e3eb6917"},{"created":false,"entry":"files:scph5501.bin","path":"scph5501.bin","sha1":"0555c6fae8906f3f09baf5988f00e55f88e9f30b"},{"created":false,"entry":"files:scph5502.bin","path":"scph5502.bin","sha1":"f6bc2d1f5eb6593de7d089c425ac681d6fffd3f0"}],"findings":[],"id":"2026-10-27-98b9d80687bc","install":"installer","platform":"retrobat","platform_system":"sony-playstation","platform_version":"8.3.1","probed_at":"2026-10-27T21:46:41+00:00","records":["2026-10-27-c6d5fc766117"],"rounds":1,"schema_version":1,"source":{"installer_summary":"/pak000.pk4, base/pak002.pk4, base/pak003.pk4, base/pak004.pk4 return-to-castle-wolfenstein (realrtcw): main/sp_pak1.pk3 sonic-mania (sonic-mania): Data.rsdk sonic3-air (sonic3-air): Sonic_Knuckles_wSonic3.bin starship (starship): baserom.us.rev1.z64 Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":5561,"path":"install/retrobat.json","sha256":"94a79556469df55169be485274bfb6c6defb7a52a85319440112d0c8f89df1fb"},"pack":{"file":"RetroBat_8.3.1_BIOS_Pack.zip","members":5561,"sha256":"89bdc445768e9568bd88737871f1e713df3d08fe0e191de18d228291d6e40647","size":5644690738},"repo_commit":"7433d49666b848062b67cf3a16975be907705ab2","save_dir_files":41},"staged":7,"system":"sony-playstation","target":"windows","verdict":"boots","verdict_evidence":{"detail":"1 of 1 repetitions: frame 530 shows Now Loading with the yellow bubble","frame":530,"repetitions":["boots"],"rule":"repetitions_agree","sha1":"e5af1f2023d0d729ce7aabf52d8e03f75bb8d230","stages":["bios","game"]}}
{"content":{"catalog":"redump","label":"Bust-A-Move 2 - Arcade Edition (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/swanstation_libretro.so.zip","file":"swanstation_libretro.so","last_modified":"Tue, 27 Oct 2026 05:20:50 GMT","sha256":"fc65bb2d662c3ad762b611a62ac578f78efd260431d3b8c090f0eb40887a77ea"},"emulator":"swanstation","error":null,"files_opened":[{"created":false,"entry":"files:scph5501.bin","path":"scph5501.bin","sha1":"0555c6fae8906f3f09baf5988f00e55f88e9f30b"}],"findings":[],"id":"2026-10-27-c0cd95f153a0","install":"installer","platform":"retrobat","platform_system":"sony-playstation","platform_version":"8.3.1","probed_at":"2026-10-27T21:48:52+00:00","records":["2026-10-27-feb3fc839667"],"rounds":1,"schema_version":1,"source":{"installer_summary":"/pak000.pk4, base/pak002.pk4, base/pak003.pk4, base/pak004.pk4 return-to-castle-wolfenstein (realrtcw): main/sp_pak1.pk3 sonic-mania (sonic-mania): Data.rsdk sonic3-air (sonic3-air): Sonic_Knuckles_wSonic3.bin starship (starship): baserom.us.rev1.z64 Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":5561,"path":"install/retrobat.json","sha256":"94a79556469df55169be485274bfb6c6defb7a52a85319440112d0c8f89df1fb"},"pack":{"file":"RetroBat_8.3.1_BIOS_Pack.zip","members":5561,"sha256":"89bdc445768e9568bd88737871f1e713df3d08fe0e191de18d228291d6e40647","size":5644690738},"repo_commit":"7433d49666b848062b67cf3a16975be907705ab2","save_dir_files":41},"staged":307,"system":"sony-playstation","target":"windows","verdict":"boots","verdict_evidence":{"detail":"1 of 1 repetitions: frame 1300 shows Now Loading with the yellow bubble","frame":1300,"repetitions":["boots"],"rule":"repetitions_agree","sha1":"e5af1f2023d0d729ce7aabf52d8e03f75bb8d230","stages":["bios","game"]}}
{"content":{"catalog":"redump","label":"After Burner III (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/blastem_libretro.so.zip","file":"blastem_libretro.so","last_modified":"Tue, 27 Oct 2026 06:40:24 GMT","sha256":"1901fcbccef88c088328a18e680e11f3626175ea4cc36ba31674286afdc7ac9f"},"emulator":"blastem","error":null,"files_opened":[{"created":false,"entry":"bios_MD.bin","path":"bios_MD.bin","sha1":"3f50b76b0529db7f79c396b5e808cc0786ffc311"},{"created":false,"entry":"bios_CD_U.bin","path":"bios_CD_U.bin","sha1":"f4f315adcef9b8feb0364c21ab7f0eaf5457f3ed"}],"findings":[],"id":"2026-10-27-fd43eb05c3ce","install":"pack","platform":"retroarch","platform_system":"sega-mega-cd","platform_version":"v1.22.2","probed_at":"2026-10-27T21:51:08+00:00","records":["2026-10-27-fffd76b0df0c"],"rounds":1,"schema_version":1,"source":{"manifest":null,"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"7433d49666b848062b67cf3a16975be907705ab2"},"staged":9,"system":"sega-mega-cd","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"After Burner III (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/blastem_libretro.so.zip","file":"blastem_libretro.so","last_modified":"Tue, 27 Oct 2026 06:40:24 GMT","sha256":"1901fcbccef88c088328a18e680e11f3626175ea4cc36ba31674286afdc7ac9f"},"emulator":"blastem","error":null,"files_opened":[{"created":false,"entry":"files:bios_MD.bin","path":"bios_MD.bin","sha1":"3f50b76b0529db7f79c396b5e808cc0786ffc311"},{"created":false,"entry":"files:bios_CD_U.bin","path":"bios_CD_U.bin","sha1":"f4f315adcef9b8feb0364c21ab7f0eaf5457f3ed"}],"findings":[],"id":"2026-10-27-50353e16d141","install":"installer","platform":"retroarch","platform_system":"sega-mega-cd","platform_version":"v1.22.2","probed_at":"2026-10-27T21:53:14+00:00","records":["2026-10-27-888669b2583b"],"rounds":1,"schema_version":1,"source":{"installer_summary":"-af6705283a8fc4932/tmp/pack_probe/retroarch/installer/system 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"7433d49666b848062b67cf3a16975be907705ab2","save_dir_files":106},"staged":9,"system":"sega-mega-cd","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"After Burner III (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/blastem_libretro.so.zip","file":"blastem_libretro.so","last_modified":"Tue, 27 Oct 2026 06:40:24 GMT","sha256":"1901fcbccef88c088328a18e680e11f3626175ea4cc36ba31674286afdc7ac9f"},"emulator":"blastem","error":null,"files_opened":[{"created":false,"entry":"files:bios_MD.bin","path":"bios_MD.bin","sha1":"3f50b76b0529db7f79c396b5e808cc0786ffc311"},{"created":false,"entry":"files:bios_CD_U.bin","path":"bios_CD_U.bin","sha1":"f4f315adcef9b8feb0364c21ab7f0eaf5457f3ed"}],"findings":[],"id":"2026-10-27-0acbb63a8c6b","install":"installer","platform":"retroarch","platform_system":"sega-mega-cd","platform_version":"v1.22.2","probed_at":"2026-10-27T21:53:14+00:00","records":["2026-10-27-888669b2583b"],"rounds":1,"schema_version":1,"source":{"installer_summary":"<dest> 37 files were not installed: the collection does not hold them, or its copy fails their check. Needed to start an emulator (1 file): jazz-jackrabbit-2 (jazz2-native): jazz2/Source/Anims.j2a Each emulator's page says what these files are: https://abdess.github.io/retrobios/emulators/ To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":10986,"path":"install/retroarch.json","sha256":"115639363828622f29ac8784bc534bb8560a0198ca57aaa19be3f649b9bb8199"},"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"7433d49666b848062b67cf3a16975be907705ab2","save_dir_files":106},"staged":9,"system":"sega-mega-cd","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Bust-A-Move 2 - Arcade Edition (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/mednafen_psx_libretro.so.zip","file":"mednafen_psx_libretro.so","last_modified":"Tue, 27 Oct 2026 05:05:54 GMT","sha256":"a89200443c0afa594e85e5e77630921d5e5b04ebf9c499597f3e6f1c947b0c87"},"emulator":"beetle_psx","error":null,"files_opened":[{"created":false,"entry":"scph5501.bin","path":"scph5501.bin","sha1":"0555c6fae8906f3f09baf5988f00e55f88e9f30b"}],"findings":[],"id":"2026-10-27-a2f102062caa","install":"pack","platform":"retroarch","platform_system":"sony-playstation","platform_version":"v1.22.2","probed_at":"2026-10-27T21:55:45+00:00","records":["2026-10-27-cb2f506d7cc9"],"rounds":1,"schema_version":1,"source":{"manifest":null,"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"a2d30046f2903132fe478661edbbf75c7d2a4767"},"staged":24,"system":"sony-playstation","target":"linux-x86_64","verdict":"boots","verdict_evidence":{"detail":"1 of 1 repetitions: frame 1280 shows Now Loading with the yellow bubble","frame":1280,"repetitions":["boots"],"rule":"repetitions_agree","sha1":"d51ab7783f8eeafc63a28f14ce39f8e2babeffb3","stages":["bios","game"]}}
{"content":{"catalog":"redump","label":"Bust-A-Move 2 - Arcade Edition (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/mednafen_psx_hw_libretro.so.zip","file":"mednafen_psx_hw_libretro.so","last_modified":"Tue, 27 Oct 2026 05:06:00 GMT","sha256":"d16c889c9f12bd3265edc3c9d4b0e6e24c1f244d1d8d475235f6a74e65e5b10b"},"emulator":"beetle_psx","error":null,"files_opened":[{"created":false,"entry":"scph5501.bin","path":"scph5501.bin","sha1":"0555c6fae8906f3f09baf5988f00e55f88e9f30b"}],"findings":[],"id":"2026-10-27-46d676fbc1ea","install":"pack","platform":"retroarch","platform_system":"sony-playstation","platform_version":"v1.22.2","probed_at":"2026-10-27T21:58:05+00:00","records":["2026-10-27-01436f3dd1dd"],"rounds":1,"schema_version":1,"source":{"manifest":null,"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"a2d30046f2903132fe478661edbbf75c7d2a4767"},"staged":24,"system":"sony-playstation","target":"linux-x86_64","verdict":"boots","verdict_evidence":{"detail":"1 of 1 repetitions: frame 1280 shows Now Loading with the yellow bubble","frame":1280,"repetitions":["boots"],"rule":"repetitions_agree","sha1":"d51ab7783f8eeafc63a28f14ce39f8e2babeffb3","stages":["bios","game"]}}
{"content":{"catalog":"redump","label":"Bust-A-Move 2 - Arcade Edition (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/pcsx_rearmed_libretro.so.zip","file":"pcsx_rearmed_libretro.so","last_modified":"Sun, 25 Oct 2026 06:43:04 GMT","sha256":"bfda3f667f8ea8c2f5cc939b970628174b6f491ad32d7f6b143728322df46af6"},"emulator":"pcsx_rearmed","error":null,"files_opened":[{"created":false,"entry":"scph5500.bin","path":"scph5500.bin","sha1":"b05def971d8ec59f346f2d9ac21fb742e3eb6917"},{"created":false,"entry":"scph5501.bin","path":"scph5501.bin","sha1":"0555c6fae8906f3f09baf5988f00e55f88e9f30b"},{"created":false,"entry":"scph5502.bin","path":"scph5502.bin","sha1":"f6bc2d1f5eb6593de7d089c425ac681d6fffd3f0"}],"findings":[],"id":"2026-10-27-74b70e46cfb2","install":"pack","platform":"retroarch","platform_system":"sony-playstation","platform_version":"v1.22.2","probed_at":"2026-10-27T22:00:07+00:00","records":["2026-10-27-258389f4d7f9"],"rounds":1,"schema_version":1,"source":{"manifest":null,"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"44e08162359530f95bb4d34687ca7b22e01296d5"},"staged":22,"system":"sony-playstation","target":"linux-x86_64","verdict":"boots","verdict_evidence":{"detail":"1 of 1 repetitions: frame 530 shows Now Loading with the yellow bubble","frame":530,"repetitions":["boots"],"rule":"repetitions_agree","sha1":"e5af1f2023d0d729ce7aabf52d8e03f75bb8d230","stages":["bios","game"]}}
@@ -80,9 +80,9 @@
{"content":{"catalog":"redump","label":"Bust-A-Move 2 - Arcade Edition (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/mednafen_psx_libretro.so.zip","file":"mednafen_psx_libretro.so","last_modified":"Tue, 27 Oct 2026 05:05:54 GMT","sha256":"a89200443c0afa594e85e5e77630921d5e5b04ebf9c499597f3e6f1c947b0c87"},"emulator":"beetle_psx","error":null,"files_opened":[{"created":false,"entry":"scph5501.bin","path":"scph5501.bin","sha1":"0555c6fae8906f3f09baf5988f00e55f88e9f30b"}],"findings":[],"id":"2026-10-27-35f5003364b6","install":"pack","platform":"batocera","platform_system":"sony-playstation","platform_version":"43.1","probed_at":"2026-10-27T22:23:32+00:00","records":["2026-10-27-0959ceac43e0"],"rounds":1,"schema_version":1,"source":{"manifest":null,"pack":{"file":"Batocera_43.1_BIOS_Pack.zip","members":14725,"sha256":"494c82fe9aff94e0ad6bc1cad0e14f00719ca5dccf057293009659572988806a","size":6969317213},"repo_commit":"44e08162359530f95bb4d34687ca7b22e01296d5"},"staged":10,"system":"sony-playstation","target":"x86_64","verdict":"boots","verdict_evidence":{"detail":"1 of 1 repetitions: frame 1280 shows Now Loading with the yellow bubble","frame":1280,"repetitions":["boots"],"rule":"repetitions_agree","sha1":"d51ab7783f8eeafc63a28f14ce39f8e2babeffb3","stages":["bios","game"]}}
{"content":{"catalog":"redump","label":"Bust-A-Move 2 - Arcade Edition (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/pcsx_rearmed_libretro.so.zip","file":"pcsx_rearmed_libretro.so","last_modified":"Sun, 25 Oct 2026 06:43:04 GMT","sha256":"bfda3f667f8ea8c2f5cc939b970628174b6f491ad32d7f6b143728322df46af6"},"emulator":"pcsx_rearmed","error":null,"files_opened":[{"created":false,"entry":"scph5500.bin","path":"scph5500.bin","sha1":"b05def971d8ec59f346f2d9ac21fb742e3eb6917"},{"created":false,"entry":"scph5501.bin","path":"scph5501.bin","sha1":"0555c6fae8906f3f09baf5988f00e55f88e9f30b"},{"created":false,"entry":"scph5502.bin","path":"scph5502.bin","sha1":"f6bc2d1f5eb6593de7d089c425ac681d6fffd3f0"}],"findings":[],"id":"2026-10-27-2e558db8013d","install":"pack","platform":"batocera","platform_system":"sony-playstation","platform_version":"43.1","probed_at":"2026-10-27T22:24:58+00:00","records":["2026-10-27-9e53883a5566"],"rounds":1,"schema_version":1,"source":{"manifest":null,"pack":{"file":"Batocera_43.1_BIOS_Pack.zip","members":14725,"sha256":"494c82fe9aff94e0ad6bc1cad0e14f00719ca5dccf057293009659572988806a","size":6969317213},"repo_commit":"44e08162359530f95bb4d34687ca7b22e01296d5"},"staged":7,"system":"sony-playstation","target":"x86_64","verdict":"boots","verdict_evidence":{"detail":"1 of 1 repetitions: frame 530 shows Now Loading with the yellow bubble","frame":530,"repetitions":["boots"],"rule":"repetitions_agree","sha1":"e5af1f2023d0d729ce7aabf52d8e03f75bb8d230","stages":["bios","game"]}}
{"content":{"catalog":"redump","label":"Bust-A-Move 2 - Arcade Edition (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/swanstation_libretro.so.zip","file":"swanstation_libretro.so","last_modified":"Tue, 27 Oct 2026 05:20:50 GMT","sha256":"fc65bb2d662c3ad762b611a62ac578f78efd260431d3b8c090f0eb40887a77ea"},"emulator":"swanstation","error":null,"files_opened":[{"created":false,"entry":"scph5501.bin","path":"scph5501.bin","sha1":"0555c6fae8906f3f09baf5988f00e55f88e9f30b"}],"findings":[],"id":"2026-10-27-44d39a8db0d9","install":"pack","platform":"batocera","platform_system":"sony-playstation","platform_version":"43.1","probed_at":"2026-10-27T22:25:46+00:00","records":["2026-10-27-bc55bc2a98c6"],"rounds":1,"schema_version":1,"source":{"manifest":null,"pack":{"file":"Batocera_43.1_BIOS_Pack.zip","members":14725,"sha256":"494c82fe9aff94e0ad6bc1cad0e14f00719ca5dccf057293009659572988806a","size":6969317213},"repo_commit":"44e08162359530f95bb4d34687ca7b22e01296d5"},"staged":258,"system":"sony-playstation","target":"x86_64","verdict":"boots","verdict_evidence":{"detail":"1 of 1 repetitions: frame 1300 shows Now Loading with the yellow bubble","frame":1300,"repetitions":["boots"],"rule":"repetitions_agree","sha1":"e5af1f2023d0d729ce7aabf52d8e03f75bb8d230","stages":["bios","game"]}}
{"content":{"catalog":"redump","label":"Bust-A-Move 2 - Arcade Edition (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/mednafen_psx_libretro.so.zip","file":"mednafen_psx_libretro.so","last_modified":"Tue, 27 Oct 2026 05:05:54 GMT","sha256":"a89200443c0afa594e85e5e77630921d5e5b04ebf9c499597f3e6f1c947b0c87"},"emulator":"beetle_psx","error":null,"files_opened":[{"created":false,"entry":"files:scph5501.bin","path":"scph5501.bin","sha1":"0555c6fae8906f3f09baf5988f00e55f88e9f30b"}],"findings":[],"id":"2026-10-27-c47c2647917e","install":"installer","platform":"batocera","platform_system":"sony-playstation","platform_version":"43.1","probed_at":"2026-10-27T22:27:45+00:00","records":["2026-10-27-f2d677e3e4fc"],"rounds":1,"schema_version":1,"source":{"installer_summary":"tem/.claude/worktrees/agent-af6705283a8fc4932/tmp/pack_probe/batocera/installer/system/, <dest>/Source/, <dest>/base/ and 10 more folders. To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":14725,"path":"install/batocera.json","sha256":"960b377a8e03a9333bb4853e54425a0f889eecf9342c9c1aadebf3601ae27f20"},"pack":{"file":"Batocera_43.1_BIOS_Pack.zip","members":14725,"sha256":"494c82fe9aff94e0ad6bc1cad0e14f00719ca5dccf057293009659572988806a","size":6969317213},"repo_commit":"44e08162359530f95bb4d34687ca7b22e01296d5","save_dir_files":23},"staged":10,"system":"sony-playstation","target":"x86_64","verdict":"boots","verdict_evidence":{"detail":"1 of 1 repetitions: frame 1280 shows Now Loading with the yellow bubble","frame":1280,"repetitions":["boots"],"rule":"repetitions_agree","sha1":"d51ab7783f8eeafc63a28f14ce39f8e2babeffb3","stages":["bios","game"]}}
{"content":{"catalog":"redump","label":"Bust-A-Move 2 - Arcade Edition (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/pcsx_rearmed_libretro.so.zip","file":"pcsx_rearmed_libretro.so","last_modified":"Sun, 25 Oct 2026 06:43:04 GMT","sha256":"bfda3f667f8ea8c2f5cc939b970628174b6f491ad32d7f6b143728322df46af6"},"emulator":"pcsx_rearmed","error":null,"files_opened":[{"created":false,"entry":"files:scph5500.bin","path":"scph5500.bin","sha1":"b05def971d8ec59f346f2d9ac21fb742e3eb6917"},{"created":false,"entry":"files:scph5501.bin","path":"scph5501.bin","sha1":"0555c6fae8906f3f09baf5988f00e55f88e9f30b"},{"created":false,"entry":"files:scph5502.bin","path":"scph5502.bin","sha1":"f6bc2d1f5eb6593de7d089c425ac681d6fffd3f0"}],"findings":[],"id":"2026-10-27-328db80ddaba","install":"installer","platform":"batocera","platform_system":"sony-playstation","platform_version":"43.1","probed_at":"2026-10-27T22:28:53+00:00","records":["2026-10-27-77ae5a4a34e4"],"rounds":1,"schema_version":1,"source":{"installer_summary":"tem/.claude/worktrees/agent-af6705283a8fc4932/tmp/pack_probe/batocera/installer/system/, <dest>/Source/, <dest>/base/ and 10 more folders. To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":14725,"path":"install/batocera.json","sha256":"960b377a8e03a9333bb4853e54425a0f889eecf9342c9c1aadebf3601ae27f20"},"pack":{"file":"Batocera_43.1_BIOS_Pack.zip","members":14725,"sha256":"494c82fe9aff94e0ad6bc1cad0e14f00719ca5dccf057293009659572988806a","size":6969317213},"repo_commit":"44e08162359530f95bb4d34687ca7b22e01296d5","save_dir_files":23},"staged":7,"system":"sony-playstation","target":"x86_64","verdict":"boots","verdict_evidence":{"detail":"1 of 1 repetitions: frame 530 shows Now Loading with the yellow bubble","frame":530,"repetitions":["boots"],"rule":"repetitions_agree","sha1":"e5af1f2023d0d729ce7aabf52d8e03f75bb8d230","stages":["bios","game"]}}
{"content":{"catalog":"redump","label":"Bust-A-Move 2 - Arcade Edition (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/swanstation_libretro.so.zip","file":"swanstation_libretro.so","last_modified":"Tue, 27 Oct 2026 05:20:50 GMT","sha256":"fc65bb2d662c3ad762b611a62ac578f78efd260431d3b8c090f0eb40887a77ea"},"emulator":"swanstation","error":null,"files_opened":[{"created":false,"entry":"files:scph5501.bin","path":"scph5501.bin","sha1":"0555c6fae8906f3f09baf5988f00e55f88e9f30b"}],"findings":[],"id":"2026-10-27-3443028e79fd","install":"installer","platform":"batocera","platform_system":"sony-playstation","platform_version":"43.1","probed_at":"2026-10-27T22:30:09+00:00","records":["2026-10-27-c17d693b47cf"],"rounds":1,"schema_version":1,"source":{"installer_summary":"tem/.claude/worktrees/agent-af6705283a8fc4932/tmp/pack_probe/batocera/installer/system/, <dest>/Source/, <dest>/base/ and 10 more folders. To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":14725,"path":"install/batocera.json","sha256":"960b377a8e03a9333bb4853e54425a0f889eecf9342c9c1aadebf3601ae27f20"},"pack":{"file":"Batocera_43.1_BIOS_Pack.zip","members":14725,"sha256":"494c82fe9aff94e0ad6bc1cad0e14f00719ca5dccf057293009659572988806a","size":6969317213},"repo_commit":"44e08162359530f95bb4d34687ca7b22e01296d5","save_dir_files":23},"staged":258,"system":"sony-playstation","target":"x86_64","verdict":"boots","verdict_evidence":{"detail":"1 of 1 repetitions: frame 1300 shows Now Loading with the yellow bubble","frame":1300,"repetitions":["boots"],"rule":"repetitions_agree","sha1":"e5af1f2023d0d729ce7aabf52d8e03f75bb8d230","stages":["bios","game"]}}
{"content":{"catalog":"redump","label":"Bust-A-Move 2 - Arcade Edition (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/mednafen_psx_libretro.so.zip","file":"mednafen_psx_libretro.so","last_modified":"Tue, 27 Oct 2026 05:05:54 GMT","sha256":"a89200443c0afa594e85e5e77630921d5e5b04ebf9c499597f3e6f1c947b0c87"},"emulator":"beetle_psx","error":null,"files_opened":[{"created":false,"entry":"files:scph5501.bin","path":"scph5501.bin","sha1":"0555c6fae8906f3f09baf5988f00e55f88e9f30b"}],"findings":[],"id":"2026-10-27-83d50aaa94c9","install":"installer","platform":"batocera","platform_system":"sony-playstation","platform_version":"43.1","probed_at":"2026-10-27T22:27:45+00:00","records":["2026-10-27-f2d677e3e4fc"],"rounds":1,"schema_version":1,"source":{"installer_summary":"<dest>/, <dest>/Source/, <dest>/base/ and 10 more folders. To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":14725,"path":"install/batocera.json","sha256":"960b377a8e03a9333bb4853e54425a0f889eecf9342c9c1aadebf3601ae27f20"},"pack":{"file":"Batocera_43.1_BIOS_Pack.zip","members":14725,"sha256":"494c82fe9aff94e0ad6bc1cad0e14f00719ca5dccf057293009659572988806a","size":6969317213},"repo_commit":"44e08162359530f95bb4d34687ca7b22e01296d5","save_dir_files":23},"staged":10,"system":"sony-playstation","target":"x86_64","verdict":"boots","verdict_evidence":{"detail":"1 of 1 repetitions: frame 1280 shows Now Loading with the yellow bubble","frame":1280,"repetitions":["boots"],"rule":"repetitions_agree","sha1":"d51ab7783f8eeafc63a28f14ce39f8e2babeffb3","stages":["bios","game"]}}
{"content":{"catalog":"redump","label":"Bust-A-Move 2 - Arcade Edition (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/pcsx_rearmed_libretro.so.zip","file":"pcsx_rearmed_libretro.so","last_modified":"Sun, 25 Oct 2026 06:43:04 GMT","sha256":"bfda3f667f8ea8c2f5cc939b970628174b6f491ad32d7f6b143728322df46af6"},"emulator":"pcsx_rearmed","error":null,"files_opened":[{"created":false,"entry":"files:scph5500.bin","path":"scph5500.bin","sha1":"b05def971d8ec59f346f2d9ac21fb742e3eb6917"},{"created":false,"entry":"files:scph5501.bin","path":"scph5501.bin","sha1":"0555c6fae8906f3f09baf5988f00e55f88e9f30b"},{"created":false,"entry":"files:scph5502.bin","path":"scph5502.bin","sha1":"f6bc2d1f5eb6593de7d089c425ac681d6fffd3f0"}],"findings":[],"id":"2026-10-27-29a98aa66a34","install":"installer","platform":"batocera","platform_system":"sony-playstation","platform_version":"43.1","probed_at":"2026-10-27T22:28:53+00:00","records":["2026-10-27-77ae5a4a34e4"],"rounds":1,"schema_version":1,"source":{"installer_summary":"<dest>/, <dest>/Source/, <dest>/base/ and 10 more folders. To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":14725,"path":"install/batocera.json","sha256":"960b377a8e03a9333bb4853e54425a0f889eecf9342c9c1aadebf3601ae27f20"},"pack":{"file":"Batocera_43.1_BIOS_Pack.zip","members":14725,"sha256":"494c82fe9aff94e0ad6bc1cad0e14f00719ca5dccf057293009659572988806a","size":6969317213},"repo_commit":"44e08162359530f95bb4d34687ca7b22e01296d5","save_dir_files":23},"staged":7,"system":"sony-playstation","target":"x86_64","verdict":"boots","verdict_evidence":{"detail":"1 of 1 repetitions: frame 530 shows Now Loading with the yellow bubble","frame":530,"repetitions":["boots"],"rule":"repetitions_agree","sha1":"e5af1f2023d0d729ce7aabf52d8e03f75bb8d230","stages":["bios","game"]}}
{"content":{"catalog":"redump","label":"Bust-A-Move 2 - Arcade Edition (USA)","region":"north-america"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/swanstation_libretro.so.zip","file":"swanstation_libretro.so","last_modified":"Tue, 27 Oct 2026 05:20:50 GMT","sha256":"fc65bb2d662c3ad762b611a62ac578f78efd260431d3b8c090f0eb40887a77ea"},"emulator":"swanstation","error":null,"files_opened":[{"created":false,"entry":"files:scph5501.bin","path":"scph5501.bin","sha1":"0555c6fae8906f3f09baf5988f00e55f88e9f30b"}],"findings":[],"id":"2026-10-27-020dd1920ba1","install":"installer","platform":"batocera","platform_system":"sony-playstation","platform_version":"43.1","probed_at":"2026-10-27T22:30:09+00:00","records":["2026-10-27-c17d693b47cf"],"rounds":1,"schema_version":1,"source":{"installer_summary":"<dest>/, <dest>/Source/, <dest>/base/ and 10 more folders. To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":14725,"path":"install/batocera.json","sha256":"960b377a8e03a9333bb4853e54425a0f889eecf9342c9c1aadebf3601ae27f20"},"pack":{"file":"Batocera_43.1_BIOS_Pack.zip","members":14725,"sha256":"494c82fe9aff94e0ad6bc1cad0e14f00719ca5dccf057293009659572988806a","size":6969317213},"repo_commit":"44e08162359530f95bb4d34687ca7b22e01296d5","save_dir_files":23},"staged":258,"system":"sony-playstation","target":"x86_64","verdict":"boots","verdict_evidence":{"detail":"1 of 1 repetitions: frame 1300 shows Now Loading with the yellow bubble","frame":1300,"repetitions":["boots"],"rule":"repetitions_agree","sha1":"e5af1f2023d0d729ce7aabf52d8e03f75bb8d230","stages":["bios","game"]}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/mednafen_saturn_libretro.so.zip","file":"mednafen_saturn_libretro.so","last_modified":"Tue, 27 Oct 2026 07:34:40 GMT","sha256":"2cef16a3444d45032ad0ae0d523cbff0e5655f4bc15eb33406c81212f54dc9c1"},"emulator":"beetle_saturn","error":null,"files_opened":[{"created":false,"entry":"sega_101.bin","path":"sega_101.bin","sha1":"df94c5b4d47eb3cc404d88b33a8fda237eaf4720"}],"findings":[],"id":"2026-10-27-41d8ddbf0157","install":"pack","platform":"retroarch","platform_system":"sega-saturn","platform_version":"v1.22.2","probed_at":"2026-10-27T22:38:01+00:00","records":["2026-10-27-b35ffbd53148"],"rounds":1,"schema_version":1,"source":{"manifest":null,"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"83712af0cea136bfc15a7088c06c27af028d3251"},"staged":19,"system":"sega-saturn","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/kronos_libretro.so.zip","file":"kronos_libretro.so","last_modified":"Tue, 27 Oct 2026 06:30:48 GMT","sha256":"ca7d0655cb4283b1749ddd2751450d2ec0fd2ea3a3686bde5c4b626cb99e06ac"},"emulator":"kronos","error":null,"files_opened":[],"findings":[],"id":"2026-10-27-3f4e8af52ea7","install":"pack","platform":"retroarch","platform_system":"sega-saturn","platform_version":"v1.22.2","probed_at":"2026-10-27T22:48:37+00:00","records":["2026-10-27-c30af9f8fdf6"],"rounds":1,"schema_version":1,"source":{"manifest":null,"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"83712af0cea136bfc15a7088c06c27af028d3251"},"staged":18,"system":"sega-saturn","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: retro_load_game returned false and no error pattern matched","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/yabasanshiro_libretro.so.zip","file":"yabasanshiro_libretro.so","last_modified":"Tue, 27 Oct 2026 06:26:02 GMT","sha256":"d75ae811201373f0b3db69b4258f5d19ee42bfb81231af8abeb6a8389a8417ec"},"emulator":"yabasanshiro","error":null,"files_opened":[],"findings":[],"id":"2026-10-27-01198b318217","install":"pack","platform":"retroarch","platform_system":"sega-saturn","platform_version":"v1.22.2","probed_at":"2026-10-27T22:53:33+00:00","records":["2026-10-27-6448739cb5b6"],"rounds":1,"schema_version":1,"source":{"manifest":null,"pack":{"file":"RetroArch_v1.22.2_BIOS_Pack.zip","members":10986,"sha256":"2a99c4568ea11beec6a38a7851a4bc1a122309357f601118981674d5d64dbba0","size":4337327025},"repo_commit":"83712af0cea136bfc15a7088c06c27af028d3251"},"staged":13,"system":"sega-saturn","target":"linux-x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: retro_load_game returned false and no error pattern matched","repetitions":["unknown"],"rule":"repetitions_agree"}}
@@ -96,14 +96,14 @@
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/mednafen_saturn_libretro.so.zip","file":"mednafen_saturn_libretro.so","last_modified":"Tue, 27 Oct 2026 07:34:40 GMT","sha256":"2cef16a3444d45032ad0ae0d523cbff0e5655f4bc15eb33406c81212f54dc9c1"},"emulator":"beetle_saturn","error":null,"files_opened":[{"created":false,"entry":"sega_101.bin","path":"sega_101.bin","sha1":"df94c5b4d47eb3cc404d88b33a8fda237eaf4720"}],"findings":[],"id":"2026-10-27-4ebba9f9c0df","install":"pack","platform":"batocera","platform_system":"sega-saturn","platform_version":"43.1","probed_at":"2026-10-27T23:18:01+00:00","records":["2026-10-27-613759bd1faf"],"rounds":1,"schema_version":1,"source":{"manifest":null,"pack":{"file":"Batocera_43.1_BIOS_Pack.zip","members":14725,"sha256":"494c82fe9aff94e0ad6bc1cad0e14f00719ca5dccf057293009659572988806a","size":6969317213},"repo_commit":"83712af0cea136bfc15a7088c06c27af028d3251"},"staged":11,"system":"sega-saturn","target":"x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/kronos_libretro.so.zip","file":"kronos_libretro.so","last_modified":"Tue, 27 Oct 2026 06:30:48 GMT","sha256":"ca7d0655cb4283b1749ddd2751450d2ec0fd2ea3a3686bde5c4b626cb99e06ac"},"emulator":"kronos","error":null,"files_opened":[],"findings":[],"id":"2026-10-27-2629752432de","install":"pack","platform":"batocera","platform_system":"sega-saturn","platform_version":"43.1","probed_at":"2026-10-27T23:19:16+00:00","records":["2026-10-27-89d7c65a2d30"],"rounds":1,"schema_version":1,"source":{"manifest":null,"pack":{"file":"Batocera_43.1_BIOS_Pack.zip","members":14725,"sha256":"494c82fe9aff94e0ad6bc1cad0e14f00719ca5dccf057293009659572988806a","size":6969317213},"repo_commit":"83712af0cea136bfc15a7088c06c27af028d3251"},"staged":11,"system":"sega-saturn","target":"x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: retro_load_game returned false and no error pattern matched","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/yabasanshiro_libretro.so.zip","file":"yabasanshiro_libretro.so","last_modified":"Tue, 27 Oct 2026 06:26:02 GMT","sha256":"d75ae811201373f0b3db69b4258f5d19ee42bfb81231af8abeb6a8389a8417ec"},"emulator":"yabasanshiro","error":null,"files_opened":[],"findings":[],"id":"2026-10-27-226e22f6fa88","install":"pack","platform":"batocera","platform_system":"sega-saturn","platform_version":"43.1","probed_at":"2026-10-27T23:21:32+00:00","records":["2026-10-27-19b6b995c8b3"],"rounds":1,"schema_version":1,"source":{"manifest":null,"pack":{"file":"Batocera_43.1_BIOS_Pack.zip","members":14725,"sha256":"494c82fe9aff94e0ad6bc1cad0e14f00719ca5dccf057293009659572988806a","size":6969317213},"repo_commit":"83712af0cea136bfc15a7088c06c27af028d3251"},"staged":5,"system":"sega-saturn","target":"x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: retro_load_game returned false and no error pattern matched","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/mednafen_saturn_libretro.so.zip","file":"mednafen_saturn_libretro.so","last_modified":"Tue, 27 Oct 2026 07:34:40 GMT","sha256":"2cef16a3444d45032ad0ae0d523cbff0e5655f4bc15eb33406c81212f54dc9c1"},"emulator":"beetle_saturn","error":null,"files_opened":[{"created":false,"entry":"files:sega_101.bin","path":"sega_101.bin","sha1":"df94c5b4d47eb3cc404d88b33a8fda237eaf4720"}],"findings":[],"id":"2026-10-27-1ef12db748b4","install":"installer","platform":"batocera","platform_system":"sega-saturn","platform_version":"43.1","probed_at":"2026-10-27T23:28:01+00:00","records":["2026-10-27-af15e4bf2a6c"],"rounds":1,"schema_version":1,"source":{"installer_summary":"tem/.claude/worktrees/agent-af6705283a8fc4932/tmp/pack_probe/batocera/installer/system/, <dest>/Source/, <dest>/base/ and 10 more folders. To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":14725,"path":"install/batocera.json","sha256":"960b377a8e03a9333bb4853e54425a0f889eecf9342c9c1aadebf3601ae27f20"},"pack":{"file":"Batocera_43.1_BIOS_Pack.zip","members":14725,"sha256":"494c82fe9aff94e0ad6bc1cad0e14f00719ca5dccf057293009659572988806a","size":6969317213},"repo_commit":"83712af0cea136bfc15a7088c06c27af028d3251","save_dir_files":23},"staged":11,"system":"sega-saturn","target":"x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/kronos_libretro.so.zip","file":"kronos_libretro.so","last_modified":"Tue, 27 Oct 2026 06:30:48 GMT","sha256":"ca7d0655cb4283b1749ddd2751450d2ec0fd2ea3a3686bde5c4b626cb99e06ac"},"emulator":"kronos","error":null,"files_opened":[],"findings":[],"id":"2026-10-27-6e7e85fca75c","install":"installer","platform":"batocera","platform_system":"sega-saturn","platform_version":"43.1","probed_at":"2026-10-27T23:37:55+00:00","records":["2026-10-27-6cb5e0f338df"],"rounds":1,"schema_version":1,"source":{"installer_summary":"tem/.claude/worktrees/agent-af6705283a8fc4932/tmp/pack_probe/batocera/installer/system/, <dest>/Source/, <dest>/base/ and 10 more folders. To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":14725,"path":"install/batocera.json","sha256":"960b377a8e03a9333bb4853e54425a0f889eecf9342c9c1aadebf3601ae27f20"},"pack":{"file":"Batocera_43.1_BIOS_Pack.zip","members":14725,"sha256":"494c82fe9aff94e0ad6bc1cad0e14f00719ca5dccf057293009659572988806a","size":6969317213},"repo_commit":"83712af0cea136bfc15a7088c06c27af028d3251","save_dir_files":23},"staged":11,"system":"sega-saturn","target":"x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: retro_load_game returned false and no error pattern matched","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/yabasanshiro_libretro.so.zip","file":"yabasanshiro_libretro.so","last_modified":"Tue, 27 Oct 2026 06:26:02 GMT","sha256":"d75ae811201373f0b3db69b4258f5d19ee42bfb81231af8abeb6a8389a8417ec"},"emulator":"yabasanshiro","error":null,"files_opened":[],"findings":[],"id":"2026-10-27-5f6ba47b3c86","install":"installer","platform":"batocera","platform_system":"sega-saturn","platform_version":"43.1","probed_at":"2026-10-27T23:50:03+00:00","records":["2026-10-27-828497f9002d"],"rounds":1,"schema_version":1,"source":{"installer_summary":"tem/.claude/worktrees/agent-af6705283a8fc4932/tmp/pack_probe/batocera/installer/system/, <dest>/Source/, <dest>/base/ and 10 more folders. To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":14725,"path":"install/batocera.json","sha256":"960b377a8e03a9333bb4853e54425a0f889eecf9342c9c1aadebf3601ae27f20"},"pack":{"file":"Batocera_43.1_BIOS_Pack.zip","members":14725,"sha256":"494c82fe9aff94e0ad6bc1cad0e14f00719ca5dccf057293009659572988806a","size":6969317213},"repo_commit":"83712af0cea136bfc15a7088c06c27af028d3251","save_dir_files":23},"staged":5,"system":"sega-saturn","target":"x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: retro_load_game returned false and no error pattern matched","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/mednafen_saturn_libretro.so.zip","file":"mednafen_saturn_libretro.so","last_modified":"Tue, 27 Oct 2026 07:34:40 GMT","sha256":"2cef16a3444d45032ad0ae0d523cbff0e5655f4bc15eb33406c81212f54dc9c1"},"emulator":"beetle_saturn","error":null,"files_opened":[{"created":false,"entry":"files:sega_101.bin","path":"sega_101.bin","sha1":"df94c5b4d47eb3cc404d88b33a8fda237eaf4720"}],"findings":[],"id":"2026-10-27-bcbd05911326","install":"installer","platform":"batocera","platform_system":"sega-saturn","platform_version":"43.1","probed_at":"2026-10-27T23:28:01+00:00","records":["2026-10-27-af15e4bf2a6c"],"rounds":1,"schema_version":1,"source":{"installer_summary":"<dest>/, <dest>/Source/, <dest>/base/ and 10 more folders. To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":14725,"path":"install/batocera.json","sha256":"960b377a8e03a9333bb4853e54425a0f889eecf9342c9c1aadebf3601ae27f20"},"pack":{"file":"Batocera_43.1_BIOS_Pack.zip","members":14725,"sha256":"494c82fe9aff94e0ad6bc1cad0e14f00719ca5dccf057293009659572988806a","size":6969317213},"repo_commit":"83712af0cea136bfc15a7088c06c27af028d3251","save_dir_files":23},"staged":11,"system":"sega-saturn","target":"x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/kronos_libretro.so.zip","file":"kronos_libretro.so","last_modified":"Tue, 27 Oct 2026 06:30:48 GMT","sha256":"ca7d0655cb4283b1749ddd2751450d2ec0fd2ea3a3686bde5c4b626cb99e06ac"},"emulator":"kronos","error":null,"files_opened":[],"findings":[],"id":"2026-10-27-4a878b5f4350","install":"installer","platform":"batocera","platform_system":"sega-saturn","platform_version":"43.1","probed_at":"2026-10-27T23:37:55+00:00","records":["2026-10-27-6cb5e0f338df"],"rounds":1,"schema_version":1,"source":{"installer_summary":"<dest>/, <dest>/Source/, <dest>/base/ and 10 more folders. To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":14725,"path":"install/batocera.json","sha256":"960b377a8e03a9333bb4853e54425a0f889eecf9342c9c1aadebf3601ae27f20"},"pack":{"file":"Batocera_43.1_BIOS_Pack.zip","members":14725,"sha256":"494c82fe9aff94e0ad6bc1cad0e14f00719ca5dccf057293009659572988806a","size":6969317213},"repo_commit":"83712af0cea136bfc15a7088c06c27af028d3251","save_dir_files":23},"staged":11,"system":"sega-saturn","target":"x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: retro_load_game returned false and no error pattern matched","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/yabasanshiro_libretro.so.zip","file":"yabasanshiro_libretro.so","last_modified":"Tue, 27 Oct 2026 06:26:02 GMT","sha256":"d75ae811201373f0b3db69b4258f5d19ee42bfb81231af8abeb6a8389a8417ec"},"emulator":"yabasanshiro","error":null,"files_opened":[],"findings":[],"id":"2026-10-27-c50f17aa847e","install":"installer","platform":"batocera","platform_system":"sega-saturn","platform_version":"43.1","probed_at":"2026-10-27T23:50:03+00:00","records":["2026-10-27-828497f9002d"],"rounds":1,"schema_version":1,"source":{"installer_summary":"<dest>/, <dest>/Source/, <dest>/base/ and 10 more folders. To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":14725,"path":"install/batocera.json","sha256":"960b377a8e03a9333bb4853e54425a0f889eecf9342c9c1aadebf3601ae27f20"},"pack":{"file":"Batocera_43.1_BIOS_Pack.zip","members":14725,"sha256":"494c82fe9aff94e0ad6bc1cad0e14f00719ca5dccf057293009659572988806a","size":6969317213},"repo_commit":"83712af0cea136bfc15a7088c06c27af028d3251","save_dir_files":23},"staged":5,"system":"sega-saturn","target":"x86_64","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: retro_load_game returned false and no error pattern matched","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/mednafen_saturn_libretro.so.zip","file":"mednafen_saturn_libretro.so","last_modified":"Tue, 27 Oct 2026 07:34:40 GMT","sha256":"2cef16a3444d45032ad0ae0d523cbff0e5655f4bc15eb33406c81212f54dc9c1"},"emulator":"beetle_saturn","error":null,"files_opened":[{"created":false,"entry":"sega_101.bin","path":"sega_101.bin","sha1":"df94c5b4d47eb3cc404d88b33a8fda237eaf4720"}],"findings":[],"id":"2026-10-27-804ca236cadc","install":"pack","platform":"retrobat","platform_system":"sega-saturn","platform_version":"8.3.1","probed_at":"2026-10-27T23:51:45+00:00","records":["2026-10-27-07310c597c37"],"rounds":1,"schema_version":1,"source":{"manifest":null,"pack":{"file":"RetroBat_8.3.1_BIOS_Pack.zip","members":5561,"sha256":"89bdc445768e9568bd88737871f1e713df3d08fe0e191de18d228291d6e40647","size":5644690738},"repo_commit":"83712af0cea136bfc15a7088c06c27af028d3251"},"staged":13,"system":"sega-saturn","target":"windows","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/kronos_libretro.so.zip","file":"kronos_libretro.so","last_modified":"Tue, 27 Oct 2026 06:30:48 GMT","sha256":"ca7d0655cb4283b1749ddd2751450d2ec0fd2ea3a3686bde5c4b626cb99e06ac"},"emulator":"kronos","error":null,"files_opened":[],"findings":[],"id":"2026-10-27-bb15cfe730d7","install":"pack","platform":"retrobat","platform_system":"sega-saturn","platform_version":"8.3.1","probed_at":"2026-10-27T23:52:42+00:00","records":["2026-10-27-6bd260b246f8"],"rounds":1,"schema_version":1,"source":{"manifest":null,"pack":{"file":"RetroBat_8.3.1_BIOS_Pack.zip","members":5561,"sha256":"89bdc445768e9568bd88737871f1e713df3d08fe0e191de18d228291d6e40647","size":5644690738},"repo_commit":"83712af0cea136bfc15a7088c06c27af028d3251"},"staged":11,"system":"sega-saturn","target":"windows","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: retro_load_game returned false and no error pattern matched","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/yabasanshiro_libretro.so.zip","file":"yabasanshiro_libretro.so","last_modified":"Tue, 27 Oct 2026 06:26:02 GMT","sha256":"d75ae811201373f0b3db69b4258f5d19ee42bfb81231af8abeb6a8389a8417ec"},"emulator":"yabasanshiro","error":null,"files_opened":[],"findings":[],"id":"2026-10-27-babce101aafc","install":"pack","platform":"retrobat","platform_system":"sega-saturn","platform_version":"8.3.1","probed_at":"2026-10-27T23:52:42+00:00","records":["2026-10-27-b92d0c40b7cb"],"rounds":1,"schema_version":1,"source":{"manifest":null,"pack":{"file":"RetroBat_8.3.1_BIOS_Pack.zip","members":5561,"sha256":"89bdc445768e9568bd88737871f1e713df3d08fe0e191de18d228291d6e40647","size":5644690738},"repo_commit":"83712af0cea136bfc15a7088c06c27af028d3251"},"staged":7,"system":"sega-saturn","target":"windows","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: retro_load_game returned false and no error pattern matched","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/ymir_libretro.so.zip","file":"ymir_libretro.so","last_modified":"Tue, 27 Oct 2026 05:34:56 GMT","sha256":"237d154fa6ef5caccc1d2899e0a2444947e4391a81bd241803932d1319832712"},"emulator":"ymir","error":null,"files_opened":[{"created":false,"entry":"sega_101.bin","path":"sega_101.bin","sha1":"df94c5b4d47eb3cc404d88b33a8fda237eaf4720"},{"created":false,"entry":"mpr-17933.bin","path":"mpr-17933.bin","sha1":"faa8ea183a6d7bbe5d4e03bb1332519800d3fbc3"},{"created":false,"entry":"saturn_bios.bin","path":"saturn_bios.bin","sha1":"2b8cb4f87580683eb4d760e4ed210813d667f0a2"},{"created":false,"entry":"cdb/cdb_rom.bin","path":"cdb/cdb_rom.bin","sha1":"b3c20fbe57cd2eb595e9edac86817e5948dccae4"}],"findings":[],"id":"2026-10-27-19073ee28285","install":"pack","platform":"retrobat","platform_system":"sega-saturn","platform_version":"8.3.1","probed_at":"2026-10-27T23:52:54+00:00","records":["2026-10-27-e4aee262160e"],"rounds":1,"schema_version":1,"source":{"manifest":null,"pack":{"file":"RetroBat_8.3.1_BIOS_Pack.zip","members":5561,"sha256":"89bdc445768e9568bd88737871f1e713df3d08fe0e191de18d228291d6e40647","size":5644690738},"repo_commit":"83712af0cea136bfc15a7088c06c27af028d3251"},"staged":8,"system":"sega-saturn","target":"windows","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/mednafen_saturn_libretro.so.zip","file":"mednafen_saturn_libretro.so","last_modified":"Tue, 27 Oct 2026 07:34:40 GMT","sha256":"2cef16a3444d45032ad0ae0d523cbff0e5655f4bc15eb33406c81212f54dc9c1"},"emulator":"beetle_saturn","error":null,"files_opened":[{"created":false,"entry":"files:sega_101.bin","path":"sega_101.bin","sha1":"df94c5b4d47eb3cc404d88b33a8fda237eaf4720"}],"findings":[],"id":"2026-10-27-ce9ff2f7f69e","install":"installer","platform":"retrobat","platform_system":"sega-saturn","platform_version":"8.3.1","probed_at":"2026-10-27T23:54:19+00:00","records":["2026-10-27-dcac17ec3f00"],"rounds":1,"schema_version":1,"source":{"installer_summary":".claude/worktrees/agent-af6705283a8fc4932/tmp/pack_probe/retrobat/installer/system/, <dest>/base/, <dest>/devilutionx/ and 1 more folders. To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":5561,"path":"install/retrobat.json","sha256":"ef2c453bbd23f10a19322b9b31f0983bfc3cdc36bcea5442f88f42b5a2eb9608"},"pack":{"file":"RetroBat_8.3.1_BIOS_Pack.zip","members":5561,"sha256":"89bdc445768e9568bd88737871f1e713df3d08fe0e191de18d228291d6e40647","size":5644690738},"repo_commit":"83712af0cea136bfc15a7088c06c27af028d3251","save_dir_files":41},"staged":13,"system":"sega-saturn","target":"windows","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/kronos_libretro.so.zip","file":"kronos_libretro.so","last_modified":"Tue, 27 Oct 2026 06:30:48 GMT","sha256":"ca7d0655cb4283b1749ddd2751450d2ec0fd2ea3a3686bde5c4b626cb99e06ac"},"emulator":"kronos","error":null,"files_opened":[],"findings":[],"id":"2026-10-27-3c840e36bf04","install":"installer","platform":"retrobat","platform_system":"sega-saturn","platform_version":"8.3.1","probed_at":"2026-10-27T23:54:19+00:00","records":["2026-10-27-41b7958405f2"],"rounds":1,"schema_version":1,"source":{"installer_summary":".claude/worktrees/agent-af6705283a8fc4932/tmp/pack_probe/retrobat/installer/system/, <dest>/base/, <dest>/devilutionx/ and 1 more folders. To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":5561,"path":"install/retrobat.json","sha256":"ef2c453bbd23f10a19322b9b31f0983bfc3cdc36bcea5442f88f42b5a2eb9608"},"pack":{"file":"RetroBat_8.3.1_BIOS_Pack.zip","members":5561,"sha256":"89bdc445768e9568bd88737871f1e713df3d08fe0e191de18d228291d6e40647","size":5644690738},"repo_commit":"83712af0cea136bfc15a7088c06c27af028d3251","save_dir_files":41},"staged":11,"system":"sega-saturn","target":"windows","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: retro_load_game returned false and no error pattern matched","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/yabasanshiro_libretro.so.zip","file":"yabasanshiro_libretro.so","last_modified":"Tue, 27 Oct 2026 06:26:02 GMT","sha256":"d75ae811201373f0b3db69b4258f5d19ee42bfb81231af8abeb6a8389a8417ec"},"emulator":"yabasanshiro","error":null,"files_opened":[],"findings":[],"id":"2026-10-27-90f89c3310ca","install":"installer","platform":"retrobat","platform_system":"sega-saturn","platform_version":"8.3.1","probed_at":"2026-10-27T23:54:20+00:00","records":["2026-10-27-b25e77568729"],"rounds":1,"schema_version":1,"source":{"installer_summary":".claude/worktrees/agent-af6705283a8fc4932/tmp/pack_probe/retrobat/installer/system/, <dest>/base/, <dest>/devilutionx/ and 1 more folders. To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":5561,"path":"install/retrobat.json","sha256":"ef2c453bbd23f10a19322b9b31f0983bfc3cdc36bcea5442f88f42b5a2eb9608"},"pack":{"file":"RetroBat_8.3.1_BIOS_Pack.zip","members":5561,"sha256":"89bdc445768e9568bd88737871f1e713df3d08fe0e191de18d228291d6e40647","size":5644690738},"repo_commit":"83712af0cea136bfc15a7088c06c27af028d3251","save_dir_files":41},"staged":7,"system":"sega-saturn","target":"windows","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: retro_load_game returned false and no error pattern matched","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/ymir_libretro.so.zip","file":"ymir_libretro.so","last_modified":"Tue, 27 Oct 2026 05:34:56 GMT","sha256":"237d154fa6ef5caccc1d2899e0a2444947e4391a81bd241803932d1319832712"},"emulator":"ymir","error":null,"files_opened":[{"created":false,"entry":"files:sega_101.bin","path":"sega_101.bin","sha1":"df94c5b4d47eb3cc404d88b33a8fda237eaf4720"},{"created":false,"entry":"files:mpr-17933.bin","path":"mpr-17933.bin","sha1":"faa8ea183a6d7bbe5d4e03bb1332519800d3fbc3"},{"created":false,"entry":"files:saturn_bios.bin","path":"saturn_bios.bin","sha1":"2b8cb4f87580683eb4d760e4ed210813d667f0a2"},{"created":false,"entry":"files:cdb/cdb_rom.bin","path":"cdb/cdb_rom.bin","sha1":"b3c20fbe57cd2eb595e9edac86817e5948dccae4"}],"findings":[],"id":"2026-10-27-373980ad54bf","install":"installer","platform":"retrobat","platform_system":"sega-saturn","platform_version":"8.3.1","probed_at":"2026-10-27T23:54:32+00:00","records":["2026-10-27-9b443640216e"],"rounds":1,"schema_version":1,"source":{"installer_summary":".claude/worktrees/agent-af6705283a8fc4932/tmp/pack_probe/retrobat/installer/system/, <dest>/base/, <dest>/devilutionx/ and 1 more folders. To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":5561,"path":"install/retrobat.json","sha256":"ef2c453bbd23f10a19322b9b31f0983bfc3cdc36bcea5442f88f42b5a2eb9608"},"pack":{"file":"RetroBat_8.3.1_BIOS_Pack.zip","members":5561,"sha256":"89bdc445768e9568bd88737871f1e713df3d08fe0e191de18d228291d6e40647","size":5644690738},"repo_commit":"83712af0cea136bfc15a7088c06c27af028d3251","save_dir_files":41},"staged":8,"system":"sega-saturn","target":"windows","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/mednafen_saturn_libretro.so.zip","file":"mednafen_saturn_libretro.so","last_modified":"Tue, 27 Oct 2026 07:34:40 GMT","sha256":"2cef16a3444d45032ad0ae0d523cbff0e5655f4bc15eb33406c81212f54dc9c1"},"emulator":"beetle_saturn","error":null,"files_opened":[{"created":false,"entry":"files:sega_101.bin","path":"sega_101.bin","sha1":"df94c5b4d47eb3cc404d88b33a8fda237eaf4720"}],"findings":[],"id":"2026-10-27-38228b00f155","install":"installer","platform":"retrobat","platform_system":"sega-saturn","platform_version":"8.3.1","probed_at":"2026-10-27T23:54:19+00:00","records":["2026-10-27-dcac17ec3f00"],"rounds":1,"schema_version":1,"source":{"installer_summary":"<dest>/, <dest>/base/, <dest>/devilutionx/ and 1 more folders. To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":5561,"path":"install/retrobat.json","sha256":"ef2c453bbd23f10a19322b9b31f0983bfc3cdc36bcea5442f88f42b5a2eb9608"},"pack":{"file":"RetroBat_8.3.1_BIOS_Pack.zip","members":5561,"sha256":"89bdc445768e9568bd88737871f1e713df3d08fe0e191de18d228291d6e40647","size":5644690738},"repo_commit":"83712af0cea136bfc15a7088c06c27af028d3251","save_dir_files":41},"staged":13,"system":"sega-saturn","target":"windows","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/kronos_libretro.so.zip","file":"kronos_libretro.so","last_modified":"Tue, 27 Oct 2026 06:30:48 GMT","sha256":"ca7d0655cb4283b1749ddd2751450d2ec0fd2ea3a3686bde5c4b626cb99e06ac"},"emulator":"kronos","error":null,"files_opened":[],"findings":[],"id":"2026-10-27-c59960b4781f","install":"installer","platform":"retrobat","platform_system":"sega-saturn","platform_version":"8.3.1","probed_at":"2026-10-27T23:54:19+00:00","records":["2026-10-27-41b7958405f2"],"rounds":1,"schema_version":1,"source":{"installer_summary":"<dest>/, <dest>/base/, <dest>/devilutionx/ and 1 more folders. To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":5561,"path":"install/retrobat.json","sha256":"ef2c453bbd23f10a19322b9b31f0983bfc3cdc36bcea5442f88f42b5a2eb9608"},"pack":{"file":"RetroBat_8.3.1_BIOS_Pack.zip","members":5561,"sha256":"89bdc445768e9568bd88737871f1e713df3d08fe0e191de18d228291d6e40647","size":5644690738},"repo_commit":"83712af0cea136bfc15a7088c06c27af028d3251","save_dir_files":41},"staged":11,"system":"sega-saturn","target":"windows","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: retro_load_game returned false and no error pattern matched","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/yabasanshiro_libretro.so.zip","file":"yabasanshiro_libretro.so","last_modified":"Tue, 27 Oct 2026 06:26:02 GMT","sha256":"d75ae811201373f0b3db69b4258f5d19ee42bfb81231af8abeb6a8389a8417ec"},"emulator":"yabasanshiro","error":null,"files_opened":[],"findings":[],"id":"2026-10-27-52334b9682db","install":"installer","platform":"retrobat","platform_system":"sega-saturn","platform_version":"8.3.1","probed_at":"2026-10-27T23:54:20+00:00","records":["2026-10-27-b25e77568729"],"rounds":1,"schema_version":1,"source":{"installer_summary":"<dest>/, <dest>/base/, <dest>/devilutionx/ and 1 more folders. To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":5561,"path":"install/retrobat.json","sha256":"ef2c453bbd23f10a19322b9b31f0983bfc3cdc36bcea5442f88f42b5a2eb9608"},"pack":{"file":"RetroBat_8.3.1_BIOS_Pack.zip","members":5561,"sha256":"89bdc445768e9568bd88737871f1e713df3d08fe0e191de18d228291d6e40647","size":5644690738},"repo_commit":"83712af0cea136bfc15a7088c06c27af028d3251","save_dir_files":41},"staged":7,"system":"sega-saturn","target":"windows","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: retro_load_game returned false and no error pattern matched","repetitions":["unknown"],"rule":"repetitions_agree"}}
{"content":{"catalog":"redump","label":"Lunar - Silver Star Story Complete (Japan)","region":"japan"},"core":{"artifact":"https://buildbot.libretro.com/nightly/linux/x86_64/latest/ymir_libretro.so.zip","file":"ymir_libretro.so","last_modified":"Tue, 27 Oct 2026 05:34:56 GMT","sha256":"237d154fa6ef5caccc1d2899e0a2444947e4391a81bd241803932d1319832712"},"emulator":"ymir","error":null,"files_opened":[{"created":false,"entry":"files:sega_101.bin","path":"sega_101.bin","sha1":"df94c5b4d47eb3cc404d88b33a8fda237eaf4720"},{"created":false,"entry":"files:mpr-17933.bin","path":"mpr-17933.bin","sha1":"faa8ea183a6d7bbe5d4e03bb1332519800d3fbc3"},{"created":false,"entry":"files:saturn_bios.bin","path":"saturn_bios.bin","sha1":"2b8cb4f87580683eb4d760e4ed210813d667f0a2"},{"created":false,"entry":"files:cdb/cdb_rom.bin","path":"cdb/cdb_rom.bin","sha1":"b3c20fbe57cd2eb595e9edac86817e5948dccae4"}],"findings":[],"id":"2026-10-27-3b4ca79d1253","install":"installer","platform":"retrobat","platform_system":"sega-saturn","platform_version":"8.3.1","probed_at":"2026-10-27T23:54:32+00:00","records":["2026-10-27-9b443640216e"],"rounds":1,"schema_version":1,"source":{"installer_summary":"<dest>/, <dest>/base/, <dest>/devilutionx/ and 1 more folders. To check this later, run the same command with --check.","manifest":{"generated":"2026-10-27T10:27:58Z","pack_files":5561,"path":"install/retrobat.json","sha256":"ef2c453bbd23f10a19322b9b31f0983bfc3cdc36bcea5442f88f42b5a2eb9608"},"pack":{"file":"RetroBat_8.3.1_BIOS_Pack.zip","members":5561,"sha256":"89bdc445768e9568bd88737871f1e713df3d08fe0e191de18d228291d6e40647","size":5644690738},"repo_commit":"83712af0cea136bfc15a7088c06c27af028d3251","save_dir_files":41},"staged":8,"system":"sega-saturn","target":"windows","verdict":"unknown","verdict_evidence":{"detail":"1 of 1 repetitions: no reference frame is known for this content on this core","repetitions":["unknown"],"rule":"repetitions_agree"}}
+974
View File
@@ -0,0 +1,974 @@
install.py:0: error: "Invocation" has no attribute "__iter__" (not iterable) [attr-defined]
install.py:0: error: "None" object is not iterable [misc]
install.py:0: error: "OSError" has no attribute "attempts" [attr-defined]
install.py:0: error: "_Unclosed" has no attribute "name" [attr-defined]
install.py:0: error: "bool" has no attribute "name" [attr-defined]
install.py:0: error: "bool" has no attribute "parent" [attr-defined]
install.py:0: error: "object" has no attribute "get" [attr-defined]
install.py:0: error: "object" has no attribute "get" [attr-defined]
install.py:0: error: "object" has no attribute "rstrip" [attr-defined]
install.py:0: error: "object" object is not iterable [misc]
install.py:0: error: "object" object is not iterable [misc]
install.py:0: error: "str" has no attribute "append" [attr-defined]
install.py:0: error: "str" has no attribute "append" [attr-defined]
install.py:0: error: Argument 1 to "Path" has incompatible type "object"; expected "Union[str, PathLike[str]]" [arg-type]
install.py:0: error: Argument 1 to "Path" has incompatible type "object"; expected "Union[str, PathLike[str]]" [arg-type]
install.py:0: error: Argument 1 to "_ZippedLookup" has incompatible type "Optional[FolderIndex]"; expected "FolderIndex" [arg-type]
install.py:0: error: Argument 1 to "__iadd__" of "list" has incompatible type "Invocation"; expected "Iterable[str]" [arg-type]
install.py:0: error: Argument 1 to "_digest_file" has incompatible type "Optional[Path]"; expected "Path" [arg-type]
install.py:0: error: Argument 1 to "_folder_writable" has incompatible type "Optional[Path]"; expected "Path" [arg-type]
install.py:0: error: Argument 1 to "_listed_names" has incompatible type "bool"; expected "Path" [arg-type]
install.py:0: error: Argument 1 to "_nearest_folder" has incompatible type "Optional[Path]"; expected "Path" [arg-type]
install.py:0: error: Argument 1 to "_replace_released" has incompatible type "Optional[Path]"; expected "Path" [arg-type]
install.py:0: error: Argument 1 to "append" of "list" has incompatible type "Optional[CardApp]"; expected "CardApp" [arg-type]
install.py:0: error: Argument 1 to "append" of "list" has incompatible type "Union[TuiKey, TuiMouse]"; expected "TuiKey" [arg-type]
install.py:0: error: Argument 1 to "cannot_write_words" has incompatible type "Optional[Path]"; expected "Path" [arg-type]
install.py:0: error: Argument 1 to "chmod" has incompatible type "Optional[Path]"; expected "Union[int, Union[str, bytes, PathLike[str], PathLike[bytes]]]" [arg-type]
install.py:0: error: Argument 1 to "copy_source_refusal" has incompatible type "object"; expected "Optional[Path]" [arg-type]
install.py:0: error: Argument 1 to "first_holding" of "FolderIndex" has incompatible type "set[Optional[Any]]"; expected "set[int]" [arg-type]
install.py:0: error: Argument 1 to "len" has incompatible type "Optional[Any]"; expected "Sized" [arg-type]
install.py:0: error: Argument 1 to "len" has incompatible type "Optional[Any]"; expected "Sized" [arg-type]
install.py:0: error: Argument 1 to "len" has incompatible type "Optional[Any]"; expected "Sized" [arg-type]
install.py:0: error: Argument 1 to "len" has incompatible type "Optional[list[dict[Any, Any]]]"; expected "Sized" [arg-type]
install.py:0: error: Argument 1 to "remove" of "list" has incompatible type "int"; expected "FolderIndex" [arg-type]
install.py:0: error: Argument 1 to "replace" has incompatible type "Optional[Path]"; expected "Union[str, bytes, PathLike[str], PathLike[bytes]]" [arg-type]
install.py:0: error: Argument 1 to "setdefault" of "MutableMapping" has incompatible type "Optional[Any]"; expected "str" [arg-type]
install.py:0: error: Argument 1 to "settimeout" of "socket" has incompatible type "object"; expected "Optional[float]" [arg-type]
install.py:0: error: Argument 1 to "shown_path" has incompatible type "Optional[Path]"; expected "Union[Path, str]" [arg-type]
install.py:0: error: Argument 1 to "shown_path" has incompatible type "Optional[Path]"; expected "Union[Path, str]" [arg-type]
install.py:0: error: Argument 1 to "shown_path" has incompatible type "Optional[Path]"; expected "Union[Path, str]" [arg-type]
install.py:0: error: Argument 1 to "shown_path" has incompatible type "Optional[Path]"; expected "Union[Path, str]" [arg-type]
install.py:0: error: Argument 2 to "_browse_to" has incompatible type "object"; expected "Optional[Path]" [arg-type]
install.py:0: error: Argument 2 to "_browse_to" has incompatible type "object"; expected "Optional[Path]" [arg-type]
install.py:0: error: Argument 2 to "_choose_card" has incompatible type "Optional[Path]"; expected "Path" [arg-type]
install.py:0: error: Argument 2 to "_choose_card" has incompatible type "object"; expected "Path" [arg-type]
install.py:0: error: Argument 2 to "_found_elsewhere" has incompatible type "Optional[FolderIndex]"; expected "FolderIndex" [arg-type]
install.py:0: error: Argument 2 to "_setup_label" has incompatible type "Optional[Path]"; expected "Path" [arg-type]
install.py:0: error: Argument 2 to "_toggle_region" has incompatible type "object"; expected "str" [arg-type]
install.py:0: error: Argument 2 to "core_dirs" has incompatible type "Optional[Path]"; expected "Path" [arg-type]
install.py:0: error: Argument 2 to "detected_os" has incompatible type "Optional[Path]"; expected "Path" [arg-type]
install.py:0: error: Argument 2 to "first_holding" of "FolderIndex" has incompatible type "set[Optional[Any]]"; expected "set[str]" [arg-type]
install.py:0: error: Argument 2 to "from_bytes" of "int" has incompatible type "str"; expected "Literal['little', 'big']" [arg-type]
install.py:0: error: Argument 2 to "insert" of "list" has incompatible type "str"; expected "TuiLine" [arg-type]
install.py:0: error: Argument 2 to "insert" of "list" has incompatible type "str"; expected "TuiLine" [arg-type]
install.py:0: error: Argument 2 to "insert" of "list" has incompatible type "str"; expected "TuiLine" [arg-type]
install.py:0: error: Argument 2 to "insert" of "list" has incompatible type "str"; expected "TuiLine" [arg-type]
install.py:0: error: Argument 2 to "insert" of "list" has incompatible type "str"; expected "TuiLine" [arg-type]
install.py:0: error: Argument 3 to "CardSetup" has incompatible type "Optional[str]"; expected "str" [arg-type]
install.py:0: error: Argument 3 to "_choose" has incompatible type "Optional[Path]"; expected "Path" [arg-type]
install.py:0: error: Argument 3 to "_choose" has incompatible type "object"; expected "Path" [arg-type]
install.py:0: error: Argument 3 to "_misplaced" has incompatible type "Optional[FolderIndex]"; expected "FolderIndex" [arg-type]
install.py:0: error: Argument 3 to "_wrong_contents" has incompatible type "Optional[FolderIndex]"; expected "FolderIndex" [arg-type]
install.py:0: error: Argument 3 to "create_connection" has incompatible type "object"; expected "Optional[Union[tuple[Any, ...], str, Buffer]]" [arg-type]
install.py:0: error: Argument 3 to "keep_regions" has incompatible type "list[str]"; expected "frozenset[Any]" [arg-type]
install.py:0: error: Argument 4 to "_write_verified" has incompatible type "Callable[[], IO[bytes]]"; expected "Callable[[], ContextManager[BinaryIO]]" [arg-type]
install.py:0: error: Argument 6 to "_compose" has incompatible type "tuple[()]"; expected "list[Any]" [arg-type]
install.py:0: error: Argument 6 to "_compose" has incompatible type "tuple[()]"; expected "list[Any]" [arg-type]
install.py:0: error: Argument 6 to "_compose" has incompatible type "tuple[()]"; expected "list[Any]" [arg-type]
install.py:0: error: Argument 7 to "_install_data_member" has incompatible type "object"; expected "list[tuple[str, str]]" [arg-type]
install.py:0: error: Cannot determine type of "cores" [has-type]
install.py:0: error: Cannot determine type of "mount" [has-type]
install.py:0: error: Cannot determine type of "mount" [has-type]
install.py:0: error: Cannot determine type of "plat" [has-type]
install.py:0: error: Cannot determine type of "plat" [has-type]
install.py:0: error: Cannot determine type of "plat" [has-type]
install.py:0: error: Cannot determine type of "regions" [has-type]
install.py:0: error: Cannot determine type of "system" [has-type]
install.py:0: error: Cannot determine type of "system" [has-type]
install.py:0: error: Cannot determine type of "system" [has-type]
install.py:0: error: Cannot determine type of "systems" [has-type]
install.py:0: error: Cannot infer type of lambda [misc]
install.py:0: error: Cannot infer type of lambda [misc]
install.py:0: error: Cannot infer type of lambda [misc]
install.py:0: error: Cannot infer type of lambda [misc]
install.py:0: error: Generator has incompatible item type "int"; expected "bool" [misc]
install.py:0: error: Incompatible default for argument "after" (default has type "tuple[()]", argument has type "list[Any]") [assignment]
install.py:0: error: Incompatible default for argument "copied" (default has type "tuple[()]", argument has type "list[str]") [assignment]
install.py:0: error: Incompatible default for argument "cores" (default has type "tuple[()]", argument has type "list[str]") [assignment]
install.py:0: error: Incompatible default for argument "footer" (default has type "tuple[()]", argument has type "list[Any]") [assignment]
install.py:0: error: Incompatible default for argument "omitted" (default has type "tuple[()]", argument has type "list[dict[Any, Any]]") [assignment]
install.py:0: error: Incompatible default for argument "pinned" (default has type "tuple[()]", argument has type "list[Any]") [assignment]
install.py:0: error: Incompatible default for argument "regions" (default has type "tuple[()]", argument has type "list[str]") [assignment]
install.py:0: error: Incompatible default for argument "systems" (default has type "tuple[()]", argument has type "list[str]") [assignment]
install.py:0: error: Incompatible default for argument "trees" (default has type "tuple[()]", argument has type "list[tuple[dict[Any, Any], dict[str, dict[Any, Any]]]]") [assignment]
install.py:0: error: Incompatible return value type (got "IO[bytes]", expected "ContextManager[BinaryIO]") [return-value]
install.py:0: error: Incompatible return value type (got "Optional[Path]", expected "Path") [return-value]
install.py:0: error: Incompatible return value type (got "Union[Any, object]", expected "str") [return-value]
install.py:0: error: Incompatible return value type (got "list[TuiLine]", expected "list[str]") [return-value]
install.py:0: error: Incompatible return value type (got "list[TuiLine]", expected "list[str]") [return-value]
install.py:0: error: Incompatible return value type (got "list[tuple[Optional[str], str]]", expected "list[tuple[str, str]]") [return-value]
install.py:0: error: Incompatible return value type (got "object", expected "dict[Any, Any]") [return-value]
install.py:0: error: Incompatible types in "yield" (actual type "IO[bytes]", expected type "BinaryIO") [misc]
install.py:0: error: Incompatible types in "yield" (actual type "tuple[str, int, Callable[[Any], IO[bytes]]]", expected type "tuple[str, int, Callable[[], BinaryIO]]") [misc]
install.py:0: error: Incompatible types in "yield" (actual type "tuple[str, int, Callable[[Any], Optional[IO[bytes]]]]", expected type "tuple[str, int, Callable[[], BinaryIO]]") [misc]
install.py:0: error: Incompatible types in assignment (expression has type "FolderIndex", base class "tuple" defined the type as "Callable[[Any, SupportsIndex, SupportsIndex], int]") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "FolderIndex", base class "tuple" defined the type as "Callable[[Any, SupportsIndex, SupportsIndex], int]") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "FolderIndex", variable has type "int") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "GamesChoice", variable has type "Optional[tuple[list[str], list[str], list[str]]]") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "GamesChoice", variable has type "Optional[tuple[list[str], list[str], list[str]]]") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "GamesChoice", variable has type "Optional[tuple[list[str], list[str], list[str]]]") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "Optional[Progress]", variable has type "Progress") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "Optional[frozenset[Any]]", variable has type "Optional[tuple[int, str]]") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "Optional[frozenset[Any]]", variable has type "list[str]") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "Optional[int]", variable has type "int") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "Optional[str]", variable has type "str") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "Path", variable has type "bool") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "Union[Any, bool]", variable has type "str") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "Union[Any, list[Any]]", variable has type "set[str]") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "Union[tuple[list[str], list[str], list[str]], str, GamesChoice, None]", variable has type "Optional[tuple[list[str], list[str], list[str]]]") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "_TemporaryFileWrapper[bytes]", variable has type "_Unclosed") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "float", variable has type "Optional[int]") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "int", base class "tuple" defined the type as "Callable[[Any, SupportsIndex, SupportsIndex], int]") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "int", base class "tuple" defined the type as "Callable[[Any], int]") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "int", variable has type "list[dict[Any, Any]]") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "int", variable has type "str") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "list[dict[Any, Any]]", variable has type "int") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "list[str]", variable has type "Invocation") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "list[str]", variable has type "str") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "set[int]", variable has type "int") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "set[int]", variable has type "list[dict[Any, Any]]") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "set[int]", variable has type "list[dict[Any, Any]]") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "str", target has type "int") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "str", variable has type "Optional[Path]") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "str", variable has type "Optional[tuple[list[str], list[str], list[str]]]") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "str", variable has type "bool") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "tuple[int, str]", variable has type "Optional[frozenset[Any]]") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "tuple[tuple[str, Any], tuple[str, Any], tuple[str, Any], tuple[str, Any], tuple[str, Any], tuple[str, Any], tuple[str, Any]]", variable has type "tuple[tuple[str, Any], tuple[str, Any], tuple[str, Any], tuple[str, Any]]") [assignment]
install.py:0: error: Incompatible types in assignment (expression has type "tuple[tuple[str, Any], tuple[str, Any], tuple[str, Any], tuple[str, Any], tuple[str, Any]]", variable has type "tuple[tuple[str, Any], tuple[str, Any], tuple[str, Any], tuple[str, Any]]") [assignment]
install.py:0: error: Item "None" of "Optional[BinaryIO]" has no attribute "truncate" [union-attr]
install.py:0: error: Item "None" of "Optional[Element[str]]" has no attribute "iter" [union-attr]
install.py:0: error: Item "None" of "Optional[PackSource]" has no attribute "name" [union-attr]
install.py:0: error: Item "None" of "Optional[PackSource]" has no attribute "name" [union-attr]
install.py:0: error: Item "None" of "Optional[Path]" has no attribute "__iter__" (not iterable) [union-attr]
install.py:0: error: Item "None" of "Optional[Path]" has no attribute "__iter__" (not iterable) [union-attr]
install.py:0: error: Item "None" of "Optional[Path]" has no attribute "append" [union-attr]
install.py:0: error: Item "None" of "Optional[Path]" has no attribute "read_text" [union-attr]
install.py:0: error: Item "None" of "Optional[Path]" has no attribute "write_text" [union-attr]
install.py:0: error: Item "None" of "Optional[Terminal]" has no attribute "stream" [union-attr]
install.py:0: error: Item "None" of "Optional[Terminal]" has no attribute "stream" [union-attr]
install.py:0: error: Item "None" of "Optional[Terminal]" has no attribute "stream" [union-attr]
install.py:0: error: Item "None" of "Optional[Terminal]" has no attribute "stream" [union-attr]
install.py:0: error: Item "None" of "Optional[TuiHits]" has no attribute "frame" [union-attr]
install.py:0: error: Item "None" of "Optional[TuiHits]" has no attribute "shown" [union-attr]
install.py:0: error: Item "Path" of "Optional[Path]" has no attribute "__iter__" (not iterable) [union-attr]
install.py:0: error: Item "Path" of "Optional[Path]" has no attribute "__iter__" (not iterable) [union-attr]
install.py:0: error: Item "Path" of "Optional[Path]" has no attribute "append" [union-attr]
install.py:0: error: List comprehension has incompatible type List[object]; expected List[str] [misc]
install.py:0: error: List item 0 has incompatible type "int"; expected "FolderIndex" [list-item]
install.py:0: error: List item 0 has incompatible type "tuple[Optional[str], str]"; expected "tuple[str, str]" [list-item]
install.py:0: error: List item 0 has incompatible type "tuple[Optional[str], str]"; expected "tuple[str, str]" [list-item]
install.py:0: error: List item 3 has incompatible type "tuple[Optional[str], str]"; expected "tuple[str, str]" [list-item]
install.py:0: error: Module has no attribute "HKEY_CURRENT_USER" [attr-defined]
install.py:0: error: Module has no attribute "HKEY_LOCAL_MACHINE" [attr-defined]
install.py:0: error: Module has no attribute "LK_NBLCK" [attr-defined]
install.py:0: error: Module has no attribute "OpenKey" [attr-defined]
install.py:0: error: Module has no attribute "QueryValueEx" [attr-defined]
install.py:0: error: Module has no attribute "locking" [attr-defined]
install.py:0: error: Name "found" already defined on line 0 [no-redef]
install.py:0: error: Name "top" already defined on line 0 [no-redef]
install.py:0: error: Need type annotation for "removed" (hint: "removed: list[<type>] = ...") [var-annotated]
install.py:0: error: Need type annotation for "words" (hint: "words: list[<type>] = ...") [var-annotated]
install.py:0: error: No overload variant of "__getitem__" of "list" matches argument type "object" [call-overload]
install.py:0: error: No overload variant of "min" matches argument types "float", "object" [call-overload]
install.py:0: error: Unsupported left operand type for + ("None") [operator]
install.py:0: error: Unsupported left operand type for + ("None") [operator]
install.py:0: error: Unsupported left operand type for + ("None") [operator]
install.py:0: error: Unsupported left operand type for < ("object") [operator]
install.py:0: error: Unsupported operand types for + ("object" and "int") [operator]
install.py:0: error: Unsupported operand types for + ("object" and "int") [operator]
install.py:0: error: Unsupported operand types for / ("Path" and "None") [operator]
install.py:0: error: Unsupported operand types for / ("Path" and "None") [operator]
install.py:0: error: Unsupported operand types for > ("str" and "int") [operator]
install.py:0: error: Unsupported operand types for in ("object" and "str") [operator]
install.py:0: error: Unsupported right operand type for in ("int") [operator]
install.py:0: error: Value of type "Optional[Match[str]]" is not indexable [index]
install.py:0: error: Value of type "Optional[Match[str]]" is not indexable [index]
install.py:0: error: Value of type "Optional[dict[Any, Any]]" is not indexable [index]
install.py:0: error: Value of type "Optional[tuple[str, str]]" is not indexable [index]
install.py:0: error: Value of type "Optional[tuple[str, str]]" is not indexable [index]
install.py:0: error: Value of type "Optional[tuple[str, str]]" is not indexable [index]
install.py:0: error: Value of type "Optional[tuple[str, str]]" is not indexable [index]
install.py:0: error: Value of type "Optional[tuple[str, str]]" is not indexable [index]
install.py:0: error: Value of type "Optional[tuple[str, str]]" is not indexable [index]
install.py:0: error: Value of type "Optional[tuple[str, str]]" is not indexable [index]
install.py:0: error: Value of type "object" is not indexable [index]
install.py:0: error: Value of type "object" is not indexable [index]
install.py:0: error: Value of type variable "SupportsRichComparisonT" of "min" cannot be "object" [type-var]
install.py:0: error: Value of type variable "SupportsRichComparisonT" of "sorted" cannot be "Optional[Any]" [type-var]
scripts/campaign.py:0: error: "object" has no attribute "__enter__" [attr-defined]
scripts/campaign.py:0: error: "object" has no attribute "__enter__" [attr-defined]
scripts/campaign.py:0: error: "object" has no attribute "__enter__" [attr-defined]
scripts/campaign.py:0: error: "object" has no attribute "__exit__" [attr-defined]
scripts/campaign.py:0: error: "object" has no attribute "__exit__" [attr-defined]
scripts/campaign.py:0: error: "object" has no attribute "__exit__" [attr-defined]
scripts/campaign.py:0: error: "object" has no attribute "decode" [attr-defined]
scripts/campaign.py:0: error: Incompatible types in assignment (expression has type "str", variable has type "bytes") [assignment]
scripts/campaign.py:0: error: Invalid index type "bytes" for "dict[str, str]"; expected type "str" [index]
scripts/campaign.py:0: error: Item "None" of "Optional[dict[Any, Any]]" has no attribute "get" [union-attr]
scripts/campaign.py:0: error: No overload variant of "Popen" matches argument types "list[str]", "bool", "dict[str, object]" [call-overload]
scripts/campaign.py:0: error: Unpacked dict entry 0 has incompatible type "object"; expected "SupportsKeysAndGetItem[Any, Any]" [dict-item]
scripts/campaign.py:0: error: Unsupported operand types for / ("Path" and "bytes") [operator]
scripts/campaign.py:0: error: Value of type "object" is not indexable [index]
scripts/campaign.py:0: error: Value of type "object" is not indexable [index]
scripts/campaign_profiles.py:0: error: Incompatible types in assignment (expression has type "int", variable has type "str") [assignment]
scripts/campaign_profiles.py:0: error: Incompatible types in assignment (expression has type "tuple[str, int]", target has type "tuple[int, int]") [assignment]
scripts/campaign_profiles.py:0: error: Unsupported operand types for + ("str" and "int") [operator]
scripts/campaign_rules.py:0: error: "object" not callable [operator]
scripts/campaign_rules.py:0: error: Argument 1 to "get" of "dict" has incompatible type "Optional[str]"; expected "str" [arg-type]
scripts/campaign_rules.py:0: error: No overload variant of "set" matches argument type "object" [call-overload]
scripts/check_freshness.py:0: error: Argument 2 to "unresolved_target_cores" has incompatible type "dict[str, set[str]]"; expected "dict[str, str]" [arg-type]
scripts/check_freshness.py:0: error: Argument 2 to "unresolved_target_cores" has incompatible type "dict[str, set[str]]"; expected "dict[str, str]" [arg-type]
scripts/check_freshness.py:0: error: Argument 2 to "unresolved_target_cores" has incompatible type "dict[str, set[str]]"; expected "dict[str, str]" [arg-type]
scripts/check_freshness.py:0: error: Argument 2 to "unresolved_target_cores" has incompatible type "dict[str, set[str]]"; expected "dict[str, str]" [arg-type]
scripts/check_freshness.py:0: error: Item "None" of "Optional[Match[str]]" has no attribute "group" [union-attr]
scripts/check_freshness.py:0: error: Need type annotation for "overrides" (hint: "overrides: dict[<type>, <type>] = ...") [var-annotated]
scripts/check_platform_folder.py:0: error: Argument 1 to "exit" has incompatible type "Union[str, HTTPError]"; expected "Union[str, int, None]" [arg-type]
scripts/check_platform_folder.py:0: error: Argument 1 to "read" of "ZipFile" has incompatible type "Optional[str]"; expected "Union[str, ZipInfo]" [arg-type]
scripts/check_platform_folder.py:0: error: Incompatible types in assignment (expression has type "list[str]", variable has type "dict[str, str]") [assignment]
scripts/check_release_assets.py:0: error: Argument 1 to "get" of "dict" has incompatible type "Optional[str]"; expected "str" [arg-type]
scripts/common.py:0: error: Argument "sha1_candidates" to "declared_hash_verdict" has incompatible type "list[str]"; expected "set[Any]" [arg-type]
scripts/common.py:0: error: Argument "sha256_candidates" to "declared_hash_verdict" has incompatible type "list[str]"; expected "set[Any]" [arg-type]
scripts/common.py:0: error: Argument 1 to "append" of "list" has incompatible type "tuple[Any, Any, Any]"; expected "str" [arg-type]
scripts/common.py:0: error: Argument 2 to "name_match_size_ok" has incompatible type "str"; expected "Optional[int]" [arg-type]
scripts/common.py:0: error: Cannot determine type of "m" [has-type]
scripts/common.py:0: error: Cannot determine type of "size" [has-type]
scripts/common.py:0: error: Incompatible return value type (got "str", expected "tuple[Optional[str], str]") [return-value]
scripts/common.py:0: error: Incompatible return value type (got "str", expected "tuple[Optional[str], str]") [return-value]
scripts/common.py:0: error: Incompatible types in assignment (expression has type "Optional[tuple[str, str]]", variable has type "Optional[str]") [assignment]
scripts/common.py:0: error: Incompatible types in assignment (expression has type "Optional[tuple[str, str]]", variable has type "Optional[str]") [assignment]
scripts/common.py:0: error: Name "folded" already defined on line 0 [no-redef]
scripts/common.py:0: error: Unpacking a string is disallowed [misc]
scripts/common.py:0: error: Unpacking a string is disallowed [misc]
scripts/common.py:0: error: Unsupported left operand type for & ("None") [operator]
scripts/core_probe.py:0: error: Incompatible types in assignment (expression has type "list[list[Any]]", target has type "Optional[str]") [assignment]
scripts/core_probe.py:0: error: Incompatible types in assignment (expression has type "list[str]", target has type "Optional[str]") [assignment]
scripts/core_probe.py:0: error: Item "None" of "Optional[Path]" has no attribute "name" [union-attr]
scripts/core_probe.py:0: error: Item "None" of "Optional[Path]" has no attribute "open" [union-attr]
scripts/core_probe.py:0: error: Need type annotation for "info" [var-annotated]
scripts/core_probe.py:0: error: Value of type "Optional[Any]" is not indexable [index]
scripts/cross_reference.py:0: error: Need type annotation for "declared" (hint: "declared: dict[<type>, <type>] = ...") [var-annotated]
scripts/cross_reference.py:0: error: Need type annotation for "platform_data_dirs" (hint: "platform_data_dirs: dict[<type>, <type>] = ...") [var-annotated]
scripts/cross_reference.py:0: error: Need type annotation for "report" (hint: "report: dict[<type>, <type>] = ...") [var-annotated]
scripts/dedup.py:0: error: "Sequence[str]" has no attribute "append" [attr-defined]
scripts/derivations.py:0: error: Argument 1 to "_gf2_times" has incompatible type "tuple[int, ...]"; expected "list[int]" [arg-type]
scripts/derivations.py:0: error: Argument 1 to "_gf2_times" has incompatible type "tuple[int, ...]"; expected "list[int]" [arg-type]
scripts/derivations.py:0: error: Argument 1 to "get" of "dict" has incompatible type "tuple[Optional[int], str]"; expected "tuple[int, str]" [arg-type]
scripts/derivations.py:0: error: Incompatible types in assignment (expression has type "Optional[ZipFile]", variable has type "ZipFile") [assignment]
scripts/dumpcatalog.py:0: error: Need type annotation for "snapshots" (hint: "snapshots: dict[<type>, <type>] = ...") [var-annotated]
scripts/export_native.py:0: error: "object" has no attribute "carries" [attr-defined]
scripts/export_native.py:0: error: "object" has no attribute "clears" [attr-defined]
scripts/export_native.py:0: error: "object" has no attribute "component_url" [attr-defined]
scripts/export_native.py:0: error: "object" has no attribute "destination" [attr-defined]
scripts/export_native.py:0: error: "object" has no attribute "fills" [attr-defined]
scripts/export_native.py:0: error: "object" has no attribute "lands" [attr-defined]
scripts/export_native.py:0: error: "object" has no attribute "name" [attr-defined]
scripts/export_native.py:0: error: "object" has no attribute "names_anew" [attr-defined]
scripts/export_native.py:0: error: "object" has no attribute "native_sources" [attr-defined]
scripts/export_native.py:0: error: "object" has no attribute "native_system" [attr-defined]
scripts/export_native.py:0: error: "object" has no attribute "platform" [attr-defined]
scripts/export_native.py:0: error: "object" has no attribute "platform" [attr-defined]
scripts/export_native.py:0: error: "object" has no attribute "platform_name" [attr-defined]
scripts/export_native.py:0: error: "object" has no attribute "required_value" [attr-defined]
scripts/export_native.py:0: error: "object" has no attribute "required_value" [attr-defined]
scripts/export_native.py:0: error: "object" has no attribute "required_value" [attr-defined]
scripts/export_native.py:0: error: "object" has no attribute "size" [attr-defined]
scripts/export_native.py:0: error: "object" has no attribute "size" [attr-defined]
scripts/export_native.py:0: error: "object" has no attribute "states" [attr-defined]
scripts/export_native.py:0: error: "object" has no attribute "states" [attr-defined]
scripts/export_native.py:0: error: "object" has no attribute "states" [attr-defined]
scripts/export_native.py:0: error: "object" has no attribute "states" [attr-defined]
scripts/export_native.py:0: error: "object" has no attribute "states" [attr-defined]
scripts/export_native.py:0: error: "object" has no attribute "written" [attr-defined]
scripts/export_native.py:0: error: "object" has no attribute "written_list" [attr-defined]
scripts/export_native.py:0: error: "object" has no attribute "written_list" [attr-defined]
scripts/export_native.py:0: error: Argument 1 to "_read_archive" has incompatible type "Optional[Any]"; expected "Callable[[bytes], dict[str, str]]" [arg-type]
scripts/export_native.py:0: error: Argument 1 to "_read_archive" has incompatible type "Optional[Any]"; expected "Callable[[bytes], dict[str, str]]" [arg-type]
scripts/exporter/baseline.py:0: error: Incompatible types in assignment (expression has type "Optional[int]", variable has type "int") [assignment]
scripts/exporter/baseline.py:0: error: No overload variant of "int" matches argument type "object" [call-overload]
scripts/exporter/batocera_exporter.py:0: error: Argument 1 to "append" of "list" has incompatible type "tuple[tuple[Any, ...], str]"; expected "tuple[tuple[Any, ...], dict[Any, Any]]" [arg-type]
scripts/exporter/batocera_exporter.py:0: error: Incompatible types in assignment (expression has type "Optional[tuple[str, Optional[str]]]", target has type "Optional[tuple[str, str]]") [assignment]
scripts/exporter/batocera_exporter.py:0: error: Incompatible types in assignment (expression has type "dict[Any, Any]", variable has type "str") [assignment]
scripts/exporter/batocera_exporter.py:0: error: Item "None" of "Optional[Match[str]]" has no attribute "group" [union-attr]
scripts/exporter/batocera_exporter.py:0: error: Item "None" of "Union[Any, dict[Any, Any], None]" has no attribute "get" [union-attr]
scripts/exporter/batocera_exporter.py:0: error: Signature of "writable" incompatible with supertype "scripts.exporter.base_exporter.BaseExporter" [override]
scripts/exporter/misterfpga_exporter.py:0: error: "object" has no attribute "size" [attr-defined]
scripts/exporter/misterfpga_exporter.py:0: error: Argument 1 to "written" of "Exporter" has incompatible type "object"; expected "NativeFile" [arg-type]
scripts/exporter/misterfpga_exporter.py:0: error: Argument 1 to "written" of "Exporter" has incompatible type "object"; expected "NativeFile" [arg-type]
scripts/exporter/misterfpga_exporter.py:0: error: Return type "dict[str, Union[str, bytes]]" of "render" incompatible with return type "dict[str, str]" in supertype "scripts.exporter.base_exporter.BaseExporter" [override]
scripts/exporter/retrodeck_exporter.py:0: error: Argument 1 to "add" of "set" has incompatible type "tuple[str, str]"; expected "tuple[str, str, tuple[str, ...]]" [arg-type]
scripts/exporter/retrodeck_exporter.py:0: error: Incompatible types in assignment (expression has type "dict[Any, Any]", variable has type "OrderedDict[Any, Any]") [assignment]
scripts/exporter/retrodeck_exporter.py:0: error: Incompatible types in assignment (expression has type "dict[Any, Any]", variable has type "OrderedDict[Any, Any]") [assignment]
scripts/exporter/retrodeck_exporter.py:0: error: Incompatible types in assignment (expression has type "tuple[str, str, tuple[str, ...]]", variable has type "tuple[str, str]") [assignment]
scripts/exporter/retropie_exporter.py:0: error: "object" has no attribute "__iter__"; maybe "__dir__" or "__str__"? (not iterable) [attr-defined]
scripts/exporter/retropie_exporter.py:0: error: "object" has no attribute "__iter__"; maybe "__dir__" or "__str__"? (not iterable) [attr-defined]
scripts/exporter/retropie_exporter.py:0: error: Argument 2 to "_extended" of "Exporter" has incompatible type "Optional[tuple[int, int, list[str]]]"; expected "tuple[int, int, list[str]]" [arg-type]
scripts/exporter/retropie_exporter.py:0: error: Expected iterable as variadic argument [misc]
scripts/exporter/retropie_exporter.py:0: error: Value of type "Optional[tuple[int, int, list[str]]]" is not indexable [index]
scripts/exporter/retropie_exporter.py:0: error: Value of type "Optional[tuple[int, int, list[str]]]" is not indexable [index]
scripts/exporter/retropie_exporter.py:0: error: Value of type "Optional[tuple[int, int, list[str]]]" is not indexable [index]
scripts/exporter/romm_exporter.py:0: error: Signature of "writable" incompatible with supertype "scripts.exporter.base_exporter.BaseExporter" [override]
scripts/game_rules.py:0: error: Item "None" of "Optional[dict[str, dict[Any, Any]]]" has no attribute "get" [union-attr]
scripts/generate_db.py:0: error: Name "matched" already defined on line 0 [no-redef]
scripts/generate_db.py:0: error: Need type annotation for "aliases" (hint: "aliases: dict[<type>, <type>] = ...") [var-annotated]
scripts/generate_db.py:0: error: Need type annotation for "aliases" (hint: "aliases: dict[<type>, <type>] = ...") [var-annotated]
scripts/generate_db.py:0: error: Need type annotation for "by_name" (hint: "by_name: dict[<type>, <type>] = ...") [var-annotated]
scripts/generate_db.py:0: error: Need type annotation for "by_path_suffix" (hint: "by_path_suffix: dict[<type>, <type>] = ...") [var-annotated]
scripts/generate_db.py:0: error: Need type annotation for "files" (hint: "files: dict[<type>, <type>] = ...") [var-annotated]
scripts/generate_db.py:0: error: Unsupported left operand type for | ("None") [operator]
scripts/generate_event_schema.py:0: error: Argument 1 to "module_from_spec" has incompatible type "Optional[ModuleSpec]"; expected "ModuleSpec" [arg-type]
scripts/generate_event_schema.py:0: error: Item "None" of "Optional[ModuleSpec]" has no attribute "loader" [union-attr]
scripts/generate_event_schema.py:0: error: Item "None" of "Union[Loader, Any, None]" has no attribute "exec_module" [union-attr]
scripts/generate_games_index.py:0: error: Argument 1 to "fallback_set" has incompatible type "Optional[dict[Any, Any]]"; expected "dict[Any, Any]" [arg-type]
scripts/generate_installer_doc.py:0: error: "object" has no attribute "add" [attr-defined]
scripts/generate_installer_doc.py:0: error: Argument 1 to "__init__" of "SimpleHTTPRequestHandler" has incompatible type "*tuple[object, ...]"; expected "BaseServer" [arg-type]
scripts/generate_installer_doc.py:0: error: Argument 1 to "__init__" of "SimpleHTTPRequestHandler" has incompatible type "*tuple[object, ...]"; expected "Union[socket, tuple[bytes, socket]]" [arg-type]
scripts/generate_installer_doc.py:0: error: Argument 1 to "enter_context" of "_BaseExitStack" has incompatible type "object"; expected "AbstractContextManager[Never, Optional[bool]]" [arg-type]
scripts/generate_installer_doc.py:0: error: Argument 1 to "join" of "str" has incompatible type "Union[bool, list[str], str, None]"; expected "Iterable[str]" [arg-type]
scripts/generate_installer_doc.py:0: error: Argument 1 to "module_from_spec" has incompatible type "Optional[ModuleSpec]"; expected "ModuleSpec" [arg-type]
scripts/generate_installer_doc.py:0: error: Argument 1 to "sample_writers" has incompatible type "_LazySandbox"; expected "Sandbox" [arg-type]
scripts/generate_installer_doc.py:0: error: Argument 1 to "startswith" of "str" has incompatible type "Optional[str]"; expected "Union[str, tuple[str, ...]]" [arg-type]
scripts/generate_installer_doc.py:0: error: Argument 2 has incompatible type "*tuple[object, ...]"; expected "Optional[Union[tuple[Any, ...], str, Buffer]]" [arg-type]
scripts/generate_installer_doc.py:0: error: Argument 2 has incompatible type "*tuple[object, ...]"; expected "Optional[float]" [arg-type]
scripts/generate_installer_doc.py:0: error: Argument 3 has incompatible type "**dict[str, object]"; expected "Optional[Union[tuple[Any, ...], str, Buffer]]" [arg-type]
scripts/generate_installer_doc.py:0: error: Argument 3 has incompatible type "**dict[str, object]"; expected "Optional[float]" [arg-type]
scripts/generate_installer_doc.py:0: error: Argument 3 to "__init__" of "SimpleHTTPRequestHandler" has incompatible type "**dict[str, object]"; expected "BaseServer" [arg-type]
scripts/generate_installer_doc.py:0: error: Argument 3 to "__init__" of "SimpleHTTPRequestHandler" has incompatible type "**dict[str, object]"; expected "Union[socket, tuple[bytes, socket]]" [arg-type]
scripts/generate_installer_doc.py:0: error: Argument 3 to "run" of "Sandbox" has incompatible type "**dict[str, bool]"; expected "Optional[Path]" [arg-type]
scripts/generate_installer_doc.py:0: error: Argument 3 to "run" of "Sandbox" has incompatible type "**dict[str, bool]"; expected "tuple[Any, ...]" [arg-type]
scripts/generate_installer_doc.py:0: error: Incompatible return value type (got "tuple[int, ...]", expected "tuple[int, int]") [return-value]
scripts/generate_installer_doc.py:0: error: Incompatible types in assignment (expression has type "Union[str, bytes, bytearray]", variable has type "str") [assignment]
scripts/generate_installer_doc.py:0: error: Item "None" of "Optional[ModuleSpec]" has no attribute "loader" [union-attr]
scripts/generate_installer_doc.py:0: error: Item "None" of "Union[Loader, Any, None]" has no attribute "exec_module" [union-attr]
scripts/generate_installer_doc.py:0: error: Name "_install._OsRule" is not defined [name-defined]
scripts/generate_launcher_index.py:0: error: Argument 1 to "module_from_spec" has incompatible type "Optional[ModuleSpec]"; expected "ModuleSpec" [arg-type]
scripts/generate_launcher_index.py:0: error: Item "None" of "Optional[ModuleSpec]" has no attribute "loader" [union-attr]
scripts/generate_launcher_index.py:0: error: Item "None" of "Union[Loader, Any, None]" has no attribute "exec_module" [union-attr]
scripts/generate_pack.py:0: error: Argument 1 to "_narrowings" has incompatible type "Union[str, bool]"; expected "str" [arg-type]
scripts/generate_pack.py:0: error: Argument 1 to "_release_asset_name" has incompatible type "Optional[str]"; expected "str" [arg-type]
scripts/generate_pack.py:0: error: Argument 10 to "generate_pack" has incompatible type "**dict[str, Union[dict[Any, Any], Any, set[str], list[str], str, bool, None]]"; expected "Optional[bool]" [arg-type]
scripts/generate_pack.py:0: error: Argument 10 to "generate_pack" has incompatible type "**dict[str, Union[dict[Any, Any], Any, set[str], list[str], str, bool, None]]"; expected "Optional[dict[Any, Any]]" [arg-type]
scripts/generate_pack.py:0: error: Argument 10 to "generate_pack" has incompatible type "**dict[str, Union[dict[Any, Any], Any, set[str], list[str], str, bool, None]]"; expected "Optional[list[dict[Any, Any]]]" [arg-type]
scripts/generate_pack.py:0: error: Argument 10 to "generate_pack" has incompatible type "**dict[str, Union[dict[Any, Any], Any, set[str], list[str], str, bool, None]]"; expected "Optional[list[str]]" [arg-type]
scripts/generate_pack.py:0: error: Argument 10 to "generate_pack" has incompatible type "**dict[str, Union[dict[Any, Any], Any, set[str], list[str], str, bool, None]]"; expected "Optional[set[str]]" [arg-type]
scripts/generate_pack.py:0: error: Argument 10 to "generate_pack" has incompatible type "**dict[str, Union[dict[Any, Any], Any, set[str], list[str], str, bool, None]]"; expected "Optional[str]" [arg-type]
scripts/generate_pack.py:0: error: Argument 10 to "generate_pack" has incompatible type "**dict[str, Union[dict[Any, Any], Any, set[str], list[str], str, bool, None]]"; expected "bool" [arg-type]
scripts/generate_pack.py:0: error: Argument 10 to "generate_pack" has incompatible type "**dict[str, Union[dict[Any, Any], Any, set[str], list[str], str, bool, None]]"; expected "str" [arg-type]
scripts/generate_pack.py:0: error: Argument 4 to "_manifest_core_index" has incompatible type "dict_values[str, dict[Any, Any]]"; expected "list[dict[Any, Any]]" [arg-type]
scripts/generate_pack.py:0: error: Argument 4 to "_narrowings" has incompatible type "Union[str, bool]"; expected "bool" [arg-type]
scripts/generate_pack.py:0: error: Argument 5 to "_narrowings" has incompatible type "Union[str, bool]"; expected "bool" [arg-type]
scripts/generate_pack.py:0: error: Argument 7 to "generate_pack" has incompatible type "**dict[str, Union[dict[Any, Any], Any, set[str], list[str], str, bool, None]]"; expected "Optional[bool]" [arg-type]
scripts/generate_pack.py:0: error: Argument 7 to "generate_pack" has incompatible type "**dict[str, Union[dict[Any, Any], Any, set[str], list[str], str, bool, None]]"; expected "Optional[dict[Any, Any]]" [arg-type]
scripts/generate_pack.py:0: error: Argument 7 to "generate_pack" has incompatible type "**dict[str, Union[dict[Any, Any], Any, set[str], list[str], str, bool, None]]"; expected "Optional[dict[str, str]]" [arg-type]
scripts/generate_pack.py:0: error: Argument 7 to "generate_pack" has incompatible type "**dict[str, Union[dict[Any, Any], Any, set[str], list[str], str, bool, None]]"; expected "Optional[list[dict[Any, Any]]]" [arg-type]
scripts/generate_pack.py:0: error: Argument 7 to "generate_pack" has incompatible type "**dict[str, Union[dict[Any, Any], Any, set[str], list[str], str, bool, None]]"; expected "Optional[list[str]]" [arg-type]
scripts/generate_pack.py:0: error: Argument 7 to "generate_pack" has incompatible type "**dict[str, Union[dict[Any, Any], Any, set[str], list[str], str, bool, None]]"; expected "Optional[set[str]]" [arg-type]
scripts/generate_pack.py:0: error: Argument 7 to "generate_pack" has incompatible type "**dict[str, Union[dict[Any, Any], Any, set[str], list[str], str, bool, None]]"; expected "Optional[str]" [arg-type]
scripts/generate_pack.py:0: error: Argument 7 to "generate_pack" has incompatible type "**dict[str, Union[dict[Any, Any], Any, set[str], list[str], str, bool, None]]"; expected "bool" [arg-type]
scripts/generate_pack.py:0: error: Argument 7 to "generate_pack" has incompatible type "**dict[str, Union[dict[Any, Any], Any, set[str], list[str], str, bool, None]]"; expected "str" [arg-type]
scripts/generate_pack.py:0: error: Argument 9 to "generate_pack" has incompatible type "**dict[str, object]"; expected "Optional[bool]" [arg-type]
scripts/generate_pack.py:0: error: Argument 9 to "generate_pack" has incompatible type "**dict[str, object]"; expected "Optional[dict[Any, Any]]" [arg-type]
scripts/generate_pack.py:0: error: Argument 9 to "generate_pack" has incompatible type "**dict[str, object]"; expected "Optional[list[dict[Any, Any]]]" [arg-type]
scripts/generate_pack.py:0: error: Argument 9 to "generate_pack" has incompatible type "**dict[str, object]"; expected "Optional[list[str]]" [arg-type]
scripts/generate_pack.py:0: error: Argument 9 to "generate_pack" has incompatible type "**dict[str, object]"; expected "Optional[set[str]]" [arg-type]
scripts/generate_pack.py:0: error: Argument 9 to "generate_pack" has incompatible type "**dict[str, object]"; expected "Optional[str]" [arg-type]
scripts/generate_pack.py:0: error: Argument 9 to "generate_pack" has incompatible type "**dict[str, object]"; expected "bool" [arg-type]
scripts/generate_pack.py:0: error: Argument 9 to "generate_pack" has incompatible type "**dict[str, object]"; expected "str" [arg-type]
scripts/generate_pack.py:0: error: Need type annotation for "missing_files" (hint: "missing_files: list[<type>] = ...") [var-annotated]
scripts/generate_pack.py:0: error: Unsupported target for indexed assignment ("Optional[dict[str, PackRecord]]") [index]
scripts/generate_readme.py:0: error: "object" has no attribute "TUI_SYSTEMS_ROW" [attr-defined]
scripts/generate_readme.py:0: error: Argument 1 to "module_from_spec" has incompatible type "Optional[ModuleSpec]"; expected "ModuleSpec" [arg-type]
scripts/generate_readme.py:0: error: Item "None" of "Optional[ModuleSpec]" has no attribute "loader" [union-attr]
scripts/generate_readme.py:0: error: Item "None" of "Union[Loader, Any, None]" has no attribute "exec_module" [union-attr]
scripts/generate_site.py:0: error: "object" has no attribute "EVERYTHING_IN_PLACE" [attr-defined]
scripts/generate_site.py:0: error: "object" has no attribute "TUI_CHOOSE_TITLE" [attr-defined]
scripts/generate_site.py:0: error: "object" has no attribute "TUI_FOLDER_TITLE" [attr-defined]
scripts/generate_site.py:0: error: "object" has no attribute "TUI_FOUND_TITLE" [attr-defined]
scripts/generate_site.py:0: error: "object" has no attribute "TUI_INSTALL_ROW" [attr-defined]
scripts/generate_site.py:0: error: "object" has no attribute "TUI_SYSTEMS_ROW" [attr-defined]
scripts/generate_site.py:0: error: "object" has no attribute "TUI_SYSTEMS_ROW" [attr-defined]
scripts/generate_site.py:0: error: "object" has no attribute "__iter__"; maybe "__dir__" or "__str__"? (not iterable) [attr-defined]
scripts/generate_site.py:0: error: "object" has no attribute "emulator_names" [attr-defined]
scripts/generate_site.py:0: error: "object" has no attribute "values" [attr-defined]
scripts/generate_site.py:0: error: "set[str]" has no attribute "get" [attr-defined]
scripts/generate_site.py:0: error: Argument 1 to "module_from_spec" has incompatible type "Optional[ModuleSpec]"; expected "ModuleSpec" [arg-type]
scripts/generate_site.py:0: error: Argument 1 to "setdefault" of "MutableMapping" has incompatible type "tuple[str, str, str]"; expected "tuple[str, str]" [arg-type]
scripts/generate_site.py:0: error: Argument 2 to "_version_said" has incompatible type "Union[Any, dict[Any, Any], None]"; expected "dict[Any, Any]" [arg-type]
scripts/generate_site.py:0: error: Argument 3 to "_blocks_in_runs" has incompatible type "Callable[[list[str]], float]"; expected "Callable[[list[str]], int]" [arg-type]
scripts/generate_site.py:0: error: Argument 3 to "_render_platform_systems" has incompatible type "Optional[dict[Any, Any]]"; expected "dict[Any, Any]" [arg-type]
scripts/generate_site.py:0: error: Argument 4 to "_emulator_part_page" has incompatible type "list[str]"; expected "list[tuple[str, range]]" [arg-type]
scripts/generate_site.py:0: error: Argument 5 to "_card_index" has incompatible type "list[str]"; expected "list[tuple[str, range]]" [arg-type]
scripts/generate_site.py:0: error: Cannot determine type of "entries" [has-type]
scripts/generate_site.py:0: error: Cannot determine type of "entries" [has-type]
scripts/generate_site.py:0: error: Cannot determine type of "entries" [has-type]
scripts/generate_site.py:0: error: Cannot determine type of "stem" [has-type]
scripts/generate_site.py:0: error: Expected iterable as variadic argument [misc]
scripts/generate_site.py:0: error: Generator has incompatible item type "int"; expected "bool" [misc]
scripts/generate_site.py:0: error: Incompatible types in assignment (expression has type "Optional[Any]", target has type "str") [assignment]
scripts/generate_site.py:0: error: Incompatible types in assignment (expression has type "Optional[str]", variable has type "str") [assignment]
scripts/generate_site.py:0: error: Incompatible types in assignment (expression has type "Optional[str]", variable has type "str") [assignment]
scripts/generate_site.py:0: error: Incompatible types in assignment (expression has type "Union[dict[Any, Any], str, None]", variable has type "str") [assignment]
scripts/generate_site.py:0: error: Incompatible types in assignment (expression has type "dict[Any, Any]", variable has type "int") [assignment]
scripts/generate_site.py:0: error: Incompatible types in assignment (expression has type "dict[str, set[str]]", variable has type "set[str]") [assignment]
scripts/generate_site.py:0: error: Incompatible types in assignment (expression has type "dict[str, str]", variable has type "dict[str, tuple[str, dict[str, list[Any]]]]") [assignment]
scripts/generate_site.py:0: error: Incompatible types in assignment (expression has type "list[dict[str, Sequence[str]]]", target has type "str") [assignment]
scripts/generate_site.py:0: error: Incompatible types in assignment (expression has type "list[str]", target has type "str") [assignment]
scripts/generate_site.py:0: error: Incompatible types in assignment (expression has type "list[str]", variable has type "str") [assignment]
scripts/generate_site.py:0: error: Incompatible types in assignment (expression has type "list[str]", variable has type "str") [assignment]
scripts/generate_site.py:0: error: Incompatible types in assignment (expression has type "list[str]", variable has type "str") [assignment]
scripts/generate_site.py:0: error: Incompatible types in assignment (expression has type "list[tuple[str, Any]]", variable has type "Optional[dict[Any, Any]]") [assignment]
scripts/generate_site.py:0: error: Incompatible types in assignment (expression has type "list[tuple[str, list[int]]]", variable has type "list[str]") [assignment]
scripts/generate_site.py:0: error: Incompatible types in assignment (expression has type "tuple[Any, Union[Any, str]]", variable has type "str") [assignment]
scripts/generate_site.py:0: error: Incompatible types in assignment (expression has type "tuple[str, dict[str, list[Any]]]", variable has type "str") [assignment]
scripts/generate_site.py:0: error: Incompatible types in assignment (expression has type "tuple[str, str]", variable has type "tuple[str, str, str]") [assignment]
scripts/generate_site.py:0: error: Invalid index type "str" for "dict[tuple[str, str], dict[Any, Any]]"; expected type "tuple[str, str]" [index]
scripts/generate_site.py:0: error: Item "None" of "Optional[ModuleSpec]" has no attribute "loader" [union-attr]
scripts/generate_site.py:0: error: Item "None" of "Optional[dict[Any, Any]]" has no attribute "__iter__" (not iterable) [union-attr]
scripts/generate_site.py:0: error: Item "None" of "Optional[str]" has no attribute "startswith" [union-attr]
scripts/generate_site.py:0: error: Item "None" of "Union[Any, dict[Any, Any], None]" has no attribute "get" [union-attr]
scripts/generate_site.py:0: error: Item "None" of "Union[Loader, Any, None]" has no attribute "exec_module" [union-attr]
scripts/generate_site.py:0: error: Need type annotation for "arcade" (hint: "arcade: list[<type>] = ...") [var-annotated]
scripts/generate_site.py:0: error: Need type annotation for "links" (hint: "links: list[<type>] = ...") [var-annotated]
scripts/generate_site.py:0: error: Need type annotation for "machines" (hint: "machines: list[<type>] = ...") [var-annotated]
scripts/generate_site.py:0: error: Need type annotation for "record" [var-annotated]
scripts/generate_site.py:0: error: Need type annotation for "sample" [var-annotated]
scripts/generate_site.py:0: error: No overload variant of "get" of "dict" matches argument type "str" [call-overload]
scripts/generate_site.py:0: error: Unpacking a string is disallowed [misc]
scripts/generate_site.py:0: error: Value of type "Optional[Match[str]]" is not indexable [index]
scripts/generate_site.py:0: error: Value of type "int" is not indexable [index]
scripts/generate_site.py:0: error: Value of type "int" is not indexable [index]
scripts/generate_site.py:0: error: Value of type "int" is not indexable [index]
scripts/generate_site.py:0: error: Value of type "int" is not indexable [index]
scripts/generate_site.py:0: error: Value of type "int" is not indexable [index]
scripts/generate_site.py:0: error: Value of type "int" is not indexable [index]
scripts/generate_site.py:0: error: Value of type "int" is not indexable [index]
scripts/generate_site.py:0: error: Value of type "int" is not indexable [index]
scripts/generate_site.py:0: error: Value of type "int" is not indexable [index]
scripts/generate_site.py:0: error: Value of type "object" is not indexable [index]
scripts/hashing.py:0: error: No overload variant of "open" matches argument types "object", "str" [call-overload]
scripts/launchers.py:0: error: Argument 1 to "len" has incompatible type "Optional[list[str]]"; expected "Sized" [arg-type]
scripts/launchers.py:0: error: Incompatible types in assignment (expression has type "Optional[dict[Any, Any]]", variable has type "dict[Any, Any]") [assignment]
scripts/launchers.py:0: error: Item "None" of "Optional[list[str]]" has no attribute "__iter__" (not iterable) [union-attr]
scripts/measurement_records.py:0: error: Argument 1 to "add" of "set" has incompatible type "Optional[Any]"; expected "str" [arg-type]
scripts/migrate.py:0: error: Incompatible return value type (got "None", expected "tuple[Any, ...]") [return-value]
scripts/migrate.py:0: error: Incompatible return value type (got "None", expected "tuple[Any, ...]") [return-value]
scripts/migrate.py:0: error: Incompatible return value type (got "None", expected "tuple[Any, ...]") [return-value]
scripts/migrate.py:0: error: Incompatible return value type (got "None", expected "tuple[Any, ...]") [return-value]
scripts/migrate.py:0: error: Incompatible return value type (got "None", expected "tuple[Any, ...]") [return-value]
scripts/migrate.py:0: error: Incompatible return value type (got "None", expected "tuple[Any, ...]") [return-value]
scripts/migrate.py:0: error: Incompatible return value type (got "None", expected "tuple[Any, ...]") [return-value]
scripts/pack_probe.py:0: error: Need type annotation for "out" (hint: "out: list[<type>] = ...") [var-annotated]
scripts/pack_probe.py:0: error: Need type annotation for "units" (hint: "units: list[<type>] = ...") [var-annotated]
scripts/packextras.py:0: error: Argument 4 to "_emulator_ships" has incompatible type "Optional[dict[Any, Any]]"; expected "dict[Any, Any]" [arg-type]
scripts/packextras.py:0: error: Item "None" of "Optional[list[dict[Any, Any]]]" has no attribute "append" [union-attr]
scripts/packextras.py:0: error: Need type annotation for "profile" [var-annotated]
scripts/packresolve.py:0: error: Incompatible types in assignment (expression has type "Optional[Any]", variable has type "str") [assignment]
scripts/packresolve.py:0: error: Incompatible types in assignment (expression has type "Optional[Any]", variable has type "str") [assignment]
scripts/packverify.py:0: error: Incompatible types in assignment (expression has type "Union[Any, str, None]", variable has type "str") [assignment]
scripts/packverify.py:0: error: Incompatible types in assignment (expression has type "dict[str, str]", variable has type "str") [assignment]
scripts/packverify.py:0: error: Invalid index type "str" for "str"; expected type "Union[SupportsIndex, slice[Any, Any, Any]]" [index]
scripts/packverify.py:0: error: Need type annotation for "errors" (hint: "errors: list[<type>] = ...") [var-annotated]
scripts/packverify.py:0: error: Unsupported target for indexed assignment ("str") [index]
scripts/pipeline.py:0: error: "object" has no attribute "members" [attr-defined]
scripts/pipeline.py:0: error: "object" has no attribute "members" [attr-defined]
scripts/pipeline.py:0: error: "object" has no attribute "sources" [attr-defined]
scripts/pipeline.py:0: error: "object" has no attribute "sources" [attr-defined]
scripts/pipeline.py:0: error: Item "None" of "Optional[IO[str]]" has no attribute "__iter__" (not iterable) [union-attr]
scripts/profile_sync.py:0: error: "list[tuple[int, int, str]]" has no attribute "items" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "host" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "host" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "host" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "host" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "host" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "host" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "host" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "host" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "name" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "name" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "slug" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "slug" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "slug" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "slug" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "slug" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "slug" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "slug" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "slug" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "slug" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "slug" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "slug" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "slug" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "slug" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "slug" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "slug" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "slug" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "slug" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "slug" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "slug" [attr-defined]
scripts/profile_sync.py:0: error: "object" has no attribute "slug" [attr-defined]
scripts/profile_sync.py:0: error: "object" object is not iterable [misc]
scripts/profile_sync.py:0: error: Argument "entry" to "Citation" has incompatible type "Union[dict[Any, Any], list[Any]]"; expected "Optional[dict[Any, Any]]" [arg-type]
scripts/profile_sync.py:0: error: Argument 1 to "_anchor_tokens" has incompatible type "Optional[dict[Any, Any]]"; expected "dict[Any, Any]" [arg-type]
scripts/profile_sync.py:0: error: Argument 1 to "append" of "list" has incompatible type "object"; expected "str" [arg-type]
scripts/profile_sync.py:0: error: Argument 1 to "entry_hashes" has incompatible type "Optional[dict[Any, Any]]"; expected "dict[Any, Any]" [arg-type]
scripts/profile_sync.py:0: error: Argument 1 to "setdefault" of "MutableMapping" has incompatible type "Optional[int]"; expected "int" [arg-type]
scripts/profile_sync.py:0: error: Argument 1 to "version_tag_candidates" has incompatible type "Optional[Any]"; expected "str" [arg-type]
scripts/profile_sync.py:0: error: Argument 4 to "RepoView" has incompatible type "Optional[str]"; expected "str" [arg-type]
scripts/profile_sync.py:0: error: Argument 4 to "_set_pin" has incompatible type "Optional[str]"; expected "str" [arg-type]
scripts/profile_sync.py:0: error: Argument 4 to "_set_pin" has incompatible type "Optional[str]"; expected "str" [arg-type]
scripts/profile_sync.py:0: error: Cannot determine type of "actual" [has-type]
scripts/profile_sync.py:0: error: Cannot determine type of "old_lines" [has-type]
scripts/profile_sync.py:0: error: Cannot infer type of lambda [misc]
scripts/profile_sync.py:0: error: Cannot infer type of lambda [misc]
scripts/profile_sync.py:0: error: Incompatible return value type (got "object", expected "tuple[Any, list[str]]") [return-value]
scripts/profile_sync.py:0: error: Incompatible types in assignment (expression has type "dict[int, list[Any]]", variable has type "list[tuple[int, int, str]]") [assignment]
scripts/profile_sync.py:0: error: Invalid index type "Optional[int]" for "list[str]"; expected type "SupportsIndex" [index]
scripts/profile_sync.py:0: error: Invalid index type "tuple[str, Optional[int], tuple[Any, ...], str]" for "dict[tuple[str, Optional[int]], tuple[RepoView, str]]"; expected type "tuple[str, Optional[int]]" [index]
scripts/profile_sync.py:0: error: Invalid index type "tuple[str, Optional[int], tuple[Any, ...], str]" for "dict[tuple[str, Optional[int]], tuple[RepoView, str]]"; expected type "tuple[str, Optional[int]]" [index]
scripts/profile_sync.py:0: error: Invalid index type "tuple[str, str, Optional[int], tuple[str, ...], Union[RepoView, Any, None], str]" for "dict[tuple[str, str, Optional[int]], Optional[list[str]]]"; expected type "tuple[str, str, Optional[int]]" [index]
scripts/profile_sync.py:0: error: Invalid index type "tuple[str, str, Optional[int], tuple[str, ...], Union[RepoView, Any, None], str]" for "dict[tuple[str, str, Optional[int]], Optional[list[str]]]"; expected type "tuple[str, str, Optional[int]]" [index]
scripts/profile_sync.py:0: error: Item "None" of "Optional[Match[str]]" has no attribute "start" [union-attr]
scripts/profile_sync.py:0: error: Item "None" of "Optional[VersionReport]" has no attribute "declared" [union-attr]
scripts/profile_sync.py:0: error: Item "None" of "Optional[VersionReport]" has no attribute "latest_release" [union-attr]
scripts/profile_sync.py:0: error: Item "None" of "Optional[dict[Any, Any]]" has no attribute "get" [union-attr]
scripts/profile_sync.py:0: error: Item "None" of "Optional[dict[Any, Any]]" has no attribute "get" [union-attr]
scripts/profile_sync.py:0: error: Item "None" of "Optional[str]" has no attribute "startswith" [union-attr]
scripts/profile_sync.py:0: error: List item 0 has incompatible type "Optional[int]"; expected "int" [list-item]
scripts/profile_sync.py:0: error: Unsupported operand types for + ("None" and "int") [operator]
scripts/profile_sync.py:0: error: Unsupported target for indexed assignment ("object") [index]
scripts/profile_sync.py:0: error: Value of type "Optional[tuple[int, int]]" is not indexable [index]
scripts/profile_sync.py:0: error: Value of type "object" is not indexable [index]
scripts/profile_sync.py:0: error: Value of type "object" is not indexable [index]
scripts/provenance_report.py:0: error: Incompatible types in assignment (expression has type "int", variable has type "set[Any]") [assignment]
scripts/provenance_report.py:0: error: List comprehension has incompatible type List[tuple[str, str, Any]]; expected List[tuple[str, str]] [misc]
scripts/refresh_data_dirs.py:0: error: Item "None" of "Optional[IO[bytes]]" has no attribute "__enter__" [union-attr]
scripts/refresh_data_dirs.py:0: error: Item "None" of "Optional[IO[bytes]]" has no attribute "__exit__" [union-attr]
scripts/refresh_stale.py:0: error: Argument "area" to "Job" has incompatible type "Optional[Any]"; expected "str" [arg-type]
scripts/refresh_stale.py:0: error: Argument 1 to "_command_for" has incompatible type "Optional[Any]"; expected "str" [arg-type]
scripts/refresh_stale.py:0: error: Argument 1 to "add" of "set" has incompatible type "tuple[Optional[Any], str]"; expected "tuple[str, str]" [arg-type]
scripts/region.py:0: error: Value of type variable "SupportsRichComparisonT" of "min" cannot be "Optional[int]" [type-var]
scripts/region_check.py:0: error: Dict entry 0 has incompatible type "str": "dict[str, Optional[Path]]"; expected "str": "dict[str, Path]" [dict-item]
scripts/region_check.py:0: error: Dict entry 1 has incompatible type "str": "dict[str, Optional[Path]]"; expected "str": "dict[str, Path]" [dict-item]
scripts/region_check.py:0: error: Dict entry 2 has incompatible type "str": "dict[str, Optional[Path]]"; expected "str": "dict[str, Path]" [dict-item]
scripts/safeparse.py:0: error: Invalid base class "base" [misc]
scripts/safeparse.py:0: error: Variable "base" is not valid as a type [valid-type]
scripts/scraper/_hash_merge.py:0: error: Unsupported operand types for + ("None" and "int") [operator]
scripts/scraper/_hash_merge.py:0: error: Unsupported operand types for - ("None" and "int") [operator]
scripts/scraper/arcade_parent_importer.py:0: error: "IO[bytes]" has no attribute "close_archive" [attr-defined]
scripts/scraper/arcade_parent_importer.py:0: error: Argument 1 to "fbneo_sets" has incompatible type "list[Callable[[Any], Any]]"; expected "list[Callable[[], BufferedIOBase]]" [arg-type]
scripts/scraper/arcade_parent_importer.py:0: error: Argument 1 to "read_sets" has incompatible type "list[Callable[[Any], Any]]"; expected "list[Callable[[], BufferedIOBase]]" [arg-type]
scripts/scraper/arcade_parent_importer.py:0: error: Dict entry 2 has incompatible type "str": "dict[str, str]"; expected "str": "str" [dict-item]
scripts/scraper/arcade_parent_importer.py:0: error: Dict entry 2 has incompatible type "str": "dict[str, str]"; expected "str": "str" [dict-item]
scripts/scraper/arcade_parent_importer.py:0: error: Dict entry 2 has incompatible type "str": "dict[str, str]"; expected "str": "str" [dict-item]
scripts/scraper/arcade_parent_importer.py:0: error: Incompatible return value type (got "IO[bytes]", expected "BufferedIOBase") [return-value]
scripts/scraper/arcade_parent_importer.py:0: error: Incompatible types in assignment (expression has type "Optional[str]", variable has type "str") [assignment]
scripts/scraper/arcade_parent_importer.py:0: error: List comprehension has incompatible type List[Callable[[], BufferedIOBase]]; expected List[Callable[[Any], Any]] [misc]
scripts/scraper/base_scraper.py:0: error: "object" has no attribute "read" [attr-defined]
scripts/scraper/batocera_launchers.py:0: error: "expr" has no attribute "left" [attr-defined]
scripts/scraper/batocera_launchers.py:0: error: "expr" has no attribute "value" [attr-defined]
scripts/scraper/batocera_launchers.py:0: error: "expr" has no attribute "value" [attr-defined]
scripts/scraper/batocera_launchers.py:0: error: "expr" has no attribute "value" [attr-defined]
scripts/scraper/batocera_launchers.py:0: error: "stmt" has no attribute "body" [attr-defined]
scripts/scraper/batocera_launchers.py:0: error: "stmt" has no attribute "body" [attr-defined]
scripts/scraper/batocera_launchers.py:0: error: "stmt" has no attribute "value" [attr-defined]
scripts/scraper/batocera_launchers.py:0: error: Argument "depends_on_option" to "Launcher" has incompatible type "Union[str, bytes, int, float, complex, ellipsis, None]"; expected "Optional[str]" [arg-type]
scripts/scraper/batocera_launchers.py:0: error: Argument "names" to "Launcher" has incompatible type "list[Union[str, bytes, int, float, complex, ellipsis, None]]"; expected "list[str]" [arg-type]
scripts/scraper/batocera_launchers.py:0: error: Argument "passes_to" to "Launcher" has incompatible type "Union[str, bytes, int, float, complex, ellipsis, None]"; expected "Optional[str]" [arg-type]
scripts/scraper/batocera_launchers.py:0: error: Argument 1 to "append" of "list" has incompatible type "Union[str, bytes, int, float, complex, ellipsis, None]"; expected "str" [arg-type]
scripts/scraper/batocera_launchers.py:0: error: Argument 1 to "join" of "str" has incompatible type "list[Union[str, bytes, int, float, complex, ellipsis, None]]"; expected "Iterable[str]" [arg-type]
scripts/scraper/batocera_launchers.py:0: error: Argument 1 to "ref" of "Source" has incompatible type "list[Union[tuple[int, Optional[int]], tuple[int, int]]]"; expected "list[tuple[int, int]]" [arg-type]
scripts/scraper/batocera_launchers.py:0: error: Argument 1 to <set> has incompatible type "Union[str, bytes, int, float, complex, ellipsis, None]"; expected "str" [arg-type]
scripts/scraper/batocera_launchers.py:0: error: Argument 2 to "_string_lists" has incompatible type "Optional[expr]"; expected "AST" [arg-type]
scripts/scraper/batocera_launchers.py:0: error: Argument 2 to "_string_lists" has incompatible type "Optional[expr]"; expected "AST" [arg-type]
scripts/scraper/batocera_launchers.py:0: error: Argument 3 to "_mentions" has incompatible type "set[Optional[str]]"; expected "set[str]" [arg-type]
scripts/scraper/batocera_launchers.py:0: error: Argument 3 to "_raise_message" has incompatible type "Optional[str]"; expected "str" [arg-type]
scripts/scraper/batocera_launchers.py:0: error: If x = b'abc' then f"{x}" or "{}".format(x) produces "b'abc'", not "abc". If this is desired behavior, use f"{x!r}" or "{!r}".format(x). Otherwise, decode the bytes [str-bytes-safe]
scripts/scraper/batocera_launchers.py:0: error: If x = b'abc' then f"{x}" or "{}".format(x) produces "b'abc'", not "abc". If this is desired behavior, use f"{x!r}" or "{!r}".format(x). Otherwise, decode the bytes [str-bytes-safe]
scripts/scraper/batocera_launchers.py:0: error: If x = b'abc' then f"{x}" or "{}".format(x) produces "b'abc'", not "abc". If this is desired behavior, use f"{x!r}" or "{!r}".format(x). Otherwise, decode the bytes [str-bytes-safe]
scripts/scraper/batocera_launchers.py:0: error: If x = b'abc' then f"{x}" or "{}".format(x) produces "b'abc'", not "abc". If this is desired behavior, use f"{x!r}" or "{!r}".format(x). Otherwise, decode the bytes [str-bytes-safe]
scripts/scraper/batocera_launchers.py:0: error: If x = b'abc' then f"{x}" or "{}".format(x) produces "b'abc'", not "abc". If this is desired behavior, use f"{x!r}" or "{!r}".format(x). Otherwise, decode the bytes [str-bytes-safe]
scripts/scraper/batocera_launchers.py:0: error: Incompatible return value type (got "tuple[Union[str, bytes, int, float, complex, ellipsis, None], Union[str, bytes, int, float, complex, ellipsis, None]]", expected "Optional[tuple[str, Any]]") [return-value]
scripts/scraper/batocera_launchers.py:0: error: Incompatible types in assignment (expression has type "Optional[str]", variable has type "str") [assignment]
scripts/scraper/batocera_launchers.py:0: error: Item "None" of "Optional[expr]" has no attribute "lineno" [union-attr]
scripts/scraper/batocera_launchers.py:0: error: List comprehension has incompatible type List[Optional[str]]; expected List[str] [misc]
scripts/scraper/batocera_launchers.py:0: error: List comprehension has incompatible type List[tuple[int, Optional[int]]]; expected List[tuple[int, int]] [misc]
scripts/scraper/batocera_launchers.py:0: error: List item 0 has incompatible type "tuple[int, Optional[int]]"; expected "tuple[int, int]" [list-item]
scripts/scraper/batocera_launchers.py:0: error: List item 0 has incompatible type "tuple[int, Optional[int]]"; expected "tuple[int, int]" [list-item]
scripts/scraper/batocera_launchers.py:0: error: List item 0 has incompatible type "tuple[int, Optional[int]]"; expected "tuple[int, int]" [list-item]
scripts/scraper/batocera_launchers.py:0: error: List item 0 has incompatible type "tuple[int, Optional[int]]"; expected "tuple[int, int]" [list-item]
scripts/scraper/batocera_launchers.py:0: error: List item 1 has incompatible type "tuple[Union[int, Any], Optional[int]]"; expected "tuple[int, int]" [list-item]
scripts/scraper/batocera_launchers.py:0: error: List item 1 has incompatible type "tuple[int, Optional[int]]"; expected "tuple[int, int]" [list-item]
scripts/scraper/batocera_launchers.py:0: error: Need type annotation for "launchers" (hint: "launchers: list[<type>] = ...") [var-annotated]
scripts/scraper/batocera_launchers.py:0: error: Unsupported left operand type for + ("ellipsis") [operator]
scripts/scraper/batocera_launchers.py:0: error: Unsupported operand types for + ("bytes" and "str") [operator]
scripts/scraper/batocera_launchers.py:0: error: Unsupported operand types for + ("complex" and "str") [operator]
scripts/scraper/batocera_launchers.py:0: error: Unsupported operand types for + ("float" and "str") [operator]
scripts/scraper/batocera_launchers.py:0: error: Unsupported operand types for + ("int" and "str") [operator]
scripts/scraper/batocera_launchers.py:0: error: Unsupported operand types for in ("Union[str, bytes, int, float, complex, ellipsis]" and "str") [operator]
scripts/scraper/bizhawk_scraper.py:0: error: Name "BaseScraper" already defined (possibly by an import) [no-redef]
scripts/scraper/bizhawk_scraper.py:0: error: Name "BiosRequirement" already defined (possibly by an import) [no-redef]
scripts/scraper/bizhawk_scraper.py:0: error: Name "fetch_github_latest_version" already defined (possibly by an import) [no-redef]
scripts/scraper/bizhawk_scraper.py:0: error: Name "requirement_entry" already defined (possibly by an import) [no-redef]
scripts/scraper/bizhawk_scraper.py:0: error: Name "scraper_cli" already defined (possibly by an import) [no-redef]
scripts/scraper/configgen_launchers.py:0: error: Incompatible return value type (got "AST", expected "Union[Assign, AnnAssign]") [return-value]
scripts/scraper/coreinfo_scraper.py:0: error: Name "BaseScraper" already defined (possibly by an import) [no-redef]
scripts/scraper/coreinfo_scraper.py:0: error: Name "BiosRequirement" already defined (possibly by an import) [no-redef]
scripts/scraper/coreinfo_scraper.py:0: error: Name "fetch_github_latest_version" already defined (possibly by an import) [no-redef]
scripts/scraper/coreinfo_scraper.py:0: error: Name "github_headers" already defined (possibly by an import) [no-redef]
scripts/scraper/emudeck_launchers.py:0: error: Item "None" of "Optional[str]" has no attribute "split" [union-attr]
scripts/scraper/emudeck_launchers.py:0: error: Name "Launcher" already defined (possibly by an import) [no-redef]
scripts/scraper/emudeck_launchers.py:0: error: Name "LauncherPatternMissing" already defined (possibly by an import) [no-redef]
scripts/scraper/emudeck_launchers.py:0: error: Name "RepoTree" already defined (possibly by an import) [no-redef]
scripts/scraper/emudeck_launchers.py:0: error: Name "Script" already defined (possibly by an import) [no-redef]
scripts/scraper/emudeck_launchers.py:0: error: Name "describe_keys" already defined (possibly by an import) [no-redef]
scripts/scraper/emudeck_launchers.py:0: error: Name "settings" already defined (possibly by an import) [no-redef]
scripts/scraper/emudeck_launchers.py:0: error: Name "source_ref" already defined (possibly by an import) [no-redef]
scripts/scraper/emudeck_launchers.py:0: error: Name "words" already defined (possibly by an import) [no-redef]
scripts/scraper/emudeck_launchers.py:0: error: Need type annotation for "records" (hint: "records: list[<type>] = ...") [var-annotated]
scripts/scraper/emudeck_scraper.py:0: error: Name "BaseScraper" already defined (possibly by an import) [no-redef]
scripts/scraper/emudeck_scraper.py:0: error: Name "BiosRequirement" already defined (possibly by an import) [no-redef]
scripts/scraper/emudeck_scraper.py:0: error: Name "RepoTree" already defined (possibly by an import) [no-redef]
scripts/scraper/emudeck_scraper.py:0: error: Name "emulator_of_script" already defined (possibly by an import) [no-redef]
scripts/scraper/emudeck_scraper.py:0: error: Name "extract_launchers" already defined (possibly by an import) [no-redef]
scripts/scraper/emudeck_scraper.py:0: error: Name "fetch_branch_head" already defined (possibly by an import) [no-redef]
scripts/scraper/emudeck_scraper.py:0: error: Name "fetch_github_latest_version" already defined (possibly by an import) [no-redef]
scripts/scraper/emudeck_scraper.py:0: error: Name "github_headers" already defined (possibly by an import) [no-redef]
scripts/scraper/emudeck_scraper.py:0: error: Name "requirement_entry" already defined (possibly by an import) [no-redef]
scripts/scraper/emudeck_scraper.py:0: error: Need type annotation for "entries" (hint: "entries: list[<type>] = ...") [var-annotated]
scripts/scraper/libretro_scraper.py:0: error: Unpacked dict entry 0 has incompatible type "Collection[str]"; expected "SupportsKeysAndGetItem[Any, Any]" [dict-item]
scripts/scraper/mame_devices.py:0: error: Incompatible types in "yield" (actual type "IO[bytes]", expected type "BufferedIOBase") [misc]
scripts/scraper/mame_hash_scraper.py:0: error: Item "None" of "Optional[dict[str, Any]]" has no attribute "get" [union-attr]
scripts/scraper/minui_scraper.py:0: error: Cannot infer type of lambda [misc]
scripts/scraper/minui_scraper.py:0: error: Name "BaseScraper" already defined (possibly by an import) [no-redef]
scripts/scraper/minui_scraper.py:0: error: Name "BiosRequirement" already defined (possibly by an import) [no-redef]
scripts/scraper/minui_scraper.py:0: error: Name "fetch_branch_head" already defined (possibly by an import) [no-redef]
scripts/scraper/minui_scraper.py:0: error: Name "fetch_bytes" already defined (possibly by an import) [no-redef]
scripts/scraper/minui_scraper.py:0: error: Name "github_headers" already defined (possibly by an import) [no-redef]
scripts/scraper/minui_scraper.py:0: error: Name "scraper_cli" already defined (possibly by an import) [no-redef]
scripts/scraper/misterfpga_scraper.py:0: error: Name "BaseScraper" already defined (possibly by an import) [no-redef]
scripts/scraper/misterfpga_scraper.py:0: error: Name "BiosRequirement" already defined (possibly by an import) [no-redef]
scripts/scraper/misterfpga_scraper.py:0: error: Name "_read_limited" already defined (possibly by an import) [no-redef]
scripts/scraper/misterfpga_scraper.py:0: error: Name "fetch_branch_head" already defined (possibly by an import) [no-redef]
scripts/scraper/misterfpga_scraper.py:0: error: Name "requirement_entry" already defined (possibly by an import) [no-redef]
scripts/scraper/misterfpga_scraper.py:0: error: Name "scraper_cli" already defined (possibly by an import) [no-redef]
scripts/scraper/myminui_scraper.py:0: error: Name "minui_scraper" already defined (by an import) [no-redef]
scripts/scraper/myminui_scraper.py:0: error: Name "scraper_cli" already defined (possibly by an import) [no-redef]
scripts/scraper/nextui_scraper.py:0: error: Name "minui_scraper" already defined (by an import) [no-redef]
scripts/scraper/nextui_scraper.py:0: error: Name "scraper_cli" already defined (possibly by an import) [no-redef]
scripts/scraper/recalbox_launchers.py:0: error: "AST" has no attribute "lineno" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "AST" has no attribute "lineno" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "AST" has no attribute "lineno" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "AST" has no attribute "value" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "AST" has no attribute "value" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "AST" has no attribute "value" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "AST" has no attribute "value" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "AST" has no attribute "value" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "AST" has no attribute "value" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "AST" has no attribute "value" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "AST" has no attribute "value" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "AST" has no attribute "value" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "None" object is not iterable [misc]
scripts/scraper/recalbox_launchers.py:0: error: "expr" has no attribute "args" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "expr" has no attribute "attr" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "expr" has no attribute "comparators" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "expr" has no attribute "elts" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "expr" has no attribute "id" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "expr" has no attribute "value" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "expr" has no attribute "value" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "expr" has no attribute "value" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "expr" has no attribute "value" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "expr" has no attribute "value" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "expr" has no attribute "value" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "expr" has no attribute "value" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "expr" has no attribute "values" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "expr" has no attribute "values" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "stmt" has no attribute "value" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "stmt" has no attribute "value" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "stmt" has no attribute "value" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "stmt" has no attribute "value" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "stmt" has no attribute "value" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "stmt" has no attribute "value" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "stmt" has no attribute "value" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "stmt" has no attribute "value" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: "stmt" has no attribute "value" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: Argument "emulator" to "Launcher" has incompatible type "Union[str, bytes, int, float, complex, ellipsis, None]"; expected "str" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument "emulator" to "Launcher" has incompatible type "Union[str, bytes, int, float, complex, ellipsis, None]"; expected "str" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument "fails_when_missing" to "Launcher" has incompatible type "Union[str, bytes, int, float, complex, ellipsis, None]"; expected "Union[bool, str]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument "names" to "Launcher" has incompatible type "list[Optional[str]]"; expected "list[str]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument "names" to "Launcher" has incompatible type "list[Union[str, bytes, int, float, complex, ellipsis, None]]"; expected "list[str]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument "passes_to" to "Launcher" has incompatible type "Union[str, bytes, int, float, complex, ellipsis, None]"; expected "Optional[str]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument "slot" to "Launcher" has incompatible type "Union[str, bytes, int, float, complex, ellipsis, None]"; expected "Optional[str]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 1 to "append" of "list" has incompatible type "Optional[str]"; expected "str" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 1 to "append" of "list" has incompatible type "Optional[str]"; expected "str" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 1 to "append" of "list" has incompatible type "Union[str, bytes, int, float, complex, ellipsis, None]"; expected "str" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 1 to "append" of "list" has incompatible type "Union[str, bytes, int, float, complex, ellipsis, None]"; expected "str" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 1 to "index" of "list" has incompatible type "Optional[stmt]"; expected "stmt" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 1 to "join" has incompatible type "*list[Optional[str]]"; expected "str" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 1 to "join" of "str" has incompatible type "list[Union[str, bytes, int, float, complex, ellipsis, None]]"; expected "Iterable[str]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 1 to "join" of "str" has incompatible type "list[Union[str, bytes, int, float, complex, ellipsis, None]]"; expected "Iterable[str]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 1 to "join" of "str" has incompatible type "list[Union[str, bytes, int, float, complex, ellipsis, None]]"; expected "Iterable[str]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 1 to "ref" of "Source" has incompatible type "list[tuple[int, Optional[int]]]"; expected "list[tuple[int, int]]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 1 to "ref" of "Source" has incompatible type "list[tuple[int, Optional[int]]]"; expected "list[tuple[int, int]]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 1 to "setdefault" of "MutableMapping" has incompatible type "Union[str, bytes, int, float, complex, ellipsis, None]"; expected "str" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 4 to "record" has incompatible type "list[tuple[int, Optional[int]]]"; expected "list[tuple[int, int]]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[bool]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[bool]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[bool]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[bool]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[bool]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[dict[str, list[str]]]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[dict[str, list[str]]]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[dict[str, list[str]]]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[dict[str, list[str]]]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[dict[str, list[str]]]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[str]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[str]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[str]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[str]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[str]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Union[bool, str]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Union[bool, str]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "Union[bool, str]" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "str" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "str" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "str" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "str" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: Argument 5 to "Launcher" has incompatible type "**dict[str, object]"; expected "str" [arg-type]
scripts/scraper/recalbox_launchers.py:0: error: If x = b'abc' then f"{x}" or "{}".format(x) produces "b'abc'", not "abc". If this is desired behavior, use f"{x!r}" or "{!r}".format(x). Otherwise, decode the bytes [str-bytes-safe]
scripts/scraper/recalbox_launchers.py:0: error: If x = b'abc' then f"{x}" or "{}".format(x) produces "b'abc'", not "abc". If this is desired behavior, use f"{x!r}" or "{!r}".format(x). Otherwise, decode the bytes [str-bytes-safe]
scripts/scraper/recalbox_launchers.py:0: error: If x = b'abc' then f"{x}" or "{}".format(x) produces "b'abc'", not "abc". If this is desired behavior, use f"{x!r}" or "{!r}".format(x). Otherwise, decode the bytes [str-bytes-safe]
scripts/scraper/recalbox_launchers.py:0: error: If x = b'abc' then f"{x}" or "{}".format(x) produces "b'abc'", not "abc". If this is desired behavior, use f"{x!r}" or "{!r}".format(x). Otherwise, decode the bytes [str-bytes-safe]
scripts/scraper/recalbox_launchers.py:0: error: Incompatible return value type (got "Union[str, bytes, int, float, complex, ellipsis, None]", expected "Optional[str]") [return-value]
scripts/scraper/recalbox_launchers.py:0: error: Incompatible return value type (got "dict[str, tuple[list[Union[str, bytes, int, float, complex, ellipsis, None]], AST]]", expected "dict[str, tuple[list[str], stmt]]") [return-value]
scripts/scraper/recalbox_launchers.py:0: error: Incompatible return value type (got "tuple[list[Optional[str]], If]", expected "tuple[list[str], If]") [return-value]
scripts/scraper/recalbox_launchers.py:0: error: Incompatible types in assignment (expression has type "Optional[stmt]", variable has type "stmt") [assignment]
scripts/scraper/recalbox_launchers.py:0: error: Incompatible types in assignment (expression has type "Optional[str]", target has type "str") [assignment]
scripts/scraper/recalbox_launchers.py:0: error: Incompatible types in assignment (expression has type "tuple[Union[str, bytes, int, float, complex, ellipsis, None], Optional[str]]", variable has type "Optional[tuple[str, str]]") [assignment]
scripts/scraper/recalbox_launchers.py:0: error: Item "None" of "Optional[FunctionDef]" has no attribute "args" [union-attr]
scripts/scraper/recalbox_launchers.py:0: error: Item "None" of "Optional[FunctionDef]" has no attribute "name" [union-attr]
scripts/scraper/recalbox_launchers.py:0: error: Item "None" of "Optional[expr]" has no attribute "keys" [union-attr]
scripts/scraper/recalbox_launchers.py:0: error: Item "None" of "Optional[expr]" has no attribute "values" [union-attr]
scripts/scraper/recalbox_launchers.py:0: error: Item "None" of "Optional[list[str]]" has no attribute "__iter__" (not iterable) [union-attr]
scripts/scraper/recalbox_launchers.py:0: error: Item "None" of "Optional[stmt]" has no attribute "body" [union-attr]
scripts/scraper/recalbox_launchers.py:0: error: Item "None" of "Optional[stmt]" has no attribute "lineno" [union-attr]
scripts/scraper/recalbox_launchers.py:0: error: Item "None" of "Optional[stmt]" has no attribute "lineno" [union-attr]
scripts/scraper/recalbox_launchers.py:0: error: Item "None" of "Optional[stmt]" has no attribute "orelse" [union-attr]
scripts/scraper/recalbox_launchers.py:0: error: Item "expr" of "Optional[expr]" has no attribute "keys" [union-attr]
scripts/scraper/recalbox_launchers.py:0: error: Item "expr" of "Optional[expr]" has no attribute "values" [union-attr]
scripts/scraper/recalbox_launchers.py:0: error: Item "stmt" of "Optional[stmt]" has no attribute "body" [union-attr]
scripts/scraper/recalbox_launchers.py:0: error: Item "stmt" of "Optional[stmt]" has no attribute "orelse" [union-attr]
scripts/scraper/recalbox_launchers.py:0: error: List item 0 has incompatible type "Union[str, bytes, int, float, complex, ellipsis, None]"; expected "str" [list-item]
scripts/scraper/recalbox_launchers.py:0: error: List item 0 has incompatible type "tuple[Any, Optional[int]]"; expected "tuple[int, int]" [list-item]
scripts/scraper/recalbox_launchers.py:0: error: List item 0 has incompatible type "tuple[int, Optional[int]]"; expected "tuple[int, int]" [list-item]
scripts/scraper/recalbox_launchers.py:0: error: List item 0 has incompatible type "tuple[int, Optional[int]]"; expected "tuple[int, int]" [list-item]
scripts/scraper/recalbox_launchers.py:0: error: List item 0 has incompatible type "tuple[int, Optional[int]]"; expected "tuple[int, int]" [list-item]
scripts/scraper/recalbox_launchers.py:0: error: List item 0 has incompatible type "tuple[int, Optional[int]]"; expected "tuple[int, int]" [list-item]
scripts/scraper/recalbox_launchers.py:0: error: List item 0 has incompatible type "tuple[int, Optional[int]]"; expected "tuple[int, int]" [list-item]
scripts/scraper/recalbox_launchers.py:0: error: List item 0 has incompatible type "tuple[int, Optional[int]]"; expected "tuple[int, int]" [list-item]
scripts/scraper/recalbox_launchers.py:0: error: List item 0 has incompatible type "tuple[int, Optional[int]]"; expected "tuple[int, int]" [list-item]
scripts/scraper/recalbox_launchers.py:0: error: List item 1 has incompatible type "list[Optional[str]]"; expected "str" [list-item]
scripts/scraper/recalbox_launchers.py:0: error: List item 1 has incompatible type "list[tuple[int, Optional[int]]]"; expected "tuple[int, int]" [list-item]
scripts/scraper/recalbox_launchers.py:0: error: List item 1 has incompatible type "tuple[int, Optional[int]]"; expected "tuple[int, int]" [list-item]
scripts/scraper/recalbox_launchers.py:0: error: List item 1 has incompatible type "tuple[int, Optional[int]]"; expected "tuple[int, int]" [list-item]
scripts/scraper/recalbox_launchers.py:0: error: List item 2 has incompatible type "tuple[int, Optional[int]]"; expected "tuple[int, int]" [list-item]
scripts/scraper/recalbox_launchers.py:0: error: List item 2 has incompatible type "tuple[int, Optional[int]]"; expected "tuple[int, int]" [list-item]
scripts/scraper/recalbox_launchers.py:0: error: List item 3 has incompatible type "tuple[int, Optional[int]]"; expected "tuple[int, int]" [list-item]
scripts/scraper/recalbox_launchers.py:0: error: Module has no attribute "Match" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: Module has no attribute "MatchAs" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: Module has no attribute "MatchOr" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: Module has no attribute "MatchValue" [attr-defined]
scripts/scraper/recalbox_launchers.py:0: error: Value of type variable "SupportsRichComparisonT" of "max" cannot be "Optional[int]" [type-var]
scripts/scraper/retrobat_launchers.py:0: error: Incompatible types in assignment (expression has type "Optional[tuple[str, list[tuple[int, int]]]]", variable has type "str") [assignment]
scripts/scraper/retrobat_launchers.py:0: error: Item "None" of "Optional[Match[str]]" has no attribute "group" [union-attr]
scripts/scraper/retrobat_scraper.py:0: error: Argument 1 to "urlopen" has incompatible type "BiosRequirement"; expected "Union[str, Request]" [arg-type]
scripts/scraper/retrobat_scraper.py:0: error: Incompatible types in assignment (expression has type "Request", variable has type "BiosRequirement") [assignment]
scripts/scraper/retrobat_scraper.py:0: error: Name "BATOCERA_SLUGS" already defined (possibly by an import) [no-redef]
scripts/scraper/retrobat_scraper.py:0: error: Name "BaseScraper" already defined (possibly by an import) [no-redef]
scripts/scraper/retrobat_scraper.py:0: error: Name "BiosRequirement" already defined (possibly by an import) [no-redef]
scripts/scraper/retrobat_scraper.py:0: error: Name "LAUNCHER_FILES" already defined (possibly by an import) [no-redef]
scripts/scraper/retrobat_scraper.py:0: error: Name "extract_launchers" already defined (possibly by an import) [no-redef]
scripts/scraper/retrobat_scraper.py:0: error: Name "fetch_branch_head" already defined (possibly by an import) [no-redef]
scripts/scraper/retrobat_scraper.py:0: error: Name "fetch_bytes" already defined (possibly by an import) [no-redef]
scripts/scraper/retrobat_scraper.py:0: error: Name "fetch_github_latest_version" already defined (possibly by an import) [no-redef]
scripts/scraper/retrobat_scraper.py:0: error: Name "requirement_entry" already defined (possibly by an import) [no-redef]
scripts/scraper/retrodeck_launchers.py:0: error: Incompatible types in assignment (expression has type "tuple[str, ...]", variable has type "tuple[str, str, str, str]") [assignment]
scripts/scraper/retrodeck_launchers.py:0: error: Name "Launcher" already defined (possibly by an import) [no-redef]
scripts/scraper/retrodeck_launchers.py:0: error: Name "LauncherPatternMissing" already defined (possibly by an import) [no-redef]
scripts/scraper/retrodeck_launchers.py:0: error: Name "merge_records" already defined (possibly by an import) [no-redef]
scripts/scraper/retrodeck_launchers.py:0: error: Name "source_ref" already defined (possibly by an import) [no-redef]
scripts/scraper/retrodeck_scraper.py:0: error: Name "BaseScraper" already defined (possibly by an import) [no-redef]
scripts/scraper/retrodeck_scraper.py:0: error: Name "BiosRequirement" already defined (possibly by an import) [no-redef]
scripts/scraper/retrodeck_scraper.py:0: error: Name "extract_launchers" already defined (possibly by an import) [no-redef]
scripts/scraper/retrodeck_scraper.py:0: error: Name "fetch_branch_head" already defined (possibly by an import) [no-redef]
scripts/scraper/retrodeck_scraper.py:0: error: Name "fetch_bytes" already defined (possibly by an import) [no-redef]
scripts/scraper/retrodeck_scraper.py:0: error: Name "fetch_github_latest_version" already defined (possibly by an import) [no-redef]
scripts/scraper/retrodeck_scraper.py:0: error: Name "github_headers" already defined (possibly by an import) [no-redef]
scripts/scraper/retrodeck_scraper.py:0: error: Name "requirement_entry" already defined (possibly by an import) [no-redef]
scripts/scraper/retrodeck_scraper.py:0: error: Name "scraper_cli" already defined (possibly by an import) [no-redef]
scripts/scraper/retropie_launchers.py:0: error: "int" has no attribute "rstrip" [attr-defined]
scripts/scraper/retropie_launchers.py:0: error: "int" has no attribute "strip" [attr-defined]
scripts/scraper/retropie_launchers.py:0: error: Argument 3 to "Event" has incompatible type "list[str]"; expected "list[list[str]]" [arg-type]
scripts/scraper/retropie_launchers.py:0: error: Argument 3 to "Event" has incompatible type "list[str]"; expected "list[list[str]]" [arg-type]
scripts/scraper/retropie_launchers.py:0: error: Argument 3 to "_walk" of "Scripts" has incompatible type "dict[str, str]"; expected "dict[str, list[str]]" [arg-type]
scripts/scraper/retropie_launchers.py:0: error: Incompatible types in assignment (expression has type "str", variable has type "int") [assignment]
scripts/scraper/retropie_launchers.py:0: error: List comprehension has incompatible type List[list[str]]; expected List[str] [misc]
scripts/scraper/retropie_launchers.py:0: error: List comprehension has incompatible type List[list[str]]; expected List[str] [misc]
scripts/scraper/retropie_launchers.py:0: error: List comprehension has incompatible type List[tuple[str, ...]]; expected List[tuple[str, str]] [misc]
scripts/scraper/retropie_launchers.py:0: error: No overload variant of "match" of "Pattern" matches argument type "int" [call-overload]
scripts/scraper/retropie_launchers.py:0: error: No overload variant of "search" of "Pattern" matches argument type "int" [call-overload]
scripts/scraper/retropie_scraper.py:0: error: Name "BaseScraper" already defined (possibly by an import) [no-redef]
scripts/scraper/retropie_scraper.py:0: error: Name "BiosRequirement" already defined (possibly by an import) [no-redef]
scripts/scraper/retropie_scraper.py:0: error: Name "SCRIPTMODULES" already defined (possibly by an import) [no-redef]
scripts/scraper/retropie_scraper.py:0: error: Name "_SCRIPT_SECTIONS" already defined (possibly by an import) [no-redef]
scripts/scraper/retropie_scraper.py:0: error: Name "extract_launchers" already defined (possibly by an import) [no-redef]
scripts/scraper/retropie_scraper.py:0: error: Name "fetch_branch_head" already defined (possibly by an import) [no-redef]
scripts/scraper/retropie_scraper.py:0: error: Name "scraper_cli" already defined (possibly by an import) [no-redef]
scripts/scraper/rocknix_launchers.py:0: error: Argument "search_dir" to "Launcher" has incompatible type "object"; expected "Optional[str]" [arg-type]
scripts/scraper/rocknix_launchers.py:0: error: Argument 1 to "get" of "dict" has incompatible type "Union[str, Match[str]]"; expected "str" [arg-type]
scripts/scraper/rocknix_launchers.py:0: error: Argument 1 to <set> has incompatible type "Optional[int]"; expected "int" [arg-type]
scripts/scraper/rocknix_launchers.py:0: error: Argument 2 to "next" has incompatible type "None"; expected "Match[str]" [arg-type]
scripts/scraper/rocknix_launchers.py:0: error: Argument 9 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[bool]" [arg-type]
scripts/scraper/rocknix_launchers.py:0: error: Argument 9 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[bool]" [arg-type]
scripts/scraper/rocknix_launchers.py:0: error: Argument 9 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[dict[str, list[str]]]" [arg-type]
scripts/scraper/rocknix_launchers.py:0: error: Argument 9 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[str]" [arg-type]
scripts/scraper/rocknix_launchers.py:0: error: Argument 9 to "Launcher" has incompatible type "**dict[str, object]"; expected "Optional[str]" [arg-type]
scripts/scraper/rocknix_launchers.py:0: error: Argument 9 to "Launcher" has incompatible type "**dict[str, object]"; expected "Union[bool, str]" [arg-type]
scripts/scraper/rocknix_launchers.py:0: error: Argument 9 to "Launcher" has incompatible type "**dict[str, object]"; expected "Union[bool, str]" [arg-type]
scripts/scraper/rocknix_launchers.py:0: error: Generator has incompatible item type "str"; expected "Match[str]" [misc]
scripts/scraper/rocknix_launchers.py:0: error: Name "Launcher" already defined (possibly by an import) [no-redef]
scripts/scraper/rocknix_launchers.py:0: error: Name "LauncherPatternMissing" already defined (possibly by an import) [no-redef]
scripts/scraper/rocknix_launchers.py:0: error: Name "Link" already defined (possibly by an import) [no-redef]
scripts/scraper/rocknix_launchers.py:0: error: Name "RepoTree" already defined (possibly by an import) [no-redef]
scripts/scraper/rocknix_launchers.py:0: error: Name "Script" already defined (possibly by an import) [no-redef]
scripts/scraper/rocknix_launchers.py:0: error: Name "Setting" already defined (possibly by an import) [no-redef]
scripts/scraper/rocknix_launchers.py:0: error: Name "describe_keys" already defined (possibly by an import) [no-redef]
scripts/scraper/rocknix_launchers.py:0: error: Name "settings" already defined (possibly by an import) [no-redef]
scripts/scraper/rocknix_launchers.py:0: error: Name "source_ref" already defined (possibly by an import) [no-redef]
scripts/scraper/rocknix_scraper.py:0: error: Argument 1 to "get" of "dict" has incompatible type "Optional[str]"; expected "str" [arg-type]
scripts/scraper/rocknix_scraper.py:0: error: Name "BaseScraper" already defined (possibly by an import) [no-redef]
scripts/scraper/rocknix_scraper.py:0: error: Name "BiosRequirement" already defined (possibly by an import) [no-redef]
scripts/scraper/rocknix_scraper.py:0: error: Name "RepoTree" already defined (possibly by an import) [no-redef]
scripts/scraper/rocknix_scraper.py:0: error: Name "extract_launchers" already defined (possibly by an import) [no-redef]
scripts/scraper/rocknix_scraper.py:0: error: Name "fetch_github_latest_version" already defined (possibly by an import) [no-redef]
scripts/scraper/rocknix_scraper.py:0: error: Name "md5_field" already defined (possibly by an import) [no-redef]
scripts/scraper/rocknix_scraper.py:0: error: Name "requirement_entry" already defined (possibly by an import) [no-redef]
scripts/scraper/rocknix_scraper.py:0: error: Name "scraper_cli" already defined (possibly by an import) [no-redef]
scripts/scraper/romfolders/card.py:0: error: Incompatible types in assignment (expression has type "list[str]", variable has type "str") [assignment]
scripts/scraper/romfolders/card.py:0: error: Incompatible types in assignment (expression has type "str", variable has type "Optional[Match[str]]") [assignment]
scripts/scraper/romfolders/card.py:0: error: No overload variant of "get" of "dict" matches argument types "Optional[Match[str]]", "Optional[Match[str]]" [call-overload]
scripts/scraper/romfolders/es.py:0: error: Argument 2 to "setdefault" of "MutableMapping" has incompatible type "tuple[str, Any, str]"; expected "tuple[str, str, int]" [arg-type]
scripts/scraper/romfolders/es.py:0: error: Incompatible types in assignment (expression has type "Optional[Any]", variable has type "str") [assignment]
scripts/scraper/romfolders/es.py:0: error: Incompatible types in assignment (expression has type "int", variable has type "str") [assignment]
scripts/scraper/romfolders/es.py:0: error: Incompatible types in assignment (expression has type "int", variable has type "str") [assignment]
scripts/scraper/romfolders/es.py:0: error: List item 0 has incompatible type "None"; expected "dict[Any, Any]" [list-item]
scripts/scraper/romfolders/es.py:0: error: Value of type "Optional[str]" is not indexable [index]
scripts/scraper/romm_scraper.py:0: error: Name "BaseScraper" already defined (possibly by an import) [no-redef]
scripts/scraper/romm_scraper.py:0: error: Name "BiosRequirement" already defined (possibly by an import) [no-redef]
scripts/scraper/romm_scraper.py:0: error: Name "fetch_bytes" already defined (possibly by an import) [no-redef]
scripts/scraper/romm_scraper.py:0: error: Name "fetch_github_latest_version" already defined (possibly by an import) [no-redef]
scripts/scraper/romm_scraper.py:0: error: Name "requirement_entry" already defined (possibly by an import) [no-redef]
scripts/scraper/romset_dat_importer.py:0: error: "IO[bytes]" has no attribute "close_archive" [attr-defined]
scripts/scraper/romset_dat_importer.py:0: error: "object" has no attribute "__iter__"; maybe "__dir__" or "__str__"? (not iterable) [attr-defined]
scripts/scraper/romset_dat_importer.py:0: error: Incompatible return value type (got "IO[bytes]", expected "ZipExtFile") [return-value]
scripts/scraper/shell_launchers.py:0: error: Name "LauncherShapeError" already defined (possibly by an import) [no-redef]
scripts/scraper/shell_launchers.py:0: error: Name "fetch_bytes" already defined (possibly by an import) [no-redef]
scripts/scraper/shell_launchers.py:0: error: Name "github_headers" already defined (possibly by an import) [no-redef]
scripts/scraper/targets/amberelec_targets_scraper.py:0: error: Name "BUILDS_OF" already defined (possibly by an import) [no-redef]
scripts/scraper/targets/amberelec_targets_scraper.py:0: error: Name "ES_SYSTEMS_TEMPLATE" already defined (possibly by an import) [no-redef]
scripts/scraper/targets/amberelec_targets_scraper.py:0: error: Name "RUNNERS" already defined (possibly by an import) [no-redef]
scripts/scraper/targets/amberelec_targets_scraper.py:0: error: Name "_not_cores" already defined (possibly by an import) [no-redef]
scripts/scraper/targets/amberelec_targets_scraper.py:0: error: Name "es_cores" already defined (possibly by an import) [no-redef]
scripts/scraper/targets/amberelec_targets_scraper.py:0: error: Name "fetch_bytes" already defined (possibly by an import) [no-redef]
scripts/scraper/targets/amberelec_targets_scraper.py:0: error: Name "xml_systems" already defined (possibly by an import) [no-redef]
scripts/scraper/targets/batocera_targets_scraper.py:0: error: Name "github_headers" already defined (possibly by an import) [no-redef]
scripts/scraper/targets/emuelec_targets_scraper.py:0: error: Name "BUILDS_OF" already defined (possibly by an import) [no-redef]
scripts/scraper/targets/emuelec_targets_scraper.py:0: error: Name "ES_SYSTEMS_TEMPLATE" already defined (possibly by an import) [no-redef]
scripts/scraper/targets/emuelec_targets_scraper.py:0: error: Name "PORTS_TEMPLATE" already defined (possibly by an import) [no-redef]
scripts/scraper/targets/emuelec_targets_scraper.py:0: error: Name "RUNNERS" already defined (possibly by an import) [no-redef]
scripts/scraper/targets/emuelec_targets_scraper.py:0: error: Name "SystemEmulators" already defined (possibly by an import) [no-redef]
scripts/scraper/targets/emuelec_targets_scraper.py:0: error: Name "_not_cores" already defined (possibly by an import) [no-redef]
scripts/scraper/targets/emuelec_targets_scraper.py:0: error: Name "es_cores" already defined (possibly by an import) [no-redef]
scripts/scraper/targets/emuelec_targets_scraper.py:0: error: Name "fetch_bytes" already defined (possibly by an import) [no-redef]
scripts/scraper/targets/emuelec_targets_scraper.py:0: error: Name "github_headers" already defined (possibly by an import) [no-redef]
scripts/scraper/targets/emuelec_targets_scraper.py:0: error: Name "port_engines" already defined (possibly by an import) [no-redef]
scripts/scraper/targets/emuelec_targets_scraper.py:0: error: Name "with_ports" already defined (possibly by an import) [no-redef]
scripts/scraper/targets/lakka_targets_scraper.py:0: error: Name "fetch_bytes" already defined (possibly by an import) [no-redef]
scripts/scraper/targets/lakka_targets_scraper.py:0: error: Name "github_headers" already defined (possibly by an import) [no-redef]
scripts/scraper/targets/recalbox_targets_scraper.py:0: error: Name "PlatformScraper" already defined (possibly by an import) [no-redef]
scripts/scraper/targets/recalbox_targets_scraper.py:0: error: Name "SYSTEMS_TREE_URL" already defined (possibly by an import) [no-redef]
scripts/scraper/targets/recalbox_targets_scraper.py:0: error: Name "board_cores" already defined (possibly by an import) [no-redef]
scripts/scraper/targets/recalbox_targets_scraper.py:0: error: Name "fetch_bytes" already defined (possibly by an import) [no-redef]
scripts/scraper/targets/rocknix_targets_scraper.py:0: error: Name "fetch_bytes" already defined (possibly by an import) [no-redef]
scripts/scraper/targets/rocknix_targets_scraper.py:0: error: Name "github_headers" already defined (possibly by an import) [no-redef]
scripts/scraper/targets/rocknix_targets_scraper.py:0: error: Name "standalone_emulators" already defined (possibly by an import) [no-redef]
scripts/sect233r1.py:0: error: Incompatible types in assignment (expression has type "Optional[tuple[int, int]]", variable has type "tuple[int, int]") [assignment]
scripts/site_insights.py:0: error: Item "list[Any]" of "Union[dict[Any, Any], list[Any]]" has no attribute "get" [union-attr]
scripts/site_insights.py:0: error: Item "list[Any]" of "Union[dict[Any, Any], list[Any]]" has no attribute "get" [union-attr]
scripts/site_insights.py:0: error: Item "list[Any]" of "Union[dict[Any, Any], list[Any]]" has no attribute "get" [union-attr]
scripts/site_insights.py:0: error: Item "list[Any]" of "Union[dict[Any, Any], list[Any]]" has no attribute "get" [union-attr]
scripts/sitediagrams.py:0: error: "AST" has no attribute "value" [attr-defined]
scripts/sitediagrams.py:0: error: Argument 1 to "lstrip" of "bytes" has incompatible type "str"; expected "Optional[Buffer]" [arg-type]
scripts/sitediagrams.py:0: error: If x = b'abc' then f"{x}" or "{}".format(x) produces "b'abc'", not "abc". If this is desired behavior, use f"{x!r}" or "{!r}".format(x). Otherwise, decode the bytes [str-bytes-safe]
scripts/sitediagrams.py:0: error: Incompatible types in assignment (expression has type "Union[str, bytes, int, float, complex, ellipsis, Any, None]", variable has type "str") [assignment]
scripts/sitediagrams.py:0: error: Item "None" of "Union[str, bytes, int, float, complex, ellipsis, None]" has no attribute "lstrip" [union-attr]
scripts/sitediagrams.py:0: error: Item "complex" of "Union[str, bytes, int, float, complex, ellipsis, None]" has no attribute "lstrip" [union-attr]
scripts/sitediagrams.py:0: error: Item "ellipsis" of "Union[str, bytes, int, float, complex, ellipsis, None]" has no attribute "lstrip" [union-attr]
scripts/sitediagrams.py:0: error: Item "float" of "Union[str, bytes, int, float, complex, ellipsis, None]" has no attribute "lstrip" [union-attr]
scripts/sitediagrams.py:0: error: Item "int" of "Union[str, bytes, int, float, complex, ellipsis, None]" has no attribute "lstrip" [union-attr]
scripts/siteguides.py:0: error: Argument 1 to "tuple" has incompatible type "list[tuple[str, ...]]"; expected "Iterable[tuple[str, str, str, str, str]]" [arg-type]
scripts/siteguides.py:0: error: Incompatible types in assignment (expression has type "tuple[str, ...]", target has type "tuple[str, str, str]") [assignment]
scripts/sitemeasurements.py:0: error: Argument 1 to "permalink" has incompatible type "Optional[Any]"; expected "str" [arg-type]
scripts/sitemeasurements.py:0: error: Argument 2 to "permalink" has incompatible type "Optional[Any]"; expected "str" [arg-type]
scripts/sitemeasurements.py:0: error: Value of type "Optional[Match[str]]" is not indexable [index]
scripts/siterender.py:0: error: "None" object is not iterable [misc]
scripts/siterender.py:0: error: Argument 1 to "add" of "set" has incompatible type "Optional[tuple[str, str]]"; expected "tuple[str, str]" [arg-type]
scripts/sitestarlight.py:0: error: "object" has no attribute "items" [attr-defined]
scripts/sitestarlight.py:0: error: Argument "key" to "max" has incompatible type overloaded function; expected "Callable[[str], Union[SupportsDunderLT[Any], SupportsDunderGT[Any]]]" [arg-type]
scripts/sitestarlight.py:0: error: Incompatible types in assignment (expression has type "Optional[dict[str, int]]", variable has type "dict[str, int]") [assignment]
scripts/slot.py:0: error: Value of type variable "SupportsRichComparisonT" of "min" cannot be "Optional[int]" [type-var]
scripts/sourceref.py:0: error: Incompatible types in assignment (expression has type "Optional[str]", variable has type "str") [assignment]
scripts/upstream.py:0: error: "object" has no attribute "get" [attr-defined]
scripts/upstream.py:0: error: Incompatible types in assignment (expression has type "Optional[str]", variable has type "str") [assignment]
scripts/upstream.py:0: error: Incompatible types in assignment (expression has type "Optional[str]", variable has type "str") [assignment]
scripts/upstream.py:0: error: Value of type "object" is not indexable [index]
scripts/validate_pr.py:0: error: "Collection[Any]" has no attribute "add" [attr-defined]
scripts/validate_pr.py:0: error: "Collection[Any]" has no attribute "setdefault" [attr-defined]
scripts/validate_pr.py:0: error: "Collection[Any]" has no attribute "setdefault" [attr-defined]
scripts/validate_pr.py:0: error: "Collection[Any]" has no attribute "update" [attr-defined]
scripts/validate_pr.py:0: error: "Collection[Any]" has no attribute "update" [attr-defined]
scripts/validate_pr.py:0: error: "Collection[Any]" has no attribute "update" [attr-defined]
scripts/validate_pr.py:0: error: "Collection[Any]" has no attribute "update" [attr-defined]
scripts/validate_pr.py:0: error: "_MutuallyExclusiveGroup" has no attribute "append" [attr-defined]
scripts/validate_pr.py:0: error: "add" of "set" does not return a value (it only ever returns None) [func-returns-value]
scripts/validate_pr.py:0: error: Argument 1 to "_note_sizes" has incompatible type "Collection[Any]"; expected "dict[str, list[Any]]" [arg-type]
scripts/validate_pr.py:0: error: Incompatible types in assignment (expression has type "list[Never]", variable has type "_MutuallyExclusiveGroup") [assignment]
scripts/validate_pr.py:0: error: Incompatible types in assignment (expression has type "set[Any]", variable has type "list[Any]") [assignment]
scripts/validate_pr.py:0: error: List item 0 has incompatible type "None"; expected "int" [list-item]
scripts/validate_pr.py:0: error: Need type annotation for "checks" (hint: "checks: list[<type>] = ...") [var-annotated]
scripts/validate_pr.py:0: error: Need type annotation for "expected" [var-annotated]
scripts/validate_pr.py:0: error: Need type annotation for "known" [var-annotated]
scripts/validate_schemas.py:0: error: "object" has no attribute "get" [attr-defined]
scripts/validate_schemas.py:0: error: "object" has no attribute "get" [attr-defined]
scripts/validate_schemas.py:0: error: "object" has no attribute "get" [attr-defined]
scripts/validate_schemas.py:0: error: "object" has no attribute "get" [attr-defined]
scripts/validate_schemas.py:0: error: "object" has no attribute "get" [attr-defined]
scripts/validate_schemas.py:0: error: "object" has no attribute "get" [attr-defined]
scripts/validate_schemas.py:0: error: "object" has no attribute "get" [attr-defined]
scripts/validate_schemas.py:0: error: "object" has no attribute "get" [attr-defined]
scripts/validate_schemas.py:0: error: "object" has no attribute "get" [attr-defined]
scripts/validate_schemas.py:0: error: "object" has no attribute "get" [attr-defined]
scripts/validate_schemas.py:0: error: Argument 1 to "_semantic_database_checks" has incompatible type "object"; expected "dict[Any, Any]" [arg-type]
scripts/validate_schemas.py:0: error: Argument 3 to "_validate_json_files" has incompatible type "Callable[[Path, dict[Any, Any]], list[str]]"; expected "Optional[Callable[[Path, object], list[str]]]" [arg-type]
scripts/validate_schemas.py:0: error: Argument 3 to "_validate_json_files" has incompatible type "Callable[[Path, dict[Any, Any]], list[str]]"; expected "Optional[Callable[[Path, object], list[str]]]" [arg-type]
scripts/validate_schemas.py:0: error: Unpacked dict entry 0 has incompatible type "object"; expected "SupportsKeysAndGetItem[str, str]" [dict-item]
scripts/validation.py:0: error: "dict[str, str]" has no attribute "startswith" [attr-defined]
scripts/validation.py:0: error: Argument 1 to "_merged_reason" has incompatible type "list[Optional[str]]"; expected "list[str]" [arg-type]
scripts/validation.py:0: error: Argument 1 to "set" has incompatible type "Union[dict[Any, Any], list[str], Any, None]"; expected "Iterable[Any]" [arg-type]
scripts/validation.py:0: error: Argument 1 to "setdefault" of "MutableMapping" has incompatible type "tuple[Optional[Any], Optional[Any]]"; expected "tuple[str, str]" [arg-type]
scripts/validation.py:0: error: Argument 2 to "frontend_digest_matches" has incompatible type "Optional[str]"; expected "str" [arg-type]
scripts/validation.py:0: error: Argument 3 to "_entry_rule" has incompatible type "list[str]"; expected "set[str]" [arg-type]
scripts/validation.py:0: error: Incompatible types in assignment (expression has type "str", variable has type "dict[str, str]") [assignment]
scripts/validation.py:0: error: Item "None" of "Optional[Match[str]]" has no attribute "group" [union-attr]
scripts/validation.py:0: error: Item "None" of "Optional[Match[str]]" has no attribute "group" [union-attr]
scripts/validation.py:0: error: Item "None" of "Optional[Match[str]]" has no attribute "group" [union-attr]
scripts/validation.py:0: error: Item "None" of "Optional[str]" has no attribute "lower" [union-attr]
scripts/verify.py:0: error: Item "None" of "Optional[dict[Any, Any]]" has no attribute "setdefault" [union-attr]
scripts/version_basis.py:0: error: Too many arguments for "describe_form" [call-arg]
+1 -4
View File
@@ -1,6 +1,6 @@
platform: emudeck
source: https://github.com/dragoonDorise/EmuDeck/tree/dddb30229adbbd54d5ff7283cfd70e11c4322c26
scraped_at: '2026-11-06T07:10:22Z'
scraped_at: '2026-11-06T13:46:57Z'
targets:
steamos:
architecture: x86_64
@@ -348,7 +348,6 @@ targets:
- freechaf
- freeintv
- frodo
- fsuae
- fuse
- galaksija
- gam4980
@@ -430,7 +429,6 @@ targets:
- nxengine
- o2em
- oberon
- omicron
- openlara
- opera
- panda3ds
@@ -511,7 +509,6 @@ targets:
- vice_xplus4
- vice_xscpu64
- vice_xvic
- video_processor
- vircon32
- virtualjaguar
- virtualxt
+27 -1
View File
@@ -16,7 +16,8 @@ description = "BIOS collection manager for retrogaming platforms"
# install.py is the only entry point a user runs before cloning, and both
# bootstraps accept 3.8, so the floor stays where the bootstraps put it. That
# floor covers install.py alone: the build scripts under scripts/ need 3.9
# (pipeline.py checks it), and CI runs the test suite on 3.12.
# (common.py, which every build script imports, checks it), and CI runs the
# test suite on 3.12.
requires-python = ">=3.8"
dependencies = [
"pyyaml",
@@ -37,9 +38,34 @@ dev = [
# installs only in its isolated build environment and 3.12 no longer
# bundles: without it the guard skipped on every CI run.
"setuptools>=61",
# The type check CI runs, pinned: another mypy reports other errors
# than the ones mypy-baseline.txt holds.
"mypy==1.18.2",
"mypy-baseline==0.7.4",
]
# The site is built by Astro Starlight from website/package.json and its
# lockfile (npm ci --prefix website): no Python package builds it.
[project.urls]
Repository = "https://github.com/Abdess/retrobios"
# The annotations are checked, not only written. Third-party packages are left
# out (no_site_packages) so the result does not depend on what the machine
# has installed: yaml, jsonschema and the rest read as Any everywhere. The
# errors the code carried when the check started sit in mypy-baseline.txt.
# CI fails on an error that is not there and on an entry that no longer
# occurs: `mypy > out.txt`, then `mypy-baseline filter < out.txt`, and
# `mypy-baseline sync < out.txt` once the fix is in.
[tool.mypy]
files = ["install.py", "scripts"]
python_version = "3.9"
explicit_package_bases = true
ignore_missing_imports = true
no_site_packages = true
disable_error_code = ["import-untyped"]
cache_dir = "tmp/mypy_cache"
[tool.mypy-baseline]
baseline_path = "mypy-baseline.txt"
ignore_categories = ["note"]
sort_baseline = true
+3
View File
@@ -116,6 +116,9 @@ def main() -> int:
parser.add_argument("--json", action="store_true", help="print the list as JSON")
parser.add_argument("--strict", action="store_true", help="exit 1 while a file is listed")
args = parser.parse_args()
from common import work_from_repo_root # noqa: PLC0415
work_from_repo_root(args, parser, ["db", "emulators_dir", "platforms_dir", "install_dir"])
rows = bundled_only(
load_database(args.db), load_emulator_profiles(args.emulators_dir),
+6 -3
View File
@@ -83,14 +83,17 @@ from collections.abc import Callable, Iterator, Sequence
from dataclasses import dataclass, field
from pathlib import Path
import yaml
sys.path.insert(0, str(Path(__file__).resolve().parent))
# First: core_probe stops an interpreter older than 3.9 before anything else
# fails on it.
import core_probe
import yaml
import autorun
import campaign_profiles
import campaign_rules as rules
import core_probe
import measurement_records as mr
ROOT = Path(__file__).resolve().parent.parent
+38 -17
View File
@@ -54,11 +54,13 @@ import pin_installer # noqa: E402
import refresh_data_dirs # noqa: E402
import upstream # noqa: E402
from common import ( # noqa: E402
InputMissing,
apply_target_overrides,
list_registered_platforms,
load_emulator_profiles,
load_platform_registry,
require_directory,
suggest_names,
upstream_profile_index,
write_text_atomic,
yaml_load,
@@ -73,9 +75,13 @@ REPO_ROOT = Path(__file__).resolve().parents[1]
CORE_INFO_REPO = "https://github.com/libretro/libretro-core-info"
# The git blob of every .info as last reviewed: `--record-coreinfo` writes it.
CORE_INFO_RECORD = REPO_ROOT / "platforms" / "_core_info.json"
NO_INTRO_MIRROR = "https://github.com/hugo19941994/auto-datfile-generator"
NO_INTRO_RELEASE = "Daily_Rebuild"
NO_INTRO_ASSET = "no-intro.zip"
NO_INTRO_MIRROR = game_dat_importer.NOINTRO_MIRROR
NO_INTRO_RELEASE = game_dat_importer.NOINTRO_RELEASE
NO_INTRO_ASSET = game_dat_importer.NOINTRO_ASSET
# The mirror rebuilds daily. A pack older than this is a mirror that stopped:
# hugo19941994's failed every day from 2026-07-08, and comparing our import
# date with its asset read OK for four months.
NO_INTRO_MAX_AGE_DAYS = 7
TOSEC_DOWNLOADS = "https://www.tosecdev.org/downloads"
MAME_REPO = "https://github.com/mamedev/mame"
FBNEO_REPO = "https://github.com/libretro/FBNeo"
@@ -893,7 +899,10 @@ def record_core_info(
"""
unknown = sorted(set(names) - set(blobs))
if unknown:
raise ValueError(f"no such .info in core-info: {', '.join(unknown)}")
raise InputMissing(
f"no such .info in core-info: {', '.join(unknown)}. "
+ suggest_names(unknown, list(blobs), "libretro-core-info")
)
recorded = load_core_info_record(path) or {}
recorded.update({n: blobs[n] for n in (names or blobs)})
payload = {"repository": CORE_INFO_REPO, "blobs": dict(sorted(recorded.items()))}
@@ -1083,6 +1092,25 @@ def _no_intro_asset_date(cache_dir: str, offline: bool) -> str:
return ""
def _today() -> str:
return datetime.now(timezone.utc).strftime("%Y-%m-%d")
def _no_intro_row(subject: str, local: str, updated: str) -> Finding:
"""Our import against the mirror's pack, and the pack against today."""
age = (datetime.fromisoformat(_today()) - datetime.fromisoformat(updated)).days
if age > NO_INTRO_MAX_AGE_DAYS:
return Finding(
"catalogs", subject, STALE, local=local, remote=updated,
detail=f"the mirror last rebuilt {NO_INTRO_ASSET} on {updated}, {age} days ago, "
f"though it rebuilds daily: {NO_INTRO_MIRROR}/actions",
)
return Finding(
"catalogs", subject, STALE if updated > local else OK,
local=local, remote=updated, detail=f"{NO_INTRO_ASSET} rebuilt {updated}",
)
def _check_nointro_games(cache_dir: str, offline: bool) -> Finding:
"""games/catalogs/no-intro/ against the pack it was read from. The pack
holds every DAT: rebuilt after the catalogs were read, it may carry
@@ -1094,10 +1122,7 @@ def _check_nointro_games(cache_dir: str, offline: bool) -> Finding:
updated = _no_intro_asset_date(cache_dir, offline)
if not updated:
return Finding("catalogs", subject, UNKNOWN, local=fetched, detail="asset not listed")
return Finding(
"catalogs", subject, STALE if updated > fetched else OK,
local=fetched, remote=updated, detail=f"{NO_INTRO_ASSET} rebuilt {updated}",
)
return _no_intro_row(subject, fetched, updated)
def redump_datfile_version(code: str) -> str:
@@ -1171,14 +1196,7 @@ def _check_no_intro(cache_dir: str, offline: bool) -> Finding:
updated = _no_intro_asset_date(cache_dir, offline)
if not updated:
return Finding("catalogs", "no-intro", UNKNOWN, local=imported, detail="asset not listed")
return Finding(
"catalogs",
"no-intro",
STALE if updated > imported else OK,
local=imported,
remote=updated,
detail=f"{NO_INTRO_ASSET} rebuilt {updated}",
)
return _no_intro_row("no-intro", imported, updated)
def tosec_latest_pack(html: str) -> str | None:
@@ -1839,7 +1857,10 @@ def main() -> int:
if args.record_coreinfo is not None:
blobs = core_info_blobs(args.cache_dir, args.offline)
if not blobs:
raise RuntimeError("core-info listing unavailable: nothing recorded")
raise InputMissing(
f"core-info listing not in {args.cache_dir}: run without --offline"
if args.offline else "core-info listing unavailable: the GitHub API did not answer"
)
done = record_core_info(blobs, args.record_coreinfo)
print(f"recorded {len(done)} .info file(s) as reviewed")
return 0
+8 -8
View File
@@ -1,11 +1,9 @@
"""Check a BIOS folder against one platform's list, from the published data only:
python check_platform_folder.py batocera path/to/bios. Exit 1 on a file wrong or missing."""
"""Usage: python check_platform_folder.py batocera path/to/bios. Exit 1 on a file wrong or missing."""
from __future__ import annotations
import hashlib
import json
import sys
import urllib.error
import urllib.request
import zipfile
from pathlib import Path
@@ -42,14 +40,12 @@ def check(platform: str, root: Path, api: str = API) -> list[tuple[str, str]]:
"""(destination, ok | wrong | missing) per entry. With no destination (EmuDeck), any file with its hash passes."""
with urllib.request.urlopen(f"{api}{platform}.json") as response:
contract = json.load(response)["items"][0]["contract"]
mode, results = contract["verification_mode"], []
loose = [path for path in root.iterdir() if path.is_file()] if root.is_dir() else []
mode, results, loose = contract["verification_mode"], [], [p for p in root.iterdir() if p.is_file()]
for system_id, system in contract["systems"].items():
listed = [e for e in system.get("files") or [] if not e.get("destination")]
for entry in (e for e in system.get("files") or [] if e.get("destination")):
path = root / entry["destination"]
verdict = "ok" if accepts(entry, path, mode) else "wrong" if path.is_file() else "missing"
results.append((entry["destination"], verdict))
results.append((entry["destination"], "ok" if accepts(entry, path, mode) else "wrong" if path.is_file() else "missing"))
if listed:
held = any(accepts(e, path, mode) for e in listed for path in loose)
results.append((f"{system_id}: any file", "ok" if held else "missing"))
@@ -57,12 +53,16 @@ def check(platform: str, root: Path, api: str = API) -> list[tuple[str, str]]:
if __name__ == "__main__":
if len(sys.argv) != 3:
sys.exit(__doc__)
try:
found = check(sys.argv[1], Path(sys.argv[2]))
except urllib.error.HTTPError as error: # a 404: no platform has that name
except urllib.request.HTTPError as error: # a 404: no platform has that name
with urllib.request.urlopen(API.replace("platforms/", "catalog.json")) as response:
known = sorted(i["url"][10:-5] for i in json.load(response)["items"] if i["url"].startswith("manifests/"))
sys.exit(f"unknown platform: {sys.argv[1]}. Known: {', '.join(known)}" if error.code == 404 else error)
except OSError as error: # no such folder, or no network (URLError)
sys.exit(f"error: {error}")
for verdict in ("ok", "wrong", "missing"):
names = sorted({dest for dest, seen in found if seen == verdict})
print(f"{verdict}: {len(names)}" + "".join(f"\n {name}" for name in names if verdict != "ok"))
+101 -15
View File
@@ -9,6 +9,7 @@ from __future__ import annotations
from collections.abc import Callable, Iterable
from collections import Counter
import argparse
import filecmp
import hashlib
import functools
@@ -19,6 +20,16 @@ import signal
import sys
import zipfile
from pathlib import Path
from typing import Any, TextIO
# Every build script imports this module. verify.py, slots.py, validate_pr.py
# and cross_reference.py started under 3.8 and stopped halfway on a
# str.removeprefix AttributeError, which named no version.
if sys.version_info < (3, 9):
sys.exit(
f"{Path(sys.argv[0]).name} needs Python 3.9 or newer, "
f"this is {sys.version.split()[0]}"
)
try:
@@ -53,6 +64,33 @@ class DatabaseUnreadable(InputMissing):
"""The database a command was pointed at does not exist or is not JSON."""
class SourceUnreadable(ValueError):
"""A profile or platform file that is not valid YAML. Not an InputMissing:
the callers that skip a platform whose file is absent must not skip one
whose file is damaged. run_cli prints the message on one line."""
def source_yaml(stream: TextIO) -> Any:
"""Parse one of our YAML sources, naming the file a syntax error is in.
Every profile is loaded whatever the command, so one misindented key in
an unrelated profile stopped `verify.py --emulator handy` on a 37-line
traceback, the faulty file named only near its end.
"""
if yaml is None:
return yaml_load(stream)
try:
return yaml_load(stream)
except yaml.YAMLError as exc:
mark = getattr(exc, "problem_mark", None)
where = f"{stream.name}:{mark.line + 1}" if mark else stream.name
problem = getattr(exc, "problem", None) or str(exc).splitlines()[0]
raise SourceUnreadable(
f"{where}: {problem}. Check it with: "
"python scripts/validate_schemas.py --source-only"
) from None
def load_database(db_path: str) -> dict:
"""Load database.json and return parsed dict.
@@ -64,6 +102,18 @@ def load_database(db_path: str) -> dict:
with open(db_path) as f:
return json.load(f)
except FileNotFoundError:
# A mistyped --db beside the real database was told to rescan the
# whole collection into a second file under the typo.
import difflib # noqa: PLC0415
typed = Path(db_path)
close = difflib.get_close_matches(
typed.name, [p.name for p in typed.parent.glob("*.json")], n=1, cutoff=0.8
)
if close:
raise DatabaseUnreadable(
f"{db_path} not found. Did you mean {typed.with_name(close[0])}?"
) from None
raise DatabaseUnreadable(
f"{db_path} not found. Build it with: python scripts/generate_db.py "
f"--force --bios-dir bios --output {db_path}"
@@ -302,7 +352,7 @@ def _inherited_yaml(platform_name: str, platforms_dir: str) -> tuple[dict, list[
raise FileNotFoundError(f"Platform config not found: {config_file}")
with open(config_file) as f:
config = yaml_load(f) or {}
config = source_yaml(f) or {}
if "inherits" not in config:
return config, [platform_name]
@@ -348,7 +398,7 @@ def load_platform_config(platform_name: str, platforms_dir: str = "platforms") -
reg_real = os.path.realpath(registry_path)
if reg_real not in _shared_yml_cache:
with open(registry_path) as f:
_shared_yml_cache[reg_real] = yaml_load(f) or {}
_shared_yml_cache[reg_real] = source_yaml(f) or {}
reg = _shared_yml_cache[reg_real]
# The platform's own entry first, then its parents' for what it does
# not say: RetroPie's status, scraper and install are its own, its
@@ -387,7 +437,7 @@ def load_platform_config(platform_name: str, platforms_dir: str = "platforms") -
shared_real = os.path.realpath(shared_path)
if shared_real not in _shared_yml_cache:
with open(shared_path) as f:
_shared_yml_cache[shared_real] = yaml_load(f) or {}
_shared_yml_cache[shared_real] = source_yaml(f) or {}
shared = _shared_yml_cache[shared_real]
shared_groups = shared.get("shared_groups", {})
for system in config.get("systems", {}).values():
@@ -494,7 +544,7 @@ def load_data_dir_registry(platforms_dir: str = "platforms") -> dict:
if not os.path.exists(registry_path):
return {}
with open(registry_path) as f:
data = yaml_load(f) or {}
data = source_yaml(f) or {}
return data.get("data_directories", {})
@@ -504,7 +554,7 @@ def load_platform_registry(platforms_dir: str = "platforms") -> dict:
if not os.path.exists(registry_path):
return {}
with open(registry_path) as f:
return (yaml_load(f) or {}).get("platforms", {})
return (source_yaml(f) or {}).get("platforms", {})
def list_registered_platforms(platforms_dir: str = "platforms") -> list[str]:
@@ -521,7 +571,7 @@ def list_registered_platforms(platforms_dir: str = "platforms") -> list[str]:
if not os.path.exists(registry_path):
raise InputMissing(f"no platform registry at {registry_path}")
with open(registry_path) as f:
registry = yaml_load(f) or {}
registry = source_yaml(f) or {}
platforms = []
for name, meta in sorted(registry.get("platforms", {}).items()):
config_path = os.path.join(platforms_dir, meta.get("config", f"{name}.yml"))
@@ -621,6 +671,31 @@ def suggest_names(
return f"{listing_flag} lists all {total}."
def work_from_repo_root(
args: argparse.Namespace, parser: argparse.ArgumentParser, path_flags: list[str]
) -> None:
"""Run from the repository root, whichever directory the command started in.
database.json records every file from the root and the data registry
names its caches the same way, so a run from scripts/ ended on a
FileNotFoundError traceback. A path the caller typed is read from where
they typed it, a default from the root.
"""
root = Path(__file__).resolve().parent.parent
if Path.cwd().resolve() == root:
return
for flag in path_flags:
value = getattr(args, flag, None)
if value and value != parser.get_default(flag):
# A Path stays a Path for the code that joins onto it.
setattr(args, flag, type(value)(os.path.abspath(value)))
os.chdir(root)
if getattr(args, "platform", None):
# Read before the move, the registry was not there to map
# "RetroArch" to its slug.
args.platform = platform_arg(args.platform)
def platform_arg(value: str) -> str:
"""--platform as typed, mapped to the registry's slug when it names one.
@@ -669,7 +744,7 @@ def _target_overrides(platform_name: str, targets_dir: str) -> dict:
if not os.path.exists(overrides_file):
return {}
with open(overrides_file) as f:
all_overrides = yaml_load(f) or {}
all_overrides = source_yaml(f) or {}
return all_overrides.get(platform_name, {}).get("targets", {})
@@ -690,7 +765,7 @@ def platform_files_target(platform: str, target: str, platforms_dir: str = "plat
if not os.path.exists(target_file):
return False
with open(target_file) as f:
targets = (yaml_load(f) or {}).get("targets", {})
targets = (source_yaml(f) or {}).get("targets", {})
return target in _target_alias_index(targets, _target_overrides(platform, targets_dir))
@@ -710,7 +785,7 @@ def canonical_target_name(
if not os.path.exists(target_file):
continue
with open(target_file) as f:
targets = (yaml_load(f) or {}).get("targets", {})
targets = (source_yaml(f) or {}).get("targets", {})
canonical = _target_alias_index(
targets, _target_overrides(platform_name, targets_dir)
).get(target)
@@ -764,7 +839,7 @@ def load_target_config(
f"(platforms with targets: {', '.join(with_targets)})"
)
with open(target_file) as f:
data = yaml_load(f) or {}
data = source_yaml(f) or {}
targets = data.get("targets", {})
overrides = _target_overrides(platform_name, targets_dir)
@@ -822,7 +897,7 @@ def list_available_targets(
if not os.path.exists(target_file):
return []
with open(target_file) as f:
data = yaml_load(f) or {}
data = source_yaml(f) or {}
# The count --target filters on: overrides applied, as load_target_config
# applies them. The scraped list counted Batocera's machine variants and
@@ -2229,7 +2304,7 @@ def load_emulator_profiles(
raise InputMissing(f"no emulator profile directory at {emulators_dir}")
for f in source_yaml_paths(emu_path):
with open(f) as fh:
profile = yaml_load(fh) or {}
profile = source_yaml(fh) or {}
if "emulator" not in profile:
continue
_normalize_hash_fields(profile)
@@ -2359,7 +2434,7 @@ def group_identical_platforms(
try:
raw_path = os.path.join(platforms_dir, f"{platform}.yml")
with open(raw_path) as f:
raw = yaml_load(f) or {}
raw = source_yaml(f) or {}
inherits[platform] = "inherits" in raw
config = load_platform_config(platform, platforms_dir)
except FileNotFoundError:
@@ -3503,6 +3578,9 @@ def build_target_cores_cache(
raise
notes.append(f"INFO: Skipping {p}: no hardware targets")
skip.append(p)
except SourceUnreadable:
# A damaged targets file is not a platform without the target.
raise
except ValueError as e:
if is_all:
notes.append(f"INFO: Skipping {p}: {e}")
@@ -3530,7 +3608,7 @@ def _unknown_target_message(target: str, platforms: list[str], platforms_dir: st
if not os.path.exists(target_file):
continue
with open(target_file) as f:
targets = (yaml_load(f) or {}).get("targets", {})
targets = (source_yaml(f) or {}).get("targets", {})
overrides = _target_overrides(platform, targets_dir)
for name in _target_alias_index(targets, overrides):
owners.setdefault(name, []).append(platform)
@@ -3624,10 +3702,18 @@ def run_cli(main: Callable[[], int | None]) -> None:
for name in ("SIGTERM", "SIGHUP"):
if hasattr(signal, name):
signal.signal(getattr(signal, name), _exit_on_signal)
# Redirected, stdout is block-buffered and stderr is not: the --strict
# verdict landed on the first line of the log, before the report it
# closes. Line buffering keeps the two in the order they were written.
# A stream a caller swapped in (a test's StringIO) has nothing to set.
reconfigure = getattr(sys.stdout, "reconfigure", None)
if reconfigure is not None:
reconfigure(line_buffering=True)
try:
code = main()
sys.stdout.flush()
except (InputMissing, ArtifactLockBusy, ArtifactDirectoryMissing) as exc:
except (InputMissing, SourceUnreadable, ArtifactLockBusy,
ArtifactDirectoryMissing) as exc:
print(f"ERROR: {exc}", file=sys.stderr)
sys.exit(1)
except BrokenPipeError:
+8
View File
@@ -40,6 +40,14 @@ from collections.abc import Iterable, Iterator, Sequence
from dataclasses import dataclass, field
from pathlib import Path
# The probe tools do not import common.py, which states the 3.9 floor for the
# other scripts. Under 3.8 they stopped on a str.removesuffix AttributeError.
if sys.version_info < (3, 9):
sys.exit(
f"{Path(sys.argv[0]).name} needs Python 3.9 or newer, "
f"this is {sys.version.split()[0]}"
)
ROOT = Path(__file__).resolve().parent.parent
MIN_BENCH_REPETITIONS = 5
DEFAULT_WORK_DIR = ROOT / "tmp" / "core_probe"
+3
View File
@@ -1191,6 +1191,9 @@ def main() -> None:
"--list-emulators", action="store_true", help="List available emulators"
)
args = parser.parse_args()
from common import work_from_repo_root # noqa: PLC0415
work_from_repo_root(args, parser, ["emulators_dir", "platforms_dir", "db"])
if args.list_emulators:
ignored = [flag for flag, on in (
("--emulator", args.emulator), ("--platform", args.platform),
+21 -8
View File
@@ -221,12 +221,19 @@ class Exporter(BaseExporter):
ours = str(entry.get("path") or entry.get("name", "")).split("/")[:-1]
return not {d.casefold() for d in theirs} & {d.casefold() for d in ours}
def _bios_element(self, fe: NativeFile, native_id: str) -> str:
def _bios_element(
self, fe: NativeFile, native_id: str, also: tuple[NativeFile, ...] = ()
) -> str:
"""``also`` are further additions at fe's path: Bios.cpp reads one
element per path, and its md5 and core lists take every one of them."""
group = (fe, *also)
md5 = dict.fromkeys(h for f in group for h in f.hashes("md5"))
cores = dict.fromkeys(c for f in group for c in f.cores())
attrs = [f"path={quoteattr(self._path(fe))}"]
attrs.append(f'md5={quoteattr(",".join(fe.hashes("md5")))}')
attrs.append(f'core={quoteattr(",".join(fe.cores()))}')
attrs.append(f'md5={quoteattr(",".join(md5))}')
attrs.append(f'core={quoteattr(",".join(cores))}')
if not self.required_value(fe):
if not any(self.required_value(f) for f in group):
attrs.append('mandatory="false"')
elif fe.native("mandatory_declared", None) is True:
attrs.append('mandatory="true"')
@@ -343,11 +350,17 @@ class Exporter(BaseExporter):
}
ours: dict[str, tuple[NativeSystem, dict[str, tuple[NativeFile, str]]]] = {}
for system in systems.values():
writable = [fe for fe in system.files if self.writable(fe)]
if writable:
# Two additions at one path (two cores, two dumps) are one
# element: keyed by path, the second replaced the first and its
# md5 left the file while both were counted added.
at_path: dict[str, list[NativeFile]] = {}
for fe in system.files:
if self.writable(fe):
at_path.setdefault(self._path(fe), []).append(fe)
if at_path:
ours[system.native_id] = (system, {
self._path(fe): (fe, self._bios_element(fe, system.native_id))
for fe in writable
path: (group[0], self._bios_element(group[0], system.native_id, tuple(group[1:])))
for path, group in at_path.items()
})
def element(attrs: dict[str, str]) -> str:
+15 -4
View File
@@ -215,6 +215,7 @@ class Exporter(BaseExporter):
ours: list[OrderedDict],
additions: list[OrderedDict] | None = None,
appended: set[tuple[str, str]] | None = None,
held_back: list[int] | None = None,
) -> list[OrderedDict]:
"""Correct the component's own list, never replace it.
@@ -301,13 +302,19 @@ class Exporter(BaseExporter):
for e in merged
for system in (_systems_of(e) or [""])
}
for entry in additions or []:
for index, entry in enumerate(additions or []):
key = (str(entry.get("filename", "")), str(entry.get("system", "")), _paths_key(entry))
if key[0] and key not in held:
held.add(key)
merged.append(entry)
elif held_back is not None:
held_back.append(index)
return merged
def lands(self, fe: NativeFile) -> bool:
"""An addition the list already held is not written a second time."""
return self.writable(fe) and id(fe) not in getattr(self, "_held_back", set())
def render(
self,
systems: dict[str, NativeSystem],
@@ -317,6 +324,7 @@ class Exporter(BaseExporter):
) -> dict[str, str]:
self._place_additions(systems)
self._appended: set[int] = set()
self._held_back: set[int] = set()
grouped = self._by_component(systems)
produced: dict[str, str] = {}
@@ -331,25 +339,28 @@ class Exporter(BaseExporter):
continue
entries = [self._entry(fe) for fe in files if fe.platform is not None]
additions = [self._entry(fe) for fe in files if fe.platform is None]
added = [fe for fe in files if fe.platform is None]
additions = [self._entry(fe) for fe in added]
appended: set[tuple[str, str]] = set()
held_back: list[int] = []
for component_value in manifest.values():
if not isinstance(component_value, dict):
continue
holder = self._bios_holder(component_value)
if holder is None:
component_value["bios"] = self._merge(
None, entries, additions, appended
None, entries, additions, appended, held_back
)
else:
container, key = holder
written = container.get(key)
merged = self._merge(written, entries, additions, appended)
merged = self._merge(written, entries, additions, appended, held_back)
# A single object stays one while nothing is added to it.
container[key] = (
merged[0] if isinstance(written, dict) and len(merged) == 1 else merged
)
break
self._held_back.update(id(added[index]) for index in held_back)
# A declared entry whose revision the platform does not hold is
# written beside theirs: a new line, not a corrected value.
self._appended.update(
+20 -9
View File
@@ -336,6 +336,8 @@ class Exporter(BaseExporter):
systems_of.setdefault(str(name).lower(), set()).add(fe.native_system)
known = set(systems_of)
self._skipped: dict[str, list[str]] = {}
# Rewritten, with a file of a system no clause lists left out.
self._partial: list[str] = []
self._named: set[int] = set()
produced: dict[str, str] = {}
@@ -400,12 +402,11 @@ class Exporter(BaseExporter):
homes.setdefault(owners[0], []).append(fe)
else:
homeless = True
if homeless:
# No enumeration of that system to extend, and a sentence we
# would have to write ourselves is a documentation change,
# not a correction.
skip("whose help text lists no files of that system to add to", module_id)
# No enumeration of that system to extend, and a sentence we
# would have to write ourselves is a documentation change, not a
# correction. With nothing placed the package is left as is.
if not homes:
skip("whose help text lists no files of that system to add to", module_id)
continue
added = sum(len(self._in_search_order(fes)) for fes in homes.values())
@@ -428,6 +429,8 @@ class Exporter(BaseExporter):
f'rp_module_help="{new_help}"',
1,
)
if homeless:
self._partial.append(module_id)
return produced
@@ -454,12 +457,20 @@ class Exporter(BaseExporter):
) -> str:
"""Packages are the unit here, not file entries."""
skipped: dict[str, list[str]] = getattr(self, "_skipped", {})
def shown(modules: list[str]) -> str:
names = ", ".join(sorted(modules)[:4])
return names + (f" and {len(modules) - 4} more" if len(modules) > 4 else "")
parts = [f"{len(produced)} packages updated"]
partial = getattr(self, "_partial", [])
if partial:
parts.append(
f"Updated in part: {shown(partial)}, whose help text lists no files "
"of one of their systems to add to"
)
for reason, modules in sorted(skipped.items()):
shown = ", ".join(sorted(modules)[:4])
if len(modules) > 4:
shown += f" and {len(modules) - 4} more"
parts.append(f"Left as is: {shown}, {reason}")
parts.append(f"Left as is: {shown(modules)}, {reason}")
return ". ".join(parts)
def validate(
+13 -2
View File
@@ -175,6 +175,9 @@ class Exporter(BaseExporter):
ours: dict[str, dict[str, str]] = {}
added: dict[str, set[str]] = {}
# A rom name is one line: an addition whose name an earlier entry
# took is not written, and was counted added.
self._shadowed: set[int] = set()
for system, files in self.exportable(systems):
rendered: dict[str, str] = {}
for fe in files:
@@ -194,7 +197,11 @@ class Exporter(BaseExporter):
sha1 = fe.record_hash("sha1")
if sha1:
parts.append(f"sha1 {sha1}")
rendered.setdefault(name, f"\trom ( {' '.join(parts)} )")
if name in rendered:
if fe.platform is None:
self._shadowed.add(id(fe))
continue
rendered[name] = f"\trom ( {' '.join(parts)} )"
if fe.platform is None:
added.setdefault(system.native_id, set()).add(name)
if rendered:
@@ -241,7 +248,11 @@ class Exporter(BaseExporter):
return {self.native_filename(): "\n".join(lines)}
def lands(self, fe: NativeFile) -> bool:
return self.writable(fe) and id(fe) not in getattr(self, "_untitled", set())
return (
self.writable(fe)
and id(fe) not in getattr(self, "_untitled", set())
and id(fe) not in getattr(self, "_shadowed", set())
)
def validate(
self,
+3
View File
@@ -247,6 +247,9 @@ def main() -> int:
help="profiles the rules are checked against (default emulators)")
parser.add_argument("--json", action="store_true", help="print the summary as JSON")
args = parser.parse_args()
from common import work_from_repo_root # noqa: PLC0415
work_from_repo_root(args, parser, ["regions", "extras", "headers", "emulators_dir"])
regions = load_yaml(args.regions)
extras = load_yaml(args.extras)
+17 -7
View File
@@ -43,6 +43,7 @@ from common import (
require_directory,
target_listing_line,
suggest_names,
system_index,
require_platform,
load_target_config,
archive_entry,
@@ -164,7 +165,9 @@ class PackRecord:
self.sources: dict[str, str] = {}
def _add_pack_member(zf: zipfile.ZipFile, source_path: str, arcname: str) -> None:
def _add_pack_member(
zf: zipfile.ZipFile | PackRecord, source_path: str, arcname: str
) -> None:
"""Add a file to the pack with metadata that does not depend on the build.
ZipFile.write copies the source file's mtime into the member. For a file
@@ -197,7 +200,9 @@ def _add_pack_member(zf: zipfile.ZipFile, source_path: str, arcname: str) -> Non
shutil.copyfileobj(source, target, 1024 * 1024)
def _write_generated_member(zf: zipfile.ZipFile, arcname: str, text: str) -> None:
def _write_generated_member(
zf: zipfile.ZipFile | PackRecord, arcname: str, text: str
) -> None:
"""Write a pack member the builder composes rather than copies.
READMEs, instruction notes and the manifest are produced at build time,
@@ -581,7 +586,7 @@ def _data_directory_members(
def _pack_data_directories(
zf: zipfile.ZipFile,
zf: zipfile.ZipFile | PackRecord,
pack_systems: dict,
data_registry: dict | None,
platform_name: str,
@@ -1476,7 +1481,9 @@ def generate_pack(
def _extract_zip_to_archive(
source_zip: str, dest_prefix: str, target_zf: zipfile.ZipFile
source_zip: str,
dest_prefix: str,
target_zf: zipfile.ZipFile | PackRecord,
) -> None:
"""Extract contents of a source ZIP into target ZIP under dest_prefix."""
with zipfile.ZipFile(source_zip, "r") as src:
@@ -1507,7 +1514,7 @@ def _extract_zip_to_archive(
def _add_zip_to_pack(
source_zip: str,
dest_path: str,
target_zf: zipfile.ZipFile,
target_zf: zipfile.ZipFile | PackRecord,
file_entry: dict | None = None,
) -> None:
"""Write a source ZIP into the pack, byte for byte.
@@ -1555,7 +1562,7 @@ class DamagedArchiveError(OSError):
def _pack_data_tree(
zf: zipfile.ZipFile,
zf: zipfile.ZipFile | PackRecord,
local_cache: str,
dd_dest: str,
seen_destinations: set[str],
@@ -2053,7 +2060,10 @@ def generate_system_pack(
f"No emulators found for system(s): {', '.join(system_ids)}",
file=sys.stderr,
)
print(suggest_names(system_ids, sorted(all_systems), "--list-systems"),
# --list-systems merges spellings that differ in case or separator:
# the hint counted 579 spellings for the 532 lines it prints.
print(suggest_names(system_ids, sorted(all_systems), "--list-systems",
listed=len(system_index(profiles))),
file=sys.stderr)
return None
+7 -2
View File
@@ -14,7 +14,6 @@ Usage:
from __future__ import annotations
from siterender import SECTION_LABELS, WIKI_SRC_DIR
import argparse
import csv
import hashlib
@@ -56,6 +55,7 @@ from common import (
load_platform_config,
load_provenance_snapshots,
native_layer,
require_directory,
require_yaml,
resolution_is_hash_exact,
resolve_local_file,
@@ -64,6 +64,7 @@ from common import (
unique_emulator_profiles,
yaml_load,
)
from siterender import SECTION_LABELS, WIKI_SRC_DIR
from artifacts import ArtifactLockBusy, artifact_lock
from artifacts import json_text as _json_text
from cross_reference import FileConsumers, entry_target, held_copy
@@ -2330,7 +2331,7 @@ def generate_data_page(exports: list[dict], measurements_sqlite: Path | None = N
f"({REPO_URL}/blob/main/scripts/check_platform_folder.py). A test runs it "
"against the verifier on a sample folder, so the two give the same answer. "
"It exits 1 when a file is wrong or missing. For an unknown platform it "
"prints the known ones.",
"prints the known ones, and it names a folder that does not exist.",
"",
"`install.py --check` answers another question by default: whether the folder "
"holds what the pack installs, the manifest above. With `--declared-only`, or "
@@ -12393,6 +12394,10 @@ def main() -> None:
args = parser.parse_args()
if args.docs_dir is None:
args.docs_dir = str(Path(args.site_dir) / STARLIGHT_CONTENT)
# Before any write: the public assets and the bootstraps went out first,
# and a mistyped folder stopped the run only after them.
require_directory(args.emulators_dir, "--emulators-dir")
require_directory(args.platforms_dir, "--platforms-dir")
try:
# Two runs over one docs/ delete each other's pages and scratch
# files in the sweep, so the second is refused instead.
+3
View File
@@ -146,6 +146,9 @@ def main() -> int:
"--strict", action="store_true", help="exit non-zero when any is found"
)
args = parser.parse_args()
from common import work_from_repo_root # noqa: PLC0415
work_from_repo_root(args, parser, ["bios_dir"])
from common import require_directory # noqa: PLC0415
require_directory(args.bios_dir)
+4 -1
View File
@@ -26,7 +26,10 @@ def list_platforms() -> list[str]:
def main() -> None:
parser = argparse.ArgumentParser(allow_abbrev=False, description="List available platforms")
parser.parse_args()
args = parser.parse_args()
from common import work_from_repo_root # noqa: PLC0415
work_from_repo_root(args, parser, [])
platforms = list_platforms()
+123 -54
View File
@@ -20,6 +20,7 @@ import re
import subprocess
import sys
import tempfile
import time
from collections import Counter
from collections.abc import Callable, Iterable, Iterator, Sequence
from dataclasses import asdict, dataclass, field, replace
@@ -80,6 +81,9 @@ from upstream import CompareResult, find_renamed
DEFAULT_CACHE = upstream.CACHE_DIR
ANON_QUOTA = 60
TRIAGE_PATH_SAMPLE = 5
# A pass that asks the forges says where it is at this interval: an online
# --all --triage ran 15 minutes without a word and read as hung.
PROGRESS_SECONDS = 30
STATUS_ORDER = (
"ANCHORED", "UNCHECKED", "EXTERNAL", "BINARY", "SHIFTED", "RENAMED", "MOVED",
@@ -4991,35 +4995,40 @@ def _print_extras_from(
print(f" {line}")
class _Progress:
"""A stderr line every PROGRESS_SECONDS while a pass asks the forges."""
def __init__(self, total: int, doing: str, quiet: bool) -> None:
self.total, self.doing, self.quiet = total, doing, quiet
self.last = time.monotonic()
def step(self, done: int, name: str) -> None:
now = time.monotonic()
if not self.quiet and now - self.last >= PROGRESS_SECONDS:
print(f"{self.doing}: {done} of {self.total}, at {name}", file=sys.stderr, flush=True)
self.last = now
def _interrupted(done: int, total: int, what: str) -> None:
print(f"interrupted after {done} of {total} profiles: {what}", file=sys.stderr, flush=True)
def _print_triage(
args: argparse.Namespace, selected: dict, reports: list[ProfileReport]
) -> None:
"""Profiles ranked by drift, worst first."""
) -> bool:
"""Profiles ranked by drift, worst first. False when Ctrl-C cut the
scoring short: the ranking then covers the profiles scored."""
ranked = []
sampled = 0
for report in reports:
profile = selected[report.name]
version = None
commits = 0
refused = ""
repo = select_repo(profile)
if report.head and repo is not None:
paths = _cited_paths(report)
try:
version = check_version(profile, repo, args.cache_dir, args.offline)
for path in paths[:TRIAGE_PATH_SAMPLE]:
commits += upstream.commits_touching(
repo, path, report.pin, args.cache_dir, args.offline,
head=report.head,
)
except upstream.UpstreamError as exc:
# One forge refusing a request (Eden's answers 403 to commit
# lookups) leaves this profile unscored, not the whole ranking.
refused = "commit history unreachable"
print(f"{report.name}: {exc}", file=sys.stderr)
if len(paths) > TRIAGE_PATH_SAMPLE and not refused:
sampled += 1
ranked.append((drift_score(report, version, commits), report, refused))
progress = _Progress(len(reports), "scored", args.offline or len(reports) < 2)
complete = True
try:
for done, report in enumerate(reports):
progress.step(done, report.name)
sampled += _score(args, selected, report, ranked)
except KeyboardInterrupt:
_interrupted(len(ranked), len(reports), "the ranking covers those scored")
complete = False
if sampled:
# One line for the run: a notice per profile buried the ranking
# under 254 lines of stderr.
@@ -5037,6 +5046,37 @@ def _print_triage(
pending += bool(report.needs_review() or report.uncheckable())
print(f"{score:5d} {report.name:30s} {state}")
print(f"{len(ranked)} profiles, {pending} with something to review")
return complete
def _score(
args: argparse.Namespace, selected: dict, report: ProfileReport, ranked: list
) -> bool:
"""Append one profile's drift score to ``ranked``. True when its commit
count was read on a sample of the paths it cites."""
profile = selected[report.name]
version = None
commits = 0
refused = ""
sampled = False
repo = select_repo(profile)
if report.head and repo is not None:
paths = _cited_paths(report)
try:
version = check_version(profile, repo, args.cache_dir, args.offline)
for path in paths[:TRIAGE_PATH_SAMPLE]:
commits += upstream.commits_touching(
repo, path, report.pin, args.cache_dir, args.offline,
head=report.head,
)
except upstream.UpstreamError as exc:
# One forge refusing a request (Eden's answers 403 to commit
# lookups) leaves this profile unscored, not the whole ranking.
refused = "commit history unreachable"
print(f"{report.name}: {exc}", file=sys.stderr)
sampled = len(paths) > TRIAGE_PATH_SAMPLE and not refused
ranked.append((drift_score(report, version, commits), report, refused))
return sampled
def _refuse_flag_combinations(args: argparse.Namespace) -> None:
@@ -5260,30 +5300,24 @@ def main() -> None:
return
reports = []
for name, profile in selected.items():
profile_path = Path(args.emulators_dir) / f"{name}.yml"
try:
report = _build_full_report(args, name, profile, profile_path, failed)
except upstream.RateLimitError as exc:
# A quota is one forge's: git.libretro.com answering 429 said
# nothing about the 600 profiles on GitHub. upstream stops asking
# that host, so the rest of the pass costs it nothing.
print(f"{name}: {exc}", file=sys.stderr)
report = ProfileReport(
name=name, entries=[], counts={},
skipped=f"rate limited: {exc.host or exc}",
)
failed.add(name)
reports.append(report)
continue
reports.append(report)
if writes:
try:
_apply_writes(args, name, profile, report)
except YamlWriteError as exc:
# The guard already left the file untouched, so keep going.
print(f"{name}: write refused: {exc}", file=sys.stderr)
failed.add(name)
quiet = args.offline or len(selected) < 2
if not quiet:
print(
f"reading {len(selected)} profiles against their forges, a line every "
f"{PROGRESS_SECONDS} s. --offline answers from the cache alone.",
file=sys.stderr, flush=True,
)
progress = _Progress(len(selected), "read", quiet)
complete = True
try:
for name, profile in selected.items():
progress.step(len(reports), name)
_read_one(args, name, profile, reports, failed, writes)
except KeyboardInterrupt:
# What was read is still worth printing: a ranking of 200 profiles
# beats none after 15 minutes.
_interrupted(len(reports), len(selected), "the output covers those read")
complete = False
# --changed-only narrows every output, not the text report alone: the
# documented `--all --changed-only --json` listed every profile.
@@ -5291,14 +5325,49 @@ def main() -> None:
report for report in reports
if not args.changed_only or report.needs_review() or report.name in failed
]
_emit(args, selected, reports, shown)
complete = _emit(args, selected, reports, shown) is not False and complete
_refresh_source_paths(args)
if not complete:
raise SystemExit(130)
if failed or (args.strict and any(
report.needs_review() or report.uncheckable() for report in reports
)):
raise SystemExit(1)
def _read_one(
args: argparse.Namespace,
name: str,
profile: dict,
reports: list[ProfileReport],
failed: set[str],
writes: bool,
) -> None:
"""Build one profile's report into ``reports``, then apply the writes."""
profile_path = Path(args.emulators_dir) / f"{name}.yml"
try:
report = _build_full_report(args, name, profile, profile_path, failed)
except upstream.RateLimitError as exc:
# A quota is one forge's: git.libretro.com answering 429 said
# nothing about the 600 profiles on GitHub. upstream stops asking
# that host, so the rest of the pass costs it nothing.
print(f"{name}: {exc}", file=sys.stderr)
reports.append(ProfileReport(
name=name, entries=[], counts={},
skipped=f"rate limited: {exc.host or exc}",
))
failed.add(name)
return
reports.append(report)
if writes:
try:
_apply_writes(args, name, profile, report)
except YamlWriteError as exc:
# The guard already left the file untouched, so keep going.
print(f"{name}: write refused: {exc}", file=sys.stderr)
failed.add(name)
# Profiles this run wrote. Their new pins name trees the site's record of
# cited source paths does not hold yet.
_WRITTEN: set[str] = set()
@@ -5400,8 +5469,9 @@ def _emit(
selected: dict,
reports: list[ProfileReport],
shown: list[ProfileReport],
) -> None:
"""Write the reports in the form the flags ask for."""
) -> bool | None:
"""Write the reports in the form the flags ask for. False when the
triage was cut short."""
if args.as_json:
print(json.dumps([report_to_dict(r) for r in shown], indent=2))
return
@@ -5417,8 +5487,7 @@ def _emit(
print(url)
return
if args.triage:
_print_triage(args, selected, shown)
return
return _print_triage(args, selected, shown)
for report in shown:
print(format_report(report, args.changed_only))
_print_extras(args, selected[report.name], report)
+3
View File
@@ -384,6 +384,9 @@ def main() -> int:
"(the pipeline writes derivable.json)",
)
args = parser.parse_args()
from common import work_from_repo_root # noqa: PLC0415
work_from_repo_root(args, parser, ["db", "provenance_dir", "emulators_dir", "write_derivable"])
if args.write_derivable and not args.derive:
parser.error("--write-derivable records what --derive finds: pass both")
+19 -9
View File
@@ -148,18 +148,28 @@ def _run_check_freshness(areas: tuple[str, ...], extra: list[str]) -> list[dict]
if areas and set(areas) != set(AUTO_AREAS + MANUAL_AREAS):
cmd += ["--only", ",".join(areas)]
cmd += extra
proc = subprocess.run(
cmd, cwd=REPO_ROOT, capture_output=True, text=True, check=False, timeout=1800
)
if proc.returncode not in (0, 1):
try:
proc = subprocess.run(
cmd, cwd=REPO_ROOT, capture_output=True, text=True, check=False, timeout=1800
)
except subprocess.TimeoutExpired as exc:
raise RuntimeError(
f"check_freshness.py did not finish in {exc.timeout:.0f} s: run "
f"`{' '.join(cmd[1:])} > report.json` alone, then pass --findings report.json"
) from exc
# Exit 1 is the STALE rows, and also a crash: only a JSON list on stdout
# tells them apart, and the crash's own message is on stderr.
try:
findings = json.loads(proc.stdout) if proc.returncode in (0, 1) else None
except json.JSONDecodeError:
findings = None
if not isinstance(findings, list):
tail = (proc.stderr or proc.stdout).strip().splitlines()[-3:]
raise RuntimeError(
"check_freshness.py failed:\n" + "\n".join(tail or ["(no output)"])
f"check_freshness.py failed (exit {proc.returncode}):\n"
+ "\n".join(tail or ["(no output)"])
)
try:
return json.loads(proc.stdout)
except json.JSONDecodeError as exc:
raise RuntimeError(f"check_freshness.py returned unreadable JSON: {exc}") from exc
return findings
def load_findings(path: Path, areas: tuple[str, ...]) -> list[dict]:
+3
View File
@@ -201,6 +201,9 @@ def main() -> int:
)
parser.add_argument("--json", action="store_true", help="Machine-readable output")
args = parser.parse_args()
from common import work_from_repo_root # noqa: PLC0415
work_from_repo_root(args, parser, ["db", "emulators_dir"])
db = load_database(args.db)
profiles = load_emulator_profiles(args.emulators_dir)
+8
View File
@@ -36,6 +36,14 @@ import urllib.request
from collections.abc import Callable, Iterable
from pathlib import Path
# The probe tools do not import common.py, which states the 3.9 floor for the
# other scripts. Under 3.8 they stopped on a str.removesuffix AttributeError.
if sys.version_info < (3, 9):
sys.exit(
f"{Path(sys.argv[0]).name} needs Python 3.9 or newer, "
f"this is {sys.version.split()[0]}"
)
sys.path.insert(0, str(Path(__file__).resolve().parent))
import yaml # noqa: E402
+2 -2
View File
@@ -1122,7 +1122,7 @@ def main() -> int:
which.add_argument("--all", action="store_true", help="every profile with an arcade source")
parser.add_argument("--emulators-dir", default="emulators",
help="profiles whose BIOS sets are read (default emulators)")
parser.add_argument("--database", default="database.json",
parser.add_argument("--db", default="database.json",
help="collection index, to name BIOS sets the collection lacks")
parser.add_argument("--output-dir", type=Path, default=DEFAULT_OUTPUT,
help=f"where the parent maps are written (default {DEFAULT_OUTPUT})")
@@ -1133,7 +1133,7 @@ def main() -> int:
args = parser.parse_args()
profiles = load_emulator_profiles(args.emulators_dir, skip_aliases=False)
names = collection_names(Path(args.database))
names = collection_names(Path(args.db))
failed = False
for profile in sorted(PROFILES) if args.all else args.profile:
if profile not in profiles:
+8 -2
View File
@@ -14,6 +14,9 @@ games/catalogs/ and never in provenance/.
No-Intro comes from the auto-datfile-generator release asset (Dat-o-Matic
bans automated clients), Redump from redump.info's per-system datfile route.
The mirror is dantob's fork: hugo19941994's original has failed its daily
rebuild since Dat-o-Matic's 2026-07 re-layout (no-intro.zip last rebuilt
2026-07-08), and the fork carries the fix (d4a9d769, 2026-07-31).
Every download is cached under .cache/game-dats/ with what the server said
about it, so a second run reads nothing from the network and writes the same
bytes. A DAT's region tag is a market label, never the value a core computes.
@@ -49,8 +52,11 @@ SOURCES = ("no-intro", "redump")
CACHE_DIR = Path(".cache") / "game-dats"
OUTPUT_DIR = Path("games") / "catalogs"
NOINTRO_MIRROR = "https://github.com/dantob/auto-datfile-generator"
NOINTRO_RELEASE = "Daily_Rebuild"
NOINTRO_RELEASE_API = (
"https://api.github.com/repos/hugo19941994/auto-datfile-generator/releases/tags/Daily_Rebuild"
NOINTRO_MIRROR.replace("https://github.com/", "https://api.github.com/repos/")
+ f"/releases/tags/{NOINTRO_RELEASE}"
)
NOINTRO_ASSET = "no-intro.zip"
REDUMP_DATFILE_URL = "https://redump.info/datfile/{code}"
@@ -120,7 +126,7 @@ LICENCES: dict[str, dict] = {
"website or its operators is required for such use."
),
"mirror": {
"repo": "https://github.com/hugo19941994/auto-datfile-generator",
"repo": NOINTRO_MIRROR,
"licence": "MIT",
"scope": "the mirror's scripts only, the DATs it republishes stay under the terms above",
},
@@ -16,6 +16,7 @@ import sys
import urllib.error
import urllib.request
from datetime import datetime, timezone
from pathlib import Path
import yaml
@@ -32,6 +33,7 @@ STEAMOS_API = (
WINDOWS_API = (
"https://api.github.com/repos/EmuDeck/emudeck-we/contents/functions/EmuScripts"
)
RETROARCH_TARGETS = Path(__file__).resolve().parents[3] / "platforms" / "targets" / "retroarch.yml"
def _fetch(url: str) -> str:
headers = {"User-Agent": "retrobios-scraper/1.0"}
@@ -75,7 +77,7 @@ class Scraper(BaseTargetScraper):
return self._revision
def _fetch_cores_for_target(
self, api_url: str, label: str, arch: str = "x86_64"
self, api_url: str, label: str, retroarch_target: str
) -> list[str]:
print(f" fetching {label} EmuScripts...", file=sys.stderr)
scripts = _list_emuscripts(api_url)
@@ -94,7 +96,7 @@ class Scraper(BaseTargetScraper):
standalone_count = len(cores)
# EmuDeck ships RetroArch = all its libretro cores are available
if has_retroarch:
ra_cores = self._load_retroarch_cores(arch)
ra_cores = self._load_retroarch_cores(retroarch_target)
for c in ra_cores:
if c not in seen:
seen.add(c)
@@ -108,24 +110,21 @@ class Scraper(BaseTargetScraper):
return sorted(cores)
@staticmethod
def _load_retroarch_cores(arch: str) -> list[str]:
"""Load RetroArch target cores for given architecture."""
import os
target_path = os.path.join("platforms", "targets", "retroarch.yml")
with open(target_path) as f:
def _load_retroarch_cores(target: str, path: Path = RETROARCH_TARGETS) -> list[str]:
"""The buildbot's libretro cores for one RetroArch target, by name:
linux-x86_64 and windows-x86_64 share an architecture, not a list."""
with path.open(encoding="utf-8") as f:
data = yaml_load(f) or {}
# Find a target matching the architecture
for tinfo in data.get("targets", {}).values():
if tinfo.get("architecture") == arch and tinfo.get("cores"):
return tinfo["cores"]
raise RuntimeError(f"no {arch} core list in {target_path}")
cores = ((data.get("targets") or {}).get(target) or {}).get("cores")
if not cores:
raise RuntimeError(f"no {target} core list in {path}")
return cores
def fetch_targets(self) -> dict:
steamos_cores = self._fetch_cores_for_target(
f"{STEAMOS_API}?ref={self.revision}", "SteamOS"
f"{STEAMOS_API}?ref={self.revision}", "SteamOS", "linux-x86_64"
)
windows_cores = self._fetch_cores_for_target(WINDOWS_API, "Windows")
windows_cores = self._fetch_cores_for_target(WINDOWS_API, "Windows", "windows-x86_64")
targets: dict[str, dict] = {}
if steamos_cores:
+3
View File
@@ -1009,6 +1009,9 @@ def main() -> int:
"without it the run reports them and exits 0",
)
args = parser.parse_args()
from common import work_from_repo_root # noqa: PLC0415
work_from_repo_root(args, parser, ["db", "platforms_dir", "emulators_dir"])
import contextlib
+41 -38
View File
@@ -41,8 +41,10 @@ from common import (
_foreign_tree,
_owner_tokens,
platform_arg,
work_from_repo_root,
target_listing_line,
suggest_names,
system_index,
require_platform,
archive_entry,
archive_is_optional,
@@ -129,29 +131,6 @@ DEFAULT_EMULATORS_DIR = "emulators"
REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
def work_from_repo_root(
args: argparse.Namespace, parser: argparse.ArgumentParser, path_flags: list[str]
) -> None:
"""Run from the repository root, whichever directory the command started in.
database.json records every file from the root and the data registry
names its caches the same way, so a run from scripts/ ended on a
FileNotFoundError traceback. A path the caller typed is read from where
they typed it, a default from the root.
"""
if os.path.realpath(os.getcwd()) == os.path.realpath(REPO_ROOT):
return
for flag in path_flags:
value = getattr(args, flag, None)
if value and value != parser.get_default(flag):
setattr(args, flag, os.path.abspath(value))
os.chdir(REPO_ROOT)
if getattr(args, "platform", None):
# Read before the move, the registry was not there to map
# "RetroArch" to its slug.
args.platform = platform_arg(args.platform)
# Status model: aligned with Batocera BiosStatus (batocera-systems:967-969)
@@ -1808,7 +1787,8 @@ def _print_undeclared_entry(
ref_part = f" [{u['source_ref']}]" if u.get("source_ref") else ""
print(f" validates {checks_label}{ref_part}")
else:
print(f" [{'+'.join(checks)}]")
# A bare "[size]" under the entry said nothing to a reader.
print(f" validates {'+'.join(checks)}")
def _split_undeclared(undeclared: list[dict]) -> tuple[list[dict], list[dict], list[dict]]:
@@ -1920,10 +1900,15 @@ def _print_undeclared_section(result: dict, verbose: bool) -> None:
u for u in bundled
if u["required"] and u.get("category", "bios") != "game_data"
]
names = ", ".join(sorted({u["name"] for u in shown}))
named = sorted({u["name"] for u in shown})
# The required firmware alone read as the whole count: 14 names
# for 154 entries, nothing saying the rest existed.
hidden = len({u["name"] for u in bundled}) - len(named)
more = f"{hidden} more, " if named else ""
items = named + ([f"{more}--verbose lists them"] if hidden else [])
print(
f" Bundled with their emulator, not collected: {len(bundled)}"
+ (f" ({names})" if names else "")
+ (f" ({', '.join(items)})" if items else "")
)
if unplaced:
print(f" Core files held but not packed: {len(unplaced)} "
@@ -2611,7 +2596,10 @@ def verify_system(
f"No emulators found for system(s): {', '.join(system_ids)}",
file=sys.stderr,
)
print(suggest_names(system_ids, sorted(all_systems), "--list-systems"),
# --list-systems merges spellings that differ in case or separator:
# the hint counted 579 spellings for the 532 lines it prints.
print(suggest_names(system_ids, sorted(all_systems), "--list-systems",
listed=len(system_index(profiles))),
file=sys.stderr)
sys.exit(1)
@@ -2821,7 +2809,7 @@ def _main(held: contextlib.ExitStack) -> None:
parser = argparse.ArgumentParser(allow_abbrev=False, description="Platform-native BIOS verification")
parser.add_argument("--platform", "-p", type=platform_arg, help="Platform name")
parser.add_argument(
"--all", action="store_true", help="Verify all active platforms"
"--all", action="store_true", help="Verify every registered platform"
)
parser.add_argument(
"--emulator", "-e", help="Emulator profile name(s), comma-separated"
@@ -3121,6 +3109,13 @@ def _overall_summary(group_results: list[tuple[dict, list[str]]]) -> str:
named = [f"{name} {count}" for name, count in counts.items() if count]
return f" ({', '.join(named)})" if named else ""
def on(groups: tuple[str, ...]) -> str:
"""The platforms a file is missing on, by the shorter side."""
if len(group_results) < 2 or len(groups) * 2 <= len(group_results):
return ", ".join(groups)
others = [" / ".join(g) for _, g in group_results if " / ".join(g) not in groups]
return "every platform" + (f" but {', '.join(others)}" if others else "")
parts = []
for severity, label in ((Severity.CRITICAL, "critical"), (Severity.WARNING, "warning"),
(Severity.INFO, "info")):
@@ -3139,18 +3134,26 @@ def _overall_summary(group_results: list[tuple[dict, list[str]]]) -> str:
parts.append(f"{total} {'discrepancy' if total == 1 else 'discrepancies'}{where(counts)}")
lines = [f"{platforms} platforms: {', '.join(parts)}"]
missing = {
" / ".join(group): sorted({
# Grouped by file, not by platform: sfiii2a.zip missing everywhere was
# counted and printed once per platform, 24 files for 10 distinct ones.
holders: dict[str, list[str]] = {}
for r, group in group_results:
for name in sorted({
u["name"] for u in _core_required_missing(_split_undeclared(
r.get("undeclared_files", []))[1])
})
for r, group in group_results
}
total = sum(len(names) for names in missing.values())
if total:
detail = "; ".join(f"{group}: {', '.join(names)}"
for group, names in missing.items() if names)
lines.append(f"{total} core file(s) a core cannot run without are missing ({detail})")
}):
holders.setdefault(name, []).append(" / ".join(group))
if holders:
by_platforms: dict[tuple[str, ...], list[str]] = {}
for name, groups in sorted(holders.items()):
by_platforms.setdefault(tuple(groups), []).append(name)
detail = "; ".join(
f"{', '.join(names)} ({on(groups)})"
for groups, names in sorted(by_platforms.items(),
key=lambda item: (-len(item[0]), item[1]))
)
lines.append(f"{len(holders)} core file(s) a core cannot run without are "
f"missing: {detail}")
for category, label in _NOT_FIRMWARE.items():
counts = {
" / ".join(group): len((r.get("missing_not_firmware") or {}).get(category, []))
+78
View File
@@ -0,0 +1,78 @@
"""A disposable copy of the checkout, for tests that run a writer and expect
it to refuse.
Run in the checkout, a regression made the very write the test guards
against: generate_site rewrote website/src/data/published-parts.json and the
FAQ page whatever --docs-dir said, and a pipeline whose lock probe failed
would regenerate database.json and install/. A file another session had
already changed listed the same name in `git diff --name-only` before and
after, so its edits were lost without a signal.
The copy holds every file git tracks or would track, as the working tree has
it. bios/ and data/ (17 GB and 600 MB of inputs no such test writes) are
links to the checkout's.
"""
from __future__ import annotations
import atexit
import hashlib
import os
import shutil
import subprocess
import tempfile
from functools import cache
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parent.parent
LINKED = ("bios", "data")
@cache
def scratch_checkout() -> Path:
"""The copy, built once per test process and removed at its exit."""
root = Path(tempfile.mkdtemp(prefix="checkout-", dir=REPO_ROOT / "tmp" / "tests"))
# A detached worktree with nothing checked out: the scripts that read
# HEAD (the site's bootstrap pin) find this commit.
subprocess.run(
["git", "worktree", "add", "--quiet", "--detach", "--no-checkout", str(root), "HEAD"],
cwd=REPO_ROOT, capture_output=True, check=True,
)
atexit.register(_remove, root)
listed = subprocess.run(
["git", "ls-files", "-z", "--cached", "--others", "--exclude-standard"],
cwd=REPO_ROOT, capture_output=True, check=True,
).stdout.decode("utf-8")
for name in filter(None, listed.split("\0")):
source = REPO_ROOT / name
if name.split("/", 1)[0] in LINKED or not source.is_file() or source.is_symlink():
continue
target = root / name
target.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(source, target)
for name in LINKED:
if (REPO_ROOT / name).exists():
(root / name).symlink_to(REPO_ROOT / name, target_is_directory=True)
return root
def _remove(root: Path) -> None:
subprocess.run(["git", "worktree", "remove", "--force", str(root)],
cwd=REPO_ROOT, capture_output=True, check=False)
shutil.rmtree(root, ignore_errors=True)
def snapshot(root: Path) -> dict[str, str]:
"""The SHA-1 of every file under root, links not followed. A file
written with the bytes it held is no change: what is caught is a file
whose content a run replaced. Scratch space, caches, bytecode and lock
files are no output."""
seen = {}
for directory, dirs, files in os.walk(root):
dirs[:] = [d for d in dirs if d != "__pycache__"
and Path(directory, d) not in (root / "tmp", root / ".cache")]
for name in files:
path = Path(directory) / name
if name != ".lock" and not path.is_symlink():
seen[str(path.relative_to(root))] = hashlib.sha1(path.read_bytes()).hexdigest()
return seen
+2
View File
@@ -9,6 +9,8 @@ corrected it later, every other reader of the resolution did not.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import hashlib
import json
import shutil
+2
View File
@@ -12,6 +12,8 @@ BIOS root of platforms that do not run that emulator.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import hashlib
import sys
import tempfile
+2
View File
@@ -8,6 +8,8 @@ libretro core, while verify set the entry aside. Reads the repository.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import os
import sys
import unittest
+2
View File
@@ -9,6 +9,8 @@ was not where it looks.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import hashlib
import os
import sys
+2
View File
@@ -7,6 +7,8 @@ the slot missing and the manifest omitted it.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import re
import sys
import tempfile
+2
View File
@@ -8,6 +8,8 @@ the firmware of cores its image never had.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import sys
import unittest
from pathlib import Path
+2
View File
@@ -2,6 +2,8 @@
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import io
import json
import tempfile
+2
View File
@@ -7,6 +7,8 @@ seven of the eight members Batocera checks were missing.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import hashlib
import os
import shutil
+2
View File
@@ -9,6 +9,8 @@ those members were never read there, and the archive matched no recipe.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import hashlib
import sys
import unittest
+13 -6
View File
@@ -7,6 +7,8 @@ ZIPs, which surfaces as BadZipFile far from its cause.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import os
import subprocess
import sys
@@ -25,6 +27,7 @@ from common import ( # noqa: E402
hold_repository_outputs,
publish_hold,
)
from tests.scratchtree import scratch_checkout # noqa: E402
def _tempdir(test: unittest.TestCase) -> str:
@@ -115,11 +118,13 @@ class PackLockCliTest(unittest.TestCase):
self.dir = _tempdir(self)
def _run(self, argv: list[str]) -> subprocess.CompletedProcess:
# In a copy: a pipeline that missed the lock regenerated
# database.json and install/ wherever it ran.
return subprocess.run(
[sys.executable, *argv],
capture_output=True,
text=True,
cwd=str(REPO_ROOT),
cwd=str(scratch_checkout()),
timeout=300,
)
@@ -234,11 +239,12 @@ class PipelineHoldsItsFixedOutputs(unittest.TestCase):
def test_a_second_pipeline_is_refused_whatever_its_output_dir(self):
scratch = _tempdir(self)
with hold_repository_outputs(str(REPO_ROOT)):
checkout = scratch_checkout()
with hold_repository_outputs(str(checkout)):
proc = subprocess.run(
[sys.executable, "scripts/pipeline.py", "--offline", "--skip-docs",
"--output-dir", scratch],
capture_output=True, text=True, cwd=str(REPO_ROOT), timeout=120,
capture_output=True, text=True, cwd=str(checkout), timeout=120,
)
self.assertEqual(proc.returncode, 1, proc.stdout + proc.stderr)
self.assertIn("another run is writing database.json", proc.stderr)
@@ -260,11 +266,12 @@ class StandaloneWritersHonourTheRepositoryHold(unittest.TestCase):
env = {k: v for k, v in os.environ.items() if k != "RETROBIOS_HELD_ARTIFACT_DIR"}
return subprocess.run(
[sys.executable, *argv], capture_output=True, text=True,
cwd=str(REPO_ROOT), timeout=300, env=env, check=False,
cwd=str(scratch_checkout()), timeout=300, env=env, check=False,
)
def test_a_writer_of_a_fixed_output_is_refused(self):
with hold_repository_outputs(str(REPO_ROOT)):
# The writers run in a copy, where a missed lock writes nothing of ours.
with hold_repository_outputs(str(scratch_checkout())):
for argv in (
["scripts/generate_db.py", "--bios-dir", "bios", "--output", "database.json"],
["scripts/generate_pack.py", "--all", "--manifest", "--offline",
@@ -369,7 +376,7 @@ class SiteGenerationHoldsDocs(unittest.TestCase):
with artifact_lock(docs):
result = subprocess.run(
[sys.executable, "scripts/generate_site.py", "--docs-dir", docs],
cwd=REPO_ROOT, capture_output=True, text=True, timeout=600,
cwd=scratch_checkout(), capture_output=True, text=True, timeout=600,
)
self.assertEqual(result.returncode, 1, result.stdout + result.stderr)
self.assertIn("in use by another run", result.stderr)
+2
View File
@@ -8,6 +8,8 @@ path in bios/: a scan running beside the copy hashed the truncated file.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import os
import sys
import tempfile
+161 -1
View File
@@ -2,6 +2,8 @@
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import ast
import contextlib
import hashlib
@@ -136,6 +138,41 @@ class ReadmeRegressions(unittest.TestCase):
self.assertNotIn("SyntaxError", proc.stderr)
self.assertIn("generate_pack.py needs Python 3.9", proc.stderr)
def test_every_script_names_the_floor_under_an_older_interpreter(self):
"""Only generate_pack.py and pipeline.py checked the version. verify.py,
slots.py, validate_pr.py and cross_reference.py started under 3.8 and
stopped halfway on a str.removeprefix AttributeError."""
import shutil # noqa: PLC0415
python38 = shutil.which("python3.8")
if python38 is None:
if os.environ.get("CI"):
self.fail("CI must provide python3.8")
self.skipTest("no python3.8 on PATH")
commands = (
["verify.py", "--emulator", "handy"],
["verify.py", "--platform", "batocera"],
["validate_pr.py", "--json", "README.md"],
["cross_reference.py", "--emulator", "handy"],
["slots.py"],
["identity.py"],
["generate_site.py", "--help"],
["campaign.py", "--help"],
["region_check.py", "--help"],
)
for command in commands:
with self.subTest(command=" ".join(command)):
# -E -s rather than -I: -I drops the script's folder from
# sys.path, so the imports would fail before any check.
proc = subprocess.run(
[python38, "-E", "-s", f"scripts/{command[0]}", *command[1:]],
cwd=ROOT, capture_output=True, text=True, timeout=60,
check=False,
)
self.assertEqual(proc.returncode, 1, proc.stderr)
self.assertNotIn("Traceback", proc.stderr)
self.assertIn(f"{command[0]} needs Python 3.9", proc.stderr)
def test_the_floor_interpreter_imports_every_script(self):
"""Every module under scripts/ is loaded by a real interpreter of the
floor version, as the installer's 3.8 floor is proven by running it.
@@ -218,6 +255,46 @@ class AModuleRunAloneHasItsScratchDirectory(unittest.TestCase):
self.assertEqual(proc.stdout.split(), [scratch, scratch])
class EveryTestModuleImportsTheIsolation(unittest.TestCase):
"""tests/__init__.py keeps a run offline, its scratch under tmp/ and its
installer cache its own, but only `discover -s tests -t .` imported it:
`discover tests` ran with RETROBIOS_OFFLINE unset, scratch in /tmp and
the user's real cache. Each module now imports the package first."""
def test_the_package_import_comes_before_any_other(self):
missing = []
for path in sorted((ROOT / "tests").glob("test_*.py")):
body = ast.parse(path.read_text(encoding="utf-8")).body
imports = [
node for node in body
if isinstance(node, (ast.Import, ast.ImportFrom))
and getattr(node, "module", None) != "__future__"
]
first = imports[0] if imports else None
if not (isinstance(first, ast.Import)
and [alias.name for alias in first.names] == ["tests"]):
missing.append(path.name)
self.assertEqual(missing, [])
def test_discover_without_a_top_level_runs_isolated(self):
env = {k: v for k, v in os.environ.items()
if k not in ("RETROBIOS_OFFLINE", "TMPDIR", "RETROBIOS_CACHE")}
proc = subprocess.run(
[sys.executable, "-c",
"import os, sys, tempfile, unittest\n"
"unittest.TestLoader().discover('tests', pattern='test_artifact_lock.py')\n"
"print(os.environ.get('RETROBIOS_OFFLINE'), tempfile.gettempdir(),"
" os.environ.get('RETROBIOS_CACHE'))\n"],
cwd=ROOT, env=env, capture_output=True, text=True, timeout=120,
check=False,
)
self.assertEqual(proc.returncode, 0, proc.stderr)
offline, scratch, cache = proc.stdout.split()
self.assertEqual(offline, "1")
self.assertEqual(scratch, str(ROOT / "tmp" / "tests"))
self.assertEqual(cache, str(ROOT / "tmp" / "tests" / "cache"))
class ReleaseSigningRegressions(unittest.TestCase):
"""A checksum list published beside its own artifacts proves nothing.
@@ -2834,6 +2911,50 @@ class DeclaredDependenciesMatchTheDocumentedWorkflows(unittest.TestCase):
)
class TheAnnotationsAreChecked(unittest.TestCase):
"""Every signature carried type hints and nothing read them: six pack
helpers declared `zipfile.ZipFile` while every caller also passed a
PackRecord, and 990 such contradictions went through CI green. mypy now
runs in CI against mypy-baseline.txt, the errors the code carried when the
check started."""
BASELINE = ROOT / "mypy-baseline.txt"
ENTRY = re.compile(r"(?P<path>[^:]+\.py):0: error: .+ \[[a-z-]+\]")
def test_ci_holds_the_code_to_the_baseline(self):
body = (ROOT / ".github" / "workflows" / "validate.yml").read_text(
encoding="utf-8"
)
self.assertIn("mypy-baseline filter", body)
self.assertNotIn("--allow-unsynced", body)
def test_every_baseline_entry_names_a_file_that_exists(self):
stale = []
for line in self.BASELINE.read_text(encoding="utf-8").splitlines():
match = self.ENTRY.fullmatch(line)
self.assertIsNotNone(match, f"unreadable baseline entry: {line}")
if not (ROOT / match["path"]).is_file():
stale.append(match["path"])
self.assertEqual(stale, [], "baseline entries for files that are gone")
def test_the_code_reports_no_error_outside_the_baseline(self):
for module in ("mypy", "mypy_baseline"):
try:
__import__(module)
except ImportError:
self.skipTest(f"{module} is not installed (pip install -e '.[dev]')")
report = subprocess.run(
[sys.executable, "-m", "mypy"],
cwd=ROOT, capture_output=True, text=True, check=False,
)
result = subprocess.run(
[sys.executable, "-m", "mypy_baseline", "filter", "--no-colors"],
cwd=ROOT, input=report.stdout, capture_output=True, text=True,
check=False,
)
self.assertEqual(result.returncode, 0, result.stdout)
class TheProjectInstallsWithPip(unittest.TestCase):
"""pyproject declared a dev extra that pip could not install: without a
[build-system] and an explicit module list, setuptools' flat-layout
@@ -4991,9 +5112,34 @@ class VerifyAllSummaryNamesWhatIsWrong(unittest.TestCase):
[(clean, ["RetroArch"]), (warned, ["RetroDECK"]), (core_miss, ["ROCKNIX"])]
)
self.assertIn("1 warning (RetroDECK 1)", summary)
self.assertIn("ROCKNIX: n64.psh", summary)
self.assertIn("n64.psh (ROCKNIX)", summary)
self.assertIn("0 critical,", summary)
def test_a_file_missing_on_several_platforms_is_counted_once(self):
"""sfiii2a.zip missing on 15 platforms read '24 core file(s)' for 10
distinct files, the name printed 15 times on one line."""
sys.path.insert(0, str(ROOT / "scripts"))
import verify
def missing(*names: str) -> dict:
return {"severity_counts": {}, "undeclared_files": [
{"name": name, "required": True, "in_repo": False,
"category": "bios", "in_pack": True} for name in names
]}
summary = verify._overall_summary([
(missing("sfiii2a.zip"), ["Batocera"]),
(missing("sfiii2a.zip", "ROM"), ["RetroPie"]),
(missing("sfiii2a.zip"), ["RomM"]),
(missing(), ["MinUI"]),
])
self.assertIn(
"2 core file(s) a core cannot run without are missing: "
"sfiii2a.zip (every platform but MinUI); ROM (RetroPie)",
summary,
)
self.assertEqual(summary.count("sfiii2a.zip"), 1)
class OneOutputFormPerRun(unittest.TestCase):
@@ -5956,6 +6102,20 @@ class TheRepairCommandWritesTheFileNamed(unittest.TestCase):
load_database(target)
self.assertIn(f"--output {target}", str(caught.exception))
def test_a_typo_beside_the_database_names_the_database(self):
"""--db databse.json beside database.json was told to rescan the whole
collection into a second file named after the typo."""
from scripts.common import DatabaseUnreadable, load_database
with tempfile.TemporaryDirectory(dir=TMP_ROOT) as directory:
(Path(directory) / "database.json").write_text("{}")
typo = Path(directory) / "databse.json"
with self.assertRaises(DatabaseUnreadable) as caught:
load_database(str(typo))
message = str(caught.exception)
self.assertIn(f"Did you mean {typo.with_name('database.json')}?", message)
self.assertNotIn("generate_db.py", message)
class VerifyPacksRefusesWhatItCannotDo(unittest.TestCase):
"""The --verify-packs refusals lived in the --all-variants checks, which
+2
View File
@@ -7,6 +7,8 @@ a function returning canned CI runs.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import contextlib
import io
import json
+2
View File
@@ -9,6 +9,8 @@ under it: amiberry, fsuae and vice were never in a target list.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import sys
import unittest
from pathlib import Path
+2
View File
@@ -9,6 +9,8 @@ a list, and verify accepts any listed md5.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import hashlib
import sys
import tempfile
+2
View File
@@ -9,6 +9,8 @@ the Batocera BIOS folder.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import sys
import unittest
from pathlib import Path
+2
View File
@@ -7,6 +7,8 @@ Oric and Tangerine: one machine, two folders, two pages.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import subprocess
import unittest
from pathlib import Path
+2
View File
@@ -13,6 +13,8 @@ entry is written with the hash of the file the emulator ships.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import hashlib
import sys
import unittest
+2
View File
@@ -10,6 +10,8 @@ directory cache is not a collection.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import os
import sys
import unittest
+2
View File
@@ -10,6 +10,8 @@ resume and rerun on a changed core.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import contextlib
import hashlib
import io
+2
View File
@@ -7,6 +7,8 @@ went red. The flag lived in retrobat.yml and vanished at the next scrape.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import contextlib
import hashlib
import io
+2
View File
@@ -2,6 +2,8 @@
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import sys
import unittest
from pathlib import Path
+39 -4
View File
@@ -8,6 +8,8 @@ report is folded, since each of those decides whether a row says STALE.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import json
import os
import sys
@@ -316,8 +318,23 @@ class CoreResolutionTests(unittest.TestCase):
record.write_text(cf.json.dumps({"blobs": {"a": "1", "b": "1"}}))
cf.record_core_info({"a": "2", "b": "2"}, ["a"], record)
self.assertEqual(cf.load_core_info_record(record), {"a": "2", "b": "1"})
with self.assertRaises(ValueError):
cf.record_core_info({"a": "2"}, ["ghost"], record)
with self.assertRaises(cf.InputMissing) as raised:
cf.record_core_info({"a": "2", "ghosts": "1"}, ["ghost"], record)
self.assertIn("Did you mean: ghosts?", str(raised.exception))
def test_record_errors_are_one_line(self):
"""A mistyped core and an empty offline cache ended on a traceback."""
import subprocess # noqa: PLC0415
with tempfile.TemporaryDirectory() as tmp:
proc = subprocess.run(
[sys.executable, str(REPO_ROOT / "scripts" / "check_freshness.py"), "--offline",
"--cache-dir", tmp, "--record-coreinfo"],
capture_output=True, text=True, check=False, timeout=120,
)
self.assertEqual(proc.returncode, 1)
self.assertNotIn("Traceback", proc.stderr)
self.assertIn("run without --offline", proc.stderr)
def test_offline_without_a_cached_listing_is_skipped(self):
"""Offline, the row read UNKNOWN and failed the run as an upstream
@@ -460,10 +477,28 @@ class CatalogParsingTests(unittest.TestCase):
row = cf._check_redump_games(False)
self.assertEqual((row.status, row.items), (cf.STALE, ["sony-playstation"]))
self.assertEqual(cf._check_redump_games(True).status, cf.SKIPPED)
with mock.patch.object(cf, "_game_catalogs", return_value=[{"fetched": "2026-11-03"}]):
for rebuilt, status in (("2026-07-08", cf.OK), ("2026-11-04", cf.STALE)):
with mock.patch.object(cf, "_game_catalogs", return_value=[{"fetched": "2026-11-03"}]), \
mock.patch.object(cf, "_today", return_value="2026-11-06"):
for rebuilt, status in (("2026-11-02", cf.OK), ("2026-11-04", cf.STALE)):
with mock.patch.object(cf, "_no_intro_asset_date", return_value=rebuilt):
self.assertEqual(cf._check_nointro_games("", False).status, status)
def test_a_mirror_that_stopped_rebuilding_is_stale(self):
"""The mirror failed every daily rebuild from 2026-07-08, and both
No-Intro rows read OK: an import newer than a dead pack is no
sign of a fresh catalog."""
with mock.patch.object(cf, "_today", return_value="2026-11-06"), \
mock.patch.object(cf, "_no_intro_asset_date", return_value="2026-07-08"), \
mock.patch.object(cf, "_game_catalogs", return_value=[{"fetched": "2026-11-03"}]), \
mock.patch.object(cf, "_snapshot", return_value={"imported_at": "2026-08-08"}):
for row in (cf._check_nointro_games("", False), cf._check_no_intro("", False)):
self.assertEqual(row.status, cf.STALE)
self.assertIn("2026-07-08, 121 days ago", row.detail)
def test_the_freshness_check_reads_the_importer_mirror(self):
self.assertEqual(cf.NO_INTRO_MIRROR, cf.game_dat_importer.NOINTRO_MIRROR)
self.assertIn(cf.NO_INTRO_MIRROR.removeprefix("https://github.com/"),
cf.game_dat_importer.NOINTRO_RELEASE_API)
self.assertIn("no-intro games",
[f.subject for f in cf.check_catalogs("", True)])
+2
View File
@@ -7,6 +7,8 @@ whose checksums every user's `sha256sum --check` rejected.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import sys
import unittest
from pathlib import Path
+2
View File
@@ -6,6 +6,8 @@ one. validate_schemas now refuses it.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import subprocess
import sys
import unittest
+2
View File
@@ -7,6 +7,8 @@ does not hold the file.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import re
import sys
import unittest
+2
View File
@@ -6,6 +6,8 @@ the repository, five on the site, under two different titles.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import re
import sys
import unittest
+2
View File
@@ -10,6 +10,8 @@ reader now gets the tree, or the profile says its package installs it.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import os
import sys
import unittest
@@ -8,6 +8,8 @@ frontend sees a file at the path. verify kept it MISSING, so the pack said
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import hashlib
import contextlib
import io
+2
View File
@@ -7,6 +7,8 @@ probe on it: staging, the worker process, strace, the record and its schema.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import argparse
import contextlib
import hashlib
+2
View File
@@ -10,6 +10,8 @@ read one rule (validation.core_size_refusal).
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import hashlib
import os
import sys
+2
View File
@@ -9,6 +9,8 @@ tests change an input and expect a fresh computation.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import sys
import tempfile
import unittest
+2
View File
@@ -9,6 +9,8 @@ a directory called ROM).
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import sys
import tempfile
import unittest
+2
View File
@@ -7,6 +7,8 @@ contributor with none of them.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import ast
import sys
import unittest
+2
View File
@@ -18,6 +18,8 @@ Layouts, from Azahar src/core/hw/unique_data.cpp and src/core/file_sys/otp.cpp:
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import hashlib
import struct
import sys
+2
View File
@@ -14,6 +14,8 @@ constants rather than against itself. The AES vector is from NIST SP 800-38A.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import hashlib
import shutil
import sys
+2
View File
@@ -6,6 +6,8 @@ verify only said "not cached" and refresh_data_dirs had nothing to fetch.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import sys
import unittest
from pathlib import Path
+2
View File
@@ -7,6 +7,8 @@ TypeError on the first loop.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import ast
import unittest
from pathlib import Path
+2
View File
@@ -8,6 +8,8 @@ disk ROM then served the CoCo one.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import os
import sys
import tempfile
+2
View File
@@ -8,6 +8,8 @@ set, enriched with every spelling the database knows.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import sys
import unittest
from pathlib import Path
+2
View File
@@ -9,6 +9,8 @@ are both load-bearing.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import contextlib
import io
import os
+2
View File
@@ -7,6 +7,8 @@ is two held ROMs end to end. The gap report listed them as acquisition targets.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import hashlib
import os
import shutil
+2
View File
@@ -2,6 +2,8 @@
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import hashlib
import os
import tempfile
+2
View File
@@ -9,6 +9,8 @@ reported missing while 3 584 collected files stayed out of every pack.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import hashlib
import json
import sys
+2
View File
@@ -7,6 +7,8 @@ code moves, and nothing else notices.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import ast
import hashlib
import inspect
+2
View File
@@ -9,6 +9,8 @@ tool prints, and a size is the one the release record holds.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import ast
import contextlib
import re
+2
View File
@@ -9,6 +9,8 @@ checksum of each layout and the staging location.
"""
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import contextlib
import functools
import hashlib
+2
View File
@@ -17,6 +17,8 @@ Covers:
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import contextlib
import hashlib
import io
+2
View File
@@ -9,6 +9,8 @@ upstream files.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import sys
import unittest
from pathlib import Path
+2
View File
@@ -9,6 +9,8 @@ firmware of cores its image never had.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import json
import sys
import unittest
+2
View File
@@ -9,6 +9,8 @@ names and ten "missing".
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import re
import subprocess
import sys
+2
View File
@@ -6,6 +6,8 @@ from what the cores the platform runs open, never from the entry's name.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import sys
import unittest
from pathlib import Path
+2
View File
@@ -9,6 +9,8 @@ from a file other than the one the hash describes.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import json
import sys
import unittest
+2
View File
@@ -9,6 +9,8 @@ libretro's System.dat (N88EXT0-3.ROM) as if libretro declared them.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import sys
import tempfile
import unittest
+2
View File
@@ -7,6 +7,8 @@ file from and no list to check the diff against.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import re
import sys
import tempfile
+74 -2
View File
@@ -14,6 +14,8 @@ and skip when it has not been populated (python scripts/export_native.py
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import difflib
import io
import json
@@ -801,14 +803,20 @@ class SearchOrder(unittest.TestCase):
longest = ('rp_module_id="xm7"\nrp_module_help="Copy bios files '
+ ", ".join(f"n{i}.rom" for i in range(12)) + ' and n12.rom to $biosdir"\n')
exporter = discover_exporters()["retropie"]()
produced = exporter.render(
written = exporter.render(
systems, None,
{"scriptmodules/libretrocores/lr-flycast.sh": script,
"scriptmodules/emulators/xm7.sh": longest},
)["scriptmodules/libretrocores/lr-flycast.sh"]
)
produced = written["scriptmodules/libretrocores/lr-flycast.sh"]
self.assertIn("Dreamcast BIOS file dc_boot.bin to", produced)
self.assertIn("BIOS files naomi.zip, awbios.zip and naomi2.zip to", produced)
self.assertNotIn("other.zip", produced)
# Rewritten for naomi2.zip, other.zip left out: the summary said
# "Left as is" of a package in the diff.
outcome = exporter.outcome(systems, written)
self.assertIn("Updated in part: lr-flycast,", outcome)
self.assertNotIn("Left as is: lr-flycast", outcome)
def test_cores_that_disagree_keep_the_best_rank(self):
"""Nothing is dropped on the rank here, so the best one wins.
@@ -827,6 +835,70 @@ class SearchOrder(unittest.TestCase):
self.assertEqual(entry.priority, 2)
class TwoAdditionsAtOnePath(unittest.TestCase):
"""Two cores declaring two dumps of one file the platform lacks: both
were counted added while the render wrote one. Recalbox's md5 list takes
both, a System.dat name and a RetroDECK path hold one."""
A, B = "615a" + "0" * 28, "ef49" + "0" * 28
def _addition(self, md5: str, core: str, system: str = "dos") -> NativeFile:
return NativeFile(
name="MT32_CONTROL.ROM", destination="mt32/MT32_CONTROL.ROM", native_system=system,
truth={"name": "MT32_CONTROL.ROM", "path": "mt32/MT32_CONTROL.ROM", "md5": md5,
"crc32": md5[:8], "required": True, "_cores": [core]},
runners=[(False, core)],
)
def _added(self, exporter, systems) -> list[str]:
return [c["name"] for c in landed_changes(exporter, systems).records
if c["kind"] == "added"]
def test_recalbox_writes_both_md5_in_one_element(self):
systems = {"dos": NativeSystem("dos", files=[
self._addition(self.A, "dosbox_pure"), self._addition(self.B, "dosbox_core")])}
exporter = discover_exporters()["recalbox"]()
produced = exporter.render(systems, Report(), {})["es_bios.xml"]
elements = [e for e in ET.fromstring(produced).iter("bios")]
self.assertEqual(len(elements), 1)
self.assertEqual(elements[0].get("md5").split(","), [self.A, self.B])
self.assertEqual(elements[0].get("core"), "libretro/dosbox_pure,libretro/dosbox_core")
self.assertEqual(exporter.validate(systems, {"es_bios.xml": produced}), [])
self.assertEqual(len(self._added(exporter, systems)), 2)
def test_system_dat_counts_the_line_it_wrote(self):
systems = {"DOS": NativeSystem("DOS", files=[
self._addition(self.A, "dosbox_pure", "DOS"),
self._addition(self.B, "dosbox_core", "DOS")])}
exporter = discover_exporters()["retroarch"]()
original = 'clrmamepro (\n\tname "System"\n)\n\ngame (\n\tname "System"\n' \
'\tcomment "System"\n\n\tcomment "DOS"\n\trom ( name a.bin size 1 crc 00000000 )\n)\n'
produced = exporter.render(systems, Report(), {"System.dat": original})["System.dat"]
self.assertEqual(produced.count("MT32_CONTROL.ROM"), 1)
self.assertEqual(len(self._added(exporter, systems)), 1)
def test_retrodeck_counts_the_entry_it_appended(self):
theirs = NativeFile(
name="scph1001.bin", destination="scph1001.bin", native_system="psx",
platform={"name": "scph1001.bin", "md5": "1" * 32, "component": "duckstation"})
def addition(md5: str) -> NativeFile:
return NativeFile(
name="scph5501.bin", destination="scph5501.bin", native_system="psx",
truth={"name": "scph5501.bin", "md5": md5, "required": True,
"_cores": ["duckstation"]},
runners=[(True, "duckstation")])
systems = {"psx": NativeSystem("psx", files=[theirs, addition(self.A), addition(self.B)])}
manifest = json.dumps({"duckstation": {"name": "DuckStation", "bios": [
{"filename": "scph1001.bin", "md5": "1" * 32, "system": "psx"}]}})
exporter = discover_exporters()["retrodeck"]()
produced = exporter.render(systems, Report(), {"duckstation/component_manifest.json": manifest})
bios = json.loads(produced["duckstation/component_manifest.json"])["duckstation"]["bios"]
self.assertEqual([e["filename"] for e in bios], ["scph1001.bin", "scph5501.bin"])
self.assertEqual(self._added(exporter, systems), ["scph5501.bin"])
class AdditionOrder(unittest.TestCase):
"""What we add is listed the way the code looks for it."""
+2
View File
@@ -8,6 +8,8 @@ Galaksija ROM and a PS2 ROM2.BIN.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import sys
import unittest
from pathlib import Path
+2
View File
@@ -9,6 +9,8 @@ have vanished with it.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import sys
import unittest
from pathlib import Path
+2
View File
@@ -2,6 +2,8 @@
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import tempfile
import unittest
from pathlib import Path
+2
View File
@@ -8,6 +8,8 @@ homonym tests/test_game_data_homonyms.py forbids the resolver to serve.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import hashlib
import sys
import tempfile
+2
View File
@@ -8,6 +8,8 @@ directory, and only a manual reading found it.
"""
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import sys
import tempfile
import unittest
+2
View File
@@ -7,6 +7,8 @@ attached to misterfpga by substring and checked against the full list:
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import os
import sys
import tempfile
+2
View File
@@ -6,6 +6,8 @@ today's upstream no longer carries, but the bytes are in the project's history.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import hashlib
import sys
import unittest
+2
View File
@@ -9,6 +9,8 @@ and put every file one directory too deep.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import unittest
from pathlib import Path
+2
View File
@@ -9,6 +9,8 @@ to upstream PCSX2.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import hashlib
import os
import sys
+2
View File
@@ -9,6 +9,8 @@ served while data/bluemsx held the 8 KB one.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import hashlib
import os
import shutil
+2
View File
@@ -8,6 +8,8 @@ the pack and the manifest while verify, comparing md5, called it OK.
from __future__ import annotations
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
import hashlib
import os
import sys
Loaded 100 of 286 files, more files were not shown because too many files have changed in this diff. Show more