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

    From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Sun Aug 2 22:35:14 2026
    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>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Sun Aug 2 22:35:14 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/f9c6eb1b14e99a4096db4101
    Modified Files:
    exec/load/syncretro_lib.js syncretro_lobby.js exec/tests/syncretro_config_test.js syncretro_state_test.js
    Log Message:
    SyncRetro: add the player-facing cabinet toggle

    A shared-saves console (today only the arcade) has one NVRAM and one
    high-score table for every player, and never offers a snapshot for
    that reason: a restore there would roll the shared table back. syncretro_lobby_private() previously stubbed this to "never private";
    this wires it to a real per-player, per-console preference so a
    player can opt onto a machine of their own, where their scores are
    theirs and a game resumes where they left off.

    The preference lives in the stock per-user properties file (data/user/<####>.ini, [syncretro] cabinet.<console-id>) via
    userprops.js, not inside the per-console save directory itself: that
    directory is the private -home handed to the emulator core and what
    a sysop deletes to reclaim space from a dormant player, so a
    preference living there would vanish with it. Absent, unreadable, or
    a guest account all resolve to public -- userprops.js already
    no-ops a guest's set() and defaults its get(), and a guest account
    is shared, so a "private" cabinet keyed to it would be private in
    name only.

    The picker draws the current cabinet and a toggle hint only on a
    shared-saves console, and hides the hint (though not the line) for a
    guest, whose keypress cannot persist anything. Toggling re-runs the suspended-game marking pass, since a private cabinet's snapshots are
    invisible from the public one and back.

    The toggle is bound to "C", not "P" as an earlier sketch of this
    picker assumed: "P" is already this lobby's Prev-page hotkey, spelled
    out in the shipped footer prompt, and no installed console overrides
    it.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Sun Aug 2 22:35:14 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/f9ed60eb36a5eefb17c02f31
    Modified Files:
    exec/load/syncretro_lib.js syncretro_lobby.js exec/tests/syncretro_config_test.js syncretro_state_test.js src/doors/syncretro/DESIGN.md syncretro_state.h syncretro_statekey.h test_statekey.c
    Log Message:
    syncretro: fix final-review findings on save/resume

    Close out the whole-branch review of the save/resume feature before
    merge:

    - syncretro_lobby_state_key() now returns "" when the core hash is
    empty (a case-mismatched [console] core resolves via the door's
    case-insensitive globi() but not the lobby's case-sensitive
    directory()), instead of silently keying the snapshot on romset
    and options alone. Add a regression test.
    - Document the deploy-ordering hazard in DESIGN.md: the lobby goes
    live on save, the door binary only on rebuild + deploy, and an
    older binary misreads a new flag's value as the ROM path.
    - Fix stale comments left by the syncretro_state.c/syncretro_statekey.c
    split (DESIGN.md module map, both header banners, test_statekey.c),
    and rewrite its golden-value comment to drop a reference to an
    implementation-plan step no shipped reader will see.
    - syncretro_cell() now reserves room for the " *" resume marker
    before clipping the title, so a title at or over the cell width no
    longer clips the marker away.
    - Add a "* = resumes" legend to the picker's footer prompt.
    - Declare the implicit global `f` in syncretro_state_test.js.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net