Commit Graph
123 Commits
Author SHA1 Message Date
Abdessamad Derraz 77a39b2f4e perf: reuse diffs and raise the file size cap 2026-08-10 16:48:59 +02:00
Abdessamad Derraz 77dff6377e fix: keep fbneo per-rom refs and archive names 2026-08-10 16:47:20 +02:00
Abdessamad Derraz d588ebbde4 chore: restore large files before ci coverage checks
A CI checkout omits every file over 50 MB, so verify and generate_pack
resolve those database entries against a disk that does not hold them and
report them missing. The generated README then stops matching the
committed one for a reason that has nothing to do with staleness.

restore_large_files.py writes them back from the release cache, matched by
SHA1 rather than by name, and only where the path is gitignored and
absent. The site workflow runs it, and refreshes the data directories, before
generating.
2026-08-10 14:34:27 +02:00
Abdessamad Derraz 29ff87a99b feat: publish versioned data exports
The metadata behind the verifier, the pack builder and the site is now
served as static files: a versioned JSON API, CSV extracts, a SQLite
snapshot, and a catalog carrying a SHA-256 for each artifact.

The gaps dataset covers both layers behind a layer column. It previously
held one row, the single platform-verification anomaly, while the page
offering it as a download led with the emulator-level count.

source_ref renders as a permalink pinned to the revision the profile
cites. When a profile declares two repositories, a path that belongs to
neither by name is left as plain code: a citation without a link still
names the file and the lines, a link to the wrong repository does not.

The table filter, focus outlines and tap targets are progressive
enhancement; the pages work without them.
2026-08-10 13:37:01 +02:00
Abdessamad Derraz 9001ebb992 feat: harden the installer boundary
The manifest is untrusted input. It is now read under a size limit and
validated before use: destinations are contained below the BIOS root,
repo_path stays inside bios/, release_asset is a basename, hashes match
their shape, declared totals match their lists, and every entry has a
download source.

Downloads stream against the declared size, are checked by SHA-256 then
SHA-1, land in a per-process temporary file and are installed with
os.replace. Copies into standalone-emulator directories are opt-in with
--standalone-copies so a detection never writes outside the selected
tree.

Both bootstraps verify install.py against an embedded SHA-256 before
running it, and require the Python version install.py actually needs.

A target that publishes no core list is a target with no filter, not a
broken manifest: rejecting it disabled --target for the whole platform.
2026-08-10 13:36:52 +02:00
Abdessamad Derraz 33a9934a11 feat: identify romsets from version recipes
A profile's contents: block and a DAT both state, per set, the members
one emulator version expects. Torrentzip makes archive bytes a function
of that list alone, so a recipe plus the roms reproduces the archive
exactly.

MAME ships its -listxml as a release asset and FBNeo keeps its dats in
its repository, so neither needs a browser. The importer streams the
311 MB document with a sliding window, resolves romof parents in two
passes, drops undumped members, and accumulates versions instead of
replacing them. Identical recipes shared across versions are stored once
with dats listing every version that agrees: 22 MAME versions give 23679
entries for 1726 distinct recipes, 18 MB down to 2.2 MB.

