The pack builder accepts the aliases declared in the target overrides,
so --target switch works there, but the installer's target manifests
carried only canonical names. The documented word was the one that
failed, and the installer then carried on with every file: 1911 files
and 4.1 GB where the user had asked for the 863 that target needs.
Aliases are emitted beside their canonical target, and an unknown
target now stops the run and lists what is available. A filter is
applied or refused, never ignored.
The gap analysis answered from the name index, so a core extra whose
local copy contradicts its declared hash counted as held. Under a
digest mode the builder drops exactly that file, so the coverage report
described a pack that would not contain it: seven files across
Batocera, Recalbox and RetroBat.
An entry that states what its content should be is now resolved by
content; the name still answers for entries that declare nothing to
check against, and existence mode is unchanged because there the
frontend never opens the file and the pack does carry it.
The per-emulator report counted an entry nobody can supply -- a
per-user key, a slot the user fills, a dump that was never made -- as
plainly missing. fpse-ng read 14 missing when twelve were documented as
unobtainable, which invites the wrong repair: dropping the flag,
deleting the entry, or chasing a vendor's whole install tree.
They are listed with the reason the profile records rather than hidden,
and the summary counts them apart. Platform reports are untouched.
The per-emulator report captured the status resolve_local_file returns
and then ignored it: any non-empty path became OK. An entry whose only
candidate contradicts its declared hash therefore read as covered, so a
same-named file from another system stood in for one the collection
does not hold. 36 entries across 14 profiles were affected, among them
config.ini, ROM and rom2.bin, names that collide across systems.
Emulator validation still runs first, since it names the field that
disagrees; the resolution status is consulted only when validation had
nothing to say.
export_native turns the profile data back into each platform's own
file, for a maintainer there to pick up and use, and none of the ten
exporters had a test. Coverage goes from 0 to 83%.
Writing them found the EmuDeck exporter rejecting its own output: its
export skips placeholder entries, its validate looked for them anyway
and reported the omission as a missing hash. Both sides apply the same
filter now.
The placeholder assertion initially passed for the wrong reason twice
over -- the fixture entry had no hash, so it was dropped as incomplete
rather than as a placeholder, and the assertion then read the name
while the exporters write the path. It is pinned on an unmistakable
destination now, and removing the guard fails two tests.
The requirement parser read core, hashMatchMandatory and note from
each bios element and discarded all three, which reads like a dropped
attribute: hashMatchMandatory decides whether a wrong hash is yellow or
red on Recalbox. It is not lost -- the config parser below captures it
for the YAML -- so these were leftovers, and they cost a look to
confirm that.
Two yaml imports left unused by the move to the shared loader go too.
validate_site reached complexity 43 doing three things at once. The
per-page checks and the link resolution are now separate functions and
the caller keeps only the cross-page duplicate check, which cannot run
until every page has been seen.
The first attempt left the link pass calling a closure that had moved,
and running it against the real site did not catch that: no page there
has a broken link, so the error path never ran. The unit test covering
a deliberately broken fragment did.
_diff_system reached complexity 42, and its hash-based rename fallback
is the part that stands alone: a platform is free to call a file
whatever it likes, so a name matching nothing is not yet a gap, and
counting one file as both missing and extra invents a discrepancy.
That step is now its own function at complexity 31, with the tests it
never had: pairing on any of the three digests, case folding, non-string
values, and the case where two files simply have no hashes and so are
not evidence of anything. diff_truth output is unchanged.
Regenerated with the large-file cache populated, the state CI builds
from: without it ten preserved entries resolve differently and the
counts drift by one file.