A required-only build is narrower than the platform declares by
design, like the source-restricted variants already handled, so the
full expectation must not be applied to it. --region is also refused
alongside --manifest-targets, which carries no region dimension.
Links to this site get shared on Discord, Reddit and forums, where a
page with no Open Graph tags renders as a grey rectangle. The pages
already carry a per-page title and description, so a theme override
fills the tags from those; mkdocs-material would otherwise only emit
them through its social plugin, which pulls in Pillow and CairoSVG to
render a preview image these pages do not need.
Decorated site pages carry the generation stamp twice: once as the
markdown footer and once as a rendered element. write_if_changed knew
only the first, so every page was rewritten on every run for the clock
alone.
The comparison is what makes the deploy-site freshness guard a real
staleness check rather than a guaranteed failure, and it had no tests.
generate_emulator_page carried a 228-line loop body rendering one file
row from thirty-odd optional fields, which put its complexity at 141,
more than twice the next function in the repository. The row renderer
and its badge strip are now their own functions and the page function
sits at 68.
_forge_sources went from 18 to 32 when it learned to pair each
repository with its own revision; the pairing is now its own function
and the caller is back under the threshold.
Verified by regenerating the site and diffing: all 505 pages are
identical apart from their generation timestamps.
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 cached hashes were rebuilt by iterating a set, so their order in
each database entry followed set hashing rather than a declared one. A
run with a warm cache rewrote all 7,850 entries with no content change.
The order is now the one compute_hashes returns, and a test holds a
warm-cache run byte-identical to a --force rehash.
validate_pr.py inspects paths chosen by whoever opened the pull
request, and it hashed the file before deciding whether it was a
symlink. A link to /dev/zero was read until the job timed out, and a
link out of the checkout was hashed and reported as though its target
had been contributed. The shape is now settled first, and a test that
used to hang the run covers it.
The gate had no tests at all, and neither did the 3DS crypto reached
by dynamic import from validation.py: RSA PKCS#1 v1.5, AES-128-CBC and
ECDSA over GF(2^233), all written by hand. Coverage goes from 0 to 95%
on the curve, 0 to 55% on the gate, 9 to 35% on the rest. The curve
tests check against the published SEC 2 parameters rather than against
the module: the generator satisfies the curve equation and the group
order takes it to infinity.
The database drops the duplicate PS3UPDAT.PUP entry and regains
adler32 on every file. RetroPie gains an install manifest, so the
download table reports its size instead of a dash.
Each name is one a platform or the buildbot uses for a core the
profile already documents; without it the reverse index cannot reach
the profile and target filtering skips it.
A region- or target-filtered build wrote to the same filename as the
full one. Both filters now appear in the pack and manifest names, and
verify.py accepts --region for emulator and system reports so the
coverage figures come from the same selection the builder used.
A profile whose builds live in separate repositories keys source,
upstream and source_commit by build mode. The site flattened the URLs
but read a single scalar revision, so a libretro fork could be pinned
to the standalone commit, and binding the object form into SQLite
failed outright once ymir adopted it. URL and revision are now read as
pairs.
The site also published a sitemap nothing pointed at, so robots.txt is
generated alongside it.
Two builds of the same pack from the same inputs produced different
archives. Of 67 members, 65 were already identical: only README.txt
and manifest.json differed, both stamped with the wall clock by
writestr and the second carrying a generated timestamp. Generated
members now use the epoch the archive rebuilder already applies, and
the timestamp comes from the database snapshot the pack was built
from, so the same data yields the same bytes.
Install manifests skipped archived platforms, which is why RetroPie
had none; archived means upstream is no longer scraped, not that the
packs stopped shipping. A target-filtered manifest also had no record
of its filter beyond the filename, so it carries one the way a
region-filtered manifest already does.