FAQ entry, the release_pack field and how to revisit it from download
counts, the get/ pages, and RetroPie 4.8 now installs from a computer with
the Pi's network folder as --dest. The start pages are back under their
word ceilings.
The PortMaster port now starts install.py --tui on the console (or in
foot or xterm under a compositor), with gptokeyb in kill mode on the
installer's path, retrobios.gptk, TERM=linux and a Terminus font, and
puts the console, font and mapper back on exit. pugwash screens stay as
the fallback where no terminal can show, and start in no-check mode so
PortMaster's A/B fix applies. Without a network, every launcher installs
from a pack found on the card or names the pack and the folder.
Adds launchers for Batocera and Knulli (Ports, evmapy .keys), muOS
(.muxapp in muxterm with gptokeyb2) and the Tools menu of ArkOS,
dArkOS, ROCKNIX, JELOS and AmberELEC, built by build_port.py with the
pinned installer and tested on a simulated device.
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.
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.
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.
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.
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.
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.
The installer output example showed 5865 files and no Not installable
line, while the RetroArch manifest gives 8069 and omits 11. Exit code 2
also comes from every option argparse refuses. RETROBIOS_REF holds a
file list only until the next release deletes its tag, and large files
always come from large-files. The release commit now carries the
manifests the pipeline regenerates. A RetroPie 4.8 image ships Python
3.7.3, below the bootstrap's floor, and the pages say what to use.
mkdocs was installed by the deploy alone, after the merge, and wiki/
was not a validation path: a dead link or a stray heading failed the
deploy on main with nothing in front of it. The test job now runs the
deploy's site build, and every site input triggers validation.
Troubleshooting, the FAQ and the download page sent people who only ran
the installer to verify.py, which reads the repository, not their BIOS
folder. Download links now name the exact asset of the recorded release,
the --dest example names the BIOS folder on the card, the slice layout
left with the last release that used it, and the shown verify output is
what the tool prints.
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.
Twenty-one topics were bold lines ending in a colon: MkDocs gave them no anchor to link from an issue and left them out of the page contents. They are headings now, and the prose test refuses the form.
The release built and checked the RetroPie pack with two commands after the pipeline, which left it out of the verify and pack consistency check. pipeline.py --include-archived builds and checks it with the rest.
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.
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.
Profiles, the wiki, comments, docstrings, command output and schema descriptions carried em-dashes, clause-joining semicolons, unicode arrows, box-drawing banners and check-mark glyphs. Each sentence was rewritten rather than having its character swapped. Hashes, paths, source_ref values and every cited file:line are unchanged, which a comparison of each parsed profile against the previous revision confirms.
validate_pr comments now say PASS and FAIL in words, and source_ref values in a profile's structured blocks render as code. test_prose_style fails if any of these comes back, in tracked files or in the generated site.
A count of assets misses a failed upload beside a stray file and a part
re-uploaded from an older build. check_release.py holds each asset's
GitHub sha256 against SHA256SUMS.txt and release.json, and the release
process publishes the draft only on its clean exit.
The documented command, discover tests, makes tests/ the top level,
so tests/__init__.py never ran and the variable it sets to keep tests
offline was missing from every local run. Every documented and CI
run now passes -s tests -t ., and a test requires it.
SHA256SUMS.txt sat beside the artifacts it vouches for, so whoever could
rewrite a release rewrote the list with it. The packs were already
reproducible, which answers corruption and lets a third party rebuild an
archive byte for byte; nothing answered a rewritten release.
The list is now signed with an ed25519 key kept for this alone, and the
public half is allowed_signers at the repository root, so verification
does not go through the release page: ssh-keygen -Y verify against the
committed file, then sha256sum --check. Rehearsed on all three outcomes:
a good signature, a tampered pack caught by the sums, a rewritten list
caught by the signature.
The release steps sign and upload the signature, the README points a
downloader at the procedure, and the reproducibility section says what
each half proves. Rotation keeps retired lines so past releases stay
verifiable. Three tests hold the trust root, the signing step and the
documented principal in agreement.
validate.yml triggered on pull_request alone, and it holds the only
unittest invocation in the repository: deploy-site.yml stops at
validate_schemas, generation and the freshness diff. Work lands on main
by direct push far more often than by pull request, so 1,318 cases were
guarding the road almost nothing takes.
The suite and the schema check now run on both events. validate-bios and
label-pr read pull request context and carry an event guard. The
concurrency group falls back to the ref, so a push series collapses to
the tip: what stays verified is the head of main.
The path lists are spelled out per event because the workflow parser
reads no YAML anchor, which PyYAML would have accepted in silence. Four
tests hold the wiring: the suite reachable from a push, the two path
lists equal, every job reading pull request context guarded, and no
anchor in any workflow.
The job carried if: false, which blocks workflow_dispatch as well as
push, so there was no way to cut a release through CI at all and the
comment described a temporary state that had become permanent.
Releasing is deliberate: the push trigger is gone and the job runs when
someone dispatches it. The seven-day rate limit stays as the guard
against dispatching twice, and concurrency no longer cancels a run that
may be midway through uploading assets.
The pages described workflows, an installer pinning and a CI permission
model that are not the ones in the tree. Corrected: the release process,
the CI table, the resolution chain and its statuses, the hash-mismatch
policy per verification mode, the archive convention, and the romset
recipe store.
The FAQ keeps the project's own reading of the legal question rather
than a version that reaches no conclusion.
9 new wiki pages: getting-started, faq, troubleshooting,
advanced-usage, verification-modes, adding-a-platform,
adding-a-scraper, testing-guide, release-process.
Updated architecture.md with mermaid diagrams, tools.md with
full pipeline and target/exporter sections, profiling.md with
missing fields, index.md with glossary and nav links.
Expanded CONTRIBUTING.md from stub to full contributor guide.
Filter .old.yml from load_emulator_profiles, generate_db alias
collection, and generate_readme counts. Fix BizHawk sha1 mode
in tools.md, fix RetroPie path, fix export_truth.py typos.