• mods/text override files shadowed by stock files with higher-priority

    From Rob Swindell@1:103/705 to GitLab issue in main/sbbs on Sun Jul 5 16:44:08 2026
    open https://gitlab.synchro.net/main/sbbs/-/issues/1182

    A `mods/text/` (or `mods/text/menu/`) override file is silently shadowed by a stock `text/` file whenever the stock file uses a higher-priority extension for the caller's terminal type. This is the same class of bug fixed for custom-shell menu subdirectories in 151b9b5ca7 (sports-3-formal), on the other fallback axis (mods dir → stock dir instead of menu subdir → default dir).

    ## Reported behavior

    Reported by Accession on IRC: with `mods/text/answer.asc` and stock `text/answer.msg` both present, callers were shown the stock `text/answer.msg`. Renaming the override to `mods/text/answer.msg` made it display. Expected: any `answer.*` in `mods/text/` overrides the stock file.

    ## Root cause

    In `sbbs_t::menu()` (`src/sbbs3/prntfile.cpp`), the terminal-type extension priority loop lives at the top level (rip → mon → ans → seq → msg → asc for a CP437 terminal). The mods-dir preference, however, lives inside `menu_exists_in()`, applied **per extension**: for each single extension, the mods path is checked before the stock path.

    So for a typical ANSI/CP437 caller with `mods/text/answer.asc` + `text/answer.msg`:

    1. `.ans` — not in mods, not in text → miss
    2. `.msg` — not in mods, **found in `text/`** → done; `.asc` in mods is never consulted

    A mods override therefore only wins when it uses the same (or a higher-priority) extension as the stock file. Worse, since the `.msg`/`.asc` order flips for ASCII-charset terminals, the same override works for ASCII callers and fails for CP437 callers — whether a sysop's customization is honored depends on the caller's terminal.

    This has been the behavior since mods/text support was introduced in 4f66de6561 (holes-3-create).

    ## Suggested fix

    Same surgery as 151b9b5ca7 (sports-3-formal): hoist the mods→stock fallback out of `menu_exists_in()` so the entire extension priority list is exhausted in the mods dir before the stock dir is consulted — in both `sbbs_t::menu()` and the NULL-ext path of `menu_exists()`.

    With two fallback axes (mods→stock and menu-subdir→default), the subdir axis should presumably stay outermost (shell-specific beats generic, even stock-vs-mods), giving the search order: `mods/<subdir>` → `text/<subdir>` → `mods/` → `text/`, each exhausted across all applicable extensions.

    — *Authored by Claude (Claude Code), on behalf of @rswindell*
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell@1:103/705 to GitLab issue in main/sbbs on Sun Jul 5 16:57:06 2026
    close https://gitlab.synchro.net/main/sbbs/-/issues/1182
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell@1:103/705 to GitLab note in main/sbbs on Sun Jul 5 17:12:21 2026
    https://gitlab.synchro.net/main/sbbs/-/issues/1182#note_9521

    Fixed in e0288fcd8f (yeah-33-error): `menu_exists_in()` now takes an explicit mods/stock tier parameter (with no cross-tier fallback), and both `menu()` and `menu_exists()` nest a tier loop between the menu-subdir loop and the terminal-type extension ladder. The resulting search order is `mods/<subdir>` → `text/<subdir>` → `mods/` → `text/`, each exhausted across all applicable extensions before the next directory is consulted. This also fixes the latent quirk noted in the description: width-variant files (e.g. `.40col.ans`, `.c80.ans`) in the mods dir are now found even when no plain same-extension mods file exists.

    Validated against a live terminal server on Linux (all three cases exercised over a real telnet connection):

    1. `mods/text/answer.asc` + stock `text/answer.msg`, CP437/ANSI caller (the reported scenario) → the mods `.asc` is displayed (previously the stock `.msg` was)
    2. `mods/text/answer.msg` + stock `text/answer.msg` → the mods file is displayed (same-extension override preserved)
    3. no mods files → stock `text/answer.msg` is displayed (fallback intact)

    Style follow-up in def04a30bf (sell-11-introduced).

    — *Authored by Claude (Claude Code), on behalf of @rswindell*
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)