Snapshots live in recipes/ because load_provenance_snapshots reads every
provenance/*.json as a dump catalogue, and a recipe is not one.

1113 archives now reproduce byte for byte, against 175 from profiles
alone, and spec128.zip is rebuilt from roms already held.
2026-08-10 13:36:12 +02:00
Abdessamad Derraz e8ee8b0954 fix: decide hash mismatch by native mode
A declared hash that the local dump contradicts is not one situation. An
existence platform never reads the bytes, so withholding the file lets an
upstream list error remove something the frontend would have loaded; a
hash platform would reject it, so shipping it is pointless.

The mode now decides, at every point that had an opinion: pack building,
core complement, emulator packs, manifests, conformance and
_intentional_hash_exclusion. verify.find_undeclared_files follows, since
verify and generate_pack must agree file for file.

Also here: resolution reports which evidence matched rather than a flat
"exact", a path or filename can no longer override a declared hash, and
safe_extract_zip treats a Windows backslash as the separator it is
instead of refusing the archive.
2026-08-10 13:36:03 +02:00
Abdessamad Derraz 597a8ff919 fix: quote rom and core names in yaml
YAML 1.1 reads an unquoted 01 as the integer 1 and 81 as 81, so the
manager set stopped naming the file its driver opens and the API
published "cores": [2048] as a number where consumers match strings.

Ground truth from MAME 0.289 at the revision the profile cites:
src/mame/vtech/crvision.cpp:957 loads "01" and "23".

The root cause was the scraper: _hash_merge wrote these names through an
f-string, so quoting the profiles alone would be undone on the next
refresh. _yaml_scalar now quotes every name, archive and description it
writes.
2026-08-10 13:35:42 +02:00
Abdessamad Derraz 5d417c8229 feat: add data contract validation
JSON Schemas for the database, install and pack manifests, target
manifests, site API envelopes and stats, plus the semantic invariants a
schema cannot express: declared totals matching their lists, no
destination both installed and omitted, database keys matching their
sha1. validate_site.py checks the rendered HTML for metadata, headings,
image alternatives, duplicate ids and unresolved local links.

Pack manifests are read from inside the generated archives, where
generate_pack writes them, rather than from a dist/ glob that matches
nothing.

Emulator and platform schemas gain additionalProperties: false, and
cores[] plus contents[].name must be strings: an unquoted 81 or 01 in
YAML parses as a number and stops matching the upstream name.
2026-08-10 13:35:33 +02:00
Abdessamad Derraz 45f89cc6c0 feat: add region filters and profiles 2026-08-09 14:15:56 +02:00
Abdessamad Derraz 731096cf12 chore: refresh mame bios refs from 0.289 2026-08-08 13:50:25 +02:00
Abdessamad Derraz 89211003cb fix: refresh mame refs when a driver line moves 2026-08-08 13:48:54 +02:00
Abdessamad Derraz fa6de11133 feat: parse colon continuations and header stems 2026-08-08 13:44:03 +02:00
Abdessamad Derraz 17da2ae76f feat: follow refs to a unique declared value 2026-08-08 13:39:54 +02:00
Abdessamad Derraz c8e05013d9 feat: follow a ref when its subject moved with it 2026-08-08 13:38:30 +02:00
Abdessamad Derraz 4c5ca17682 feat: judge tag-pinned profiles on their own revision 2026-08-08 13:12:35 +02:00
Abdessamad Derraz 763c159a9f feat: rewrite annotated refs keeping their prose 2026-08-08 12:35:02 +02:00
Abdessamad Derraz 16331a1712 feat: report external citations as unverifiable 2026-08-08 12:30:37 +02:00
Abdessamad Derraz dc4b23a883 feat: anchor on declared values when refs miss 2026-08-08 12:24:31 +02:00
Abdessamad Derraz 6b0306b43d feat: settle ambiguity by file line shift 2026-08-08 12:21:13 +02:00
Abdessamad Derraz 34876ba610 fix: keep refs and pin on the same revision 2026-08-08 12:16:01 +02:00
Abdessamad Derraz c585452d46 feat: resolve bare and annotated ref paths 2026-08-08 12:05:59 +02:00
Abdessamad Derraz e39a6c5894 chore: wrap long test lines 2026-08-08 11:52:28 +02:00
Abdessamad Derraz 8ffe30efc8 feat: parse annotated and mode-keyed refs 2026-08-08 11:50:25 +02:00
Abdessamad Derraz 3abeb77a48 fix: match the scoped provenance headline 2026-08-08 11:47:31 +02:00
Abdessamad Derraz a17945ec66 fix: match source_ref lines by value 2026-08-08 11:47:21 +02:00
Abdessamad Derraz 7f8a277721 fix: retry transient network failures 2026-08-08 11:37:15 +02:00
Abdessamad Derraz 19a69bbd88 fix: treat only quota signals as fatal 2026-08-08 11:27:40 +02:00
Abdessamad Derraz 2ebe29a449 fix: survive a single forge failure 2026-08-08 11:23:49 +02:00
Abdessamad Derraz 8957f86d46 fix: send github token to github only 2026-08-08 11:23:49 +02:00
Abdessamad Derraz ec51a2d6da chore: cover commented bios flags in mame 2026-08-08 11:17:21 +02:00
Abdessamad Derraz ccb9b3e94f feat: add profile sync against upstream 2026-08-08 11:17:21 +02:00
Abdessamad Derraz b26a874966 fix: link only system icons upstream serves 2026-08-08 09:59:07 +02:00
Abdessamad Derraz 25f8537a4a fix: point manifest entries at a fetchable file 2026-08-08 06:19:38 +02:00
Abdessamad Derraz c51fc233f9 fix: avoid shared scratch path in large-file cache 2026-08-08 06:19:38 +02:00
Abdessamad Derraz a483ed93b0 refactor: stream zip rebuild instead of buffering 2026-08-08 04:40:07 +02:00
Abdessamad Derraz 69d53c97c9 feat: add launchbox detection to installer 2026-08-08 04:24:17 +02:00
Abdessamad Derraz 45dbc30301 feat: lock pack artifacts during pipeline runs 2026-08-08 04:24:03 +02:00
Abdessamad Derraz f008568108 feat: publish dump provenance page 2026-08-08 03:23:35 +02:00
Abdessamad Derraz 48b415e0d5 feat: import no-intro and tosec dump catalogs 2026-08-08 02:48:06 +02:00
Abdessamad Derraz f4b02c2a43 feat: join dump-catalog provenance in database 2026-08-08 02:25:44 +02:00
Abdessamad Derraz 227ad27b15 feat: validate platform input in installers 2026-08-07 16:23:15 +02:00
Abdessamad Derraz 8bd2083e80 feat: report hash proof in existence packs 2026-08-07 16:23:15 +02:00
Abdessamad Derraz 42e2f363ec feat: audit profile refs against upstream 2026-08-07 16:23:15 +02:00
Abdessamad Derraz 3ecb72d275 fix: deflate manifest on zip append path 2026-08-07 15:45:48 +02:00
Abdessamad Derraz 587aadde08 fix: coerce numeric hashes to strings 2026-08-07 15:30:37 +02:00
Abdessamad Derraz 18c7b31734 fix: honor platform filter in cross-reference 2026-08-07 13:28:15 +02:00
Abdessamad Derraz 8663ec17b7 feat: add misterfpga platform support 2026-08-07 13:28:15 +02:00
Abdessamad Derraz 3a5cbc4c6c fix: resolve large file assets renamed by github 2026-08-07 11:53:29 +02:00
Abdessamad Derraz 792bad3fd5 fix: align pack checks with builder, purge stale packs 2026-08-06 16:41:47 +02:00