• exec/load/syncretro_lib.js syncretro_lobby.js exec/tests/syncretro_con

    From Rob Swindell (on Debian Linux)@1:103/705 to Git commit to main/sbbs/master on Sunday, August 02, 2026 22:35:14
    https://gitlab.synchro.net/main/sbbs/-/commit/1b49c18900f3a4b2d78070ca
    Modified Files:
    exec/load/syncretro_lib.js syncretro_lobby.js exec/tests/syncretro_config_test.js syncretro_state_test.js
    Log Message:
    syncretro: lobby decides suspend/resume permission and passes -state

    The lobby is the only half that knows all three inputs the suspend/resume decision needs: the console/romset save_state capability, the sysop's
    [state] auto_resume switch, and whether this player is on a private
    machine. syncretro_lobby_state_key() combines them into the key8 the door
    is handed on the command line, or "" when a snapshot is not permitted --
    the door infers nothing from -home.

    syncretro_lib.js gains the supporting, UI-free pieces: syncretro_state_list() reads a player's snapshot directory in one directory() call regardless of cartridge count (the constraint the whole design exists to satisfy); syncretro_state_marked() and syncretro_state_sweep() mark a picker entry resumable and delete snapshots whose key no longer matches (a core upgrade cleans up after itself); syncretro_core_md5() hashes the libretro core once, cached on size+mtime like the existing ROM hash cache. Discovered ROM
    objects now carry their md5, which syncretro_lobby_state_key() needs and
    which discovery had computed and discarded.

    The lobby never receives -core, so syncretro_core_path() has to find the
    same core file the door will load on its own -- it mirrors
    syncretro_config.c's sr_find_core() (named core, else the lone "*_libretro" match, at the door root or one level into any sub-directory) so both halves hash the identical file.

    The picker marks a resumable cartridge's cell with a trailing " *" and the lobby loop refreshes marks and sweeps stale snapshots after every play, from one extra directory read.

    syncretro_lobby_private() is added as a placeholder that returns
    !shared_saves: the per-player cabinet-privacy toggle for shared consoles is
    a separate feature, and until it exists a shared-saves console is never private, which is the safe default.

    Fixed along the way: the state_key auto_resume check used `ini.state.auto_resume || "true"`, but Synchronet's iniGetObject() auto-types an ini value of "false" to the JS boolean false, which is falsy -- so an explicit `auto_resume = false` was silently replaced by the "true" fallback
    and the sysop's switch could never actually disable anything. Compare String(ini.state.auto_resume) directly instead.

    exec/tests/syncretro_config_test.js also gains coverage for the end-to-end decision (capability, auto_resume, per-romset override, shared cabinet) and
    is the regression test for the auto_resume bug above; this is broader than
    the plan's file list for this task, but the decision lives in the ini-merge path that file already covers.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)