Fix static binary: pin Chez version, fix backspace, add missing transitive deps

ober

7efbad4e00699b79852d082be84630e5848c2fa8

diff --git a/Dockerfile b/Dockerfile
index d95e253..a497737 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -180,9 +180,14 @@ RUN mkdir -p /opt/qt6-static/lib/pkgconfig && \
 # at runtime via Sscheme_script (which calls dlopen internally).
 # musl's static libdl.a provides dlopen in the final static binary.
 ARG CHEZ_TAG=main
-RUN git clone --depth 1 --branch ${CHEZ_TAG} \
+ARG CHEZ_COMMIT=
+RUN git clone --depth 100 --branch ${CHEZ_TAG} \
       https://github.com/cisco/ChezScheme /tmp/ChezScheme && \
     cd /tmp/ChezScheme && \
+    if [ -n "${CHEZ_COMMIT}" ]; then \
+      echo "Pinning Chez to commit ${CHEZ_COMMIT}"; \
+      git checkout ${CHEZ_COMMIT}; \
+    fi && \
     ./configure --threads --installprefix=/opt/chez && \
     make -j$(nproc) && \
     make install && \
diff --git a/Makefile b/Makefile
index f98f1ad..d3bf713 100644
--- a/Makefile
+++ b/Makefile
@@ -231,9 +231,12 @@ DEPS_IMAGE := jemacs-deps:$(ARCH)
 
 # Build intermediate deps Docker image (run once, or when deps change).
 # Takes ~45-60 min: Qt6 static + QScintilla + Chez Scheme + all shims.
+CHEZ_COMMIT ?= 902a10098603481afce0ec8588114234c09d6318
+
 docker-deps:
 	DOCKER_BUILDKIT=1 docker build \
 	  --build-arg ARCH=$(ARCH) \
+	  --build-arg CHEZ_COMMIT=$(CHEZ_COMMIT) \
 	  --build-context jerboa-src=$(JERBOA_SRC) \
 	  --build-context gherkin-src=$(GHERKIN_SRC) \
 	  --build-context jsh-src=$(JSH_SRC) \
@@ -266,6 +269,7 @@ build-jemacs-qt-static: check-root
 	cp /src/vendor/jerboa-shell/embed-crypto.c /deps/jsh/ 2>/dev/null; \
 	cp /src/vendor/jerboa-shell/embed-crypto.h /deps/jsh/ 2>/dev/null; \
 	cp /src/vendor/jerboa-shell/ffi-shim.c /deps/jsh/ 2>/dev/null; \
+	cd /src && find lib -name '*.so' -o -name '*.wpo' | xargs rm -f 2>/dev/null; \
 	cd /src && make build SCHEME=/opt/chez/bin/scheme JERBOA=/deps/jerboa && \
 	if [ -f /src/vendor/qt_shim.cpp ]; then \
 	  echo "Rebuilding libqt_shim.a from updated qt_shim.cpp..." && \
