Always save incoming attachments

ober

87382c110d98cddf9d0e58b688280f604e58ef94

diff --git a/docs/credential-handling.md b/docs/credential-handling.md
index 46dac6c..8980225 100644
--- a/docs/credential-handling.md
+++ b/docs/credential-handling.md
@@ -41,9 +41,8 @@ delete them after debugging.
 
 ## Attachments
 
-Automatic attachment export is off by default. Set
-`JERBOA_SIGNAL_AUTO_EXPORT_ATTACHMENTS=1` to copy from the local `signal-cli`
-attachment cache to `~/Downloads/jerboa-signal/` or an absolute
+Incoming attachments are always copied from the local `signal-cli` attachment
+cache to `~/Downloads/jerboa-signal/`, or to the absolute path specified by
 `JERBOA_SIGNAL_DOWNLOAD_DIR`.
 
 Destination names are sanitized, files are created exclusively at mode `0600`,
diff --git a/docs/threat-model.md b/docs/threat-model.md
index 2fdd900..cc9584b 100644
--- a/docs/threat-model.md
+++ b/docs/threat-model.md
@@ -36,8 +36,7 @@ delegated to `signal-cli`.
   `JERBOA_SIGNAL_TRACE_SENSITIVE`, `JERBOA_SIGNAL_DB_KEY`,
   `JERBOA_SIGNAL_DB_KEY_FD`,
   `JERBOA_SIGNAL_LOG_BACKEND`, `JERBOA_SIGNAL_LOG_PERSIST`,
-  log batch/retention limits, `JERBOA_SIGNAL_AUTO_EXPORT_ATTACHMENTS`,
-  attachment quotas, `JERBOA_SIGNAL_DOWNLOAD_DIR`, and
+  log batch/retention limits, attachment quotas, `JERBOA_SIGNAL_DOWNLOAD_DIR`, and
   `JERBOA_SIGNAL_CLI_DATA_DIR`.
 - Local files: `signal-cli` account state, attachments, encrypted logs,
   migration backups, trace files, removed-conversation state, and themes.
@@ -55,7 +54,7 @@ delegated to `signal-cli`.
 - Write state and trace files through checked paths and safe wrappers. State
   files created by this app must use mode `0600` when they contain account or
   preference state.
-- Keep automatic attachment export opt-in; enforce count, file, conversation,
+- Always export inbound attachments while enforcing count, file, conversation,
   total, and free-space quotas. Pin regular sources without following symlinks,
   create mode-0600 destinations exclusively, and reject symlinked roots.
 - Bound every child stdout/stderr line before JSON parsing or diagnostic output;
diff --git a/signal/attach-save.ss b/signal/attach-save.ss
index b22365c..318b135 100644
--- a/signal/attach-save.ss
+++ b/signal/attach-save.ss
@@ -3,7 +3,7 @@
 ;;;
 ;;; signal-cli already downloads every received attachment into its data dir
 ;;; (<XDG_DATA_HOME or ~/.local/share>/signal-cli/attachments/<id>[.ext]). This
-;;; module can copy those files, when explicitly enabled, into
+;;; module copies those files into
 ;;;
 ;;;   ~/Downloads/jerboa-signal/<conversation>/<original-name>
 ;;;
@@ -36,16 +36,10 @@
   (def *export-scan-entry-limit* 100000)
   (def *copy-collision-limit* 128)
 
-  (def (truthy-env? name)
-    (let ([value (getenv name)])
-      (and (string? value)
-           (or (string-ci=? value "1")
-               (string-ci=? value "on")
-               (string-ci=? value "true")
-               (string-ci=? value "yes")))))
-
+  ;; Incoming attachments are always exported. This is intentionally not gated by
+  ;; an environment variable: the TUI tells the user where each file was saved.
   (def (attachment-auto-export-enabled?)
-    (truthy-env? "JERBOA_SIGNAL_AUTO_EXPORT_ATTACHMENTS"))
+    #t)
 
   ;; --- entry points -------------------------------------------------------
 
diff --git a/tests/test-attachments.ss b/tests/test-attachments.ss
index 343ddf6..40fdd0f 100644
--- a/tests/test-attachments.ss
+++ b/tests/test-attachments.ss
@@ -1,5 +1,5 @@
 #!chezscheme
-;;; Adversarial and concurrent checks for opt-in attachment export.
+;;; Adversarial and concurrent checks for always-on attachment export.
 
 (import (except (scheme)
                   make-hash-table hash-table?
@@ -99,12 +99,12 @@
 
 (configure-export! base data-dir)
 
-;; Export is disabled unless the operator explicitly opts in.
+;; Incoming attachments are exported without an opt-in environment setting.
 (putenv "JERBOA_SIGNAL_AUTO_EXPORT_ATTACHMENTS" "")
-(check "attachment export is opt-in"
-       (null? (save-envelope-attachments!
-                (envelope "Alice" (list (attachment "id-1" "report.txt"))))))
-(check "disabled export creates no destination root" (not (file-exists? base)))
+(let ([saved (save-envelope-attachments!
+               (envelope "Alice" (list (attachment "id-3" "always.txt"))))])
+  (check "attachment export is always enabled" (= (length saved) 1))
+  (check "always-enabled export creates destination root" (file-exists? base)))
 (putenv "JERBOA_SIGNAL_AUTO_EXPORT_ATTACHMENTS" "1")
 
 ;; Concurrent duplicate notifications produce one restrictive destination.