Step 2a advanced mame.yml's core_version and upstream_commit to a new
release and left the device ROM sets on the previous one. A plain run
that moves the pin now fetches that release's listxml into .cache/dats
and runs the device merge, which checks version and commit itself.
The acquisition report never read a profile, so XM7's required DICROM.ROM
sat among 2 287 targets at the rank of dumps no core reads. A missing
entry that a profile reads and the collection lacks is now listed first
with the profile, matched by hash or, for a hashless entry with a size,
by name and size. 29 entries on the current snapshots.
A crc32 and a size can be met by crafted bytes, so a remote download
matched on them could land in bios/. verify_content now requires every
sha256, sha1 and md5 the entry declares to match, and an entry declaring
none is reported as not verifiable from the network and nothing is
written. crc32 and size still find a file the database already holds.
verify_content read sha1 then md5 only, so an entry pinned by sha256 or
crc32 could be searched and never accepted, and one without any hash was
announced as searched. The strongest declared hash now decides, crc32
counts with its size, the database lookup reads sha256 and crc32, and an
entry with nothing to prove a download by is reported, not searched.
check_freshness exited 0 when no upstream answered. An unknown row now
holds the exit code, and a profile skipped by nature is reported skipped
so it does not hold it forever. --only names the valid areas, a stale
native row names its platform, and the summary names refresh_stale.py.
The summary in exports/<platform>.json read '82 hashes corrected' and '854 additions left out'. It now counts what the written file carries, in the exports page's terms (hashes updated to the emulator source, required flags aligned with the code). Files the format cannot carry, withheld updates and content-found labels are printed on a line of their own and stay in the report's counts.
refresh_stale ran a parent's rescrape and its children's truth and
export jobs side by side, so a child read the parent mid-rewrite. A job
now starts once the rescrapes of its ancestors have ended, and a child
no row names gets its export rewritten after them. A rescrape chain ends
on verify.py --platform, whose summary closes the report.
When two cores declare different values for one file, the truth keeps the first and marks the entry hash_conflict. Its hashes pair an entry and never replace the platform's: armsx2's GameIndex.yaml no longer overwrites System.dat's line for LRPS2.
export_native and cross_reference read data/ without the shared hold, so
a refresh could swap a tree mid-walk. hold_data_dirs skipped a cache not
yet on disk, so a refresh could install it between verify and the packs
of one pipeline run. Both now hold every registered tree.
The FBNeo import recorded the listing's blob sha for bytes fetched from a
branch URL a CDN caches, and --fetch <revision> still read the tip. The
revision is now resolved to a commit, listed and downloaded there, each
DAT is held against its blob sha, and a DAT read at a named revision is
labelled with it without replacing the tip's recorded blobs.
The pipeline locked only --output-dir while it also writes database.json,
install/, README.md and docs/. A run on a scratch output directory could
start beside the run on dist/ and rewrite them. Every run now holds the
repository's .lock first.
_patched_entry read '#{ ... }' lines as live items, found no match in the model and gave up, so atarist was written again whole (52 lines changed for 3 additions). A commented item is now left as written.
release_record rebuilt nothing from the name builder: a substring match
took RetroArch_v1.22.2_AndroidArm64V8A_BIOS_Pack.zip for the RetroArch
pack. The record now refuses any pack that is not a registered platform's
full pack and stores the platforms each pack serves, which the readers
use instead of the pack name.
RomM lists the platform firmware folder without recursing and looks each file up as slug:file_name (models/firmware.py, base_handler.list_files at 5.4.0). An addition named with a directory (fuse/48.rom) is not written.
The render writes one biosFiles item per path, as checkBios reads one md5 per item. A second addition at a held path was dropped from the file and still counted added (78 announced, 75 written).
DecideNAND (MelonDS.cs:684-706) keeps, for a DSi title, only the NAND
slots whose bit is set in header byte 0x1B0. The six DSi_Nand entries
now carry that territory, so --region keeps one 240 MB image, not six.
AUS answers oceania, as every other Australian slot does.
Systems a core covers without a file were added while walking a set,
so the hash seed placed them and two runs wrote dist/truth/<platform>.yml
in two orders. The normalized system map was built from a set too.
The buildbot serves nicaiemu_libretro (frozen at 4c9b73f7, last built
2026-10-16 05:15) beside coolbaremu_libretro. They are two builds: each
reads its own orientation list from the system directory, so both
profiles stay, each with its own core name. Both read the same .cbe
archives from the same workspace, which builds a standalone binary at
both revisions: one system id and one build type for the two.
The slot and claim decisions above change which copy some paths take
(EmuDeck neocdz.zip, RetroBat DS firmware, hiscore.dat on six platforms)
and settle case variants on folding filesystems.
Ranking contested core claims sorted the whole gap report, which
reordered every manifest. Only the claims on one contested path move now,
grouped where the first of them stood, and two spellings of a path are
one group where the filesystem folds case (RetroBat's 64DD_IPL_DEV.bin).
An entry without a destination (EmuDeck's system:md5 whitelist) no
longer counts as a pack path in verify, and step 5 prints one status for
counts and paths together. A full offline run compared all 12 archives
and 930 emulator packs path by path, every one equal.
Thirty one-line labels in verify.py, generate_site.py and
generate_truth.py named the statement under them ("# Load registry",
"# Copy branding assets"). Comments that give a reason stay, as do the
module section headers. A test reads the three files for new ones.
The which-pack page announced itself ("This page picks the right pack
for a setup") before naming a pack. The sentence goes, the pointer to
Getting started stays.
Ymir reads sega_101.bin or saturn_bios.bin, so the sega_101.bin entry
carries saturn_bios.bin as an alias. kronos, yabause and yabasanshiro
open saturn_bios.bin and fall back to sega_101.bin: they were in that
entry's _cores but not its _required_by, while their saturn_bios.bin
entry had them requiring it. A reader that requires one of an entry's
aliases now requires the entry. No reader is added, and same-name
entries kept apart by path are left alone. No export changes.
Pin moves to 2de3bf8 (v8.4.2). roms/aros-ext.bin, roms/aros-rom.bin and whdboot/game-data/whdload_db.json changed upstream and are collected at that revision. The WHDLoad database is matched on the archive SHA1 first and refreshed from the bundled copy when newer. kick02019.AROS and its .ext are names the Recalbox launcher writes, so the profile now documents the kickstart_rom_file settings instead.
Pins move to libretro/hatari 5092994 and hatari/hatari 90949cf. The port now reads floppy.raw from the system directory (floppy_sound.c:146-186), documented as an optional user sample. Upstream decodes IPF without capsimage, the icon block moved by four lines, and the launcher file names leave the tos.img note for the platform layer.
A prose citation of the port's own lines was read only in the upstream file that a source_ref attributes the path to, and a range past that file's end came back GONE although the port carries it.
The Dolphin Sys, PPSSPP assets and blueMSX trees stay required, and the
profiles now cite why. blueMSX finds no machine without Machines/, the
C-BIOS ones included, and the load fails (Src/Board/Machine.c:637-656,
libretro.c:1447-1449). Its tree reference cited libretro.c:1119-1120,
which at the pinned revision is the Sunrise IDE option, and now cites
1196-1197. PPSSPP has no internal font without flash0/font, so
sceFontOpen fails for games using the system fonts
(Core/HLE/sceFont.cpp:805-864, 984-986). Dolphin loads no GameCube font
without Sys/GC/ or an IPL dump and warns that games may crash
(Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp:328-340).
Recalbox hashes a .zip by its members. diff_truth set that composite
against the profile's container md5 and reported neocdz.zip and
neocd.zip as mismatches. _hash_mismatch now drops it through
comparable(), the rule pair_entries and the export already apply.
mkstemp creates its scratch 0600 and os.replace kept that mode, so
database.json, the manifests, the packs, the recipe snapshots and the
large-file cache were readable by their owner only. set_plain_mode
gives the scratch 0o666 less the umask, as open() would, before each
rename. A test walks every function that renames a mkstemp file.
The contributor install line left out mkdocs-material and
pymdown-extensions, so pipeline step 8b (render site) was skipped.
The ranges are the ones deploy-site.yml installs, and a test reads
them from the workflow.
profile_sync gains --changed (added or edited profiles, uncommitted
ones included) and --added, both against the merge base of --base
(origin/main by default). CONTRIBUTING runs --changed --strict instead
of one --emulator call per new profile, and the CI job runs --added
in place of its own diff loop.
eduke32 and fury declare https://voidpoint.io/terminx/eduke32 and were
skipped as an unsupported host. The instance serves the GitLab v4 API
(/api/v4/projects/terminx%2Feduke32 answers 200) and /-/raw/ paths.
GitHub, GitLab and Gitea redirect a renamed repository, and every call
follows the redirect: AloysHF/NicaiEmu answers as AloysHF/CoolbarEmu
and the profile read as current. profile_sync now reads the name the
forge answers under and counts a move as review work.
check_freshness ran profile_sync with --json and the detection flags,
which profile_sync refuses, so --profiles always reported an unreadable
report. The version check now lives on the report and travels in the
JSON and markdown outputs; check_freshness asks for --json
--check-version only.
FirmwareDatabase.cs:405-410 declares NDS+NAND_JPN, EUR, USA, AUS, CHN
and KOR, each with a placeholder hash and 251658240 + 64 bytes. In DSi
mode DecideNAND takes the first one set, limited to the regions a
DSi-enhanced header allows, and stops the load with none
(MelonDS.cs:114, 304, 484, 684-706). DSi mode is off by default, so the
entries are optional, like DSi_Firmware.bin and the DSi BIOS slots.
A missing extended ROM only raises a notice (memory.cpp:1833-1849), but
the machine then runs on the Kickstart alone. cdstrap, cd.device,
cdtv.device and cdfs.library are resident modules of the CD32 and CDTV
extended ROMs and absent from their Kickstarts, the CD32 and base CDTV
models have no floppy drive (cfgfile.cpp:9375-9379, 9405-9406), so no CD
is read or booted. Both entries stay required. The AROS replacement
stands in only for a missing Kickstart (memory.cpp:3055-3063), so the
CDTV entry loses hle_fallback.
FreeIntv declared no data tree while its alias freeintv_ts_overlay,
the same code, declared freeintv_overlays. The core reads
freeintv_overlays/<rom>.png only with the multi-screen option and draws
its embedded keypad image without one (src/libretro.c:278-280, 294,
321-325), so the tree is optional. A test holds every alias to the trees
of its core.