security: structure safe sqlite wrapper errors

ober

5d51c1e314af5c1a61b164f1c66989758eb393a3

diff --git a/docs/kimi3-security-recommmendations.md b/docs/kimi3-security-recommmendations.md
index bc62c8b..5db4e4b 100644
--- a/docs/kimi3-security-recommmendations.md
+++ b/docs/kimi3-security-recommmendations.md
@@ -472,6 +472,11 @@ eval-shaped channel; authentication shrinks who can even reach the parser.
 Today "always use `(jerboa prelude safe)`" is advice in docs. Advice is
 what a 23-minute adversary counts on users skipping.
 
+- **Status:** import-conflict cleanup landed 2026-07-27, and the safe SQLite
+  wrappers now validate SQL before handle work and map invalid handles/raw
+  backend failures to structured DB conditions. `tests/test-safe-prelude.ss`
+  passes 24/24. The default-prelude switch, explicit unsafe escape hatch,
+  application import-audit enforcement, and broader user docs remain open.
 - **Do:** (a) `jerboa run file.ss` and the script path default to resolving
   `(jerboa prelude)` as `(jerboa prelude safe)`; opting into the raw
   prelude requires an explicit `(jerboa prelude unsafe)` (rename with
diff --git a/lib/std/safe.ss b/lib/std/safe.ss
index 5b512f6..0476d08 100644
--- a/lib/std/safe.ss
+++ b/lib/std/safe.ss
@@ -213,15 +213,27 @@
               (make-message-condition
                (format #f "~a: SQLite not available — vendored jsqlite could not be loaded" who))))))
 
+  (def (raise-sqlite-contract-error who expected val)
+    (raise (condition
+            (make-db-error 'db 'sqlite)
+            (make-message-condition
+             (format #f "~a: expected sqlite ~a, got ~a" who expected val)))))
+
+  (def (raise-sqlite-query-error who sql)
+    (raise (condition
+            (make-db-query-error 'db 'sqlite sql)
+            (make-message-condition
+             (format #f "~a: SQLite operation failed" who)))))
+
   (def (check-sqlite-db! who val)
     (when-checking
       (unless (and raw-sqlite-db? (raw-sqlite-db? val))
-        (error who "expected sqlite database, got ~a" val))))
+        (raise-sqlite-contract-error who "database" val))))
 
   (def (check-sqlite-stmt! who val)
     (when-checking
       (unless (and raw-sqlite-stmt? (raw-sqlite-stmt? val))
-        (error who "expected sqlite statement, got ~a" val))))
+        (raise-sqlite-contract-error who "statement" val))))
 
   ;; ---- SQL injection heuristic detection ----
   ;; Reject SQL strings that look like they were built by concatenation.
@@ -305,12 +317,13 @@
   (def (safe-sqlite-exec db sql)
     ;; Pre: db is sqlite database, sql is string, not tainted
     ;; Post: returns 0 on success
+    (check-string! 'safe-sqlite-exec sql)
     (check-untainted! sql 'sqlite-exec)
+    (check-sql-safety! 'safe-sqlite-exec sql)
     (ensure-sqlite! 'safe-sqlite-exec)
     (check-sqlite-db! 'safe-sqlite-exec db)
-    (check-string! 'safe-sqlite-exec sql)
-    (check-sql-safety! 'safe-sqlite-exec sql)
-    (let ([rc (raw-sqlite-exec db sql)])
+    (let ([rc (try (raw-sqlite-exec db sql)
+               (catch (exn) (raise-sqlite-query-error 'safe-sqlite-exec sql)))])
       (when-checking
        (unless (and (fixnum? rc) (fx= rc 0))
          (raise (condition
@@ -324,22 +337,24 @@
 
   (def (safe-sqlite-execute db sql . params)
     ;; Pre: db is sqlite database, sql is string, params is list
-    (ensure-sqlite! 'safe-sqlite-execute)
-    (check-sqlite-db! 'safe-sqlite-execute db)
     (check-string! 'safe-sqlite-execute sql)
-    (check-untainted! 'safe-sqlite-execute sql)
+    (check-untainted! sql 'safe-sqlite-execute)
     (check-sql-safety! 'safe-sqlite-execute sql)
-    (apply raw-sqlite-execute db sql params))
+    (ensure-sqlite! 'safe-sqlite-execute)
+    (check-sqlite-db! 'safe-sqlite-execute db)
+    (try (apply raw-sqlite-execute db sql params)
+     (catch (exn) (raise-sqlite-query-error 'safe-sqlite-execute sql))))
 
   (def (safe-sqlite-query db sql . params)
     ;; Pre: db is sqlite database, sql is string
     ;; Post: returns a list of rows
-    (ensure-sqlite! 'safe-sqlite-query)
-    (check-sqlite-db! 'safe-sqlite-query db)
     (check-string! 'safe-sqlite-query sql)
-    (check-untainted! 'safe-sqlite-query sql)
+    (check-untainted! sql 'safe-sqlite-query)
     (check-sql-safety! 'safe-sqlite-query sql)
-    (let ([result (apply raw-sqlite-query db sql params)])
+    (ensure-sqlite! 'safe-sqlite-query)
+    (check-sqlite-db! 'safe-sqlite-query db)
+    (let ([result (try (apply raw-sqlite-query db sql params)
+                    (catch (exn) (raise-sqlite-query-error 'safe-sqlite-query sql)))])
       (when-checking
        (unless (list? result)
          (raise (condition
@@ -348,12 +363,13 @@
       result))
 
   (def (safe-sqlite-prepare db sql)
-    (ensure-sqlite! 'safe-sqlite-prepare)
-    (check-sqlite-db! 'safe-sqlite-prepare db)
     (check-string! 'safe-sqlite-prepare sql)
-    (check-untainted! 'safe-sqlite-prepare sql)
+    (check-untainted! sql 'safe-sqlite-prepare)
     (check-sql-safety! 'safe-sqlite-prepare sql)
-    (let ([stmt (raw-sqlite-prepare db sql)])
+    (ensure-sqlite! 'safe-sqlite-prepare)
+    (check-sqlite-db! 'safe-sqlite-prepare db)
+    (let ([stmt (try (raw-sqlite-prepare db sql)
+                  (catch (exn) (raise-sqlite-query-error 'safe-sqlite-prepare sql)))])
       (when-checking
        (unless (and raw-sqlite-stmt? (raw-sqlite-stmt? stmt))
          (raise (condition