The per-system lookup named its dictionary declared, which the file loop below reassigns to a list, so the second system of a platform page raised AttributeError.
exports/ is committed but CI cannot rebuild it, since the originals it
patches live in the local cache. The native freshness check now runs
the export offline and compares it with the committed files, and
refresh_stale writes the export again after refreshing an original.
exports/ now holds the twelve platforms' own files, corrected, with a
report of every change, read by the site's corrected files page. Two
summaries are reworded for the page: an addition the format cannot
carry is counted as left out, and RetroPie names each skipped package
by sentence instead of joining reasons with semicolons. Its parser no
longer reads "e.g" as a file name.
Batocera, Recalbox and RetroBat launch pcsx2 standalone and as LRPS2.
The name matched the standalone profile's key, so lrps2, which lists
pcsx2 among its cores, was left out and its files never reached those
packs. A name in dual_mode_cores now also resolves to the libretro
profiles that claim it.
RetroArch, Lakka, RetroPie, EmuDeck and RetroBat group NAOMI and
Atomiswave as sega-dreamcast-arcade and the Enterprise 64 and 128 as
one system. No profile uses those ids, so the emulator cell was empty.
When no id matches, a platform page now names the emulators that read
a file the system lists. Archive members do not count.
export_native now writes into exports/ by default, and beside each
platform's corrected file a report naming every change, where the run
printed five per kind. A new site page lists each platform with its
original file, a download of the corrected one and every corrected,
filled or withheld value. Each platform page links to its row.
Dropping the double-dash asides left 72 comments and docstrings with
half a dash glued to the next word ("shape -a size or a size range -is
all"). They now read as a colon, a comma or parentheses, and a prose
style test names any that comes back.
install.py --emulator NAME keeps what the named emulators read on the detected platform: their own files and the platform's files of the systems they run, as a pack built for them carries, without the systems no core is mapped to. Each emulator page now gives that command for Linux, macOS and Windows, beside the per-file links.
A libretro port carries the emulator's own sources beside its glue: pcem cites src/mem.c in the port, which is PCem's code. A citation in the port is labelled libretro glue when it is one of the libretro interface files, emulator code otherwise, and upstream emulator when it is in the original repository.
A file a core reads at several destinations is added again at each one by a second pass that worked from the raw profile entries, so files the emulator or the platform's package installs came back into the packs and manifests by that route: the installer's per-target replay disagreed with the builder on six files.
A copy filed under two consoles of one maker was listed twice with the same id, and a data directory listed the same bytes twice, so the site deploy refused 20 pages. The first card keeps the id. The pipeline only generated the pages, so it now renders them with mkdocs build --strict and runs validate_site as the deploy does. The resumed-speed test read the clock and failed on a slow runner, it now fixes the elapsed time.
The platform layer names data trees for its systems: retroarch.yml carries dolphin-sys and ppsspp-assets, and Lakka inherits them, while Lakka's core packages install both trees into the system directory. A profile records that with installed_on on its data directory, and the pack and the install manifest now leave those trees out for that platform.
A file the emulator installs itself is left out of the packs, per build and per platform. The profiling guide documents bundled, installed_on and not_bundled_on, the FAQ says why a file the emulator reads may be missing from a pack, and an emulator page names the build that installs it and the platforms whose package differs.
A data directory appeared on its emulator page as a URL whose content moves, and the 2,534 files the packs ship from these trees were on no page. Each tree now shows the revision it was fetched at and its files with size and sha1, and the site lookup by sha1 resolves them. The page description reads the repository list the JSON-LD now carries.
The structured data of an emulator page published one repository and one commit. A profile whose builds live in two repositories, or a port with an upstream_commit, now lists each repository with its own pin.
The collection DAT named its sets "Sony - PlayStation", and the data page said it audits a copy of bios/. clrmamepro and RomVault looked for a folder of that name and reported the 330 sets missing. A Logiqx set name writes a subfolder with a backslash: Sony\PlayStation.
The gaps page and the Advanced usage, Verification modes, Release process and Testing guide pages titled in Title Case beside sentence-case pages. A test now reads every wiki heading.
100 emulator names the two platforms run had no profile, so their packs carried nothing for them. Each was read from the platform's own launcher or scriptmodule: the same program as an existing profile takes the name in cores:, a different build gets its own profile read from that version, a launcher or self-contained game goes to remove_cores, and the rest are new profiles written from their source or shipped binary. The files they need that the collection lacked are collected from the upstream distributions. Bungie and splitwolf trees are read by path and stay out of dedup.
bundled describes the emulator's own release, and a platform package can differ both ways: Batocera's hcl package installs the binary alone and sends users to fetch the data, while its blueMSX core package copies the machines and databases beside the core. not_bundled_on and installed_on name those platforms, and the builder reads them through one rule.
The README opened on a sales line. It now says what a pack holds: the files its emulators read, as their source code names them, minus what the emulators install themselves.
The site linked prose citations through profile_sync, which made the site build depend on the checker. The prose runs and their patterns move to sourceref, the grammar module both read, and profile_sync re-exports them.
A file installed with its emulator is already on the user's machine and the packs leave it out. bundled_only.py lists the collected copies nothing else needs: no platform declares them, no entry of any build needs them, no install manifest ships them.
A file or tree installed with the emulator is already on the user's machine, so packs, install manifests and verify's pack count leave it out. bundled is scoped by mode like any entry: Dolphin's Sys and PPSSPP's assets ship with the standalone releases, not with the libretro cores, so they now follow the libretro build only and still reach RetroArch packs. PrimeHack, standalone only, ships its own Sys.
Counts were printed with a fixed plural and the site said "1 files" 234 times, "1 issues" and "1 entries" too. A shared helper picks the noun, and the generated-pages prose test refuses the form.
A hash mismatch row printed the hash the emulator accepts and stopped there, although the collection holds that exact dump for most rows. A column now links the held copy.
The database keeps one path per content, so a copy filed under another manufacturer was on no page of its own: the Channel F BIOS sat under Arcade > FBNeo and Fairchild had no system page. Every folder holding a copy now lists it, read from the full paths by_path_suffix records, and the index counts each content once.
Recalbox lists accepted md5s joined by commas, and platform pages printed the list as one code span. The site search took it for a single word, so 198 accepted values could not be found. Each value now has its own span.
A profile that reads a libretro core and the original emulator cited both trees alike, and readers could not tell whether the core or the emulator asked for a file. A cited path now opens with source or upstream, the repository its lines are in. Emulator code a port carries is attributed upstream when the original holds the same value on the cited line.
profile_sync --attribute-refs writes the words from where the lines are found and follows a word already written. The site links each citation to that repository's pin, labels it libretro core or upstream emulator, and says on each file card whose code asks for it. A recale keeps the word, and mame_ref_audit reads the tree it names.
A source_ref written as `stella src/a.c:120` names the repository its lines are in. The path is read without the word, and --rebase-refs wrote the new span back without it, losing the attribution.
Notes, file notes and platform details carried file:line citations as plain text although profile_sync keeps each on the profile's pin. A citation now links when the profile reads one repository and the path is rooted or already used by a structured source_ref. Platform detail source_refs go through the same renderer as file cards.
A card named only the platforms whose own list declares the file. A RetroBat user looking up scph5501.bin found every platform but RetroBat, whose pack installs it for six cores. The cards now read the install manifests and add each pack that places the file, with the destination it gives it.
Platform pages matched emulators to systems by the exact id, so the RetroArch page listed none for sega-mega-drive (genesis_plus_gx says sega-megadrive), and listed every emulator of a system instead of those the platform runs. Emulator cards linked only ids a platform uses: 2,057 of 4,215 system lines had no link, now 327, the rest having no page. Ids are compared as _norm_system_id reads them, and a system only profiles name is placed by the files they file under it.
The pack table, its parts sentence and the install commands were typed by hand from figures release.json already held. A copied cell or an old collection total at the top is how issue 81 happened. release_notes.py renders them and appends the hand-written account of what changed.
PR validation runs validate_schemas.py --source-only and the pipeline did not, so a profile with an unquoted numeric core name passed every step and failed CI on push. It is step 0 now, skipped where jsonschema is not installed.
Paid Android emulators announce versions that circulate only rebuilt or re-signed. The profile stays on the newest unmodified build, and version_source.no_genuine_copy names the release searched for, so check_freshness stops flagging it until the page announces a later one.
1024 bytes named scph5501.bin, a name every declaration sizes at 524288, were reported "File size OK" and offered a .variants slot at the repository root. The review now warns when no declaration of the name accepts the size, and places a variant beside the folder that holds the name.
Generating the model for every platform met the same two GameIndex.yaml declarations once per platform, and check_freshness opened on six identical warnings.
check_buildbot does not fail the run, yet the summary printed it FAILED right above Pipeline COMPLETE. It now prints WARN and a line saying the difference does not fail the run. The total is aligned under the step durations.
Offline, check_freshness labelled every scraped target list static and counted it OK although nothing was compared. Other sections say SKIPPED offline, and now this one does too.
A 2 GB part drew a 98-column line, and on an 80-column console every redraw wrapped and left a copy behind. The bar now shrinks to the width and goes below ten columns of room.
Scrapers resolve their tag or branch head in the constructor, which ran outside the try in scraper_cli: a refused GitHub call ended in a traceback. The error is now printed with the next step, setting GITHUB_TOKEN when the API refused an anonymous call.
The guides said files over 50 MB become release assets and that RPG Maker and ScummVM were the trees kept out of dedup. .gitignore decides the first, four committed files are over 50 MB, and NODEDUP_DIRS holds eleven trees.
generate_site --docs-dir sent the pages elsewhere but always rewrote the tracked mkdocs.yml, outside the lock taken on that folder, with the navigation of the work in progress. Two previews into two folders both wrote it. Another folder now gets <name>.mkdocs.yml beside it, docs_dir set and its paths rebased, which mkdocs builds with -f.
About forty profiles describe projects published outside any forge (Altirra, ePSXe, DraStic, mednafen, xroar). profile_sync skipped them as an unsupported host and check_freshness reported the same UNKNOWN line every run, so a new release adding a firmware went unseen. A profile can now name the page announcing its releases and a pattern for the version: --check-version reads it, and check_freshness --profiles calls the profile stale when the page announces another version than core_version.
The alias-free profile set was parsed separately from the full one, so a process asking for both read the 534 profiles twice, 1.6 s of a site build. It is now a filter over the full set.
With --all, an unknown --target skipped every platform that has targets and ran the others (BizHawk, MiSTer) unfiltered, so verify, slots and the pipeline exited 0 on a typo. A platform without targets is now left out like the rest, and a target no platform has is refused.
The pipeline rebuilds the database with --force, which discarded the previous digests and wrote whatever the CPU computed, on a host that has given an incorrect SHA-1 under load. The forced run still rehashes every file, but a digest that contradicts the cache for an unchanged mtime and size is computed again, and the two readings that agree win, with a warning naming the file.