evidence/webui-library-edits/check.py, run against build 191ff52c with a test
ROM it makes itself (a looping NES program): Add Game 201; a rename becomes
the game's RetroArch playlist label; Delete game takes the file, the playlist
entry and the details, and the game leaves the library. The console has no
RetroAchievements account, so issue 58's field is covered by the host test
only. The temporary playlist and the test files were removed afterwards.
Evidence: python3 tools/evidence.py compare evidence/: 146 replayed, 0 failed.
Co-Authored-By: Claude <noreply@anthropic.com>
Dolphin sizes its custom asset cache from MemPhysical(), whose FreeBSD branch
gives the PS5 no usable size, so the budget was 0 and every texture of a pack
was unloaded as soon as it loaded (issue 5: "Not enough system memory for
custom resources"). On __PROSPERO__ the cache now gets a fixed 512 MiB, a
share of the title's own memory (about 870 MB flexible memory free in play).
CustomAssetCache is MemPhysical's only user.
Evidence (python3 tools/evidence.py compare evidence/: 146 replayed, 0 failed):
- evidence/dolphin-texture-budget-before: build a2c7800a: the error at start.
- evidence/dolphin-texture-budget: build 191ff52c, Load Custom Textures on and
the owner's pack in place, tests/pad/dolphin-texture-pack.txt: no error, no
asset unloaded, the game to the script's STOP at about 60 frames a second.
Whether the pack's pictures show is the owner's check on the screen; Dolphin
does not log it at this level.
Co-Authored-By: Claude <noreply@anthropic.com>
PPSSPP reported its current internal resolution as its maximum geometry, so
any increase made RetroArch restart the video driver (runloop.c compares
max_width/max_height). RetroArch keeps the cached Vulkan device across that
restart and calls neither context_destroy nor context_reset, so PPSSPP's render
thread kept the freed vk_t's interface and called a null function (issue 63:
signal 11, rip=0, [rsp] inside the core). The maximum is now always 10x
(4800x2720, the largest option and the PS5 default profile), so a change is a
geometry update; with hardware rendering RetroArch creates no textures from
the maximum, and default users already had it.
Evidence (python3 tools/evidence.py compare evidence/: 146 replayed, 0 failed):
- evidence/ppsspp-resolution-crash-before: build a2c7800a, tests/pad/
ppsspp-resolution-change.txt (2880x1632 to 3840x2176 at 30 s): the second
video_vulkan init, then the reported crash, [rsp]=0x000000040084aabb.
- evidence/ppsspp-resolution-change: build 191ff52c, the same script:
SET_SYSTEM_AV_INFO 3840x2160 and NotifyDisplayResized 3840x2160 with one
video_vulkan init; the 45 s screenshot and the 55 s STOP, no crash.
Gates: tools/verify.sh, all five (format, unit 215, build, integration 215,
evidence 141), before the evidence was added.
Co-Authored-By: Claude <noreply@anthropic.com>
67b7fed made playlist labels with Json{Json::string, false, 0, text}, which the
WebUI daemon's -Wextra -Werror build refuses (missing-field-initializers for
items and fields); tools/verify.sh's unit gate failed at
test_webui_daemon's setUpClass. Json::of(text) makes a string value.
Test: python3 -m unittest tests.test_webui_daemon
tests.test_scraper.Scraper.test_delete_game
tests.test_scraper.Scraper.test_game_files_and_edited_metadata: 7 OK.
Co-Authored-By: Claude <noreply@anthropic.com>
A game added twice (a CHD and an ISO of one disc) could not be removed from the
library (issue 57). The game sheet's Files tab has a Delete game button, which
calls POST /api/library/delete: the game's file (inside the content folder or
a USB or extended drive only, as game_files allows), the files a .cue, .gdi or
.m3u names in its own folder, and its entries in every playlist. Its details
and media, keyed by its name, go only with the last copy of that name; an
archive that holds other games is refused, with nothing changed. Saves and
savestates stay. New texts in all 15 languages.
Test: python3 -m unittest tests.test_scraper (15 OK; test_delete_game: the
ISO goes and the CHD keeps the shared details, the last copy takes them, a
cue's tracks go but a name outside its folder stays, a two-game archive is
refused, a file outside content answers 404); tools/webui-strings.py --check:
821 strings, 0 problems.
Co-Authored-By: Claude <noreply@anthropic.com>
A rename in the WebUI was written only to the game's metadata (issue 55).
RetroArch's menus (XMB, RGUI) show the playlist label, which never changed,
and ES-DE took the new name only while its own was still the label, so a
second rename was dropped. src/scraper.cpp now rewrites the game's entry in
every playlist that lists its file (edit_playlist_entries, also for removals),
with Json::dump in src/scraper_json.h; ES-DE's adapter lets every field the
owner edited win (frontends/es-de/ps5/library_ps5.cpp).
Tests: python3 -m unittest tests.test_esde_library tests.test_scraper: 15 OK
(the label changes, the other entries and the playlist's fields stay; two
renames in a row both reach ES-DE's gamelist, its favourite kept).
Co-Authored-By: Claude <noreply@anthropic.com>
A sign-in removes cheevos_password and keeps cheevos_token (src/ps5_cheevos.c),
so the settings page showed the password as "Not set" and owners typed it
again (issue 58). GET /api/config now reports cheevos_password as set while a
token is saved; neither value is ever sent.
Test: python3 -m unittest tests.test_webui_secrets (the token alone reads as
set, no token as not set, the token never in the answer): OK.
Co-Authored-By: Claude <noreply@anthropic.com>
The owner added a Samba user and a share that refuses guests ([locked],
over the same folder) on the PC, saved it with the password in the console's
WebUI SMB page and started the homebrew NES ROM from Load Content > SMB.
config/smb.cfg holds the user and password; GET /api/smb answers only
password: true; retroarch.log shows smb://<pc>/locked/smb-test listed and
the ROM loaded (build a2c7800a, aa7f0b2's code).
Evidence: evidence/smb-password (python3 tools/evidence.py compare
evidence/: 141 replayed, 0 failed).
Co-Authored-By: Claude <noreply@anthropic.com>
The WebUI's new SMB page signs in to one server (guest or a user and
password), lists its shares, checks a share and folder and saves them in
config/smb.cfg on the console; the password is never answered back.
RetroArch's file browser shows the share as SMB, after INTERNAL and
EXTERNAL. smb:// paths go through RetroArch's VFS to src/ps5_smb_vfs.c
(patches/series 0136), read-only and only on the saved server: a core that
reads through the VFS streams the file, one that opens paths itself gets a
copy in /app0/smb-cache, removed when the content closes.
libsmb2 is pinned at the master revision itsPLK/ps5-pkg-manager runs on the
PS5 (LGPL-2.1-or-later), built by tools/build-libsmb2.sh for the PS5 and the
host and listed in tooling/notices/components.json: RetroArch 1.22.2 has no
SMB client. In a title, getaddrinfo is bound to the platform layer's, which
resolves nothing, so libsmb2's resolver calls go to RetroArch's own
(src/platform_wraps.c); readv, writev, getlogin_r and getprotobyname are
wrapped, so libsmb2 adds no import. SMB sockets set SO_NOSIGPIPE.
Evidence: evidence/smb-load-content (python3 tools/evidence.py compare
evidence/): on the Base PS5 the console's WebUI listed the PC's guest share
and saved share/smb-test; Load Content > SMB listed it and a homebrew NES
ROM on it ran under FCEUmm, read through the VFS (build a2c7800a,
retroarch.log read back over FTP).
Gates: tools/verify.sh (format, unit 214, build, integration, evidence 140)
with PS5_REUSE_STAGED_CORES=ps5sx2: in this worktree the SDK's prospero-lld
wrapper adds -pie to ps5sx2's link (clang passes its long object list in a
response file the wrapper cannot read), so ps5sx2 is the main checkout's
build of the same pinned revision. Host tests run a Samba server of their
own (tests/smb_server.py, no root).
Co-Authored-By: Claude <noreply@anthropic.com>
releases/v3.0.0-beta-3.md opens with the anti-piracy warning, then thanks
each contributor with what they brought (#34, #54, #53, #52, #50, #62),
then the release. assets/releases/v3.0.0-beta-3/game-forwarder.webp is the
owner's screencast as an animated WebP (1100x584, 95 frames, 6707 ms,
looping, 535016 bytes), shown inline on the release page.
Evidence: the note rendered through GitHub's Markdown API
(gh api /markdown, gfm, repository context) with github-markdown-css 5.5.1:
every icon and avatar at its set size on desktop and at 311 px of content
(a 375 px phone), no table wider than the page there; the at-a-glance
icons now carry their names, so they keep 40 px on a phone.
The owner's report: tiles deleted in the page stayed on the home screen after closing
RetroArch (from the home screen, and with the picker's Quit). The console's records showed
the removals done, but late: ShadowMountPlus refuses an uninstall while a game runs, and
the WebUI's daemon only tried again at its stop, 20 s after the title closed; a title
reopened within those 20 s left them for the next close.
The daemon now tries a tile's pending work (a removal, a new name or picture) as soon as
no program of the title is linked, and every 3 s while ShadowMountPlus still refuses (the
exiting app answers "game active" for a moment); the try at the stop stays for what is
left. ps5_forwarders::finish_pending says whether anything still waits, and runs under the
WebUI's lock (the page may be open meanwhile). README: "a few seconds after RetroArch
closes".
Evidence:
- evidence/game-forwarder-delete-on-close: on the console, a tile installed, deleted
through the WebUI while RetroArch ran ({"state":"pending"}), RetroArch closed:
/user/appmeta/PPSA99170 gone after 3.0 s; the daemon "13:18:48 not removed yet ...
game_active", "13:18:51 forwarder PPSA99170: removed"; ShadowMountPlus "uninstall
requested" at 13:18:51 (before: 20 s and more).
- tests/test_webui_daemon.py test_a_tile_removal_is_done_as_soon_as_the_title_closes:
nothing while a program is linked, the uninstall within 1.5 s of the unlink, before
the stop (2 s in the tests); test_webui_forwarders checks finish_pending's answer.
- gates: format, unit (211 tests), build, integration (211 tests), evidence (139
captures, 0 failed) - PASS.
evidence/game-forwarder-webui (tools/evidence.py distil of klog/game-forwarder-webui/
record.txt, game names masked): on the owner's base PS5 (13.40, ShadowMountPlus
1.7-beta5fix1), builds 9adce7a0 (8a31a1f) and 57fc257a (2512f39):
- the routes from the PC: a tile made (PPSA99171, its files and param.json, in
manual.lst), installed by ShadowMountPlus once RetroArch closed, opened (five
arguments, "forwarder: /app0/content/snes/<game> with snes9x, closing after it"),
renamed and re-pictured and the spike's tile deleted while RetroArch ran, both
finished by the daemon once it closed ("removed", "installed again with its new name
or icon"; /user/appmeta shows the new name and icon);
- the page in a browser: 33 systems in the picker, each with its icon; a tile made from a
SNES game's 3D box and one from a Genesis game's logo with the system's icon in the
corner ("Saving..." while ShadowMountPlus answered); an installed tile deleted ("leaves
the home screen once RetroArch closes"), uninstalled and its folder gone once RetroArch
closed; the home screen's icons are byte for byte the PNGs the page drew (512x512);
the Genesis tile opened its game with genesis_plus_gx and closed after it.
Not checked (human_check): a tile opened on the home screen while RetroArch is open
should bring up the console's prompt to close it; the control payload cannot press the
home screen.
README: "Start a game from a home screen forwarder" opens with "Make a tile in the
WebUI" (the page, ShadowMountPlus 1.7 or later, why changes wait for RetroArch to
close, where games may be); the arguments follow as "Make a forwarder by hand",
unchanged. No line removed.
Gates: format, unit (210 tests), build, integration (210 tests), evidence (138
captures, 0 failed) - PASS.
A "Game Forwarder" entry in the WebUI's sidebar (webui/forwarders.js, its section in
webui/index.html): the tiles with their picture, name, game, core and state (on the
home screen, appears / changes / leaves once RetroArch closes), a New tile editor, Edit
and Delete. ShadowMountPlus's state heads the page; without it, nothing can be made.
The editor: the system first, each behind its icon as on the Games page (a listbox
like the language picker's, by mouse or keyboard), then one of its games by name; the
name on the home screen and the core, prefilled with the game's; "Close RetroArch when
the game ends"; and the picture, drawn here in a 512x512 square and sent as a PNG:
box art, 3D box, logo, cartridge or disc always offered (greyed out when the game has
no such file yet, with a pointer to Download Media), screenshot, title screen and fan
art when it has them, RetroArch's icon; a cutout fits the square, a picture fills it
(both can be changed), and the system's icon can sit in the bottom right corner on a
dark plate. Saving says "Saving..." while ShadowMountPlus answers.
A tile opens a game in the content folder (a path inside it) or on a USB or extended
storage drive (its own path), as the library lists them (src/ps5_forwarders.cpp).
36 new texts, in every language of the WebUI (tools/webui-strings.py --check).
Evidence:
- tests/test_webui_forwarders.py test_page_in_chromium (tests/webui_forwarders_browser.cjs,
Chromium against the native server and the ShadowMountPlus stand-in): the system
picker (icon, listbox, Escape, choice), the game, name and core prefilled, the
pictures offered and greyed out, a logo fitted and a cover filling the square, the
system icon's plate in the corner, a tile created (its icon a 512x512 PNG), edited
(picture kept, corner and fill options off), deleted; no page error; nothing wider
than a 390 px phone - OK. The route tests take the drive paths' rule (a "/mnt/usb0/.."
path refused) - 4 tests OK.
- console (base PS5, ShadowMountPlus 1.7-beta5fix1), the page in a browser: the tile
list read from the console; a SNES game's tile made with its 3D box fitted
(PPSA99170, "appears on the home screen once RetroArch closes"); a second, waiting
tile deleted from the page at once; 33 systems in the picker, each with its icon.
- gates: format, unit (210 tests), build, integration (210 tests), evidence - PASS.
The host tests found a free port by binding port 0 and closing it, then started the
WebUI's server on it. In between, any connection on the machine can take that port as
its own (the same ephemeral range): the server then exits at once, "Failed to bind to
port N: Address already in use", and the test waited out its window and failed with
"the server did not start" (test_scraper, test_scraper_launchbox) or "HTTP server
exited" (test_webui). It happened in about one gate run in three, under JOBS=4 or not.
tests/webui_build.py start() starts the server, waits for its status and returns the
process, port and session token; a server that exits before answering is started again
on another port (five tries). Every harness that started the server itself uses it:
test_scraper, test_scraper_launchbox, test_scraper_screenscraper, test_webui (its start
and two restarts), test_webui_language, test_webui_transfer_browser. test_scraper's
free_port() had no other user and is gone.
Evidence:
- the cause: 40 sequential starts with each server's stderr kept: 1 failed, "Failed to
bind to port 44505: Address already in use" (exit 1, after 0.02 s); through start(),
40 of 40 started.
- python3 -m unittest tests.test_scraper tests.test_scraper_launchbox
tests.test_scraper_screenscraper: OK; tests.test_webui tests.test_webui_language
tests.test_webui_transfer_browser: 21 tests OK.
- gates on the tree with the next commit: format, unit (210 tests), build, integration
(210 tests), evidence - PASS.
src/ps5_forwarders.{h,cpp}: a tile is /data/homebrew/<id> (PPSA99170 to PPSA99269, an
id no folder has and ShadowMountPlus knows nowhere) with the tile app and payload of
step 1, libc.prx, a param.json for its id and name, an icon and forward.txt (the
arguments, which also mark the folder as a tile: nothing else is listed, changed or
removed). ShadowMountPlus's HTTP API (127.0.0.1:10101, its docs/api.md 1.7) puts it on
the home screen: manual/add at once, installed when no game runs.
Routes (src/webui_ps5.cpp): GET/POST /api/forwarders (the list with ShadowMountPlus's
state, the cores, each tile's state; create), POST /api/forwarders/edit?id=,
PUT/GET /api/forwarders/icon?id= (a 512x512 PNG, up to 2 MiB), POST
/api/forwarders/delete?id=. The library JSON carries each game's core, to prefill it.
ShadowMountPlus refuses to uninstall while a game runs, and RetroArch is one whenever
the WebUI is up: a removal of an installed tile takes it out of the manual list at
once (so no scan installs it again) and is finished by the WebUI's daemon once the
title has closed (daemon/webui_daemon.cpp -> finish_pending): uninstall, then delete
the folder. A new name or icon on an installed tile is re-registered there the same
way (uninstall, back in the manual list, scan), and every tile's app and payload are
brought up to the build's.
Found on the console and handled: ShadowMountPlus 1.7-beta5fix1 can drop a source from
its manual list as it installs it (its next scan reads app.db before the install shows
there); the tile stays installed, and a re-registration adds it back first. Its game
list can take longer than 5 s after RetroArch starts: 20 s now, and a list that does not
arrive says why instead of showing every tile as waiting.
Evidence:
- host: tests/test_webui_forwarders.py against a stand-in for ShadowMountPlus's API:
create (first free id past a plain folder and a title ShadowMountPlus knows), the
files and param.json, validation (name, content path, "..", absolute path, newline,
core), edit, icon (size and format refused, stored, served), removal while busy
(pending, out of the manual list) finished by finish_pending, at once when not
installed, re-registration after the source was dropped, binaries refreshed,
ShadowMountPlus absent - 3 tests OK.
- console (base PS5 13.40, ShadowMountPlus 1.7-beta5fix1), through the WebUI from the PC:
GET /api/forwarders: ShadowMountPlus answers, the test tile PPSA99170 installed;
POST create -> PPSA99171 (eboot.bin, launch.elf, libc.prx, icon0.png, param.json
UP9000-PPSA99171_00-FORWARDER0099171, forward.txt with five arguments), in the
manual list; RetroArch closed -> ShadowMountPlus "installed game PPSA99171";
the tile opened -> tile.log "110832 sent to 127.0.0.1:9021 (errno 0)", launch.log
five arguments, RetroArch "forwarder: /app0/content/snes/<game> with
/app0/cores/snes9x_libretro.so, closing after it"; rename and icon -> updating,
delete PPSA99170 -> pending (manual list empty); RetroArch closed -> daemon
"forwarder PPSA99170: removed", "forwarder PPSA99171: installed again with its new
name or icon"; /user/appmeta/PPSA99171 titleName "Forwarder renamed" and the new
icon (first pixel 20 60 d0), /user/appmeta/PPSA99170 and /data/homebrew/PPSA99170
gone, app.db 33 -> 31 -> 32 entries; the daemon also replaced PPSA99170's older
launch.elf with this build's.
- gates: format, unit (209 tests), build, integration (209 tests), evidence - PASS.
A home screen tile is a title of its own (PPSA99170 to PPSA99269) that starts one
game in RetroArch. Titles cannot launch titles (sceSystemServiceLaunchApp returns
0x8094000F from one, sceLncUtilLaunchApp is a null import), so the tile hands a
payload to the console's ELF loader on 127.0.0.1:9021 and exits:
- forwarder/tile.c: the tile's eboot.bin. Reads its title id from
/app0/sce_sys/param.json, stamps it into /app0/launch.elf's slot, sends it to
the loader, logs /app0/tile.log, and leaves through LoadExec("exit") (a return
from main ends in a SIGSYS error notice).
- forwarder/launch.c: the payload. Reads /data/homebrew/<tile>/forward.txt (one
argument a line: --rom, --core, --exit-after-game, src/frontend_mode_ps5.cpp),
waits for the tile to leave, and starts PPSA99169 with those arguments through
sceLncUtilLaunchApp (sceSystemServiceLaunchApp as the fallback).
- tools/build-forwarder.sh builds both; tools/build-title.sh puts them in
dist/PPSA99169/forwarder/ and counts them in the title's identity; the notices
cover both files.
Evidence:
- host: python3 -m unittest tests.test_forwarder (the tile stamps and sends the
payload byte for byte, refuses a lowercase id, a missing or a doubled slot; the
payload passes the five arguments, falls back to SystemService, and an
unstamped payload starts nothing) - OK.
- console (base PS5, 13.40, ShadowMountPlus 1.7-beta5fix1), the test tile
PPSA99170 registered through ShadowMountPlus's manual list:
tile.log "tile PPSA99170: launch payload 110832 bytes, 110832 sent to
127.0.0.1:9021 (errno 0)"; launch.log five arguments, sceLncUtilLaunchApp
00002018; RetroArch's trace "forwarder: /app0/content/nes/<game> with
/app0/cores/fceumm_libretro.so, closing after it"; the tile exited cleanly
(no error notice), back to the home screen after the game.
- gates: format, unit (206 tests), build (tile 11,123 B, payload 110,832 B),
integration (206 tests; a first run timed out starting two scraper test
servers under load, both passed alone and on the rerun), evidence - PASS.
The workflow parked from mihawk-99/PS5_RetroArch#34 gave the title build
PS5_SCREENSCRAPER_DEVID and PS5_SCREENSCRAPER_DEVPASSWORD from repository
secrets. A public repository's workflow artifacts can be downloaded by
anyone, and the account is never published, so the parked copy no longer
passes them and its header says why. Nothing runs it; no value was ever
in the file.
Evidence: grep finds ScreenScraper only in that header line; format PASS.
Build 838fd9a3 (20dd7fe with both frontends and both optional cores) on
the owner's base PS5 (1440p, 120 Hz, VRR), offline:
- framegen-off-presents-once (0132): frame generation off with a 2 left
in retroarch.cfg logs "Off: each game frame is presented once (2
presents were kept)" and runs 602 frames in 10 s; turned off from its
XMB tab mid-game, the video output reinitializes (a 2.5 s gap) and the
same happens, 602 frames in the next 10 s.
- chd-flac-hash (0133): a CHD chdman made from one of the owner's
PlayStation backups (cdlz, cdzl, cdfl). Build 22b5d122: "Could not open
track" for nine consoles, "hash generation failed". This build: the
data track opens and RetroAchievements generates the hash, stopping
only at the sign-in.
- swanstation-console: the core loads, negotiates Vulkan with
RetroArch's context and boots the owner's BIOS dump; 574 frames in
10 s while the disc boots.
- melondsds-microphone (0134): the ps5 driver opens the first user's
AudioIn port at 48 kHz, captures while melonDS DS has its microphone
on (866,816 samples), reports the mute state and closes cleanly; the
game never read its microphone, so nothing was delivered (reads are
host-tested). melonDS DS at 60 frames a second.
- forwarder-launch (#34): the relaunch test hands the title a
forwarder's --rom, --core and --exit-after-game; the game runs in
RetroArch through game mode, the title closes when it quits, and the
next home launch opens the picker.
- pr-series-frontends: the picker and ES-DE of this build start; ES-DE's
library counts 35 cores with no failures. Once, the launch right after
a self-closing forwarder run ended before main(); not reproduced.
Game file names, the disc's serial and hash, and the console user id are
replaced in the records; pictures stay on this machine. The pad scripts
the commands name are in tests/pad/. Test files, the test CHD and its
memory card, framegen.cfg and melonDS DS.opt (both written by the runs)
were removed afterwards; retroarch.cfg is byte for byte as before.
Gates on this tree: format, unit (204), build (staged cores reused),
integration (204), evidence (137 captures, 0 failed) PASS.
.gitignore keeps every Markdown file but README.md and the release notes
on this machine, and c1ed6e5's cherry-pick added
tooling/swanstation/README.md past that rule. It is untracked again (the
file stays on disk), and README.md's build section now says how to
include SwanStation, as it does for melonDS DS. AngelXex's credit stays
where it was: native.patch's header, tooling/swanstation/notices.py and
the notices table.
Evidence: git ls-files '*.md' lists README.md and releases/ only;
format PASS; tests/test_notices.py PASS; no README line removed.
The two parts of mihawk-99/PS5_RetroArch#62 (Marco Tundo) that 0131 did
not already cover. Frame generation's plan writes the presents per game
frame into video_shader_subframes, which retroarch.cfg keeps. Once frame
generation was turned off, in its menus or in ES-DE's, the 2 it left
there held every game frame for two refreshes: half speed on a 60 Hz
output. retroarch.c now sets one present per game frame whenever frame
generation is off, and logs it when it replaces a larger number.
Turning frame generation on or off in the menus reinitializes the video
output, as a Target Framerate change already did, so the plan applies
at once (src/ps5_framegen_menu.c).
A Shader Sub-Frames value set by hand no longer survives a core load
while frame generation is off; sub-frame shaders have not been tested
on this console.
Evidence: tests/test_framegen_plan.py runs the plan as the script
inserts it. Two new cases start from a 2 left in retroarch.cfg with
frame generation off, on a 60 Hz output and on a VRR one; both fail
with 0132's edit left out. Gates: format PASS; unit PASS (197 tests);
build PASS; integration PASS; evidence PASS (131 captures). The build
gate ran with PS5_REUSE_STAGED_CORES naming the 33 shipped cores: core
stamps hash absolute paths, so in a worktree every core looks changed,
and the staged cores are main's. Console run: with this series' deploy.
Co-authored-by: Marco Tundo <marco@bymar.co>
The eight tools/*.ps1 scripts came in with 4df5c68 from
ps5-native-app-boilerplate and nothing in the build, the gates or the
docs runs them: the project builds and deploys from Linux only.
tools/prepare-assets.sh only wrapped prepare-assets.ps1, so it goes
too. .gitattributes loses the CRLF rule for *.ps1 and tools/lint.sh
no longer lists .ps1 among the files whose headers it checks.
Evidence: git grep finds no reference to any removed script;
tools/verify.sh format PASS; tools/verify.sh unit PASS (283 s,
klog/unit-gate.log).
The owner's base PS5 on a 1440p display with 120 Hz and VRR (48-120 Hz):
the driver lists only the 59.94 Hz mode (its idle vblank check read 20.873
ms, VRR's floor, and restored the default mode), and RetroArch's timed
flips came 8.32-8.35 ms apart, 119.877 and 119.898 a second. Frame
generation therefore planned at 119.88 Hz (Target Framerate 120, 1.99
pictures per game frame) and, on one of the owner's SNES game backups,
presented 119.9 pictures a second with 59.9 generated and the core at 59.9
calls a second (1.65 ms a picture). A self-made NES image looping on a
black screen gave the same timing and plan; its pictures never change, so
nothing was generated.
Evidence: evidence/framegen-flip-rate-vrr, distilled from the console's
retroarch.log (build 22b5d122); python3 tools/evidence.py compare evidence:
131 replayed, 0 failed.
ES-DE's library adapter writes custom_systems/es_systems.xml and the game
lists under /app0/es-de/ES-DE before ES-DE runs, but ES-DE makes that folder
itself only once it starts. On a fresh install's first start every mkdir
below it failed, all 29 writes failed (28 game lists and the systems file)
and ES-DE showed no games; from the second start on it worked. The earlier
ES-DE evidence never met this: those consoles had ES-DE's folder already.
The adapter makes the folder first.
Evidence: tests/esde_library_test.cpp's first start now begins without the
folder and checks 0 failures and a written systems file (it fails without
this change): python3 -m unittest tests.test_esde_library OK. On the
console, evidence/esde-folder-names: the first start before the change,
'28 systems, 255 games ... 29 failures', 'systems written -1'; the second,
0 failures; the first start after it (ES-DE's folder moved aside), '34
systems, 317 games ... 0 failures', 'systems written 34', every system's
path /app0/content/<name>; a home launch of a fresh install started the
picker (picker 1, es-de 1, remembered ask -> picker). python3
tools/evidence.py compare evidence: 131 replayed, 0 failed. tools/verify.sh:
all five gates PASS.
The content scan counted a system's .zip and .7z as games only when none of
its cores took a .cue or .chd, so a core that also runs a disc system hid a
cartridge system's archives: Genesis Plus GX (Sega CD) for the Mega Drive,
Master System, SG-1000 and Game Gear, PicoDrive (Sega CD) for the 32X,
Beetle PCE (the PC Engine CD) for the PC Engine and SuperGrafx. Their
archived games were in neither ES-DE nor the WebUI's library. Whether a
system's archives are games now goes by the system: the disc systems (psx,
ps2, psp, saturn, dreamcast, segacd, pcfx, 3do, neogeocd, gc, wii) keep
theirs out, as before, since RetroArch extracts only the file it loads and a
.cue's tracks would be left behind.
Evidence: tests/ps5_library_test.c, an archived game in an ES-DE megadrive
folder whose core also takes cue and chd (counted; it was not before this
change: the test failed on the game count) beside an archived PlayStation
disc (still left out): python3 -m unittest tests.test_ps5_library OK. On
the console (evidence/esde-folder-names): ES-DE's library went from 28
systems and 255 games to 34 and 317 with the same 325 game backups, the six
systems above among the new ones. tools/verify.sh: all five gates PASS.
Testers kept reporting folders EmulationStation did not detect. The title
made a folder in content/ for each system named as RetroArch's databases
are ("Sony - PlayStation 2"); it now names each as ES-DE names the system
("ps2", "snes", "genesis", the 50 platform ids, all of them ES-DE system
names checked against ES-DE 3.5.0's own systems file), so content/ is
ES-DE's own layout, <ROM folder>/<system>.
- ps5_library_make_system_folders makes content/ first when it is missing:
a copy of the title without its empty folders had none at all, because
the frontend made content/ only later and the step gave up.
- ps5_library_rename_system_folders, at each start before any frontend:
a folder an earlier build made under RetroArch's name is renamed to the
ES-DE one, or merged into it when none of its entries' names is taken
there (else left as it is, still its system's). The paths in RetroArch's
playlists (and their scan folders) and the per-folder overrides, core
options, shader presets and remaps under config/ follow; a core whose
folder bears the content folder's own name (MAME, ScummVM) keeps its
files, which are that core's. Folders the user named (PS1) stay as they
are and are still recognised.
- The WebUI's Add Game puts a game in the system's ES-DE folder.
- README: content/<system>/ with ES-DE's names (content/Saturn/ was out of
date: only system/Saturn is made).
Evidence: tests/ps5_library_test.c (system folders by ES-DE name, a missing
content folder made, a rename, a merge, a clash left in place, a folder
whose name only begins the same, playlists, per-folder settings, a core
folder named as the content folder): python3 -m unittest
tests.test_ps5_library OK. On the console (evidence/esde-folder-names,
with the commits after this one): a home launch renamed three seeded
folders (a rename and two merges), the playlist and options file followed,
and every ES-DE system path is /app0/content/<name>. tools/verify.sh: all
five gates PASS.
build-title.sh copied Mozilla's CA bundle from .deps/es-de, which only
tools/build-esde.sh clones, and it does so after this step and only for a
build with frontends. With .deps emptied, neither the development build
(the build gate) nor the all-target build could pass: both stopped at the
missing bundle. The bundle is now fetched by itself from ES-DE at the commit
build-esde.sh pins (one pin, read from that script), checked against its
sha256 (f66dff1b..., the same file ES-DE's checkout holds), and kept in
.deps/downloads.
Evidence: the pinned URL returns sha256 f66dff1bdf8f9606...; the
all-target build (PS5_FRONTENDS='es-de picker') then ran from a fresh
.deps through ES-DE, the picker and the notices to a verified package
(dist/PS5_RetroArch.zip, python3 tools/check-notices.py dist/PPSA99169:
the licences cover every shipped executable).
A batch stream that ends inside a file left that file's .upload- temporary
until the request was freed, after the 400 answer was sent: a client reading
the folder the moment the answer arrived could still find it. The gate's
test_batch_refuses_bad_names_and_bad_streams did, once, with the gates run on
four CPUs (taskset -c 0-3). BatchUpload::abandon() now closes and removes the
cut file before the answer; the destructor calls the same.
Evidence: JOBS=4 taskset -c 0-3 nice -n 10 bash tools/verify.sh: the unit
gate failed on that test before (a .upload- file left in content/batch-c)
and passed after (197 tests OK, 1 skipped); python3 -m unittest
tests.test_webui: 17 tests OK.
The owner's base PS5, on an output that does not offer 119.88 Hz, ran the
hotfix eboot.bin built from 5c4256b (identity 1f81446a). RetroArch timed
nine flips 16.67-16.69 ms apart, 59.943 flips a second in the 59.940 Hz
mode, and frame generation planned at 59.94 Hz (a 120 target becomes 60)
instead of the 119.88 it assumed before 0131.
Evidence: evidence/framegen-flip-rate-60hz, distilled from the console's
trace.txt and retroarch.log; python3 tools/evidence.py compare evidence:
129 replayed, 0 failed.
The 59.94 Hz mode takes 120 flips a second on a VRR display and 60 on an
output without 120 Hz. 0121 assumed 119.88 Hz for every 59.94 Hz mode, so
on a 60 Hz output each picture was presented twice and games ran at half
speed with broken audio (a tester's v2.0.0-beta-2 logs: "display 119.880
Hz ... each shown 2x", 58.8 presents/s, the core at 29.6 calls/s).
Patch 0131. khr_display_ctx.c times flips once per process, on the first
swapchain, where the mode is below 100 Hz: the median of nine acquire
intervals once every image is queued, 1 s timeouts, and on a failure a
warning and the mode is believed. vulkan_common.c keeps the rate. The plan
in retroarch.c takes 119.88 only above 100 Hz, and a Target Framerate
above the display's rate becomes the display's (120 on a 60 Hz output is
60, and a 30 fps game still gets a frame made between its frames).
Evidence: evidence/framegen-flip-rate (python3 tools/evidence.py compare
evidence: 128 replayed, 0 failed). tests/test_framegen_plan.py composes
the plan from EDITS as the script applies it and runs nine cases; with
0131's edits left out it fails on the 60 Hz case. The eboot.bin built from
this tree (identity 1f81446a..., sha256 d3dc2a31...) ran on the tester's
60 Hz output, and the owner reports it worked perfectly; no log of that run
was received. Not run yet: the owner's base PS5 with its VRR display (the
console did not answer).
format PASS; evidence PASS; unit 192 of 197 OK. The 5 errors are tests
that read .deps/{ppsspp,azahar,desmume}-src, deleted with .deps on
2026-10-15 along with every core source the build gate's catalog step
reads.
The generator (framegen/src, framegen/include) and its trained network now
come from PS5_MihawkGen (github.com/mihawk-99/PS5_MihawkGen, public),
pinned at c57232a; a release build refuses any other revision. Its sources
and the d5 network are byte-identical to what the title built before (the
network sha256 31ecc7d6..., the four generator sources and the compiled
shaders; framegen.h and nn_final.comp differ only in a comment). The
RetroArch driver shim (vulkan_framegen.cpp/.h, from PS5_FrameGen 9490b0d)
moves to tooling/framegen, so all of the frame generation code in
eboot.bin is published. tooling/notices: a mihawkgen component with its
source address.
format PASS; unit (196 tests) OK.
Every game title in tracked text (test fixtures, comments, patch notes,
console evidence, the v1.0.0-beta.1 note's alt text) is now a made-up
stand-in that keeps the original's shape: its punctuation (apostrophes,
"&", " - "), region tags and, where a test depends on it, its sort order
and how a title relates to its alternate name. Evidence folders and the
Flycast pad script named after games are renamed. Only the committed
handoff/PPSA99002/eboot.bin still holds a title, inside the binary.
releases/v2.0.0-beta-2.md: PS5SX2, frame generation, RetroAchievements,
NetPlay, the WebUI in 16 languages, the library and frontend changes,
the systems tested on a Base PS5, upgrading from v1.0.0-beta.1, source
and credits. It opens with the anti-piracy banner and points, names no
game and shows no game picture: three WebUI screenshots in
assets/releases/v2.0.0-beta-2/.
Gates: format, unit (196 tests), build, evidence (127 replayed, 0
failed), check-manifest and check-notices: PASS.
- tests/input_ps5_test.cpp: ps5_fg_record_request stub (the pad script's
RECORD calls PS5_FrameGen's recorder, not linked in the host test).
- tests/test_webui_qr.py: stubs for the frame generation entries 0120 binds
beside the WebUI's (ps5_fg_menu_is_label/_is_folder, action_ok_ps5_fg,
action_ok_push_default).
- src/main.cpp, src/ps5_framegen_menu.c: tools/lint-format.sh --write
(comments re-wrapped to the line limit; no code changed).
- The frame generation code already names patches 0122-0128, which
patches/series does not list; 47879d1's TLS and password patches took
0122/0123 and are now 0129 (TLS verification) and 0130 (password).
lint-format PASS; tests test_input_ps5, test_webui_qr, test_frontend,
test_webui_secrets: OK.
- 0122: HTTPS uses MBEDTLS_SSL_VERIFY_REQUIRED (upstream verified optionally
and ignored the result), so nobody on the network path can stand in for
RetroAchievements. Its chain (GTS Root R4, cross-signed by GlobalSign Root
CA) verifies against the bundled 2017 roots.
- 0123 and src/ps5_cheevos.c: a sign-in that returns a token removes
cheevos_password from /app0/config/webui.cfg (with the empty token the
WebUI puts beside a new password) and from retroarch.cfg, which keeps its
token. The WebUI clears the old token when a new password or account is
saved, so the new account signs in with its password.
- WebUI: game, file, system and source names carry data-no-translate, and a
value inside a translated sentence is translated only on an exact match:
"Shadow of the Colossus" no longer reads as "{0} of {1}" ("Shadow sur the
Colossus" in French).
- LRPS2 leftovers: the 34 orphan option texts in each catalog, the stale
wording in ps5sx2_libretro.info and build-ps5sx2.sh. Patch count 255 -> 257.
Console (192.168.50.237, klog/retroarch-191705.log): DNS, "TLS connected",
mihawk99 logged in, game 2992 identified with verification required; after
the run webui.cfg holds no cheevos_password and retroarch.cfg an empty one
with its token kept.
Tests: test_webui_secrets (token cleared; helper removes the password, keeps
the token in retroarch.cfg), test_webui_language (a file named Shadow of the
Colossus stays as it is in French), test_frontend: OK. lint-shell PASS;
lint-format fails only in src/main.cpp and src/ps5_framegen_menu.c, not
touched here.
apply-port-patches 0122-0128: private env commands 0x25001 (the core blocks inside retro_run) and 0x25002 (emulated vsyncs a frame
covers, period in microseconds) size the generator's group from what the core says, never from a measured gap; the floor is opt-in
(PS5_FRAMEGEN_FLOOR=1); core run/cpu times in the log. The menu and its config follow. build-retroarch.sh compiles fg_splat.cpp.
main.cpp reads framegen-record-width.txt for the recorder. input_ps5.cpp: reflowed comments and calls.
The PS2 core is now PS5SX2 (Swordpdf's PCSX2 for the PS5) from the fork
../Libretro_PS5SX2, branch libretro, pinned at 308e8dc. build-ps5sx2.sh
fetches and pins its dependencies (rapidyaml 0cd25a1, glslang 275822a built
for the console, shaderc v2026.2 headers), builds the core with the fork's
ps5/libretro/Makefile.libretro, ABI-checks it and stages PCSX2's game
database in system/ps5sx2/resources. PS5SX2_DEV=1 builds the fork as it
stands. BIOS and memory cards stay in system/pcsx2/ (shared).
LRPS2 is gone: build-lrps2.sh and tooling/lrps2, its notices component,
WebUI catalog and settings-guide entries, and the title's core list.
build-title.sh empties dist/{cores,info} before staging, so a core taken
out of the list does not linger. The balanced 4K default (0102) now sets
ps5sx2_upscale to 4x; the core offers up to 8x (6x is 4K).
Also: patch 0118's tests (the block count, the XMB icon names test).
Console evidence (192.168.50.237, RADV; tools/run-title.sh --game=ps5sx2):
- Shadow of the Colossus (USA) boots and plays (klog/game-122302.png).
- tests/pad/ps5sx2-states-4k.txt: frames of 3072x2688 at 6x; a 46,562,360
byte state saved and loaded from the Quick Menu (klog/retroarch-124621.log).
- RetroAchievements: SET_SUPPORT_ACHIEVEMENTS, account logged in, disc
hashed, the core's memory map published (klog/retroarch-125231.log).
- pcsx2_libretro.{so,info} deleted from the console's cores/ and info/.
Gates: format PASS; unit and integration fail only in
test_input_ps5.test_joypad_bindings and test_webui_qr (the uncommitted
frame-generation and input work in src/, not part of this commit); notices
PASS (33 cores); manifest PASS; evidence 127 replayed, 0 failed. The title
was built with the other cores reused (PS5_REUSE_STAGED_CORES).
Options (on/off, output rate, method, cadence, working size, status on screen) are shared
through /app0/config/framegen.cfg, which the title appends when it starts RetroArch.
The Vulkan driver's shader subframes present the generated frame at j/N
between the previous and the current content frame (video_framegen, with
video_shader_subframes 2 to 4). The hooks are anchor edits; the generator and
its shim are built from ../PS5_FrameGen and the trained network is staged at
assets/framegen/network.fgw.
After the click on Settings it waited for the Settings heading, which is static and
translated while still hidden, then read the page title before navigation had run
(seen once in a full run: "Vue d'ensemble" for "Réglages"). It now waits for the title.
Evidence: three consecutive passes of tests.test_webui_language.LanguageBrowser.
Gates: bash tools/verify.sh -> verify: PASS (format unit build integration evidence)
tools/xmb-system-icons.py makes, at build time, one tab icon per RetroArch database the
title knows (src/ps5_library.c's platform table: 48), from the WebUI's system artwork
(webui/assets/systems, Linear ES-DE, MIT): each picture cropped to its hardware (the logo
and year under it removed; XMB prints the name), centred, 256 x 256 PNG, named
<database>.png in assets/xmb/monochrome/png, where XMB looks for a playlist's icon.
Game rows keep XMB's own content icon (no <database>-content.png). A playlist with
another name keeps the default icon.
Notices: the generated icons are their own part (MIT); retroarch-assets now names its
files exactly, so neither claims the other's (fnmatch's * crosses "/").
Evidence: python3 -m unittest tests.test_xmb_assets (one icon per database, 256 x 256
RGBA, the caption cropped off, no -content icons, each icon owned by one licence); the
build printed "[xmb] 48 system icons" and tools/check-notices.py passed. Contact sheet
checked by eye. Console screenshot not taken: the title refused to start on this
console ("startup refused: elevation or installation could not be verified").
Gates: bash tools/verify.sh -> verify: PASS (format unit build integration evidence)
Package the qualified title-specific resident service and start it through
local elfldr before workers when no service is ready. Wait for preflight,
verify SDK elevation and UID 0, and reuse the service on subsequent launches.
Keep installed paths and offline fallback; no Payload Manager boot hook.
Console evidence: evidence/lapy-autostart/capture.json and expectation.json.
Reproduce with evidence/lapy-autostart/README.txt, then
python3 tools/evidence.py compare evidence/.
Verified on the base PS5: cold service startup, two authenticated achievement
sessions, reuse of one service across three requests, and NetPlay relay join
with 3837/3361 input packets and 52 matching state checks. Normal title exits;
root counts 73/72 before each request. Resident service remains running.
Installed binary hashes and unchanged Payload Manager configuration verified.
Validation: 194 unit and 194 integration tests; format; all-target build with
PS5_FRONTENDS='es-de picker' and the existing pinned build/picker-template;
manifest/notices/source bundle checks; 127 evidence captures replayed.
No secrets, saves or raw console captures included. No push.
Qualify the console build with authenticated achievement-set loading, a fresh
badge download, FCEUmm LAN hosting and relay joining. The relay session exchanges
scripted controls and passes 55 direct emulation-state CRC comparisons. Normal
quit returns the elevation service's root counts to baseline.
Expose DNS/TLS failures and add a debug-only trace at the upstream state CRC
comparison. This adds one port hook, so the intentional patch-count assertion
changes from 253 to 254. Keep the requested Online Updater removal and repeatable
RetroArch runner arguments. The verified build uses the standard SDK socket API.
Online startup still requires the qualified external Lapy service; no autoload
is installed. Document the force-close teardown timeout and untested lobby/NAT
scope. Credentials, settings, saves and raw console captures are not committed.
Validation: PS5_FRONTENDS='es-de picker' with the pinned picker template;
tools/verify.sh format unit build integration evidence passed (193 unit,
193 integration). After moving only the debug trace to the received-CRC path,
24 focused frontend/patch tests and format/build passed again, followed by the
final console runs. Final format/evidence, manifest and notices checks passed.
Evidence: evidence/online-features/capture.json and expectation.json.
Replay: python3 tools/evidence.py compare evidence/ (126 captures, zero failures).
Console reproduction: evidence/online-features/README.txt and console_netplay.py.
Read-only comparison confirms both saved passwords match the working pair, while the inherited username differs and no WebUI username override exists. Formatting does not explain the difference. Validation: tools/verify.sh evidence; 125 captures passed. Console settings unchanged.
One authorized login2 request returned HTTP 200 and a token, which was discarded. No account values committed or console settings changed. Evidence: evidence/ra-host-login-provided. Validation: tools/verify.sh evidence; 125 captures passed.
One freshly authorized login2 POST using current console settings returned HTTP 401 / invalid_credentials. No credentials or tokens retained in evidence. Artifact: evidence/ra-host-login/capture.json. Validation: bash tools/verify.sh evidence; 124 captures passed. Authentication remains unresolved.
Request cooperative SDK elevation before RetroArch workers only when the
qualified external daemon is ready. Verify UID and executable identity, map
legacy filesystem paths, and retain shell LoadExec names. Picker and ES-DE
keep their normal sandbox startup. Missing daemon remains a normal launch.
Verification: tools/verify.sh format unit build integration evidence, run
with the pinned picker template. Format passed; 193 unit and 193 integration
tests passed; all shipped targets built; 123 evidence captures replayed.
Generated picker bootstrap repairs and earlier failed trials are recorded.
Console: console_test.py final-return-ra, final-esde and final-offline;
executables read-back verified; current settings preserved; test controls
removed. Badge PNG downloaded and decoded. Hosting reached player 2 once;
joining and account authentication remain unresolved. No WAN/lobby claim.
Artifact: evidence/installed-paths/{capture,expectation}.json and README.txt.
Reproduce comparison: bash tools/verify.sh evidence.
Pre-existing networking/updater/runner edits remain outside this commit;
the capture identifies the tested working-tree context.
On the base PS5, the same early-main RetroArch process fails F_SETFL with
EACCES before connect; after cooperative Lapy elevation both socket APIs
connect to both RetroAchievements endpoints with SO_ERROR=0. Record the
credential change, lost /app0 access, balanced daemon teardown, unresolved
LAN listener timeout, old-SDK startup failure and exact original restoration.
PS5SX2 comparison is source-based as requested; no production elevation.
Evidence: evidence/network-elevation/capture.json and expectation.json.
Console commands: python3 build/network-elevation/run.py baseline;
python3 build/network-elevation/run.py elevate (preparation and restoration
in evidence/network-elevation/README.txt; exact probe sources included).
Validation: bash tools/verify.sh PASS: 192 unit, 192 integration, PS5 build,
122 captures. Replay: python3 tools/evidence.py compare evidence/.
RetroArch's mbedTLS 2.6 registers /dev/urandom as its platform entropy source
unconditionally, and one failing source fails the random generator's seed, so every
TLS connection (RetroAchievements, HTTPS downloads) would fail if a title cannot open
it, which nothing here has shown it can. --wrap=mbedtls_platform_entropy_poll gives it
the title's arc4random_buf instead (the platform layer's, which the WebUI already
draws its session tokens from). No vendor change.
Evidence: evidence/network-build now records the registered source:
"<__wrap_mbedtls_platform_entropy_poll> -> arc4random_buf (= ps5_arc4random_buf)".
Gates: bash tools/verify.sh -> verify: PASS (format unit build integration evidence)
Reopened, the dialog kept the last session's systems until the new list arrived and
then replaced them, so a system chosen in between was lost and Add said "Choose a
system and a game backup." It now offers nothing but "Loading your installed systems…"
until the list is there. Found by the games page browser test, which failed this way
under load once its wait reported what the dialog said.
Evidence: tests.test_scraper.Scraper.test_games_page_in_a_browser passed three times in
a row and in the full run below.
Gates: bash tools/verify.sh -> verify: PASS (format unit build integration evidence)
The guided global settings gain two categories: Achievements (RetroAchievements on/off,
user name, password, hardcore mode) and Netplay (nickname, public lobby announce, relay
server), shown with RetroArch's defaults before RetroArch has written them. Translated
into the 15 other languages.
With networking built in, retroarch.cfg holds cheevos_password, cheevos_token and the
netplay passwords, which the settings editor's Advanced view listed like any key. Any
key ending in _password or _token is now sent as an empty value marked secret (with
whether one is saved); a password can be set (an empty one keeps the saved one) and a
token, RetroArch's own, cannot be written.
Evidence: python3 -m unittest tests.test_webui_secrets (the saved password, token and
netplay password never appear in /api/config; an empty password keeps the saved one; a
new one reaches webui.cfg; a forged token and a non-boolean switch are refused);
tests.test_webui_language (the French Achievements page shows an empty password field
marked "Non défini", no English left).
Gates: bash tools/verify.sh -> verify: PASS (format unit build integration evidence)
configure now enables networking, netplay LAN discovery, RetroAchievements (rcheevos)
and SSL through RetroArch's own mbedTLS (deps/mbedtls, its bundled CA certificates):
nothing new is linked from outside the tree. tools/build-retroarch.sh passes
-DHAVE_BUILTINMBEDTLS, which libretro-common's TLS socket needs and only upstream's
console makefiles pass by hand.
Name lookups: the SDK links getaddrinfo to a resolver that refuses every lookup (the
real one is in a module titles do not load) and no module exports getnameinfo.
src/net_shims.c replaces libretro-common's getaddrinfo_retro, freeaddrinfo_retro and
getnameinfo_retro (--wrap; wrapping getaddrinfo itself still bound the SDK libc's
refuser) and resolves names with the console's own DNS (libSceNet's
sceNetResolverStartNtoa); getnameinfo is numeric. Every RetroArch caller (netplay, the
lobby, HTTP, NAT traversal) reaches it; only mbedTLS's unused mbedtls_net_connect/bind
keep libc's.
Evidence: evidence/network-build (from build/llvm-pie.elf and build/ra/libretroarch.a:
the configure switches, 28 rcheevos and 60 mbedTLS objects, the 9 resolver callers,
the sceNetResolver imports, no null imports); python3 -m unittest tests.test_net_shims.
Console behaviour (sign-in, netplay) is not yet verified: no launcher was available.
Gates: bash tools/verify.sh -> verify: PASS (format unit build integration evidence)
EmulationStation now ships, beside Alekfull NX (still the default) and Linear:
Colorful (Simplified), Colorful (Revisited), PlayStation-X, Art Book Next, Retrofix
(Revisited) and Artflix (Revisited), all from ES-DE's own theme list. Each is pinned
by commit in frontends/es-de/themes.list, fetched by tools/build-esde.sh, copied by
frontends/es-de/stage.sh without artwork sources, and credited in the notices
(CC BY-NC-SA 2.0 or 4.0, non-commercial; Artflix states no licence of its own and
follows its origin, Alekfull's ARTFLIX). A user picks one in ES-DE's UI Settings.
Not included: Next-pixel and Not-so-epic exist only as legacy Recalbox/Batocera themes,
a format ES-DE 3 no longer loads; no ES-DE version of either was found (ES-DE's list,
GitHub, GitLab).
The title folder's es-de/themes is 847 MB; the release ZIP grows to 1.53 GB.
Evidence: python3 -m unittest tests.test_esde_themes (pins, notices, fetched commits);
the build printed "es-de: resources 17M, 8 themes in 847M" and the ZIP lists the eight
theme.xml files.
Gates: bash tools/verify.sh -> verify: PASS (format unit build integration evidence)
A failing run's request log (now kept: failed requests are printed) showed every part
of cancel.iso failing at once with net::ERR_BLOB_REFERENCED_BLOB_BROKEN: the 200 MiB
in-memory File, created beside the earlier 2 x 150 MiB ones, sometimes exceeded
Chromium's blob storage. The cancel step now sends 64 MiB (the smallest size that goes
as parts) throttled to 8 MiB/s, so the cancel lands mid-way every time. Real uploads
read files from disk and are unaffected.
The Add Game step of the games page test now waits as long as the page allows its
download start (60 s, plus the upload) and, on a timeout, says what the dialog said.
Evidence: six consecutive runs of tests.test_webui_transfer_browser passed (before:
one failure in two); the failure log is quoted above.
Gates: bash tools/verify.sh -> verify: PASS (format unit build integration evidence)
webui/i18n.js shows each English text of the page from webui/i18n/<code>.json:
English, Spanish, French, German, Italian, Portuguese (Brazil), Russian, Japanese,
Korean, Chinese (Simplified and Traditional), Vietnamese, Turkish, Polish, Dutch and
Indonesian, 776 texts each (tools/webui-strings.py lists them and checks every
catalog). Pickers with flags (lipis/flag-icons, MIT; vn, tr, pl, nl, id added): a
compact one in the header (the flag alone on a phone) and every language as a tile in
the Settings footer. The choice is POST /api/preferences, kept in
config/webui-preferences.cfg and reported by /api/status, so every device follows it
within a status check (10 s). Not covered: right-to-left languages; option texts the
cores provide stay as written.
Evidence: python3 -m unittest tests.test_webui_language: catalogs complete; the
preference refuses unknown codes and wrong tokens; Chromium finds no English text left
on any page in French, follows a choice made in another browser, works by keyboard,
and fits a 390 px phone with no sideways scroll (screenshots in
build/tmp/webui-language).
Gates: bash tools/verify.sh -> verify: PASS (format unit build integration evidence)
The transfer browser test once ran into the 600 s gate timeout in a full run
(it passes alone and under load). Its waits are now bounded (180 s to settle,
60 s for the cancel) and a timeout fails with the page's report and the
script's output instead of hanging, so a recurrence says where it stopped.
Gates: bash tools/verify.sh -> verify: PASS (format unit build integration evidence)
tools/generate-core-metadata.py now extracts the option tables of a5200, the
Beetle NeoPop/PCE/PC-FX/VB/WonderSwan cores, DOSBox-pure, Flycast, Handy,
NeoCD, Opera, PicoDrive, PokeMini, ProSystem, PUAE, ScummVM, Stella and
Virtual Jaguar: table names are detected, v1 tables are dumped
(dump-options.cpp), DOSBox's namespace tables, NeoCD's runtime builder and
Stella's legacy variables are handled. The 15 existing catalogs are
byte-identical. build-title.sh fails when a shipped core (rpcs3 aside) has no
catalog.
Evidence: build/webui-core-metadata/index.cfg lists all 33 cores; the WebUI
in a browser lists 33 profiles and Beetle PCE shows Video, Audio, Input,
Emulation Hacks, PC Engine CD and General.
Gates: bash tools/verify.sh -> verify: PASS (format unit build integration evidence)
The owner's console had ROMDirectory "" in es_settings.xml, which ES-DE reads as ~/ROMs,
/app0/es-de/ROMs: its no-games screen pointed there. And the adapter only set its
folders once ES-DE had written a settings file, so a first start never had them.
use_title_folders, before each start: ROMDirectory = /app0/content (an empty value or
ES-DE's ~/ROMs default replaced, a folder the user chose kept) and MediaDirectory = the
shared library; with no settings file yet, one with just these is written, which
ES-DE's Settings::loadFile reads and completes when it saves.
Evidence: evidence/issue-33-system-folders (the owner's first ES-DE start with its
settings set aside: ROMDirectory=/app0/content, MediaDirectory=/app0/library, 36 systems
and 3461 games; kept after ES-DE's exit; the owner's settings then restored with only
ROMDirectory changed); tests/esde_library_test.cpp (first start, ES-DE's default
replaced, the user's folder kept). tools/verify.sh: PASS (format unit build
integration evidence).
content/ had only the folders people made (and a bare "Saturn"), so a fresh install
gave no hint where games go (issue 33). ps5_library_make_system_folders makes
content/<system> for each system the installed cores' databases name, with RetroArch's
names ("Nintendo - Nintendo Entertainment System"), which every frontend's library
reads as that system. A system with a folder already, under any name ("PS1",
"Genesis"), gets none: nothing is renamed or moved. A database no platform stands for
(Satellaview, Sufami Turbo, PICO, CD32, CDTV) gets none; variants go to their system
(Wii (Digital) -> Nintendo - Wii).
- src/main.cpp runs it at each title start, before the frontend dispatch (a home-screen
launch goes to the picker from there; RetroArch's own init is too late), so a core
added later gets its folder.
- tools/system-folders.c runs the same code on the staged title in build-title.sh:
dist/PPSA99169/content holds the 46 folders of the 33 cores; video-assets.py keeps
empty folders in the release ZIP.
- The bare content/Saturn the title made is dropped (Sega - Saturn replaces it).
Evidence: evidence/issue-33-system-folders (console: 45 folders -> 52 after a home-screen
restart, the 7 missing systems added 0777, the owner's kept; dist and the ZIP: 46);
tests/ps5_library_test.c (10 made, an existing folder honoured, unknown databases and
cores without .so skipped, a second run makes none). tools/verify.sh: PASS (format unit
build integration evidence).
test_games_page_in_a_browser failed once in a full tools/verify.sh run ("downloaded
artwork is visible without reloading") and passed three times alone. The overlay's
title appears first and its media rows come from a second request; the assertion
counted the rows the moment the title showed. It now waits up to 10 s for the first
present row, then asserts as before.
Evidence: the test alone 3/3 before the change; tools/verify.sh: PASS (format unit
build integration evidence) after it.
Read back all 26 public repositories, exact commits and main revisions. All deferred repositories preserve GitHub fork relationships. Release status and single ZIP digest unchanged.
Validation: bash tools/verify.sh format evidence passed; 119 captures, zero failures. Artifact: evidence/release-beta-publication/capture.json.
Published normal Latest release with exactly PS5_RetroArch-v1.0.0-beta1.zip. Downloaded SHA-256 and extracted notices/assets match. Owner requested remaining formal forks finish through watch job.
Validation: full verify.sh passed 185 unit and 185 integration tests; format/evidence replay passed 119 captures. Artifact: evidence/release-beta-publication/capture.json.
Use the approved banner, four subtle section accents and self-contained SVG frames preserving original screenshot bytes. Keep all README notices, headings, system icons and renderer rows.
Verification: python3 tools/make-readme-frames.py; source and XML checks; browser loads 74 images without overflow; bash tools/verify.sh format evidence passes with 118 captures. Evidence: evidence/readme-galaxy. No new dependencies. Release-note changes excluded.
Move the visible frontend section above At a glance, remove four requested subsections, and restore all 33 renderer entries. README warnings preserved. Validation: format/evidence passed with 117 captures and local preview reviewed. Release-note removal excluded from this commit after approval review rejection.
Replace the Overview hero with the Games capture, document current library/media/save and QR workflows, group 33 cores with system icons, and retain every permanent warning. Keep source-build status and known limits explicit.
Verification: bash tools/verify.sh format evidence — PASS, 116 captures. Source audit: all local links resolve and 33 cores retained. Local browser: 69 images loaded, no page overflow. Evidence: evidence/readme-beta-refresh. No publication.
Keep all 18 core entries, ten screenshots and permanent warnings. Add illustrated highlights, linked contents and grouped system artwork; remove development internals and shorten public descriptions.
Validation: bash tools/verify.sh format evidence — PASS, 115 captures. Browser: 57 images loaded, no horizontal overflow. Evidence: evidence/release-beta-illustrated-notes/{capture,expectation}.json. Local preview only; no publication.
Keep opt-out available and restore the enabled default on each new draft. Browser coverage verifies source visibility, labels, manual opt-out and the default download flow.
Validation: tools/verify.sh format unit build integration evidence; 185 unit and 185 integration tests pass. Build fd8f648f deployed; defaults and config preservation verified. Evidence: evidence/webui-auto-media-default/capture.json. Replay: tools/verify.sh evidence.
Recapture Download Media with Nintendo - Game Boy Advance collapsed, hiding the game name and match. Validate updated screenshot in the local release preview. tools/verify.sh format evidence passes (113 captures). Evidence: evidence/webui-release-collapsed-recap; replay: tools/verify.sh evidence.
Replace four captures and their captions/catalog metadata. Validation: tools/verify.sh format evidence; 112 captures pass, all 15 preview images load. Evidence: evidence/webui-release-bust-a-move/capture.json. Replay: tools/verify.sh evidence.
Capture the requested Neo Geo B library, Add Game, game inspector and Download Media views from the console WebUI, with explanations and a screenshot digest catalog. Preserve the permanent warning and local QR preview.
Validation: tools/verify.sh format evidence; 111 evidence captures pass. All 15 local preview images load. Evidence: evidence/webui-release-gallery/capture.json; replay: tools/verify.sh evidence.
Fix the blocked 3D box and disc icons without changing the CSP. Check all ten media selectors decode/render in the production-server browser regression.
Validation: tools/verify.sh format unit build integration evidence; 185 unit and 185 integration tests pass. Build 8135742c deployed at Picker; all ten icons visually verified; config hashes unchanged. Evidence: evidence/webui-media-icons/capture.json. Replay: python3 tools/evidence.py compare evidence (110 captures pass).
Add a Media Inspector-based workflow for new backups, editable metadata,
LaunchBox lookup and manual/automatic media. Keep users in a live job view
until completion, then open freshly loaded artwork. Preserve prior metadata
edits and rank literal database titles above enhanced editions and variants.
Use the approved color icons, real region flags and hardware artwork for all
50 recognized systems. Restore RetroArch branding and bundle attribution.
Preview native savestate screenshots and invalidate them on replacement.
Validation: PS5_FRONTENDS='es-de picker' PS5_VULKAN_TEMPLATE="$PWD/build/picker-template"
bash tools/verify.sh format unit build integration evidence
185 unit and 185 integration tests; all shipped targets and evidence pass.
Base PS5: seven disposable-file/API checks, asset byte comparisons and
configuration preservation pass; test files removed, Picker restored.
Evidence: evidence/webui-add-game/capture.json
Replay: python3 tools/evidence.py compare evidence
Verified actual Picker, XMB, RGUI, and ES-DE captures with zbarimg and live WebUI HTTP 200. Original Picker and configurations restored. Raw images stay ignored; sanitized hashes and procedure in evidence/webui-qr-console-captures. tools/verify.sh format evidence: 107 captures pass.
Verified with tools/verify.sh format evidence (106 captures); evidence/release-note-beta1 records the updated Markdown digest. Local browser preview confirms yellow warning and linked 1.7beta4 release. Permanent warning diff audit passes.
Present the 18 added cores, Games library, media downloads, shared artwork,
storage support, stylus controls and fixes since v0.6.7-alpha.6. Preserve the
README warning verbatim and keep paragraphs on single lines for release rendering.
Apply the owner's preview edits: omit the Beta notes section, overview image
and its caption. No release, tag or package is published.
Verification: tools/verify.sh format evidence (106 captures, zero failures).
Rendered Markdown inspected in the local browser: four tables, warning image
loaded, no horizontal overflow, requested removals confirmed.
Evidence: evidence/release-note-beta1/{capture,expectation}.json.
Replace Azahar's inverted cursor in Vulkan and software rendering with the
same supersampled white pen, dark outline and lower-left nib as DeSmuME.
Keep clipping anchored to the touch point and preserve the input behavior.
Verify: tools/verify.sh format
PS5_FRONTENDS='es-de picker' PS5_VULKAN_TEMPLATE="$PWD/build/picker-template" tools/verify.sh unit build integration evidence
182 unit and 182 integration tests pass; native core ABI/provenance pass.
The parity regression fails on the old cursor and passes at 1x, 5x and 18x.
Evidence: evidence/azahar-stylus-parity/{capture,expectation}.json
Fresh base-PS5 launch draws the stylus in both captured frames and exits
cleanly; stored eboot and DS/3DS core hashes match the staged package.
105 evidence records replay successfully. Core-switch crash is unresolved.
Rasterize a slim outlined, antialiased pen at the DS output resolution.
Cast Azahar's unsigned screen dimensions before multiplying signed deltas;
the production-type regression fails before this change and passes after it.
Verification: tools/verify.sh format; PS5_FRONTENDS='es-de picker'
PS5_VULKAN_TEMPLATE="$PWD/build/picker-template" tools/verify.sh unit build
integration evidence; tools/verify.sh format evidence. 182 unit and 182
integration tests passed, 104 evidence records replayed.
Evidence: evidence/stylus-polish/{capture,expectation}.json records native
core provenance, stored console SHA-256 readback, and clean production
fresh Azahar (600 frames) and DS Close Content -> Load Content -> Azahar
runs on build 9917ddb4. Reproduce host checks with tools/verify.sh and
recorded console commands with the ignored diagnostic fixtures.
The original owner load crash is unresolved, not claimed fixed. The
active-content scripted RELOAD fault was an invalid reproduction because
it unloaded the core from inside its input callback. Diagnostic handler
changes are excluded from this commit and the deployed production build.
Adapt Proton contact tracking for relative hover and physical press/drag/release.
Keep touchpad Select in menus and other cores. Add resolution-scaled mouse
motion and clipped stylus cursors to DeSmuME and Azahar (Vulkan/software),
with reproducible core patches, build provenance and licence attribution.
Verified: format; 182 host/integration tests; all shipped native targets;
core ABI, manifest and licence checks; 103 evidence captures replayed.
Deployed build 6da657c4 to the base PS5; stored SHA-256 of eboot.bin and both
cores matches the stage. Physical controller/TV acceptance remains pending.
Reproduce:
PS5_FRONTENDS='es-de picker' PS5_VULKAN_TEMPLATE="$PWD/build/picker-template" tools/verify.sh
python3 -m unittest tests.test_input_ps5 tests.test_touchpad_stylus
Evidence: evidence/touchpad-stylus/capture.json and expectation.json.
Raw logs: klog/touchpad-stylus/ (ignored).
Bind WebUI in the common action initializer instead of the custom keyboard
branch. Preserve patch markers so existing configured trees update too.
Production callback/dispatch regression fails before the fix and passes
after it; picker and ES-DE binaries remain byte-identical.
Resolve the integration fixture race exposed by this run: browser covers
now use valid PNG data and assertions require decoded images.
Validation: PS5_FRONTENDS='es-de picker' PS5_VULKAN_TEMPLATE="$PWD/build/picker-template" tools/verify.sh
Format, unit (177 tests), and build passed. After correcting the fixture,
tools/verify.sh format integration evidence passed (177 tests).
Evidence: evidence/webui-qr-actions/capture.json and expectation.json;
reproduce with python3 tools/evidence.py compare evidence/
Deployed build 0bdc8dd8: 6 changed files verified; exact stored-byte eboot
digest matches. Owner confirmed picker/ES-DE; XMB/RGUI live recheck pending.
Picker Triangle toggles and Circle dismisses; XMB gets a WebUI tab left of
Settings; RGUI shows WebUI first; ES-DE replaces Scraper with WebUI.
Share runtime IPv4 discovery and an unchanged MIT Nayuki QR encoder.
Verify: PS5_FRONTENDS='es-de picker' PS5_VULKAN_TEMPLATE="$PWD/build/picker-template" tools/verify.sh
All five gates pass; 176 tests in each pass. Independent QR decoding,
address changes/offline recovery, picker input and menu routing tested.
Evidence: evidence/webui-qr/capture.json and expectation.json; replay with
python3 tools/evidence.py compare evidence/
Deployed build 700259e0: 9 changed files verified, 13614 retained. Exact
stored-byte digests match all three frontend binaries. On-console scans
and controller checks remain pending; no title launch performed.
python3 tools/deploy-title.py verified 9 changed files and skipped 11689
unchanged files using the prior console deployment record. A separate
SELF-disabled FTP readback verifies the exact stored eboot SHA-256; live
HTTP page assets match the staged files. The old daemon is still running,
so metadata sorting on the restarted server is not yet claimed.
Artifact: evidence/webui-games-sorting/capture.json and expectation.json.
Verification: bash tools/check-manifest.sh; tools/verify.sh evidence
(100 captures, zero failures). Raw captures remain in ignored
klog/webui-games-sorting/deploy/.