Add core production verification gate

ober

6d96b037e6c5c00a0a02794c82ae8e0164dcc08f

diff --git a/Makefile b/Makefile
index 5685741..a56cd3f 100644
--- a/Makefile
+++ b/Makefile
@@ -36,7 +36,7 @@ CHEZ_INSTALL_FLAGS = \
 	--installman=$(CHEZ_PREFIX)/share/man \
 	--installdoc=$(CHEZ_PREFIX)/share/doc \
 	--as-is
-LIBDIRS = lib:$(JERBOA_HOME)/vendor/jsqlite/src
+LIBDIRS = $(JERBOA_HOME)/lib:$(JERBOA_HOME)/vendor/jsqlite/src
 # Base directory for chez-* repos (legacy C FFI — see `make native` for Rust backend)
 JERBOA_EXT_DIR ?= $(HOME)/src
 # External chez-* library paths for legacy wrapper modules
@@ -60,7 +60,7 @@ TYPED_LLVMIR_PARITY_FN ?= sample_typed_llvmir_smoke::main
 LLVM_BIN ?= $(shell if command -v llvm-as >/dev/null 2>&1; then dirname "$$(command -v llvm-as)"; elif [ -x /opt/homebrew/opt/llvm/bin/llvm-as ]; then echo /opt/homebrew/opt/llvm/bin; elif [ -x /usr/local/opt/llvm/bin/llvm-as ]; then echo /usr/local/opt/llvm/bin; fi)
 TYPED_WRAPPER_DIR ?= build/typed/jerboa
 
-.PHONY: help chez static-supported-check chez-cross build binary binary-typed binary-typed-smoke binary-cross native-cross pure-audit typecheck typed-rust typed-llvmir typed-llvmir-check typed-llvmir-smoke typed-llvmir-parity typed-wrappers typed-build typed-wrapper-smoke typed-split-tree-smoke typed-test typed-clean test test-known-flaky test-reader test-core test-runtime test-try-debug test-stdlib test-ffi test-modules test-expanded test-contract test-ergo test-sqlite-robustness test-limits-primitives test-typed-core test-typed-parser test-typed-checker test-typed-rust test-typed-llvmir test-typed-wrappers test-pure-audit test-features test-wrappers test-phase4a test-phase4b test-phase4c test-phase4d test-phase4e test-phase4f test-phase5 test-phase5e test-phase6 test-phase7 test-phase8 test-functional test-repl test-security test-security-profile test-native test-gaps native clean-native audit audit-native security-audit clean security security-production security-profile security-hardware-smoke sbom reproducibility-report reproducibility-compare release-evidence fuzz fuzz-smoke fuzz-deep fuzz-reader-fuzz fuzz-json-fuzz fuzz-http2-fuzz fuzz-dns-fuzz fuzz-pregexp-fuzz fuzz-csv-fuzz fuzz-base64-fuzz fuzz-hex-fuzz fuzz-uri-fuzz fuzz-format-fuzz fuzz-router-fuzz fuzz-sandbox-fuzz test-rawstring test-regex test-rx test-peg test-regex-all check-docs check-docs-strict data-check docker-build docker-push
+.PHONY: help chez static-supported-check chez-cross build binary binary-typed binary-typed-smoke binary-cross native-cross pure-audit typecheck typed-rust typed-llvmir typed-llvmir-check typed-llvmir-smoke typed-llvmir-parity typed-wrappers typed-build typed-wrapper-smoke typed-split-tree-smoke typed-test typed-clean test test-known-flaky test-reader test-core test-runtime test-try-debug test-stdlib test-ffi test-modules test-expanded test-contract test-ergo test-sqlite-robustness test-limits-primitives test-typed-core test-typed-parser test-typed-checker test-typed-rust test-typed-llvmir test-typed-wrappers test-pure-audit test-features test-wrappers test-phase4a test-phase4b test-phase4c test-phase4d test-phase4e test-phase4f test-phase5 test-phase5e test-phase6 test-phase7 test-phase8 test-functional test-repl test-security test-security-profile test-native test-gaps native clean-native audit audit-native security-audit clean security security-production security-profile security-hardware-smoke sbom reproducibility-report reproducibility-compare verify release-evidence fuzz fuzz-smoke fuzz-deep fuzz-reader-fuzz fuzz-json-fuzz fuzz-http2-fuzz fuzz-dns-fuzz fuzz-pregexp-fuzz fuzz-csv-fuzz fuzz-base64-fuzz fuzz-hex-fuzz fuzz-uri-fuzz fuzz-format-fuzz fuzz-router-fuzz fuzz-sandbox-fuzz test-rawstring test-regex test-rx test-peg test-regex-all check-docs check-docs-strict data-check docker-build docker-push
 .PHONY: check-cross-tools docker fuzz-websocket-fuzz jlsp jlsp-freebsd-amd64 \
         jlsp-install jlsp-linux-amd64 jlsp-portable jmcp-freebsd-amd64 \
         jmcp-freebsd-arm64 jmcp-linux-amd64 jmcp-linux-arm64 \
@@ -123,6 +123,7 @@ help:
 	@echo "  sbom             Write local SBOM/toolchain evidence under dist/sbom"
 	@echo "  reproducibility-report  Compare two local multicall builds"
 	@echo "  reproducibility-compare Compare two independent reproducibility reports"
