generate_site.py writes the Starlight project in website/ and nothing
else: mkdocs.yml, the MkDocs hooks, theme overrides and stylesheet go,
and the wiki is written in Starlight's syntax. Both workflows set up
Node with the official actions/setup-node pinned by commit, run npm ci
from the committed lockfile, build with the strict link validator and
check the result with validate_site.py.
The search weighs a page by what it answers: Start here pages first,
a system page's cards and file names before a guide citing them, deep
guides, launchers, aliases and frozen copies after. Status badges,
hash blocks and the export change lists leave the index. The ranking
sits at the centre of a range where the 13 queries of search_gate.py
all answer, in the search box itself.
839 pages, every URL and 45,611 ids match the MkDocs build. The tests
read the Starlight content and syntax.
The audit reads driver sources from the upstream cache offline. An empty cache skipped, but one holding some drivers raised NotCachedError and failed the suite. It now skips naming the file. The testing guide lists the semantic gate test.
Tables with a download link stack on phones, the browser check covers
the lookup, a hash typed in the search, breadcrumbs, previous and next
across tabs, glossary terms and the 404 hint. validate_site budgets the
Pagefind index pieces and takes the base path without mkdocs.yml. A
test holds the picker to install.narrow() on 180 selections.
The clone map is cumulative. A run that removed sys68k_cpu21.zip and sys68k_cpu30x.zip as copies of other sets left the entries naming them canonical: their eight clones pointed at files that no longer existed and fell out of the manifests. Each clone now follows to the final canonical, and a loop is refused.
EmuELEC declares 19 files of the Tyrian 2.1 distribution (setup.ini,
netterm.int, the net*.pcx screens...) that bios/ did not hold. They
resolved only at the data directory step, against data/opentyrian, the
cache refresh_data_dirs.py fills from the opentyrian-data.zip asset. verify
gave 544/572 in a checkout holding that cache and 525/572 in one without
it, for the same commit.
The 19 files are taken from the freeware tyrian21.zip (camanis.net, sha1
29827de9), each equal to the cached copy. netset.pcx and tyrset.pcx are
the same bytes under two names, so the folder joins NODEDUP_DIRS. A test
resolves every platform entry with the data directory caches present and
fails on any that only a cache answers.
Platform guides, device groups, terminal tabs, pack README manuals and
logo credits move from Python tables to platforms/_guides.yml, checked
against the registry on load. A folder row without a path is the
registry's extract_to, written once.
Wiki pages place themselves in the navigation with order and nav_title
in their front matter. Generated docs/ and mkdocs.yml are unchanged.
Each reference and contributor page now says what it answers and gives
a real case before its rules: scph5501.bin for the check modes and the
data model, DuckStation's entry for profiles, RomM for a platform. The
verification example is the RetroBat d64_1.rom case the gaps page lists
instead of a scph5501.bin case the data cannot produce.
Emulator pages open on what the emulator reads, from the profile, and
keep their technical notes folded. System pages say what a card holds.
The data model shows a real database entry and links the one
resolution chain. Gaps tables name what they count ("Discrepancy",
"Where the files come from"), and the core inventory is titled Cores
by platform so cross-reference keeps one meaning.
The Start here pages ran 460 to 2,100 words and the first command of
Get your files sat 254 words down. Each page now opens on its action,
with short sentences and one fact per block. The facts a newcomer does
not act on moved one level down: the legal analysis to wiki/legal.md,
the project terms to wiki/reference-terms.md, the annotated run and the
installer failures to the installer page, collection figures to a new
Explore index.
tests/test_site_copy.py holds the budgets on the generated pages, and
the testing guide states them with their reasons.
Four statements the repository contradicts are rewritten: prboom.wad
is compiled into PrBoom (emulators/prboom.yml), Batocera reports a
mismatch as UNTESTED (batocera-systems checkBios), 13 hle_fallback
entries are required, and the gaps headline splits missing firmware
from game data and unread entries.
A BIOS folder can sit on a share other people write to. A retrobios-backup that is a link is no longer written through (the backup goes inside the BIOS folder instead), run folders are created for the user only and carry a marker, and --restore only takes a folder holding that marker, walking it without following links. Beginner pages label their links to the installer page as details.
A file in place whose contents differ (another revision, a personal
dump) was overwritten and lost. It is now moved to
retrobios-backup/<date-time>/ beside the folder written to, under the
same path, before the verified copy replaces it. Beside, not inside:
DuckStation, SwanStation and Rustation read every file of the BIOS
folder and BizHawk walks its firmware folder recursively.
Identical files are never kept. --dry-run counts what would be kept,
the summary and the summary event name the folder, files and bytes,
and --restore FOLDER puts the files back. Data trees and standalone
copies keep their replaced files the same way.
validate_site.py fails a page over 1 MB of HTML, a search index over
8.5 MB (1.7 MB gzip), a skipped heading level, a table header without
text, a script from another host and a diagram drawn at runtime. The
limits sit above what the site now measures (0.88 MB, 7.2 MB, 1.43 MB),
each with its reason, and each has a test.
A manufacturer page over 500 KB of Markdown becomes a summary: its
largest consoles move to pages of their own, cut into parts when one
console is still too large, and every console keeps its heading there.
MAME's 1,564 cards move to four pages, its page keeping a row per entry
with the card's old anchor. RetroDECK's arcade list gets its own page.
site.js follows a moved card by content or by its row.
The largest page drops from 10.5 MB to 0.88 MB. Emulator groups of the
navigation open by initial (65 KB to 41 KB before the content). File
cards are level 3 under a level 2, and the hook keeps the table of
contents of card pages to level 2: platform pages no longer list every
system id. Key/value cards name their columns. The sweep runs before
the decoration, which kept every page no generator wrote any more.
The redesign moved the technical questions to technical-faq.md, made the Get your files rows generated from each platform key and reduced getting-started.md to links. Tests now read those places: the pack-row test reads the rendered page. The new site scripts go through run_cli and refuse abbreviated options. The three maintenance image tools are exempt by name from the build dependency rule: their output is committed and the build only reads it. siteguides.py now triggers the site deploy, and the recipe counts match the store.
Hashes, link lists, install commands, member tables and long reference
tables leave the site search: the index drops from 21.0 MB (4.88 MB
gzip) to 6.8 MB (1.33 MB gzip). Names and prose stay searchable.
files/?hash= takes a SHA1, MD5, CRC32 or SHA256 and reads one shard of
api/v1/lookup/ (about 22 KB gzip, was 675 KB) listing the collection
card, the platforms that declare the value and the profiles that check
it. files/?sha1= still opens the card, and a sha1- anchor missing from
a page is looked up there, so a card can move between pages.
Excluded blocks are section elements: the search plugin compares
elements by tag, so a div ended at the first nested div.
EntryCategories asked every core in turn: 3.8 million proofs for 7,430
entries. ProofIndex looks each key up once, and verify --all --json is
byte-identical (24 s to 17 s). generate_site and generate_readme now share
one coverage, cached in tmp/coverage-cache keyed by its inputs, so the
README step drops from 25 s to 3 s.
The two redesign branches and the archive repair met in the testing guide and the prose rules: list test_archive_recipes, drop three clause semicolons, write the forbidden glyphs as escapes in the image test. README and mkdocs.yml regenerated from the merged generator.
Five tabs from Start here to Contribute, a level on every page, a device picker on Get your files that lists every registered platform, and platform pages that open on where the files go, the command, the pack and how to check. FAQ and troubleshooting keep the questions asked before installing, the technical ones move to their own page, and getting started points to the pages that took its content.
device_group in the registry places each platform on the device picker, in the navigation and on the home page. scripts/siteguides.py holds the guide text per platform: what it is, its BIOS folder, where the install command runs.
scripts/sitediagrams.py writes the explainer, install flow, verification modes, MinUI card, pipeline and data layer diagrams as inline SVG from the registry, the platform files, the install manifests and the pipeline step list. A page asks for one with an image comment, which the decoration pass resolves. The two mermaid diagrams of the architecture page are replaced, so no page loads mermaid from unpkg.
Platform logos and system icons are copied once by fetch_site_images.py with their source and owner recorded, and the build rewrites the remote links to the copies. validate_site refuses an image from another host. Three registry logos named a personal avatar instead of the project's (RomM, ROCKNIX, MiSTer FPGA) and MyMinUI's was a GitHub identicon, now dropped.
One 1200x630 sharing card per section, a 404 page with search and the two entry pages, and a list of screenshots that need a real device.
install.py --no-game-data leaves out the files and omissions the manifest
marks game data, in an install, --check and --dry-run, and names them with
their category. The --events summary gains left_out, one group per
category with every destination. A list without categories is refused.
Held entries carry their category and readers too, not only missing ones, so each platform page says which cores read every file it lists and where the code does it. Severity still applies to firmware gaps only.
Each missing platform entry now carries its evidence: the profile entries that read it with their source reference, the cores of its system examined without finding a reader, or why the question stays open. verify --verbose prints it, --json carries it and the platform pages show it.
A platform list can name a game's data files or a file no core it runs opens. Verify gives each missing entry a category read from the profiles of the platform's cores: firmware, game data or unread. Only firmware gaps carry a severity and fail --strict; the others are counted on their own line, and the pack check no longer counts them as pack errors. Missing firmware stays a conformance error.
The installer page says how to get the port (PortMaster's catalog once
accepted, or RetroBIOS.zip in the autoinstall folder), what it shows and
needs, and why it carries install.py. The download page links to it
from the handheld table.
AmberELEC, PAN4ELEC and EmuELEC detection now installs their own lists
at /storage/roms, the root those lists are written against; KNULLI its
own list at /userdata/bios. JELOS, KOLOS, UnofficialOS and Arch R keep
RetroArch's list with the folder their retroarch.cfg names.
build_port.py runs after split_pack.py, so RetroBIOS.zip is in the
signed checksum list and uploaded with the packs. check_release.py takes
the port from that list: it is no pack, so release.json does not record
it.
ports/RetroBIOS runs install.py on a handheld with PortMaster's own
screens (pugwash fifo_control through PortMasterDialog.txt), using only
what PortMaster 2024.02.26 and the 8.5.23 copy JELOS ships. It reads the
installer through --events. scripts/build_port.py writes RetroBIOS.zip
in the layout PortMaster's release build gives a port, with the
install.py the bootstraps pin, reproducibly. tests/test_port drives the
screens with stubbed dialog functions and a fake installer.
One JSON object per line on stdout (detection, per-file and per-system
check, download progress, summary, exit code) and the usual text on
stderr, so a program driving install.py never parses prose. EVENT_KEYS
is the one schema. The installer page documents it, and a test holds the
two equal. The handheld port reads it.
The Google Play and retroarch.com builds share com.retroarch and com.retroarch.aarch64 but build their defaults under different roots (RetroArch v1.22.2 MainMenuActivity.java:182-183). The build is told by the version code it records in retroarch.cfg, else by the folder it wrote. A Google Play folder Termux cannot write is named, as for DraStic and Flycast.
DraStic keeps its BIOS in its private data and Flycast in Android/data,
which Termux cannot write on Android 11 and later. An installed one is now
named with the files not copied, and a writable Flycast folder is a
standalone copy target.