• src/ssh/ssh-conn.c src/syncterm/Wren.adoc conn.c src/syncterm/scripts/

    From Deucе@VERT to Git commit to main/sbbs/master on Mon May 4 07:42:42 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/ab374f937dab91d23eed4d5e
    Modified Files:
    src/ssh/ssh-conn.c src/syncterm/Wren.adoc conn.c src/syncterm/scripts/sftp_app.wren sftp_queue.wren syncterm.wren src/syncterm/ssh.c term.c term.h wren_bind.c wren_host.c wren_host_internal.h
    Log Message:
    SFTP: pretend I know a thing or two about network performance

    A grab bag of changes that took SFTP throughput from ~3 MB/s with the
    serial chunk loop up to ~74 MB/s on a 10G localhost link against
    OpenSSH, and gave the queue UI live throughput / ETA readouts.

    Wren scripting / queue UI:
    - Format.bytes / Format.duration / Timer.now bindings (wraps
    byte_estimate_to_str, duration_estimate_to_str, xp_timer).
    - SFTP queue display gets a sliding-window rate + ETA per active job.
    - Hook limit bumped 8 → 256; with everything moving to Wren we were
    already at 9 onKey hooks, and an all-Wren UI will only push it
    higher.

    doterm() main loop:
    - Replaced the unconditional 1ms SLEEP with an xpevent
    (doterm_wake_evt) so result-queue completions and conn buffer
    arrivals wake the loop immediately. conn_buf_put and
    wren_result_push post the wake; auto-reset event so a single
    signal collapses to one drain pass.

    SFTP queue (sftp_queue.wren):
    - Per-job pipelining: PIPELINE_DEPTH chunk fibers per active job
    with shared offset counter (JobCtx) and Wake-driven dispatcher
    await. Out-of-order writes are fine because lf.writeBytes is
    pwrite-style; resume-from-partial is dropped (holes are unsafe).
    - Asymmetric EWMA for RTT and bandwidth (α=0.25 on bad direction,
    α=0.0625 on good — react to congestion fast, recover cautiously).
    - Adaptive chunk size targets bw × 75 ms keystroke budget, clamped
    [4 KiB, 30 KiB].
    - Adaptive pipeline depth = ceil(BDP / chunk) + 1, clamped [2, 32].
    - Bootstraps to PIPELINE_DEPTH=8 / CHUNK=30720 until first samples
    seed the estimators; reset on session start/stop.

    DeuceSSH-side fixes (src/ssh/ssh-conn.c):
    - maybe_replenish_window now routes WINDOW_ADJUST through
    send_to_wa_slot (try-lock + coalescing slow path) instead of
    blocking on tx_mtx via send_packet. Pre-credits local_window
    under buf_mtx, mirroring the ZC-mode pattern.

    SSH transport (src/syncterm/ssh.c):
    - sftp_recv_thread buffer 4 KiB → 256 KiB (static — single-thread
    accessor, never reentrant). Drains ~8 chunks per dssh_chan_read
    instead of needing 8 syscalls per chunk.
    - sftp_send no longer busy-spins when the server's window-to-us is
    exhausted; parks on dssh_chan_poll(POLL_WRITE) until the next
    inbound WINDOW_ADJUST broadcasts on poll_cnd.
    - Conservative SO_SNDBUF cap to keep keystroke latency budget
    intact under bulk SFTP load.

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

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