Skip to content

fix(bios): take the BIOS verdict from the resolver, per launching emulator and per file - #2457

Merged
danielcopper merged 3 commits into
mainfrom
feature/2190-bios-verdict
Oct 19, 2026
Merged

danielcopper merged 3 commits into
mainfrom
feature/2190-bios-verdict

Conversation

@danielcopper

@danielcopper danielcopper commented Oct 16, 2026 •

Copy link
Copy Markdown
Owner

The BIOS answer on the Library's platform page and on a game's BIOS tab now comes from the resolver's verdicts rather than from Tender's own presence checks. A platform's or a game's colour is the launching emulator's requirements_met; a file's row is the resolver's per-file verdict, and the Contents column words the check behind it: right file, wrong file, refused, not comparable, not recognised, could not be read. A one-of group, such as the PlayStation region images, is judged per region on the platform page and narrowed to the game's region on its page, and the regions the resolver states nothing for are named. The wording follows how each emulator finds its firmware: opened by name, searched for by content with what the search found, or chosen in its settings.

An emulator selector covers every emulator the resolver answers for, installed or not: L2 and R2 step through them, a carousel shows them all, the launching one is blue and one that is not installed is red. "Download required for <emulator>" and each row's download place a file where the shown emulator looks for it, and "Delete downloads" removes only what Tender downloaded. RomM library files no emulator asks for stand in a section of their own.

The emulator menus on the platform page and on a game's page, the platform header, the game page's Emulator column and the play row name a launch entry by its command: labels that run the same command are one entry, "LRPS2 / PCSX2", while one emulator's different ways to launch stay apart, such as RPCS3 by game serial against RPCS3 from a folder or an ISO. Choosing a joined entry stores its first label, and a choice stored under any of its labels reads as that entry. The BIOS part names the emulator by every label it goes by, because its firmware is the same for every way it launches.

DuckStation (Standalone) over a BIOS folder with no image of an accepted size now reads red — "PlayStation does not start without a BIOS image — DuckStation (Standalone) found no BIOS image in bios/" — and the play row shows BIOS Missing.

Tender's own reading of the console's demand (system_image) leaves the wire; the docs, the glossary and the invariant register say what is read now.

Decisions