+	@echo "  verify           Run the production security, build, test, and release evidence gates"
 	@echo "  release-evidence Write release-readiness evidence under dist/release-evidence"
 	@echo ""
 	@echo "Cross-platform binaries (one static jerboa + jerbuild/jmcp/jlsp symlinks):"
@@ -546,10 +547,16 @@ reproducibility-compare:
 	support/reproducibility-compare.sh "$(REPRO_A)" "$(REPRO_B)"
 
 release-evidence:
+	rm -rf "$(EVIDENCE_DIR)"
 	mkdir -p "$(EVIDENCE_DIR)"
 	git rev-parse HEAD > "$(EVIDENCE_DIR)/git-commit.txt"
 	git status --short > "$(EVIDENCE_DIR)/git-status.txt"
-	uname -a > "$(EVIDENCE_DIR)/build-environment.txt"
+	{ \
+		printf 'platform=%s\n' "$$(uname -srm 2>/dev/null || printf unknown)"; \
+		printf 'source_date_epoch=%s\n' "$(SOURCE_DATE_EPOCH)"; \
+		printf 'static=%s\n' "$(STATIC)"; \
+		printf 'jerboa_home_status=present\n'; \
+	} > "$(EVIDENCE_DIR)/build-environment.txt"
 	$(MAKE) audit > "$(EVIDENCE_DIR)/audit.txt" 2>&1
 	$(MAKE) jerboa-smoke > "$(EVIDENCE_DIR)/jerboa-smoke.txt" 2>&1
 	$(MAKE) unification-release-check > "$(EVIDENCE_DIR)/unification-release-check.txt" 2>&1
@@ -557,13 +564,21 @@ release-evidence:
 	$(MAKE) reproducibility-report > "$(EVIDENCE_DIR)/reproducibility-report.txt" 2>&1
 	JERBOA_RELEASE_DIR="$(RELEASE_DIR)" JERBOA_SIGNING_EVIDENCE_DIR="$(EVIDENCE_DIR)/signing" support/sign-release-artifacts.sh evidence > "$(EVIDENCE_DIR)/signing-evidence.txt" 2>&1
 	$(MAKE) sbom > "$(EVIDENCE_DIR)/sbom.txt" 2>&1
-	shasum -a 256 Makefile SECURITY.md README.md docs/release-security.md docs/release-artifacts.md support/sign-release-artifacts.sh support/sbom.sh support/fasl-cache-equivalence.ss support/reproducibility-report.sh tools/security-audit.sh > "$(EVIDENCE_DIR)/release-inputs-sha256.txt"
+	shasum -a 256 Makefile SECURITY.md README.md docs/release-security.md docs/release-artifacts.md support/sign-release-artifacts.sh support/sbom.sh support/sanitize-evidence.sh support/fasl-cache-equivalence.ss support/reproducibility-report.sh tools/security-audit.sh > "$(EVIDENCE_DIR)/release-inputs-sha256.txt"
 	rm -rf "$(EVIDENCE_DIR)/sbom" "$(EVIDENCE_DIR)/reproducibility"
 	cp -R "$(SBOM_DIR)" "$(EVIDENCE_DIR)/sbom"
 	cp -R "$(REPRO_DIR)" "$(EVIDENCE_DIR)/reproducibility"
 	grep -q '^signature_status=' "$(EVIDENCE_DIR)/signing/status.txt"
 	grep -q '^status=match$$' "$(EVIDENCE_DIR)/reproducibility/result.txt"
 	grep -q '^sbom_status=present$$' "$(EVIDENCE_DIR)/sbom/manifest.txt"
+	support/sanitize-evidence.sh "$(EVIDENCE_DIR)"
+	printf 'release_evidence_status=pass\n' > "$(EVIDENCE_DIR)/result.txt"
+
+verify:
+	$(MAKE) audit
+	$(MAKE) build
+	$(MAKE) test
+	$(MAKE) release-evidence
 
 # Cross-compiled jerbuild. Drives support/build-jerbuild.sh with TARGET_* env,
 # producing ./jerbuild-<machine> alongside the host ./jerbuild.
@@ -1012,14 +1027,14 @@ test: native
 	@set -e; \
 	for t in $(TEST_RUN_FILES); do \
 		echo "== $$t"; \
-		$(SCHEME) --libdirs $(LIBDIRS) --script "$$t"; \
+		$(NATIVE_TEST_ENV) $(SCHEME) --libdirs $(LIBDIRS) --script "$$t"; \
 	done
 
 test-known-flaky: native
 	@status=0; \
 	for t in $(TEST_QUARANTINE_FILES); do \
 		echo "== $$t"; \
-		if $(SCHEME) --libdirs $(LIBDIRS) --script "$$t"; then :; else status=1; fi; \
+		if $(NATIVE_TEST_ENV) $(SCHEME) --libdirs $(LIBDIRS) --script "$$t"; then :; else status=1; fi; \
 	done; \
 	exit $$status
 
@@ -1242,7 +1257,7 @@ test-ergo:
 	@$(SCHEME) --libdirs $(LIBDIRS) --script tests/test-jerboa-prelude-ergo.ss
 
 test-sqlite-robustness: native
-	@$(NATIVE_LD_VAR)=lib JERBOA_HOME=$(JERBOA_HOME) $(SCHEME) --libdirs $(LIBDIRS) --script tests/test-sqlite-robustness.ss
+	@$(NATIVE_TEST_ENV) $(SCHEME) --libdirs $(LIBDIRS) --script tests/test-sqlite-robustness.ss
 
 test-limits-primitives:
 	@$(SCHEME) --libdirs $(LIBDIRS) --script tests/test-limits-primitives.ss
