docs: state each verification rule once

architecture.md drew path_suffix ahead of SHA1 and listed a core
resolution that missed the retroarch list entry and built_by. Both now
link to the one statement that matches common.py. The Recalbox table
read hashMatchMandatory into verify.py, which never reads it, and
md5_composite hashes member contents, not member MD5s
(Zip.cpp:71-96). The validation index is built from the platform's
resolved profiles only. The requirement table gains the fields that
make a platform YAML reversible, and pages that name a platform list
say what changes rather than judging it.
This commit is contained in:
Abdessamad Derraz committed 2026-10-21 05:22:38 +02:00
1 parent 9edf785513
commit 5e70fe7ff5
7 files changed
+249 -110

No files matched your search

+13 -52
View File
@@ -88,7 +88,7 @@ emulators/*.yml verify.py checks generate_pack.py resolves
truth.py generates diff_truth.py export_native.py
ground truth from compares truth vs rewrites each platform's
emulator profiles scraped platform own file, corrected
emulator profiles scraped platform own file, updated
```
Pipeline runs all steps in sequence: DB, provenance report, data dirs,
@@ -127,14 +127,13 @@ graph LR
The pack combines platform baseline (layer 1) with core requirements (layer 3).
Neither too much (no files from unused cores) nor too few (no missing files for active cores).
A same-named local file that contradicts an explicit hash is recorded as an
unsafe omission on hash-verifying platforms, while existence platforms ship it and
report the divergence, because their code never reads the bytes.
A same-named local file that contradicts a declared hash is settled by the
platform's verification mode ([discrepancy detection](verification-modes.md#discrepancy-detection)).
The emulator's source code serves as ground truth for what files are needed,
what names they use, and what validation the emulator performs. Platform YAML
configs are scraped from upstream and are generally accurate, though they can
occasionally have gaps or stale entries. The emulator profiles complement the
configs are scraped from upstream and record what each platform declares. A
list kept by hand can lag behind an emulator release. The emulator profiles complement the
platform data by documenting what the code actually loads. When the two disagree,
the profile takes precedence for pack generation: files the code needs are included
even if the platform does not declare them. Files the platform declares but no
@@ -143,7 +142,8 @@ upstream may cover cases not yet profiled.
A platform YAML is regenerated by its scraper and never edited by hand: an
edit would be lost at the next scrape, and the file would stop describing the
platform. What the platform gets wrong is answered in the other two layers.
platform. Where the emulator source states something else, the profile and
`_shared.yml` carry it.
Another name for the same file is an `aliases:` entry in the profile, never a
second entry in a platform YAML or in `_shared.yml`. A name a platform's own
launcher reads, such as the 22 names Batocera's DuckStation generator tries
@@ -373,46 +373,10 @@ platform's own verification mode.
### File resolution chain
`resolve_local_file` in `common.py` tries each strategy in order, returning the
first match. Used by both `verify.py` and `generate_pack.py`.
```mermaid
graph TD
START([resolve_local_file]) --> S0{path_suffix<br/>exact match?}
S0 -- yes --> EXACT([exact])
S0 -- no --> S1{SHA1<br/>exact match?}
S1 -- yes --> EXACT
S1 -- no --> S1B{SHA256<br/>exact match?}
S1B -- yes --> EXACT
S1B -- no --> S1C{CRC32 + size,<br/>no stronger hash?}
S1C -- yes --> EXACT
S1C -- no --> S2{MD5 direct<br/>or truncated?}
S2 -- yes --> MD5([md5_exact])
S2 -- no --> S3{name + aliases<br/>no MD5?}
S3 -- yes --> EXACT
S3 -- no --> S4{name + aliases<br/>md5_composite /<br/>direct MD5?}
S4 -- match --> EXACT
S4 -- name only --> HM([hash_mismatch])
S4 -- no --> S5{zippedFile<br/>inner ROM MD5?}
S5 -- yes --> ZE([zip_exact])
S5 -- no --> S6{MAME clone<br/>map lookup?}
S6 -- yes --> MC([mame_clone])
S6 -- no --> S7{data_dir<br/>cache scan?}
S7 -- yes --> DD([data_dir])
S7 -- no --> S8{agnostic<br/>fallback?}
S8 -- yes --> AG([agnostic_fallback])
S8 -- no --> NF([not_found])
style START fill:#2d333b,stroke:#adbac7,color:#adbac7
style EXACT fill:#2d333b,stroke:#adbac7,color:#adbac7
style MD5 fill:#2d333b,stroke:#adbac7,color:#adbac7
style HM fill:#2d333b,stroke:#adbac7,color:#adbac7
style ZE fill:#2d333b,stroke:#adbac7,color:#adbac7
style MC fill:#2d333b,stroke:#adbac7,color:#adbac7
style DD fill:#2d333b,stroke:#adbac7,color:#adbac7
style AG fill:#2d333b,stroke:#adbac7,color:#adbac7
style NF fill:#2d333b,stroke:#adbac7,color:#adbac7
```
`resolve_local_file` in `common.py` turns a file entry into a local path, and
`verify.py` and `generate_pack.py` both call it. Every declared hash is tried
before a path or a name, so a path never wins over a hash. The steps, in order,
are listed under [file resolution chain](verification-modes.md#file-resolution-chain).
## Platform inheritance
@@ -420,11 +384,8 @@ Platform configs support `inherits:` to share definitions.
Lakka inherits from RetroArch, RetroPie inherits from RetroArch with `base_destination: BIOS`.
`overrides:` allows child platforms to modify specific systems from the parent.
Core resolution (`resolve_platform_cores`) uses three strategies:
- `cores: all_libretro` - include all profiles with `libretro` in their type
- `cores: [list]` - include only named profiles
- `cores:` absent - fallback to system ID intersection between platform and profiles
Which emulator profiles a platform resolves follows its `cores` field, as
[adding a platform](adding-a-platform.md#required-fields) describes.
## Hardware target filtering