@@ -294,10 +298,20 @@ build-jemacs-qt-static: check-root
 	  --compile-imported-libraries --script /src/vendor/chez-scintilla-compile-libs.ss && \
 	rm -f /deps/chez-scintilla/src/chez-scintilla/*.wpo && \
 	cp /src/vendor/jerboa-net-tcp-static.sls /deps/jerboa/lib/std/net/tcp.sls && \
+	cp /src/vendor/jerboa-net-tcp-raw-static.sls /deps/jerboa/lib/std/net/tcp-raw.sls && \
 	cp /src/vendor/jerboa-net-uri.sls /deps/jerboa/lib/std/net/uri.sls && \
-	rm -f /deps/jerboa/lib/std/net/*.wpo && \
+	rm -f /deps/jerboa/lib/std/net/*.wpo /deps/jerboa/lib/std/net/*.so && \
+	cp /src/vendor/jerboa-crypto-native-static.sls /deps/jerboa/lib/std/crypto/native.sls && \
+	rm -f /deps/jerboa/lib/std/crypto/*.wpo /deps/jerboa/lib/std/crypto/*.so && \
+	mkdir -p /deps/jerboa/lib/std/security && \
+	cp /src/vendor/jerboa-security-capsicum-static.sls /deps/jerboa/lib/std/security/capsicum.sls && \
+	rm -f /deps/jerboa/lib/std/security/*.wpo /deps/jerboa/lib/std/security/*.so && \
+	cp /src/vendor/jerboa-os-landlock-static.sls /deps/jerboa/lib/std/os/landlock.sls && \
+	rm -f /deps/jerboa/lib/std/os/landlock.wpo /deps/jerboa/lib/std/os/landlock.so && \
 	JEMACS_STATIC=1 /opt/chez/bin/scheme --libdirs /deps/jerboa/lib \
 	  --compile-imported-libraries --script /src/vendor/jerboa-compile-tcp.ss && \
+	JEMACS_STATIC=1 /opt/chez/bin/scheme --libdirs /deps/jerboa/lib \
+	  --compile-imported-libraries --script /src/vendor/jerboa-compile-tcp-raw.ss && \
 	/opt/chez/bin/scheme --libdirs /deps/jerboa/lib \
 	  --compile-imported-libraries --script /src/vendor/jerboa-compile-uri.ss && \
 	rm -f /deps/jerboa/lib/std/net/*.wpo && \
@@ -343,8 +357,10 @@ linux-static-qt-docker:
 	  -v $(CURDIR):/src:z \
 	  -v $(JERBOA)/lib/std:/host-jerboa-std:ro \
 	  -v $(COREUTILS_SRC)/lib:/host-coreutils:ro \
+	  -v $(JSH_SRC)/src:/host-jsh-src:ro \
 	  $(DEPS_IMAGE) \
 	  sh -c "apk add --no-cache libvterm-dev libvterm-static >/dev/null 2>&1; \
+	         cp -a /host-jsh-src/. /deps/jsh/src/; \
 	         cp -a /host-coreutils/. /deps/coreutils/; \
 	         find /deps/coreutils -name '*.sls' -exec sed -i 's/(load-shared-object #f)/(void)/g' {} +; \
 	         for f in \
@@ -353,7 +369,7 @@ linux-static-qt-docker:
 	           misc/rwlock.sls misc/shuffle.sls misc/string.sls misc/terminal.sls \
 	           cli/getopt.sls \
 	           net/request.sls net/uri.sls \
-	           os/fdio.sls os/signal.sls os/tty.sls \
+	           os/fdio.sls os/signal.sls os/tty.sls os/sandbox.sls \
 	           text/base64.sls text/diff.sls text/glob.sls text/hex.sls text/json.sls \
 	           crypto/digest.sls \
 	           engine.sls fiber.sls guardian.sls select.sls stm.sls task.sls \
@@ -361,12 +377,20 @@ linux-static-qt-docker:
 	           misc/thread.sls misc/wg.sls misc/pqueue.sls misc/lru-cache.sls \
 	           misc/channel.sls misc/atom.sls misc/rbtree.sls \
 	           misc/rwlock.sls misc/completion.sls misc/barrier.sls \
+	           result.sls misc/result.sls misc/fmt.sls \
+	           misc/custodian.sls misc/config.sls misc/memoize.sls \
+	           misc/terminal.sls misc/trie.sls \
+	           actor/mpsc.sls actor/core.sls actor/transport.sls \
+	           crypto/random.sls \
 	           format.sls iter.sls pregexp.sls sort.sls sugar.sls \
 	           srfi/srfi-1.sls srfi/srfi-13.sls srfi/srfi-19.sls; do \
 	           if [ -f /host-jerboa-std/\$$f ]; then \
 	             mkdir -p /deps/jerboa/lib/std/$$(dirname \$$f); \
 	             cp /host-jerboa-std/\$$f /deps/jerboa/lib/std/\$$f; \
 	             rm -f /deps/jerboa/lib/std/\$${f%.sls}.so /deps/jerboa/lib/std/\$${f%.sls}.wpo; \
+	             echo SYNC: \$$f; \
+	           else \
+	             echo SKIP: \$$f not found on host; \
 	           fi; \
 	         done; \
 	         chmod 755 /root && \
diff --git a/build-binary-qt.ss b/build-binary-qt.ss
index ded1bbb..d04f4b4 100644
--- a/build-binary-qt.ss
+++ b/build-binary-qt.ss
@@ -164,9 +164,24 @@
         "std/misc/list"
         "std/misc/alist"
         "std/misc/thread"
+        "std/misc/fmt"
         "std/os/path"
         "std/os/signal"
-        "std/os/fdio"))
+        "std/os/fdio"
+        "std/misc/custodian"
+        "std/misc/config"
+        "std/misc/memoize"
+        "std/misc/terminal"
+        "std/misc/trie"
+        "std/misc/lru-cache"
+        "std/actor/mpsc"
+        "std/actor/core"
+        "std/actor/transport"
+        "std/crypto/native"
+        "std/crypto/random"
+        "std/os/sandbox"
+        "std/os/landlock"
+        "std/security/capsicum"))
     ;; Jerboa core + sugar + repl
     (map (lambda (m) (format "~a/~a.so" jerboa-dir m))
       '("jerboa/core"
@@ -175,6 +190,7 @@
     ;; std/net/tcp and std/net/uri (compiled by step 1)
     (map (lambda (m) (format "~a/~a.so" jerboa-dir m))
       '("std/net/tcp"
+        "std/net/tcp-raw"
         "std/net/uri"))
     ;; jerboa/repl-socket (non-blocking socket FFI for debug REPL + IPC)
     (list "lib/jerboa/repl-socket.so")
@@ -222,6 +238,12 @@
         "lineedit"
         "startup"
         "stage"
+        "recording-index"
+        "recorder"
+        "player"
+        "conditions"
+        "config"
+        "sandbox"
         "lib"))
     ;; chez-pcre2 (compiled by step 1)
     (map (lambda (m) (format "~a/chez-pcre2/~a.so" pcre2-dir m))
diff --git a/lib/jerboa-emacs/qt/commands-core.sls b/lib/jerboa-emacs/qt/commands-core.sls
index cf4889f..1231d52 100644
--- a/lib/jerboa-emacs/qt/commands-core.sls
+++ b/lib/jerboa-emacs/qt/commands-core.sls
@@ -677,13 +677,7 @@
              (echo-message!
                (app-state-echo app)
                "Paredit: cannot delete delimiter")
-             (begin
-               (qt-plain-text-edit-move-cursor!
-                 ed
-                 QT_CURSOR_NEXT_CHAR
-                 'mode:
-                 QT_KEEP_ANCHOR)
-               (qt-plain-text-edit-remove-selected-text! ed)))))
+             (sci-send ed 2180))))
   (def (cmd-backward-delete-char app)
        (let ([buf (current-qt-buffer app)])
          (cond
@@ -692,34 +686,19 @@
                    [pos (qt-plain-text-edit-cursor-position ed)]
                    [ts (hash-get *terminal-state* buf)])
               (when (and ts (> pos (terminal-state-prompt-pos ts)))
-                (qt-plain-text-edit-move-cursor!
-                  ed
-                  QT_CURSOR_PREVIOUS_CHAR
-                  'mode:
-                  QT_KEEP_ANCHOR)
-                (qt-plain-text-edit-remove-selected-text! ed)))]
+                (sci-send ed 2326)))]
            [(repl-buffer? buf)
             (let* ([ed (current-qt-editor app)]
                    [pos (qt-plain-text-edit-cursor-position ed)]
                    [rs (hash-get *repl-state* buf)])
               (when (and rs (> pos (repl-state-prompt-pos rs)))
-                (qt-plain-text-edit-move-cursor!
-                  ed
-                  QT_CURSOR_PREVIOUS_CHAR
-                  'mode:
-                  QT_KEEP_ANCHOR)
-                (qt-plain-text-edit-remove-selected-text! ed)))]
+                (sci-send ed 2326)))]
            [(shell-buffer? buf)
             (let* ([ed (current-qt-editor app)]
                    [pos (qt-plain-text-edit-cursor-position ed)]
                    [ss (hash-get *shell-state* buf)])
               (when (and ss (> pos (shell-state-prompt-pos ss)))
-                (qt-plain-text-edit-move-cursor!
-                  ed
-                  QT_CURSOR_PREVIOUS_CHAR
-                  'mode:
-                  QT_KEEP_ANCHOR)
-                (qt-plain-text-edit-remove-selected-text! ed)))]
+                (sci-send ed 2326)))]
            [else
             (let* ([ed (current-qt-editor app)]
                    [pos (qt-plain-text-edit-cursor-position ed)])
@@ -732,13 +711,7 @@
                   (echo-message!
                     (app-state-echo app)
                     "Paredit: cannot delete delimiter")
-                  (begin
-                    (qt-plain-text-edit-move-cursor!
-                      ed
-                      QT_CURSOR_PREVIOUS_CHAR
-                      'mode:
-                      QT_KEEP_ANCHOR)
-                    (qt-plain-text-edit-remove-selected-text! ed))))])))
+                  (sci-send ed 2326)))])))
   (def (cmd-backward-delete-char-untabify app)
        "Delete backward, converting tabs to spaces if in leading whitespace."
        (let* ([ed (current-qt-editor app)]
diff --git a/src/jerboa-emacs/qt/commands-core.ss b/src/jerboa-emacs/qt/commands-core.ss
index 36831e7..2bf310a 100644
--- a/src/jerboa-emacs/qt/commands-core.ss
+++ b/src/jerboa-emacs/qt/commands-core.ss
@@ -719,10 +719,7 @@ Returns #t if changed, #f if not or if no record exists."
     (if (and *paredit-strict-mode*
              (not (qt-paredit-strict-allow-delete? ed pos 'forward)))
       (echo-message! (app-state-echo app) "Paredit: cannot delete delimiter")
-      (begin
-        (qt-plain-text-edit-move-cursor! ed QT_CURSOR_NEXT_CHAR
-                                         mode: QT_KEEP_ANCHOR)
-        (qt-plain-text-edit-remove-selected-text! ed)))))
+      (sci-send ed 2180))))
 
 (def (cmd-backward-delete-char app)
   (let ((buf (current-qt-buffer app)))
@@ -733,37 +730,28 @@ Returns #t if changed, #f if not or if no record exists."
               (pos (qt-plain-text-edit-cursor-position ed))
               (ts (hash-get *terminal-state* buf)))
          (when (and ts (> pos (terminal-state-prompt-pos ts)))
-           (qt-plain-text-edit-move-cursor! ed QT_CURSOR_PREVIOUS_CHAR
-                                            mode: QT_KEEP_ANCHOR)
-           (qt-plain-text-edit-remove-selected-text! ed))))
+           (sci-send ed 2326)))) ;; SCI_DELETEBACK
       ;; In REPL buffers, don't delete past the prompt.
       ((repl-buffer? buf)
        (let* ((ed (current-qt-editor app))
               (pos (qt-plain-text-edit-cursor-position ed))
               (rs (hash-get *repl-state* buf)))
          (when (and rs (> pos (repl-state-prompt-pos rs)))
-           (qt-plain-text-edit-move-cursor! ed QT_CURSOR_PREVIOUS_CHAR
-                                            mode: QT_KEEP_ANCHOR)
-           (qt-plain-text-edit-remove-selected-text! ed))))
+           (sci-send ed 2326)))) ;; SCI_DELETEBACK
       ;; Shell: don't delete past the prompt
       ((shell-buffer? buf)
        (let* ((ed (current-qt-editor app))
               (pos (qt-plain-text-edit-cursor-position ed))
               (ss (hash-get *shell-state* buf)))
          (when (and ss (> pos (shell-state-prompt-pos ss)))
-           (qt-plain-text-edit-move-cursor! ed QT_CURSOR_PREVIOUS_CHAR
-                                            mode: QT_KEEP_ANCHOR)
-           (qt-plain-text-edit-remove-selected-text! ed))))
+           (sci-send ed 2326)))) ;; SCI_DELETEBACK
       (else
        (let* ((ed (current-qt-editor app))
               (pos (qt-plain-text-edit-cursor-position ed)))
          (if (and *paredit-strict-mode* (> pos 0)
                   (not (qt-paredit-strict-allow-delete? ed (- pos 1) 'backward)))
            (echo-message! (app-state-echo app) "Paredit: cannot delete delimiter")
-           (begin
-             (qt-plain-text-edit-move-cursor! ed QT_CURSOR_PREVIOUS_CHAR
-                                              mode: QT_KEEP_ANCHOR)
-             (qt-plain-text-edit-remove-selected-text! ed))))))))
+           (sci-send ed 2326)))))))
 
 (def (cmd-backward-delete-char-untabify app)
   "Delete backward, converting tabs to spaces if in leading whitespace."
diff --git a/vendor/jerboa-compile-tcp-raw.ss b/vendor/jerboa-compile-tcp-raw.ss
new file mode 100644
index 0000000..0427966
--- /dev/null
+++ b/vendor/jerboa-compile-tcp-raw.ss
@@ -0,0 +1,2 @@
+;;; jerboa-compile-tcp-raw.ss — Recompile std/net/tcp-raw after patching for static build
+(import (std net tcp-raw))
diff --git a/vendor/jerboa-crypto-native-static.sls b/vendor/jerboa-crypto-native-static.sls
new file mode 100644
index 0000000..6f2c719
--- /dev/null
+++ b/vendor/jerboa-crypto-native-static.sls
@@ -0,0 +1,31 @@
+#!chezscheme
+;;; (std crypto native) — Static build stub
+;;; Crypto not available in static builds (no OpenSSL linked).
+;;; All functions error with "libcrypto not available".
+
+(library (std crypto native)
+  (export
+    native-md5 native-sha1 native-sha256 native-sha384 native-sha512
+    native-digest
+    native-random-bytes
+    native-random-bytes!
+    native-hmac-sha256
+    native-crypto-memcmp)
+
+  (import (chezscheme))
+
+  (define (not-available who)
+    (error who "libcrypto not available in static build"))
+
+  (define (native-md5 data) (not-available 'native-md5))
+  (define (native-sha1 data) (not-available 'native-sha1))
+  (define (native-sha256 data) (not-available 'native-sha256))
+  (define (native-sha384 data) (not-available 'native-sha384))
+  (define (native-sha512 data) (not-available 'native-sha512))
+  (define (native-digest algo data) (not-available 'native-digest))
+  (define (native-random-bytes n) (not-available 'native-random-bytes))
+  (define (native-random-bytes! bv) (not-available 'native-random-bytes!))
+  (define (native-hmac-sha256 key data) (not-available 'native-hmac-sha256))
+  (define (native-crypto-memcmp a b) (not-available 'native-crypto-memcmp))
+
+  ) ;; end library
diff --git a/vendor/jerboa-net-tcp-raw-static.sls b/vendor/jerboa-net-tcp-raw-static.sls
new file mode 100644
index 0000000..870882e
--- /dev/null
+++ b/vendor/jerboa-net-tcp-raw-static.sls
@@ -0,0 +1,172 @@
+#!chezscheme
+;;; (std net tcp-raw) — Raw fd-based TCP, chez-ssl compatible API
+;;;
+;;; Static-build version: skips load-shared-object (symbols in static binary).
+
+(library (std net tcp-raw)
+  (export
+    tcp-connect tcp-listen tcp-accept tcp-close
+    tcp-read tcp-write tcp-write-string tcp-read-all
+    tcp-set-timeout)
+
+  (import (chezscheme))
+
+  ;; ========== FFI ==========
+
+  ;; In static builds, POSIX symbols are already linked in.
+  (define _libc
+    (let ((v (getenv "JEMACS_STATIC")))
+      (if (and v (not (string=? v "")) (not (string=? v "0")))
+          #f  ; symbols already in static binary
+          (guard (exn [#t (void)])
+            (load-shared-object "libc.so.6")))))
+
+  (define c-socket    (foreign-procedure "socket" (int int int) int))
+  (define c-bind      (foreign-procedure "bind" (int void* int) int))
+  (define c-listen    (foreign-procedure "listen" (int int) int))
+  (define c-accept    (foreign-procedure "accept" (int void* void*) int))
+  (define c-connect   (foreign-procedure "connect" (int void* int) int))
+  (define c-close     (foreign-procedure "close" (int) int))
+  (define c-setsockopt (foreign-procedure "setsockopt" (int int int void* int) int))
+  (define c-read      (foreign-procedure "read" (int u8* size_t) ssize_t))
+  (define c-write     (foreign-procedure "write" (int u8* size_t) ssize_t))
+  (define c-htons     (foreign-procedure "htons" (unsigned-short) unsigned-short))
+  (define c-inet-pton (foreign-procedure "inet_pton" (int string void*) int))
+
+  ;; errno
+  (define c-errno-location (foreign-procedure "__errno_location" () void*))
+  (define (get-errno) (foreign-ref 'int (c-errno-location) 0))
+  (define EINTR 4)
+
+  ;; Constants
+  (define AF_INET 2)
+  (define SOCK_STREAM 1)
+  (define SOL_SOCKET 1)
+  (define SO_REUSEADDR 2)
+  (define SO_RCVTIMEO 20)
+  (define SO_SNDTIMEO 21)
+  (define SOCKADDR_IN_SIZE 16)
+
+  ;; ========== sockaddr_in ==========
+
+  (define (make-sockaddr-in address port)
+    (let ([buf (foreign-alloc SOCKADDR_IN_SIZE)])
+      (let lp ([i 0])
+        (when (< i SOCKADDR_IN_SIZE)
+          (foreign-set! 'unsigned-8 buf i 0)
+          (lp (+ i 1))))
+      (foreign-set! 'unsigned-short buf 0 AF_INET)
+      (foreign-set! 'unsigned-short buf 2 (c-htons port))
+      (let ([addr-ptr (+ buf 4)])
+        (when (= (c-inet-pton AF_INET address addr-ptr) 0)
+          (foreign-free buf)
+          (error 'make-sockaddr-in "invalid address" address)))
+      buf))
+
+  ;; ========== API (chez-ssl compatible) ==========
+
+  (define (tcp-connect host port)
+    (let ([fd (c-socket AF_INET SOCK_STREAM 0)])
+      (when (< fd 0)
+        (error 'tcp-connect "socket() failed"))
+      (let ([addr (make-sockaddr-in host port)])
+        (let loop ()
+          (let ([rc (c-connect fd addr SOCKADDR_IN_SIZE)])
+            (cond
+              [(>= rc 0)
+               (foreign-free addr)
+               fd]
+              [(= (get-errno) EINTR) (loop)]
+              [else
+               (foreign-free addr)
+               (c-close fd)
+               (error 'tcp-connect "connect() failed" host port)]))))))
+
+  (define tcp-listen
+    (case-lambda
+      [(port)        (tcp-listen port 128)]
+      [(port backlog)
+       (let ([fd (c-socket AF_INET SOCK_STREAM 0)])
+         (when (< fd 0)
+           (error 'tcp-listen "socket() failed"))
+         (let ([one (foreign-alloc 4)])
+           (foreign-set! 'int one 0 1)
+           (c-setsockopt fd SOL_SOCKET SO_REUSEADDR one 4)
+           (foreign-free one))
+         (let ([addr (make-sockaddr-in "0.0.0.0" port)])
+           (let ([rc (c-bind fd addr SOCKADDR_IN_SIZE)])
+             (foreign-free addr)
+             (when (< rc 0)
+               (c-close fd)
+               (error 'tcp-listen "bind() failed" port))))
+         (when (< (c-listen fd backlog) 0)
+           (c-close fd)
+           (error 'tcp-listen "listen() failed"))
+         fd)]))
+
+  (define (tcp-accept listen-fd)
+    (let loop ()
+      (let ([client-fd (c-accept listen-fd 0 0)])
+        (cond
+          [(>= client-fd 0)
+           (values client-fd "")]
+          [(= (get-errno) EINTR) (loop)]
+          [else (error 'tcp-accept "accept() failed")]))))
+
+  (define (tcp-close fd)
+    (c-close fd))
+
+  (define (tcp-read fd buf len)
+    (let loop ()
+      (let ([n (c-read fd buf len)])
+        (cond
+          [(>= n 0) n]
+          [(= (get-errno) EINTR) (loop)]
+          [else -1]))))
+
+  (define (tcp-write fd bv)
+    (let ([total (bytevector-length bv)])
+      (let loop ([offset 0])
+        (when (< offset total)
+          (let ([buf (if (= offset 0) bv
+                       (let ([tmp (make-bytevector (- total offset))])
+                         (bytevector-copy! bv offset tmp 0 (- total offset))
+                         tmp))])
+            (let ([n (c-write fd buf (- total offset))])
+              (cond
+                [(> n 0) (loop (+ offset n))]
+                [(= (get-errno) EINTR) (loop offset)]
+                [else (error 'tcp-write "write failed")])))))))
+
+  (define (tcp-write-string fd str)
+    (tcp-write fd (string->utf8 str)))
+
+  (define (tcp-read-all fd)
+    (let ([chunks '()] [total 0])
+      (let loop ()
+        (let ([buf (make-bytevector 4096)])
+          (let ([n (tcp-read fd buf 4096)])
+            (cond
+              [(> n 0)
+               (set! chunks (cons (cons buf n) chunks))
+               (set! total (+ total n))
+               (loop)]
+              [else
+               (let ([result (make-bytevector total)])
+                 (let lp ([cs (reverse chunks)] [off 0])
+                   (unless (null? cs)
+                     (let ([bv (caar cs)] [n (cdar cs)])
+                       (bytevector-copy! bv 0 result off n)
+                       (lp (cdr cs) (+ off n)))))
+                 result)]))))))
+
+  (define (tcp-set-timeout fd read-secs write-secs)
+    (let ([tv (foreign-alloc 16)])
+      (foreign-set! 'long tv 0 read-secs)
+      (foreign-set! 'long tv 8 0)
+      (c-setsockopt fd SOL_SOCKET SO_RCVTIMEO tv 16)
+      (foreign-set! 'long tv 0 write-secs)
+      (c-setsockopt fd SOL_SOCKET SO_SNDTIMEO tv 16)
+      (foreign-free tv)))
+
+  ) ;; end library
diff --git a/vendor/jerboa-os-landlock-static.sls b/vendor/jerboa-os-landlock-static.sls
new file mode 100644
index 0000000..8d75a4b
--- /dev/null
+++ b/vendor/jerboa-os-landlock-static.sls
@@ -0,0 +1,21 @@
+#!chezscheme
+;;; (std os landlock) — Static build stub (landlock available via jerboa-landlock.o)
+(library (std os landlock)
+  (export
+    landlock-available?
+    landlock-abi-version
+    landlock-enforce!
+    &landlock-error make-landlock-error landlock-error?
+    landlock-error-reason)
+
+  (import (chezscheme))
+
+  (define-condition-type &landlock-error &error
+    make-landlock-error landlock-error?
+    (reason landlock-error-reason))
+
+  (define (landlock-available?) #f)
+  (define (landlock-abi-version) 0)
+  (define (landlock-enforce! . rules) (void))
+
+  ) ;; end library
diff --git a/vendor/jerboa-repl-static.sls b/vendor/jerboa-repl-static.sls
index 2075950..050e3c8 100644
--- a/vendor/jerboa-repl-static.sls
+++ b/vendor/jerboa-repl-static.sls
@@ -92,7 +92,7 @@
     repl-history-ref)
 
   (import (except (chezscheme) cpu-time box?)
-          (std misc list))
+          (except (std misc list) partition))
 
   ;;; ========== REPL Configuration ==========
   (define-record-type repl-config
diff --git a/vendor/jerboa-security-capsicum-static.sls b/vendor/jerboa-security-capsicum-static.sls
new file mode 100644
index 0000000..7ee1b91
--- /dev/null
+++ b/vendor/jerboa-security-capsicum-static.sls
@@ -0,0 +1,47 @@
+#!chezscheme
+;;; (std security capsicum) — Static build stub (capsicum not available)
+(library (std security capsicum)
+  (export
+    capsicum-enter!
+    capsicum-available?
+    capsicum-in-capability-mode?
+    capsicum-limit-fd!
+    capsicum-compute-only-preset
+    capsicum-io-only-preset
+    capsicum-apply-preset!
+    capsicum-open-path
+    capsicum-right-read
+    capsicum-right-write
+    capsicum-right-seek
+    capsicum-right-mmap
+    capsicum-right-event
+    capsicum-right-fcntl
+    capsicum-right-ioctl
+    capsicum-right-fstat
+    capsicum-right-ftruncate
+    capsicum-right-fsync
+    capsicum-right-lookup)
+
+  (import (chezscheme))
+
+  (define (capsicum-available?) #f)
+  (define (capsicum-enter!) (void))
+  (define (capsicum-in-capability-mode?) #f)
+  (define (capsicum-limit-fd! fd rights) (void))
+  (define (capsicum-compute-only-preset) '())
+  (define (capsicum-io-only-preset) '())
+  (define (capsicum-apply-preset! fd preset) (void))
+  (define (capsicum-open-path path flags) -1)
+  (define capsicum-right-read 0)
+  (define capsicum-right-write 0)
+  (define capsicum-right-seek 0)
+  (define capsicum-right-mmap 0)
+  (define capsicum-right-event 0)
+  (define capsicum-right-fcntl 0)
+  (define capsicum-right-ioctl 0)
+  (define capsicum-right-fstat 0)
+  (define capsicum-right-ftruncate 0)
+  (define capsicum-right-fsync 0)
+  (define capsicum-right-lookup 0)
+
+  ) ;; end library