@@ -1554,12 +1569,14 @@ else
   NATIVE_LIB_EXT = so
   NATIVE_LD_VAR = LD_LIBRARY_PATH
 endif
+NATIVE_TEST_ENV = JERBOA_HOME=$(JERBOA_HOME) $(NATIVE_LD_VAR)=$(JERBOA_HOME)/lib:$${$(NATIVE_LD_VAR):-}
 RUST_NATIVE_LIB = $(RUST_NATIVE_DIR)/target/release/libjerboa_native.$(NATIVE_LIB_EXT)
 
 $(RUST_NATIVE_LIB): $(RUST_NATIVE_DIR)/src/*.rs $(RUST_NATIVE_DIR)/Cargo.toml
 	cd $(RUST_NATIVE_DIR) && cargo build --release --features full
 
-native: $(RUST_NATIVE_LIB)
+native:
+	cd $(RUST_NATIVE_DIR) && cargo build --release --features full
 	cp $(RUST_NATIVE_LIB) lib/
 ifeq ($(UNAME_S),Darwin)
 	@# Re-sign ad-hoc so dyld accepts the freshly-copied dylib.
@@ -1575,9 +1592,9 @@ clean-native:
 
 test-native: native
 	@echo "--- Rust native library tests (weeks 1-4) ---"
-	@$(NATIVE_LD_VAR)=lib $(SCHEME) --libdirs $(LIBDIRS) --script tests/test-native-rust.ss
+	@$(NATIVE_TEST_ENV) $(SCHEME) --libdirs $(LIBDIRS) --script tests/test-native-rust.ss
 	@echo "--- Rust native library tests (weeks 5-6) ---"
-	@$(NATIVE_LD_VAR)=lib $(SCHEME) --libdirs $(LIBDIRS) --script tests/test-native-rust-week5-6.ss
+	@$(NATIVE_TEST_ENV) $(SCHEME) --libdirs $(LIBDIRS) --script tests/test-native-rust-week5-6.ss
 
 audit-native:
 	@set -eu; \
diff --git a/SECURITY.md b/SECURITY.md
index 175c862..65421bd 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -20,6 +20,7 @@ cut from a clean checkout after:
 - `make sbom`, `make reproducibility-report`, and `make release-evidence`
   produce current SBOM, two-build multicall reproducibility, checksum, and
   signing-posture evidence.
+- `make verify` passes as the one-command local production gate.
 - Production release artifacts have detached publisher signatures recorded by
   `make signing-evidence` with `JERBOA_REQUIRE_RELEASE_SIGNATURES=1`.
 - RustSec, secret scanning, `.jerboa-system` manifest checks, generated
diff --git a/docs/release-artifacts.md b/docs/release-artifacts.md
index 49ba92b..f121b8b 100644
--- a/docs/release-artifacts.md
+++ b/docs/release-artifacts.md
@@ -102,9 +102,12 @@ smoke, signing status, release-input hashes, git state, and build host
 information. Release promotion requires the reproducibility report to record
 `binary_status=match`, `program_image_status=match`, `bundle_status=match`,
 `link_status=match`, `source_manifest_status=match`,
-`object_cache_equivalence_status=match`, and `status=match`. The current
-default program image kind is `compile-program`; WPO artifacts require separate
-opt-in evidence before they can be promoted.
+`object_cache_equivalence_status=match`, and `status=match`. Exact byte status
+is recorded separately in `binary_byte_status`, `program_so_byte_status`, and
+`program_wpo_byte_status`; when Chez emits byte-different but FASL-equivalent
+program images, the report records the selected match mode explicitly. The
+current default program image kind is `compile-program`; WPO artifacts require
+separate opt-in evidence before they can be promoted.
 
 To compare reports from two independent builders:
 
diff --git a/docs/release-security.md b/docs/release-security.md
index 908a3da..36742f3 100644
--- a/docs/release-security.md
+++ b/docs/release-security.md
@@ -29,6 +29,12 @@ make sbom
 make release-evidence
 ```
 
+For the local one-command gate, run:
+
+```bash
+make verify
+```
+
 `make audit` is the pull-request gate. It checks required release/security
 files, Apache/NOTICE preservation for vendored Chez, high-confidence secret
 patterns, generated-artifact ignore policy, RustSec advisories with warnings
@@ -47,12 +53,18 @@ Set `JERBOA_BINARY_DETERMINISTIC_LINK=0` only for local linker diagnostics.
 `JERBOA_BINARY_DETERMINISTIC_IDS=0` only when debugging compiler identity
 generation itself. The current runnable multicall production candidate uses
 `compile-program` by default, compiles the entry image in an isolated helper,
-canonicalizes the input Chez gensym session prefix before embedding, and strips
-nondeterministic Chez FASL metadata while preserving compile-time information
-needed by `jerboa <script>` and interactive loads. Whole-program optimization
-remains opt-in with `JERBOA_BINARY_WPO=1`; WPO promotion is blocked until its
-reproducibility evidence matches. WPO-only gensym prefix rewriting is disabled
-by default because it mutates opaque whole-program output; set
+and canonicalizes the input Chez gensym session prefix before embedding.
+Broad bare generated-token rewriting is disabled by default because it can
+mutate opaque runtime FASL data; set `JERBOA_BINARY_DETERMINISTIC_BARE_TOKENS=1`
+only for local diagnostics after `make jerboa-smoke` proves script mode still
+loads.
+Runtime-loaded Chez FASL metadata stripping is disabled by default because the
+payload is executable compiler data; set `JERBOA_BINARY_STRIP_FASL=1` only for
+local diagnostics after `make jerboa-smoke` proves the resulting binary can run
+scripts. Whole-program optimization remains opt-in with `JERBOA_BINARY_WPO=1`;
+WPO promotion is blocked until its reproducibility evidence matches. WPO-only
+gensym prefix rewriting is disabled by default because it mutates opaque
+whole-program output; set
 `JERBOA_BINARY_CANONICALIZE_WPO=1` only for local diagnostics after verifying
 `make jerboa-smoke`.
 The embedded bundle currently includes both source and a selected object cache
@@ -79,10 +91,16 @@ release artifact hashes when `dist/release/` exists.
 `make reproducibility-report` rebuilds the multicall distribution twice, hashes
 the resulting `dist/jerboa` binary, compares the embedded program image, bundle,
 `jmcp`, `jlsp`, `jerbuild`, and `jpkg` symlink manifest, and verifies that
-tracked source inputs did not change during the builds. The report must end
-with `binary_status=match`, `program_image_status=match`, `bundle_status=match`,
-`link_status=match`, `source_manifest_status=match`,
-`object_cache_equivalence_status=match`, and `status=match`.
+tracked source inputs did not change during the builds. Exact byte matches are
+recorded in `binary_byte_status`, `program_so_byte_status`, and
+`program_wpo_byte_status`. When Chez emits byte-different but
+`#%$fasl-file-equal?`-equivalent program images, the report records
+`program_image_match_mode=fasl-equivalent` and
+`binary_match_mode=embedded-program-fasl-equivalence` instead of hiding the raw
+byte mismatch. The report must end with `binary_status=match`,
+`program_image_status=match`, `bundle_status=match`, `link_status=match`,
+`source_manifest_status=match`, `object_cache_equivalence_status=match`, and
+`status=match`.
 
 Independent-builder evidence is checked with:
 
@@ -91,20 +109,20 @@ make reproducibility-compare REPRO_A=dist/reproducibility REPRO_B=/path/to/other
 ```
 
 That target compares the two report statuses, git commit, `SOURCE_DATE_EPOCH`,
-binary hash, program image hash when present, bundle hash when present, symlink
+match modes, exact hashes for byte-matched artifacts, bundle hashes, symlink
 manifest, and tracked source manifest. It exits nonzero on mismatch.
 
 Current local evidence records `binary_status=match`,
-`program_image_kind=compile-program`, `program_image_status=match`,
-`program_so_status=match`, `program_wpo_status=missing`,
-`bundle_status=match`, `link_status=match`,
-`source_manifest_status=match`, `object_cache_equivalence_status=match`, and
-`status=match`.
+`program_image_kind=compile-program`, `program_image_status=match`, exact byte
+status fields for each image, the selected match mode, `bundle_status=match`,
+`link_status=match`, `source_manifest_status=match`,
+`object_cache_equivalence_status=match`, and `status=match`.
 
 `make release-evidence` archives the production audit, multicall smoke,
 release unification check, hardware-hardening smoke, signing evidence, SBOM,
-reproducibility report, release-input hashes, git state, and host build
-environment under `dist/release-evidence/`.
+reproducibility report, release-input hashes, git state, and host-neutral build
+environment under `dist/release-evidence/`. The evidence target sanitizes and
+fails closed on private path, SSH remote, host, or `uname -a` markers.
 
 Current release artifacts must have SHA-256 files and detached publisher
 signatures. `make sign-release-artifacts` creates a canonical
diff --git a/docs/safety-guide.md b/docs/safety-guide.md
index 6792426..15d83b7 100644
--- a/docs/safety-guide.md
+++ b/docs/safety-guide.md
@@ -786,9 +786,11 @@ the safe version always wins because it is bound last.
 ### Reproducibility Evidence Needs Independent Comparison
 
 `make reproducibility-report` performs a local two-build comparison of the
-multicall binary, object cache, bundle, links, and source manifest, and exits
-nonzero on mismatch. Cross-machine reproducibility is checked by comparing
-reports from independent builders:
+multicall binary, embedded program image, object cache, bundle, links, and
+source manifest, and exits nonzero on mismatch. Exact byte statuses remain in
+the report even when the selected pass mode is Chez FASL equivalence.
+Cross-machine reproducibility is checked by comparing reports from independent
+builders:
 
 ```bash
 make reproducibility-compare REPRO_A=dist/reproducibility REPRO_B=/path/to/other/reproducibility
diff --git a/lib/std/security/sandbox.ss b/lib/std/security/sandbox.ss
index a330891..aa604e8 100644
--- a/lib/std/security/sandbox.ss
+++ b/lib/std/security/sandbox.ss
@@ -382,6 +382,14 @@
                (bytevector-copy! buf 0 chunk 0 n)
                (loop (cons chunk chunks) (+ total n)))])))))
 
+  (def (isolate-child-stdin!)
+    ;; Forked children inherit the parent's --script fd. Replace the Scheme
+    ;; input port before running the thunk so sandboxed code cannot consume the
+    ;; rest of the parent test or runner script.
+    (let ([old-input (current-input-port)])
+      (current-input-port (open-input-string ""))
+      (try (close-port old-input) (catch (exn) (void)))))
+
   ;; ========== Platform-specific protection installation ==========
 
   (def (install-linux-protections! landlock-rules seccomp-filter)
@@ -452,6 +460,7 @@
                ;; === CHILD PROCESS ===
                ;; Close read end — child only writes
                (c-close read-fd)
+               (isolate-child-stdin!)
                (try (begin ;; Install platform-specific protections
                  (install-memory-limit! max-memory-size)
 
diff --git a/support/build-jerboa-multicall.ss b/support/build-jerboa-multicall.ss
index 0119283..a4f63d3 100644
--- a/support/build-jerboa-multicall.ss
+++ b/support/build-jerboa-multicall.ss
@@ -421,8 +421,13 @@
 (define (binary-deterministic-ids?)
   (env-enabled? "JERBOA_BINARY_DETERMINISTIC_IDS" #t))
 
+(define (binary-deterministic-bare-tokens?)
+  (env-enabled? "JERBOA_BINARY_DETERMINISTIC_BARE_TOKENS" #f))
+
 (define (binary-canonicalize-wpo-prefixes?)
   (env-enabled? "JERBOA_BINARY_CANONICALIZE_WPO" #f))
+(define (binary-strip-fasl?)
+  (env-enabled? "JERBOA_BINARY_STRIP_FASL" #f))
 
 (define *binary-canonical-input-gensym-prefix-base* "jerboaseed")
 (define *binary-canonical-wpo-gensym-prefix-base* "jerboawpo")
@@ -988,7 +993,8 @@
            path token* token->canonical))])))
 
 (define (canonicalize-binary-input-bare-tokens! obj-dir source-tokens)
-  (if (binary-deterministic-ids?)
+  (if (and (binary-deterministic-ids?)
+           (binary-deterministic-bare-tokens?))
       (let ([tokens (collect-generated-bare-gensym-tokens-tree obj-dir source-tokens)])
         (canonicalize-bare-gensym-tokens-tree!
          obj-dir
@@ -997,7 +1003,9 @@
       0))
 
 (define (canonicalize-binary-input-bare-tokens-file! path source-tokens)
-  (if (and (binary-deterministic-ids?) (file-exists? path))
+  (if (and (binary-deterministic-ids?)
+           (binary-deterministic-bare-tokens?)
+           (file-exists? path))
       (let ([tokens (collect-generated-bare-gensym-session-tokens-file
                      path
                      source-tokens)])
@@ -1094,30 +1102,50 @@
     (let ([tmp (string-append program-wp-so ".stripped")])
       (when (file-exists? tmp)
         (safe-delete-file tmp))
-      (strip-fasl-file
-       program-wp-so
-       tmp
-       (fasl-strip-options inspector-source
-                           source-annotations
-                           profile-source))
-      (safe-delete-file program-wp-so)
-      (rename-file tmp program-wp-so)
-      (printf "    Stripped deterministic WPO FASL metadata: ~a~n"
-              program-wp-so))))
+      (guard (exn
+              [else
+               (when (file-exists? tmp)
+                 (safe-delete-file tmp))
+               (printf "    FASL metadata strip skipped for ~a: ~a~n"
+                       program-wp-so
+                       (condition-brief exn))])
+        (strip-fasl-file
+         program-wp-so
+         tmp
+         (fasl-strip-options inspector-source
+                             source-annotations
+                             profile-source))
+        (safe-delete-file program-wp-so)
+        (rename-file tmp program-wp-so)
+        (printf "    Stripped deterministic WPO FASL metadata: ~a~n"
+                program-wp-so)))))
+
+(define (condition-brief exn)
+  (cond
+    [(message-condition? exn) (condition-message exn)]
+    [else (format "~s" exn)]))
 
 (define (strip-binary-fasl-artifact! path)
   (let ([tmp (string-append path ".stripped")])
     (when (file-exists? tmp)
       (safe-delete-file tmp))
-    (strip-fasl-file
-     path
-     tmp
-     (fasl-strip-options inspector-source
-                         source-annotations
-                         profile-source))
-    (safe-delete-file path)
-    (rename-file tmp path)
-    1))
+    (guard (exn
+            [else
+             (when (file-exists? tmp)
+               (safe-delete-file tmp))
+             (printf "    FASL metadata strip skipped for ~a: ~a~n"
+                     path
+                     (condition-brief exn))
+             0])
+      (strip-fasl-file
+       path
+       tmp
+       (fasl-strip-options inspector-source
+                           source-annotations
+                           profile-source))
+      (safe-delete-file path)
+      (rename-file tmp path)
+      1)))
 
 (define (strip-binary-fasl-tree! root)
   (if (binary-deterministic-ids?)
@@ -1150,11 +1178,14 @@
       (when (> count 0)
         (printf "    Canonicalized Chez gensym session prefix in ~a object occurrence(s) (~a input, ~a WPO-only)~n"
                 count input-count wpo-count))
-      (strip-binary-wpo-fasl! program-wp-so)
-      (let ([strip-count (strip-binary-fasl-tree! obj-dir)])
-        (when (> strip-count 0)
-          (printf "    Stripped deterministic FASL metadata in ~a bundled object file(s)~n"
-                  strip-count))))))
+      (if (binary-strip-fasl?)
+          (begin
+            (strip-binary-wpo-fasl! program-wp-so)
+            (let ([strip-count (strip-binary-fasl-tree! obj-dir)])
+              (when (> strip-count 0)
+                (printf "    Stripped deterministic FASL metadata in ~a bundled object file(s)~n"
+                        strip-count))))
+          (printf "    Runtime FASL metadata stripping: disabled by JERBOA_BINARY_STRIP_FASL~n")))))
 
 (define (linux-x86-64-machine? target-os machine)
   (and (eq? target-os 'linux)
@@ -1451,10 +1482,12 @@
                 (+ input-gensym-count input-bare-token-count)
                 input-gensym-count
                 input-bare-token-count))
-      (let ([strip-count (strip-binary-fasl-tree! obj-dir)])
-        (when (> strip-count 0)
-          (printf "    Stripped deterministic FASL metadata in ~a program object file(s)~n"
-                  strip-count)))))
+      (if (binary-strip-fasl?)
+          (let ([strip-count (strip-binary-fasl-tree! obj-dir)])
+            (when (> strip-count 0)
+              (printf "    Stripped deterministic FASL metadata in ~a program object file(s)~n"
+                      strip-count)))
+          (printf "    Runtime FASL metadata stripping: disabled by JERBOA_BINARY_STRIP_FASL~n"))))
 
 ;; OS link libs for the FINAL cc link of the multicall binary. Cross Chez is
 ;; configured --disable-curses --disable-x11 --disable-iconv, so libkernel.a
diff --git a/support/reproducibility-compare.sh b/support/reproducibility-compare.sh
index 07b0632..c25f1f7 100755
--- a/support/reproducibility-compare.sh
+++ b/support/reproducibility-compare.sh
@@ -90,6 +90,18 @@ compare_hash_file() {
     fi
 }
 
+compare_hash_file_when_byte_matched() {
+    field=$1
+    rel=$2
+    va=$(field_value "$A/result.txt" "$field" 2>/dev/null || true)
+    vb=$(field_value "$B/result.txt" "$field" 2>/dev/null || true)
+    if [ "$va" = "match" ] && [ "$vb" = "match" ]; then
+        compare_hash_file "$rel"
+    else
+        note "$rel=skipped-$field:$va/$vb"
+    fi
+}
+
 compare_manifest() {
     rel=$1
     fa="$A/$rel"
@@ -124,7 +136,16 @@ compare_kv_field build-env.txt source_date_epoch
 for key in \
     program_image_kind \
     binary_status \
+    binary_byte_status \
+    binary_match_mode \
     program_image_status \
+    program_image_match_mode \
+    program_so_status \
+    program_so_byte_status \
+    program_so_fasl_equivalence_status \
+    program_wpo_status \
+    program_wpo_byte_status \
+    program_wpo_fasl_equivalence_status \
     bundle_status \
     link_status \
     source_manifest_status \
@@ -136,11 +157,26 @@ done
 
 for rel in \
     first-jerboa.sha256 \
-    second-jerboa.sha256 \
+    second-jerboa.sha256
+do
+    compare_hash_file_when_byte_matched binary_byte_status "$rel"
+done
+
+for rel in \
     first-program.so.sha256 \
-    second-program.so.sha256 \
+    second-program.so.sha256
+do
+    compare_hash_file_when_byte_matched program_so_byte_status "$rel"
+done
+
+for rel in \
     first-program.wp.so.sha256 \
-    second-program.wp.so.sha256 \
+    second-program.wp.so.sha256
+do
+    compare_hash_file_when_byte_matched program_wpo_byte_status "$rel"
+done
+
+for rel in \
     first-bundle.sha256 \
     second-bundle.sha256
 do
diff --git a/support/reproducibility-report.sh b/support/reproducibility-report.sh
index 2daf6fb..5ba6dce 100755
--- a/support/reproducibility-report.sh
+++ b/support/reproducibility-report.sh
@@ -84,6 +84,53 @@ env_enabled() {
     esac
 }
 
+FASL_FILE_EQ_SCRIPT=$TMP_DIR/fasl-file-equivalence.ss
+cat > "$FASL_FILE_EQ_SCRIPT" <<'EOF'
+#!chezscheme
+(import (chezscheme))
+
+(define args (command-line-arguments))
+(unless (= (length args) 2)
+  (display "usage: fasl-file-equivalence.ss A B\n" (current-error-port))
+  (exit 2))
+
+(define (condition-brief exn)
+  (cond
+    [(message-condition? exn) (condition-message exn)]
+    [else (format "~s" exn)]))
+
+(guard (exn
+        [else
+         (printf "error=~a\n" (condition-brief exn))
+         (printf "status=mismatch\n")
+         (exit 1)])
+  (if (#%$fasl-file-equal? (car args) (cadr args) #f #t)
+      (begin
+        (printf "status=match\n")
+        (exit 0))
+      (begin
+        (printf "status=mismatch\n")
+        (exit 1))))
+EOF
+
+fasl_equivalence_status() {
+    label=$1
+    a=$2
+    b=$3
+    out=$TMP_DIR/$label-fasl-equivalence.txt
+    if [ ! -f "$a" ] || [ ! -f "$b" ]; then
+        printf 'status=missing\n' > "$out"
+        printf 'missing\n'
+    elif cmp -s "$a" "$b"; then
+        printf 'byte_status=match\nstatus=match\n' > "$out"
+        printf 'match\n'
+    elif "$SCHEME_BIN" --script "$FASL_FILE_EQ_SCRIPT" "$a" "$b" > "$out" 2>&1; then
+        printf 'match\n'
+    else
+        printf 'mismatch\n'
+    fi
+}
+
 link_manifest() {
     label=$1
     (
@@ -164,38 +211,70 @@ build_once second
 source_manifest > "$TMP_DIR/source-after.sha256"
 
 if cmp -s "$TMP_DIR/first-jerboa" "$TMP_DIR/second-jerboa"; then
-    binary_status=match
+    binary_byte_status=match
 else
-    binary_status=mismatch
+    binary_byte_status=mismatch
 fi
 
+program_wpo_byte_status=missing
+program_wpo_fasl_equivalence_status=missing
 if [ -f "$TMP_DIR/first-program.wp.so" ] && [ -f "$TMP_DIR/second-program.wp.so" ]; then
     if cmp -s "$TMP_DIR/first-program.wp.so" "$TMP_DIR/second-program.wp.so"; then
-        program_wpo_status=match
+        program_wpo_byte_status=match
     else
-        program_wpo_status=mismatch
+        program_wpo_byte_status=mismatch
     fi
-else
-    program_wpo_status=missing
+    program_wpo_fasl_equivalence_status=$(fasl_equivalence_status program-wpo "$TMP_DIR/first-program.wp.so" "$TMP_DIR/second-program.wp.so")
 fi
-
+case "$program_wpo_byte_status:$program_wpo_fasl_equivalence_status" in
+    match:*) program_wpo_status=match ;;
+    missing:*) program_wpo_status=missing ;;
+    *:match) program_wpo_status=fasl-equivalent ;;
+    *) program_wpo_status=mismatch ;;
+esac
+
+program_so_byte_status=missing
+program_so_fasl_equivalence_status=missing
 if [ -f "$TMP_DIR/first-program.so" ] && [ -f "$TMP_DIR/second-program.so" ]; then
     if cmp -s "$TMP_DIR/first-program.so" "$TMP_DIR/second-program.so"; then
-        program_so_status=match
+        program_so_byte_status=match
     else
-        program_so_status=mismatch
+        program_so_byte_status=mismatch
     fi
-else
-    program_so_status=missing
+    program_so_fasl_equivalence_status=$(fasl_equivalence_status program-so "$TMP_DIR/first-program.so" "$TMP_DIR/second-program.so")
 fi
-
+case "$program_so_byte_status:$program_so_fasl_equivalence_status" in
+    match:*) program_so_status=match ;;
+    missing:*) program_so_status=missing ;;
+    *:match) program_so_status=fasl-equivalent ;;
+    *) program_so_status=mismatch ;;
+esac
+
+program_image_match_mode=missing
 if env_enabled "${JERBOA_BINARY_WPO:-0}"; then
     program_image_kind=compile-whole-program
-    program_image_status=$program_wpo_status
+    selected_program_status=$program_wpo_status
 else
     program_image_kind=compile-program
-    program_image_status=$program_so_status
+    selected_program_status=$program_so_status
 fi
+case "$selected_program_status" in
+    match)
+        program_image_status=match
+        program_image_match_mode=byte
+        ;;
+    fasl-equivalent)
+        program_image_status=match
+        program_image_match_mode=fasl-equivalent
+        ;;
+    missing)
+        program_image_status=missing
+        ;;
+    *)
+        program_image_status=mismatch
+        program_image_match_mode=mismatch
+        ;;
+esac
 
 if [ -f "$TMP_DIR/first-bundle.tar" ] && [ -f "$TMP_DIR/second-bundle.tar" ]; then
     if cmp -s "$TMP_DIR/first-bundle.tar" "$TMP_DIR/second-bundle.tar"; then
@@ -226,6 +305,17 @@ else
     object_cache_equivalence_status=mismatch
 fi
 
+if [ "$binary_byte_status" = "match" ]; then
+    binary_status=match
+    binary_match_mode=byte
+elif [ "$program_image_match_mode" = "fasl-equivalent" ]; then
+    binary_status=match
+    binary_match_mode=embedded-program-fasl-equivalence
+else
+    binary_status=mismatch
+    binary_match_mode=unexplained-byte-mismatch
+fi
+
 status=match
 for value in "$binary_status" "$program_image_status" "$bundle_status" "$link_status" "$source_manifest_status" "$object_cache_equivalence_status"; do
     if [ "$value" != "match" ]; then
@@ -236,10 +326,17 @@ done
 {
     echo "repo=jerboa"
     echo "binary_status=$binary_status"
+    echo "binary_byte_status=$binary_byte_status"
+    echo "binary_match_mode=$binary_match_mode"
     echo "program_image_kind=$program_image_kind"
     echo "program_image_status=$program_image_status"
+    echo "program_image_match_mode=$program_image_match_mode"
     echo "program_so_status=$program_so_status"
+    echo "program_so_byte_status=$program_so_byte_status"
+    echo "program_so_fasl_equivalence_status=$program_so_fasl_equivalence_status"
     echo "program_wpo_status=$program_wpo_status"
+    echo "program_wpo_byte_status=$program_wpo_byte_status"
+    echo "program_wpo_fasl_equivalence_status=$program_wpo_fasl_equivalence_status"
     echo "bundle_status=$bundle_status"
     echo "link_status=$link_status"
     echo "source_manifest_status=$source_manifest_status"
@@ -250,17 +347,17 @@ done
     echo "status=$status"
 } > "$TMP_DIR/result.txt"
 
-if [ "$binary_status" != "match" ]; then
+if [ "$binary_byte_status" = "mismatch" ]; then
     cmp -l "$TMP_DIR/first-jerboa" "$TMP_DIR/second-jerboa" \
         2>/dev/null | sed -n '1,200p' > "$TMP_DIR/binary-byte-diff-sample.txt" || true
 fi
 
-if [ "$program_wpo_status" = "mismatch" ]; then
+if [ "$program_wpo_byte_status" = "mismatch" ]; then
     cmp -l "$TMP_DIR/first-program.wp.so" "$TMP_DIR/second-program.wp.so" \
         2>/dev/null | sed -n '1,200p' > "$TMP_DIR/program-wpo-byte-diff-sample.txt" || true
 fi
 
-if [ "$program_so_status" = "mismatch" ]; then
+if [ "$program_so_byte_status" = "mismatch" ]; then
     cmp -l "$TMP_DIR/first-program.so" "$TMP_DIR/second-program.so" \
         2>/dev/null | sed -n '1,200p' > "$TMP_DIR/program-so-byte-diff-sample.txt" || true
 fi
diff --git a/support/sanitize-evidence.sh b/support/sanitize-evidence.sh
new file mode 100755
index 0000000..7373546
--- /dev/null
+++ b/support/sanitize-evidence.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+set -eu
+
+fail() {
+    printf 'sanitize-evidence: %s\n' "$*" >&2
+    exit 1
+}
+
+redact_file() {
+    file=$1
+    grep -Iq . "$file" || return 0
+    tmp=$file.sanitize.$$
+    sed -E \
+        -e 's#/Users/[^[:space:]"]+#<redacted-path>#g' \
+        -e 's#/home/[^/[:space:]"]+[^[:space:]"]*#<redacted-path>#g' \
+        -e 's#~/mine(/[^[:space:]"]*)?#<redacted-path>#g' \
+        -e 's#git@[^[:space:]"]+#<redacted-ssh-remote>#g' \
+        -e 's#users-MacBook-Pro#<redacted-host>#g' \
+        -e 's#jerboa_home=[^[:space:]]+#jerboa_home=<redacted-path>#g' \
+        -e 's#jerbuild_tool=[^[:space:]]+#jerbuild_tool=<redacted-path>#g' \
+        "$file" > "$tmp"
+    mv "$tmp" "$file"
+}
+
+[ "$#" -gt 0 ] || exit 0
+
+for path in "$@"; do
+    [ -e "$path" ] || continue
+    find "$path" -type f -print | while IFS= read -r file; do
+        redact_file "$file"
+    done
+done
+
+if command -v rg >/dev/null 2>&1; then
+    if rg -n -H '/Users/|/home/[^/[:space:]]+|~/mine|git@|uname -a|users-MacBook-Pro|jerboa_home=/Users|jerbuild_tool=/Users' "$@"; then
+        fail "private path, host, remote, or uname -a marker found in release evidence"
+    fi
+else
+    if grep -R -n -E '/Users/|/home/[^/[:space:]]+|~/mine|git@|uname -a|users-MacBook-Pro|jerboa_home=/Users|jerbuild_tool=/Users' "$@"; then
+        fail "private path, host, remote, or uname -a marker found in release evidence"
+    fi
+fi
diff --git a/tests/test-better.ss b/tests/test-better.ss
index 6109142..e484bc9 100644
--- a/tests/test-better.ss
+++ b/tests/test-better.ss
@@ -32,10 +32,9 @@
 (define allocate-foreign foreign-alloc)
 
 (define-syntax checked-ftype-set!
-  (lambda (stx)
-    (datum->syntax
-      stx
-      (cons (string->symbol "ftype-set!") (cdr (syntax->datum stx))))))
+  (syntax-rules ()
+    [(_ ftype path ptr value)
+     (ftype-set! ftype path ptr value)]))
 
 (define-syntax check
   (syntax-rules (=>)
diff --git a/tests/test-jpkg-commands.ss b/tests/test-jpkg-commands.ss
index 397b22c..3397ab1 100644
--- a/tests/test-jpkg-commands.ss
+++ b/tests/test-jpkg-commands.ss
@@ -38,6 +38,7 @@
 
 (define tmp (format "/tmp/jpkg-cmd-~a" (random-suffix)))
 (define orig-dir (current-directory))
+(when (file-exists? tmp) (remove-tree tmp))
 (mkdir-p tmp)
 (current-directory tmp)
 
diff --git a/tools/check-native-boundary.ss b/tools/check-native-boundary.ss
index 3e15a6c..1aeb877 100644
--- a/tools/check-native-boundary.ss
+++ b/tools/check-native-boundary.ss
@@ -8,8 +8,8 @@
 (define warnings '())
 
 (define skipped-dirs
-  '("." ".." ".git" ".chez" "build" "dist" "target" "node_modules" "vendor"
-    "fixtures"))
+  '("." ".." ".git" ".chez" ".chez-static" ".freebsd-sysroot" "build" "dist"
+    "target" "node_modules" "vendor" "fixtures" "lib-cross"))
 
 (define (add-error msg) (set! errors (cons msg errors)))
 (define (add-warning msg) (set! warnings (cons msg warnings)))
diff --git a/tools/security-audit.sh b/tools/security-audit.sh
index 5a1ce57..d63c920 100755
--- a/tools/security-audit.sh
+++ b/tools/security-audit.sh
@@ -33,6 +33,7 @@ for file in \
   docs/release-artifacts.md \
   docs/release-security.md \
   support/sbom.sh \
+  support/sanitize-evidence.sh \
   support/reproducibility-report.sh \
   .github/workflows/security-baseline.yml \
   .github/workflows/ci.yml