From #2190:

  • D1: The colour is the resolver's verdict for the launching emulator: met is green, not met is red, not established is grey. The one exception is a fact the resolver leaves to the caller, a game's region: where the verdict is not established only because it depends on the region of the disc, the platform page shows the per-region facts in amber, and the game page supplies the game's region (D5). A count such as "2 of 3 files … are in place" with a required file missing is red, because the verdict is not met; the sentence still says how much is there.
  • D2: The rows are the launching emulator's own requirements, each at the place the resolver names for it, with its own presence and verdict. Nothing is folded across emulators by file name. Whether a file is wanted is judged for the launching emulator. When the emulator changes, its own rows appear, and a file it lacks is placed where it looks from Tender's firmware store, downloaded into the store first where it is not there yet ([Epic] BIOS: the resolver's verdicts, and Tender's own firmware store #2219).
  • D3: A file row's verdict is the resolver's per-file verdict. A wrong image or a refused file is not met, red, with a sentence saying which. A file the resolver could not recognise, read or compare is not established, grey, with a sentence. A place it could not look at is not established, never missing. A count of files "in place" counts only files the resolver judges met.
  • D4: A refused optional declaration does not withhold the emulator's verdict. A refused required declaration is named, with the resolver's reason. An emulator missing from the answer counts as not read.
  • D5: A one-of group on the platform page is amber when its present images serve some regions, built from the resolver's per-image verdicts and regions and naming the regions covered and not covered (D10, D11). On the game page Tender narrows it to the game's own region from RomM: green when the image serving that region is met, red when it is not met, and grey with a sentence when no image serves that region or its image could not be checked. Where the game has no clear region (World, Asia, none), the platform's verdict stands.
  • D6: The resolver's notes become sentences: PCSX2's "no BIOS chosen in its settings, no game boots until one is"; how an emulator finds its firmware ("opens by name", "lists as required", "recognises … in the BIOS folder"), which words the answer and never moves the colour; a tie between two images ("for PAL two images are in place; which one SwanStation uses is not established"), which leaves the verdict unchanged.
  • D7: Amber means only one thing: a one-of group whose present images cover some regions (D5). Every "not established" mark is grey: the ? in the On-disk column, the dot of a row without a verdict, the group line for a region that could not be checked. Another emulator's files are shown on that emulator's own tab (D15), not as muted rows beside the launching emulator's. A file whose need nothing could establish gets a grey ?, not the grey ✗ that means "not required". Gold for an emulator the user picked stays; it is not a status.
  • D8: The docstrings, invariant register entries, docs/architecture/invariants.md and backend-architecture.md passages that say the verdict is not read, that presence is the row verdict, or that the console's demand never comes from requirements_met, are rewritten in this change. The trap in CLAUDE.md that names requirements_met as the verdict stays.
  • D9: Until the firmware store exists (fix(bios): match library firmware by platform and content, keep it once in Tender's firmware store, and link it where the resolver names #2191), "Download required for <emulator>" and a row's download on the platform page fetch from the RomM library to the place the resolver names for the emulator shown (D15): with Kronos shown for Saturn, saturn_bios.bin goes to bios/kronos/; with YabaSanshiro shown, to bios/. An emulator the resolver's answer holds nothing for is refused. Placing a file after the launching emulator changes (D2) is built in fix(bios): match library firmware by platform and content, keep it once in Tender's firmware store, and link it where the resolver names #2191 together with the store; until then the new emulator's missing rows are red and offer their download like any other. Where a file goes stays the same once the store exists; only where it comes from changes.
  • D10: The platform page shows amber only where the emulator's verdict is not established because of the region alone: in a one-of group at least one image is met and at least one is not met, none is not established, and nothing else in the emulator's answer is open (no required file not established, no refused required declaration). Anything else open makes it grey with its sentence. Every part of this is read from the resolver: the group's verdict, each image's verdict and regions, and the core-mode-unestablished note with the reason region-decided-by-disc. Tender counts nothing of its own here.
  • D11: The regions a one-of group states nothing for are named on the platform page from the resolver's own field for them, never collected from other notes or read out of a sentence. That field is asked for in emu-atlas#556, which blocks this issue.
  • D12: One pull request closes this issue, BIOS readiness is worded per finding mode #1883 and feat(bios): say whether a BIOS file is the right one, not just that it is there #1803, with one commit per issue in that order: all three change the same rows and sentences from the same resolver fields, and this issue's done-when already uses BIOS readiness is worded per finding mode #1883's wording. feat(bios): say whether a BIOS file is the right one, not just that it is there #1803 joins milestone v1.
  • D13: Tender's own reading of the console's demand (system_image: not demanded, held, absent, unsettled) goes. The colour is requirements_met, which already weighs the console's demand. The sentence that the console does not start without one of the images stays: that the console needs one comes from the resolver's system_firmware and its system-firmware-world-knowledge note, and which image is in place from the per-file verdicts (D3), never from presence. With no PlayStation image, SwanStation reads red: "PlayStation does not start without a BIOS image, and none of the five SwanStation knows is in place". The play-button warning follows the red verdict. The value leaves the wire, and the glossary, register and docs passages on it are rewritten with D8.
  • D14: The game page narrows to the game's region whenever the launching emulator's answer has a one-of group and the game has a clear region from RomM. Everything outside the group decides first: a plain required file not met, or the console's image demonstrably absent, is red; anything outside the group not established (a plain required file, a refused required declaration) is grey with its sentence. Otherwise the image serving the game's region decides (D5). Where no image of the group serves that region, the game reads grey even when the resolver's overall verdict is met, because the resolver states that regions no option lists are outside its verdict.
  • D15: The BIOS table on the platform page and the game page's BIOS tab carry an emulator selector over every emulator the resolver answers for, installed or not, the launching emulator first; the "tabs" of D7, D16 and D21 are its entries. Its top row reads "L2 ◀ ● <emulator> 1 / 5 ▶ R2", with Steam's own L2 and R2 glyphs: L2 and R2, and the arrows, step to the previous and next emulator, wrapping around. Below it every emulator stands with its verdict dot in a carousel, in the smallest font Tender uses on the Deck: the shown one always centred and outlined in grey, the launching one outlined in blue, the others on either side in stepping order, wrapping around, each one selectable, and a step moves the carousel visibly rather than redrawing it. A name says the emulator's state by its colour, in the top row and the carousel: the launching emulator's in blue, a not-installed emulator's in red, and red where both apply; no words are added after the name. On the game page the selector is held to about the platform page's width and centred. Steam's own dropdown is not used, because in Game Mode it opens a menu over the whole screen. An entry names no emulator source: one source answers a platform (feat(emulators): choose among every emulator source's emulators, per platform and per game #2222). The table shows the chosen emulator's requirements exactly as the resolver answers them: its places, needs, per-file verdicts and contents; a group option is shown once, not again as the plain row the group speaks for. Choosing an emulator never changes the launching emulator: the header, the count and the play-button warning stay the launching emulator's. On the platform page every emulator's rows offer their download (D9) and delete; the game page offers no BIOS download or delete of its own, and the play row's "Download BIOS" fetches for the game's own pick.
  • D16: The game page keeps its filter on every tab: a file that is not required for this launch, not met and not downloadable is left out and counted in one note naming the tab's emulator. On the launching emulator's tab: "6 more files Flycast lists — not required for this launch, nothing to download. All files are on the platform page." On another emulator's tab: "6 more files Redream lists — not required by Redream, nothing to download. All files are on the platform page." The platform page leaves nothing out.
  • D17: Red is only for a required file, or for a one-of image whose region is left uncovered. A wrong or refused optional file gets the muted ✗ a missing optional file gets, and its contents say which. The sentences are feat(bios): say whether a BIOS file is the right one, not just that it is there #1803's words naming the emulator, the same on both pages: "wrong file — not the image Beetle PSX expects", "refused — Beetle PSX does not accept a file of this size".
  • D18: A file whose place the resolver could not look at is offered no download: not on its row, not by "Download required", not by "Download all". Its row is grey and names the place: "Tender could not look into bios/kronos/, so whether saturn_bios.bin is there is not known". A download there could overwrite a file nobody could see, and a place the resolver cannot read is usually one the emulator cannot read either.
  • D19: The console in the sentence of D13 is named by RomM's platform name, the one Tender shows everywhere else.
  • D20: Whether the console's image is demonstrably absent (D14) is read from the resolver's own console-image verdict, never re-derived from the group or the rows. That verdict is asked for in emu-atlas#639, which blocks this issue.
  • D21: Every file row on both pages and for every emulator says what the shown emulator needs: "required", "optional", "one of these · for USA discs", "not required" (a library file the emulator was read and does not declare) or "need not established". On the game page the word stands on the file's own line after its name and description, set off by "·" ("bios7.bin (ARM7 BIOS) · optional"); on the platform page, whose file column is narrow, on a line under the name in the name's own cell, with the row's button centred against both lines. It replaces the line a one-of option had; whether a file is in place is told by the mark and the dot, as on every other row.
  • D22: Where an emulator that searches by content found nothing, the sentence comes only from the resolver's statement of that search (firmware-path-names-no-file with the folder it searched and how many candidates it held), never from how the emulator finds its firmware plus the verdict: "SwanStation found no BIOS image in bios/ for a Europe console", or "bios/ holds 2 files of a size SwanStation accepts, and it recognises none of them", with the statuses "No BIOS image found" and "No image recognised". Where the resolver states nothing of the search, nothing is said of it. "opens by name" is used only for an emulator that opens its firmware by name; one that searches by name and then by content "requires" its files. Where the console needs an image, D13's sentence stands first and this one follows as a note.
  • D23: A row's mark says what the resolver found: "wrong file", "refused" or "missing", so a mark never contradicts the row's contents.
  • D24: The platform page has a row of its own under "For all of <platform>": "Download all", which places each file for the platform's pick, and "Delete downloads (N)", which removes every download Tender recorded for the platform, whichever emulator it was made for; its dialog says that only Tender's downloads are removed. The label is short so that both buttons fit on one line.
  • D25: RomM library files no emulator here declares stand in a section of their own below the table on both pages, "In your RomM library, asked for by no emulator here", the same whichever emulator is shown, each with its line "not required" or "need not established" (D21). It replaces the lines "N files on server no installed emulator asks for" and "N files nothing installed could answer for. Report at …" on both pages.
  • D26: Where Tender can build no launch command for the platform's emulators, the launching emulator for the BIOS answer is the first one RetroDECK lists for the system, the one its plain launch starts, identified even when it is not installed (Switch: Ryubing (Standalone)); it then behaves like any other emulator, header, Download required and downloads included, and its red name says it is not installed. Only where no emulator is listed, or the first has no identity, does Tender take no other emulator's needs in its place: no entry for it in the selector, no "Download required" button, nothing fetched for it, and a header that states no required count and says nothing could be established, never that nothing is needed. "Download all" stays.
  • D27: Until the firmware store exists (fix(bios): match library firmware by platform and content, keep it once in Tender's firmware store, and link it where the resolver names #2191), a download record stays keyed by platform and file name: a second download of one name for another emulator replaces the first one's record, and a row's Delete removes Tender's download of that name wherever it was placed. No migration is built for it; fix(bios): match library firmware by platform and content, keep it once in Tender's firmware store, and link it where the resolver names #2191 records each placement.
  • D28: One emulator under several labels (RetroDECK lists pcsx2_libretro.so as "LRPS2" and as "PCSX2") is one option, named by every label the resolver gives it: "LRPS2 / PCSX2", whichever of them is picked.
  • D29: The note "You can still put BIOS files in your BIOS folder by hand." is not shown under D6's "No BIOS is chosen in <emulator>'s settings" sentence, where the files are there and a setting is missing. Wherever else nothing could be established, it stays.
  • D30: The rows of another emulator than the launching one are not muted: their buttons act like any other row's, and the selector says which emulator is shown and whether it launches. "For all of <platform>" and "In your RomM library, asked for by no emulator here" are sub-headings under BIOS files, smaller than a section title, so neither reads as a section of the platform page of its own. One legend at the end of the BIOS part serves both tables.
  • D31: On the Library's Platforms page, L2 and R2 step the selector (D15) of the platform shown, wherever focus is on that page, the platform list included. On the game page they step it as soon as the BIOS tab is open, wherever focus is in Tender's section; L1 and R1 are left to the game page's tabs (feat(game-page): step through the game page's tabs with L1 and R1 #2421). Steam's L2 and R2 glyphs stand beside the arrows; no Steam footer entry. On the game page, an unmet option of another emulator's one-of group is grey, not established: the region of this game is judged only for the launching emulator's group (D5, D14).
  • D32: After a step, focus that was on a row of the BIOS list stays on the same file where the new emulator lists it, goes to the new list's top row where it does not, and to the shown entry of the carousel where the new emulator lists no file; it never falls back to the top of the page. After a row's download or delete, and after the bulk buttons', focus stays on the button that was pressed and the pane keeps its place. A button that cannot be pressed is Steam's own disabled button: it keeps focus, refuses the press and shows Steam's grey, with no colour of Tender's own over it (refactor(ui): show a disabled button only in Steam's own disabled look #2427 for the rest of the panel).
  • D33: The carousel shows each emulator once, however few there are; it does not repeat entries to fill its row.
  • D34: Where the launching emulator has no identity but the resolver lists others, the selector opens on the first of them with an identity, and its own "Download required for <emulator>" is offered (D9); the header still says nothing could be established. Where no emulator is listed at all, there is no selector and no "Download required".
  • D35: Where the console needs an image and the launching emulator's answer names none — DuckStation (Standalone) with every region key empty: not met, no requirement listed, and the resolver's statement of the search it made — the header reads D13's sentence without its count clause, followed by D22's note on the search: "PlayStation does not start without a BIOS image — DuckStation (Standalone) found no BIOS image in bios/". The console is RomM's platform name (D19), the folder is the one the resolver says it searched, and the colour is red from requirements_met (D1).
  • D36: Wherever a one-of group states nothing for some regions (D11) and no game region narrows the group — on the platform page, and on the page of a game with no clear region, where the platform's verdict stands (D5) — one clause follows the group's sentence, in the game page's words: "Beetle PSX has a BIOS image for Japan only — Europe discs will not start — for USA discs Beetle PSX states no BIOS image, so whether they start could not be established". Where no image is missing, the clause follows the regions covered: "Beetle PSX has a BIOS image for Japan — for USA and Europe discs Beetle PSX states no BIOS image, so whether they start could not be established", with the status "1 / 3 regions · regions not checked".
  • D37: Wherever Tender offers or names the emulator a platform or game launches with — the game page's emulator core menu, the platform header, the game page's Emulator column, the play row — labels that run the same launch command are one entry named by every label: "LRPS2 / PCSX2", both RetroArch with pcsx2_libretro.so. Labels of one emulator that run different commands stay separate entries, because each is its own way to launch: RPCS3's "Game Serial" against "Directory / ISO", whose two labels run the same command, and EKA2L1's device variants. Choosing a merged entry writes the first label RetroDECK lists among them; an override stored under any of its labels reads as that entry. Stored overrides are not migrated, and launching is unchanged. The BIOS selector keeps grouping by emulator (D28): the firmware is the same for every way an emulator launches.
  • D38: The BIOS part — the selector, the header sentence, the tie clause, the group headings and the row notes — names the launching emulator by its identity, every label it goes by (D28), because its firmware is the same for every way it launches. The places that offer or name how a game launches name the launch entry by its command (D37). Where the two differ, as for RPCS3, the BIOS part reads "RPCS3 Game Serial (Standalone) / RPCS3 Directory (Standalone) / RPCS3 ISO (Standalone)" while the Emulator column reads the entry the game launches with.

From #1883:

  • D1: An emulator that searches by content and found an image reads as a statement, not a ratio: status "Found by content", sentence "DuckStation recognises scph5500.bin in the BIOS folder".
  • D2: One that found nothing it recognises is worded only from the resolver's statement of its search (fix(bios): take the BIOS verdict from the resolver, per launching emulator and per file #2190 D22), and its colour is the resolver's verdict (D3). Where the folder holds no file of an accepted size: "SwanStation found no BIOS image in bios/ for a USA console", and where the search states no count of files, as DuckStation (Standalone)'s does: "DuckStation (Standalone) found no BIOS image in bios/" (fix(bios): take the BIOS verdict from the resolver, per launching emulator and per file #2190 D35); where it holds files the emulator does not recognise: "bios/ holds 2 files of a size SwanStation accepts, and it recognises none of them"; where the listing did not finish: "DuckStation's BIOS folder could not be read completely"; where a candidate could not be read: "scph5501.bin could not be read". Where the console needs an image, fix(bios): take the BIOS verdict from the resolver, per launching emulator and per file #2190 D13's sentence comes first and this one follows as a note. An empty, fully listed folder reads as not met (emu-atlas#563).
  • D3: The colour is the resolver's verdict (fix(bios): take the BIOS verdict from the resolver, per launching emulator and per file #2190 D1); how an emulator finds its firmware only words the answer and never moves the colour. An emulator the resolver does not cover reads grey: "Tender cannot tell what PPSSPP needs yet — the emulator's firmware is not covered by the resolver yet". Where how an emulator finds its firmware is not established: every required file present → green, "All 2 files Beetle Saturn lists as required are in place", with the note "How Beetle Saturn finds its BIOS has not been established"; a required file missing → red, because the resolver says not met, "gba_bios.bin, which gpSP lists as required, is not in place", with the same note and the play-button warning. The file's own row reads missing and offers its download. An emulator that marks nothing required stays "Nothing required", green, without the note.
  • D4: An emulator that opens its firmware by name counts what it opens: "2 of 3 files melonDS opens by name are in place". The three modes read differently: "opens by name", "lists", "recognises … in the BIOS folder".
  • D5: A required file shown missing beside one nothing could check is red and names both: "0 / 2 required · 1 not checked · One file X opens by name is not in place, and one could not be checked"; the play-button warning reads "0/2 required".
  • D6: The On-disk mark for "nothing could say whether this file is wanted" is grey, the colour of "not established". Amber means only a one-of group whose present images serve some regions (fix(bios): take the BIOS verdict from the resolver, per launching emulator and per file #2190 D7).
  • D7: The comment's second case is settled by feat(bios): judge one-of BIOS groups by region on emu-atlas 0.21.0 #2172.

Closes #2190
Closes #1883
Closes #1803

@github-actions github-actions Bot added area:firmware BIOS/firmware management area:ui Frontend UI, game detail page area:architecture Code structure, refactoring labels Oct 16, 2026
@danielcopper
danielcopper force-pushed the feature/2190-bios-verdict branch 4 times, most recently from a0ba8cd to 5c36850 Compare October 19, 2026 13:08
…lator and per file

The colour of a platform, a game and the play badge is now the resolver's
requirements_met for the launching emulator: met, not met, or not
established. The one exception is a one-of group whose verdict is open
only because the disc's region decides it, which reads amber on the
platform page; every part of that rule is read off the resolver. Where
the game's region is clear, the game page judges the image serving that
region instead, and reads grey with a sentence where none serves it.
Where the resolver shows the console's own image absent
(system_firmware_met false), the game reads red whatever its region; a
verdict not met that nothing the resolver states explains reads grey,
and the console's image is never inferred from a group or the rows. An
emulator the answer holds no entry for counts as not read, for its rows
as for its level.

The regions a one-of group carries no option for are read off the
resolver's own statement of them (unstated on the group's
region-decided-by-disc note) and nothing else. Such a region is open: it
keeps a covered group off met and the platform off amber, and a game of
that region reads grey on its page. Wherever no game region narrows the
group, on the platform page and on the page of a game with no clear
region, where the platform's verdict stands, one clause follows the
group's sentence: "Beetle PSX has a BIOS image for Japan only — Europe
discs will not start — for USA discs Beetle PSX states no BIOS image, so
whether they start could not be established". Where no image is
missing, the clause follows the regions covered, with the status
"1 / 3 regions · regions not checked".

An emulator that names no image and finds none, DuckStation over a BIOS
folder holding nothing of a size it accepts, answers not met with no row
to show. Both reads now send that answer, so the platform reads red and
the play row warns, and the panel words the verdict rather than
"Nothing could be established" for an emulator read as stating nothing.
Where the console needs an image and the emulator names none, the
sentence is the console's need with no count: "PlayStation does not
start without a BIOS image".

Each file row is the launching emulator's own requirement at the place
the resolver names for it, with the resolver's per-file verdict rather
than presence. Placements are no longer folded across emulators by file
name, and the platform downloads place each file where the launching
emulator opens it; a game page's download places it for the game's own
pick. Every other emulator the resolver answered for gets an entry of
its own on the payload, listing that emulator's own requirements, which
both pages can show in place of the launching emulator's; showing one
never changes the colour, the counts or the badge. The game page still
lists only the rows it can act on, and counts the rest on a line that
names the shown emulator and points at the platform page.

A file whose place the resolver could not look at is never downloaded
into: its row is grey, it offers no download, and Download required
neither counts nor fetches it.

The system_image axis is gone from the wire; the console's need for an
image reaches the panel only as words under a red verdict, naming the
console by RomM's platform name. Refused required declarations, a BIOS
no one chose in PCSX2's settings, and images that tie are worded from the
resolver's own statements. Amber is never a row's colour. Fields no
surface reads (per-emulator row entries, the raw verdict, a count of
partly covered groups) leave the wire.
The resolver states how each emulator finds its firmware: it opens the
names it declares, it searches the BIOS folder by content after a
configured name, or nobody has established which. The summary now words
the required files by it ("opens by name", "lists as required" with a
note that how the emulator finds its BIOS is not established, and
"requires" for an emulator that also searches by content), states what a
search by content found instead of a ratio, names a missing file beside
one nothing could check, and says when the resolver does not cover an
emulator at all. None of it moves the colour.

What a search found is worded only from the resolver's own statements.
"Found by content" needs it to state the image was identified by its
contents. A settled search that reached no image is its statement with
the folder it searched and how many files of an accepted size it held:
"SwanStation found no BIOS image in bios/ for a USA console" (No BIOS
image found) or "bios/ holds 2 files of a size SwanStation accepts, and
it recognises none of them" (No image recognised). DuckStation's search
states the folder and no count, and is worded by the folder alone;
behind the console's need it reads "PlayStation does not start without a
BIOS image — DuckStation (Standalone) found no BIOS image in bios/". A
statement about a setting that names no file is told apart from a search
by its fields: PCSX2's empty BIOS setting names a folder with neither a
count nor regions, and still reads that no BIOS is chosen. A required
file that is not met is never read as a search that found nothing.

The resolver's answers about the launching emulator and the per-emulator
entries move from services/firmware/status.py into
services/firmware/emulator_answers.py, keeping the module under the size
threshold. A tie between two images reads "for Europe two images are in
place; which one SwanStation uses is not established".
…t is there

The platform page's Contents column words the resolver's check for every
file at its place: right file, wrong file, refused, not comparable, not
recognised, could not be read, not checked, or not established. The
words explain the row's mark and never contradict it, a folder's
contents read "not established" rather than "unknown", and a file
nothing was asked about keeps the em dash. A wrong or refused file that
is not required keeps the muted mark a missing optional file gets, and
every mark says "wrong file" or "refused" rather than "missing" where
the file is there.

The game page says the same for a wrong or a refused file, in the same
words and naming the emulator, and the platform page does not repeat
them under the row. A file whose place could not be looked at names that
place rather than reading as missing.

Every row states what the shown emulator needs of the file, on both
pages: required, optional, "one of these · for USA discs" for an option
of a one-of group, not required, or need not established. The game page
puts it on the file's own line, after its name and description, after a
"·", with tighter rows; the platform page puts it under the name, in the
name's own cell so the row's button is centred against both lines, and
sets its rows a little closer. A met required file and a met optional
file no longer read alike, and an option's line no longer says whether
it is in place; its mark or dot says that.

Where the console needs an image and a search of the BIOS folder found
nothing, the console's sentence stands first and the search's follows it
as a note. A file nothing could check and a declaration the resolver
would not follow take the same verb as the count ("opens by name",
"lists as required" or "requires"), so one emulator is never worded two
ways.

Both pages choose which emulator's requirements the BIOS table shows
with an emulator selector: a row "L2 ◀ ● <emulator> 1 / 5 ▶ R2" whose
arrows and triggers step through the emulators, wrapping around, and
under it a carousel of every emulator with its verdict dot, each
emulator once, the shown one in the middle and outlined, each chosen by
pressing it. The L2 and R2 marks are Steam's own controller glyphs. The
launching emulator comes first, its name in the accent blue and its
carousel entry outlined in it; an emulator that is not installed is
listed too, its name in red, which wins over the blue. Choosing another
never changes what launches, the header or the badge. The shown name
stands on the row's own centre, the axis the carousel centres on; on the
wide game page the selector is held to about the platform page's width
and centred. L2 and R2 step on the Library's Platforms page wherever
focus is, the platform list included, and on a game's page anywhere in
Tender's section while its BIOS tab is open; any other button, and a
trigger where no selector is shown, goes on to Steam. Steam's own
dropdown is not used: in Game Mode it opens a menu over the whole
screen, and it keeps the option it was given while the label is not a
string, so after a download its dot stayed red under a green header.
Every dot now comes from the answer the page holds.

Where none of a platform's emulators can be baked into a shortcut, the
BIOS answer is about the emulator RetroDECK declares first, installed or
not, which its plain launch starts unless an alternative emulator is set
in ES-DE: its verdict heads the BIOS part, "Download required" fetches
for it, and so does a game's "Download BIOS" where the game resolves to
no emulator. Only where that emulator cannot be identified, because no
emulator is listed or the resolver names no identity for the first one,
does the BIOS part read that nothing could be established; the backend
fetches nothing for such a pick and no row is presented as its
requirement. It has no entry in the selector, so the platform page opens
on the first other emulator and offers that one's "Download required",
and with no other there is no such button.

Focus no longer falls back to the top of the platform page. A greyed
button keeps the focus, as Steam's own greyed buttons do, and a press on
it does nothing. Its look is Steam's own grey alone: a red Delete or
Failed label is drawn only while its button can be pressed. While a
row's download or delete, or a bulk button's work, runs, the pressed
button stays enabled and the others wait greyed; a delete's dialog hands
focus back to its button, and a row left with nothing to press takes the
focus itself. After a step, focus on a row of the table stays on the
same file's row, else goes to the new table's top row, else to the
carousel's shown entry; on the game page it goes to the shown entry
where the new emulator lists no file. The pane keeps its scroll position
through a row's or a bulk button's work, put back at once and again
after Steam's own scroll, while focus stays in the BIOS part. Another
emulator's rows are not muted; on the game page an unmet option of its
one-of group reads not established, since only the launching emulator's
group is judged for the game. On the platform page every emulator's rows
offer their download and their delete, and a download, a row's own or
"Download required for <emulator>", lands where the shown emulator opens
the file. The two endpoints take that emulator's identity, and one the
answer holds no verdict for is refused with emulator_unknown rather than
placed where another emulator opens the file. "Download all" and "Delete
downloads" stand apart under the sub-heading "For all of <platform>",
smaller than a section title. The game page offers no BIOS download or
delete of its own. In the selector, one emulator identity listed under
several labels is one entry named by all of them in the list's order,
"LRPS2 / PCSX2", whichever of them is the pick, and the BIOS sentences
and rows name the launching emulator the same way. The platform page's
note that BIOS files can be put in place by hand is left out under the
sentence that no BIOS is chosen in the emulator's settings.

The RomM library's files no emulator here declares stand in a section of
their own on both pages, under the sub-heading "In your RomM library,
asked for by no emulator here", the same whichever emulator is shown; it
replaces the lines that counted them. The docs state that Tender keeps
one download record per file name on a platform, so a row's Delete
removes Tender's download of that name wherever it was placed.

The emulator menus on the platform page and on a game's page, the
platform header, the game page's Emulator column, the toast after a
game's switch, the line under the button while a platform switches, and
the emulator RetroDECK would fall back to now name an emulator by its
launch command rather than by one label: labels that run the same
command are one entry, named by all of them in RetroDECK's order.
RetroDECK lists pcsx2_libretro.so for PlayStation 2 as LRPS2 and as
PCSX2 under one command, so the menu offers "LRPS2 / PCSX2" once. Labels
of one emulator that run different commands stay separate entries,
because each is its own way to launch: RPCS3 by game serial against
"RPCS3 Directory (Standalone) / RPCS3 ISO (Standalone)", and EKA2L1's
device variants. Picking a joined entry stores its first label, and an
override stored under any of its labels reads as that entry, its check
mark, "(default)", "(system)" and "Use System Override (…)" included, so
stored overrides need no migration and launching is unchanged. The
picker payload carries an entry's labels and their joined name beside
the label a pick stores. The BIOS selector keeps one entry per emulator
identity, because the firmware is the same for every way an emulator
launches. On Arcade consoles RetroDECK's two disabled shortcut forms run
the same command and are one entry too.

Docs and comments that still described per-emulator lines on the game
page, presence as a row's verdict, the removed console axis or a
"requires" no payload produces are brought in line with the code, and
required_by_active is documented as the requirement of the emulator
whose list the row is on.
@danielcopper
danielcopper force-pushed the feature/2190-bios-verdict branch from 5c36850 to 65ea9f8 Compare October 19, 2026 14:58
@sonarqubecloud

Copy link
Copy Markdown

@danielcopper
danielcopper merged commit 710448f into main Oct 19, 2026
22 checks passed
@danielcopper
danielcopper deleted the feature/2190-bios-verdict branch October 19, 2026 17:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:architecture Code structure, refactoring area:firmware BIOS/firmware management area:ui Frontend UI, game detail page

Projects

None yet

1 participant