The build now imports romdir.py and three scraper modules through the
launcher layer: a push touching only them did not rebuild the site.
sitesteps.py was listed twice.
build_port's four archives carry install.py pinned by SHA-256, so they
change with the installer, not with the packs. The site now builds them
from its own commit and serves them under get/handheld/. Each get/ page
of Batocera, KNULLI, ROCKNIX and AmberELEC names its file, size, hash,
folder and menu, and get/linux-handhelds/ does the same for muOS, ArkOS,
dArkOS and JELOS. The installer's handheld section opens on a download
table, both tables written from sitehandheld.LAUNCHERS.
Every archive has a recipe in recipes/archives.json, and no page a user
reads said so. A short reference page says what a recipe is, how to
rebuild one archive and what exact and canonical mean. Its counts and the
README line are counted from the recipe file at each build.
The README gains a row of four badges: PyPI version, Python versions,
the Validation workflow on main and the license. Tests hold the badges,
the counts and the page's command.
Dependabot moved uv in pyproject.toml alone, while validate.yml and
CONTRIBUTING kept 0.12.9. Both pins move together, and a test now
fails when a package pinned in both carries two versions.
--fetch also exported and stopped on the absent dist/truth before any
download, so CI skipped every exporter fidelity case and tolerated the
step. --refresh-cache only downloads: the step can no longer fail
unseen.
build_pypi.py stages install.py, the launcher, __main__.py, README and
LICENSE, then runs uv build with flit_core 3.12.0 pinned and
SOURCE_DATE_EPOCH set from install.py's commit. Adds python -m retrobios,
the PyPA classifiers, keywords and project URLs. CI installs uv.
- The installer says "Every file on the list is in place." where it
said "Everything is in place.": a check covers the files the
collection holds, and the required ones it lacks follow.
- The FAQ, first install, legal and home pages state only what the
code shows (PlayStation 1 and Saturn run without a BIOS on some
emulators, save files are never touched, records are added).
- MinUI and MyMinUI show their own boot logos, and the Android,
Linux handheld and iPhone tiles show the Android robot, Tux and a
plain device icon, each credited in sources.json.
- Each Markdown copy, llms.txt and llms-full.txt name the commit
they were built from, version.json the current one, and the
answering rules tell assistants to fetch a stale copy again.
- The deploy lists the pages whose words changed (digests.json) and
posts them to IndexNow once the site is live.
scripts/build_pypi.py writes a wheel and an sdist from install.py, the
copy install.sh pins, and packaging/pypi. The version is the date of the
release in release.json. validate.yml now runs on packaging/ changes.
The build writes <page>/index.md beside each page, named in its head,
and llms-full.txt. llms.txt and the setup skill say how to answer from
the site, not from memory, and the setup_bios_files WebMCP tool gives a
setup's folder and exact file names from the picker data.
llms.txt and an ARD manifest name the pages and the JSON API, and lead
an agent setting up a device to --for-games --required-only. Every page
registers four read-only WebMCP tools: the setup command, a hash lookup,
an emulator's files and the site search.
Every signature carries annotations and nothing read them. mypy 1.18.2
over install.py and scripts/ reports 993 errors today, among them the
six pack helpers typed zipfile.ZipFile that every caller also hands a
PackRecord. The errors sit in mypy-baseline.txt and the schema job fails
on any error outside it, or on an entry that no longer occurs. Third-party
packages are left out so the result does not depend on the machine: 6 s
locally, run twice and on 3.12 and 3.13 with the same errors.
files/?sha1= of a file the collection no longer holds answered that no
file the site knows has the hash. generate_db.py now records each sha1 a
rebuild drops in retired.json, with the day and the file in its place,
backfilled from the history since 0d586ef6b (4,139 files). The lookup
answers with it and leads to the successor's card.
The buildbot answered once with something that was not ScummVM.zip. refresh_data_dirs gave up at once, Generate the site was skipped, and 228 site tests failed in its place. A failed or unreadable download is now tried three times, with waits of 5 and 20 s, and an empty archive still fails at once. The site step runs after a failed fetch, which stays red on its own step.
An ArkOS or AmberELEC games part is named on the first screen and comes
first at the folder question. Packs that lack files are said so before
any plan. The served bootstrap gives advice that fits it, and the site
build refuses a copy whose pin is not its installer.
Records that back the same field or issue claim share one line. Each
line says what the runs showed: the BIOS the core ran, the file strace
saw opened, or what a maintainer watched in an issue's run
(tests/campaign/observations.yml). A run with nothing to state stays
off the page.
Emulator pages show a run only when a profile's evidence names it or it
answers an issue, as one line naming the BIOS the core ran. The Tested
blocks, region outcomes, coverage, campaign and pack tables and the
benchmark figures are gone from the site; the records stay.
The site serves install.sh at /retrobios/i and install.ps1 at
/retrobios/i.ps1. generate_site.py writes both copies with the
installer address set to install.py at the commit the site is built
from (GITHUB_SHA in CI, HEAD locally), so the pinned SHA-256 and the
downloaded installer always come from one commit, including while a
deploy is still running.
Every command a user copies names the short address. The raw form
stays on the installer page as the fallback. Deploy Site now runs on
changes to install.sh and install.ps1. The install box weight keeps
the address length its ratio was fitted on, so no console page moves.
MAME's card pages, GroovyMAME and yaps2 read 13,000 to 16,700 words of
cards. Each entry is now a table row (name, members, status, short
hash) that opens to its card in a details block, with the site's filter
box and row counter. Pages from 150 entries and every split part use it.
Visible words: mame-files-1 16,680 to 1,612, groovymame 14,396 to 1,876.
A row costs about five elements, so a part holds 180 cards: MAME goes
from 8 parts to 9, the largest at 567 KB and 8,989 elements.
Each wanted list (TOSEC, No-Intro, Redump) opens on its counts, then one
table folded under a filter box that opens it, in place of a block per
DAT. Only the names are searched: indexed descriptions and hashes put
the PlayStation page ahead of the PlayStation 2 one.
A filtered row stayed visible on a phone: a stacked row's display:block
outweighed the hidden attribute on every stacked table.
Ubuntu 24.04 blocks the unprivileged user namespaces bubblewrap needs, so the campaign refused to run the fake cores and four FakeCorePasses tests failed, also inside the no-jsonschema replay. CI now installs bubblewrap, lifts the AppArmor restriction and proves a sandbox starts. Locally the tests name the missing sandbox instead of failing on a KeyError.
The new probes now refuse abbreviated options, read the GitHub token through github_headers, type every signature and document every option. The site build watches region_check.py and the content list, and validate.yml's tests/** counts as watching the list. The testing guide names the two new test modules.
The site compiles the index and the SQLite files from measurements/
instead of a pinned clone. The pin, the sync script, the CI clone steps,
the freshness area and its refresh handler are gone. core_probe --record
writes into measurements/ of the checkout by default, and a test fails
when a line or data file HEAD holds changed or vanished.
Each emulator with records gets a Tested block: claim, result, method, computer, core build and the permalink of its record at the pin. A Measurements page filters every test in the browser from the compact index, and the Data page lists measurements.sqlite with its tables. One SQLite file per emulator is linked from its page. wiki/measurements.md says how a test runs, held to the Start here budgets.
Both workflows fetch the pinned commit alone with git before the build, and the deploy fails without it.
The deploy job sets NODE_DISABLE_COMPILE_CACHE for the build and the search gate, and lighthouse.py passes it to its children. The paths list gains generate_event_schema.py, which the site build imports.
Without a network, muOS and ArkOS launchers ask to copy the BIOS files from the card the system does not read (muOS bind.sh, dArkOS roms2), then install with --from and the pack. CI checks that shellcheck is present, and the test fails under CI without it.