• docs/v322_new.md exec/hatchit.js sutils.ini

    From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Mon Jul 27 20:26:18 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/a1c55d65b408daa941d8fc92
    Modified Files:
    docs/v322_new.md exec/hatchit.js sutils.ini
    Log Message:
    hatchit: exit 0 on success, 1 on error

    Every interactive run of hatchit.js ended with exit status 1, including a successful hatch: the TIC and FLO files were written correctly and the
    script still reported failure.

    main() called interactive() without returning, then fell through into the non-interactive reporting code with all of its locals still undefined, so
    "File : " + file.name threw a TypeError. jsexec reports an uncaught
    exception as exit status 1, so the crash - after the hatch had already succeeded - was what the caller saw. Non-interactive runs with all four
    options exited 0, which is why this went unnoticed for so long. The same fall-through fired after a cancelled menu and after any unrecognized
    option.

    Note the exit status was NOT hatch_file() returning true: jsexec ignores
    a script's return value when setting its exit status. It uses the
    exit_code global if the script defines one, and EXIT_FAILURE for an
    uncaught exception; a module whose last statement evaluates to true (or
    to 7) still exits 0.

    Return from the interactive path, require -dir, -file, -area and -origin together in non-interactive mode, reject unrecognized options instead of silently mis-parsing them, and propagate the outcome: hatch_file() now
    returns false when a link could not be given the file (it previously
    returned true even when every TIC failed to write), and both paths exit
    with that result. A script or timed event can finally tell whether a
    hatch worked.

    Also fix -replace, which passed a boolean through to the TIC generator
    and emitted the literal line "Replaces true". Per FTS-5006 that field is
    a filename or wildcard mask, matched against the hatched file's name by
    the receiving processor, so it matched nothing and the far end refused
    the import. Bare -replace now uses the file's own 8.3 name; the new -replace=<mask> form takes an explicit mask, matching what the
    interactive "Replaces" prompt has always accepted.

    The non-interactive mode came from acn128's patch merged in 08283b18d5 (ends-3-shirts, 2022-01-14) via GitLab #274; these are all defects in
    that merge, not regressions since.

    Documented on the wiki at module:hatchit, which until now was a FIXME
    stub. Also corrects hatchit's description in the sysop utilities menu,
    which read "TIC File Processor" - TickIT's job, not the hatcher's.

    Reported by codefenix on IRC.

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

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