diff --git a/core/README.md b/core/README.md index cae2c2c..8ac0ddf 100644 --- a/core/README.md +++ b/core/README.md @@ -68,8 +68,13 @@ daylight-saving change, and requires identical engine JSON after every step. ## Size and speed (2026-10-10) Measured on one desktop with Node.js 24; not phone or download measurements. -The release module is 589,730 bytes (186,689 with gzip). Node instantiated it +The release module is 454,612 bytes (167,650 with gzip). Node instantiated it in about 2–3 ms. Reading a deliberately large state (240 chat lines, 60 -memories, 365 diary pages) took about 1.1–1.4 ms; the body-only patch read per +memories, 365 diary pages) took about 1.0–1.4 ms; the body-only patch read per tick about 0.01 ms, and one body advance about 0.01 ms (averages of 50 runs, -two runs). +three runs). + +The build is reproducible across checkouts: `core/wasm/build.sh` remaps the +checkout, Cargo registry and toolchain paths that panic locations embed, and +the release profile strips symbols. Builds of one commit from two different +checkout paths produced identical module, glue and declaration files. diff --git a/core/wasm/Cargo.toml b/core/wasm/Cargo.toml index 35b07dd..eb96839 100644 --- a/core/wasm/Cargo.toml +++ b/core/wasm/Cargo.toml @@ -24,4 +24,4 @@ opt-level = "s" lto = true codegen-units = 1 panic = "abort" -strip = "debuginfo" +strip = true diff --git a/core/wasm/build.sh b/core/wasm/build.sh index cdd6142..541614d 100755 --- a/core/wasm/build.sh +++ b/core/wasm/build.sh @@ -6,7 +6,8 @@ # # Requires Rust 1.88+ with the wasm32-unknown-unknown target and # wasm-bindgen-cli at exactly the version Cargo.lock pins for wasm-bindgen. -# Reads no other environment. OUT_DIR is replaced only after both steps pass. +# Reads CARGO_HOME (default ~/.cargo) only to remap its paths; it replaces +# any RUSTFLAGS for this build. OUT_DIR is replaced only after both steps pass. set -euo pipefail [ $# -le 1 ] || { sed -n '2,/^set -e/p' "$0" | sed '$d;s/^# \{0,1\}//' >&2; exit 2; } HERE=$(cd "$(dirname "$0")" && pwd) @@ -26,7 +27,19 @@ rustup target list --installed 2>/dev/null | grep -qx wasm32-unknown-unknown || echo "core/wasm/build.sh: run: rustup target add wasm32-unknown-unknown" >&2 exit 2 } -cargo build --release --locked --quiet --manifest-path "$HERE/Cargo.toml" --target wasm32-unknown-unknown +# Remap the checkout, Cargo registry and toolchain paths that panic locations +# would embed, so the same commit builds the same bytes on any machine and no +# build-machine path ships in the app. Symbols are stripped (Cargo.toml). +ROOT=$(dirname "$(dirname "$HERE")") +REGISTRY=${CARGO_HOME:-$HOME/.cargo}/registry/src +SYSROOT=$(rustc --print sysroot) +FLAGS=() +for map in "$ROOT=/tokenling" "$(realpath -m "$ROOT")=/tokenling" "$REGISTRY=/cargo" \ + "$(realpath -m "$REGISTRY")=/cargo" "$SYSROOT=/rust" "$(realpath -m "$SYSROOT")=/rust"; do + FLAGS+=("--remap-path-prefix=$map") +done +CARGO_ENCODED_RUSTFLAGS=$(IFS=$'\x1f'; echo "${FLAGS[*]}") \ + cargo build --release --locked --quiet --manifest-path "$HERE/Cargo.toml" --target wasm32-unknown-unknown STAGE=$(mktemp -d) trap 'rm -rf "$STAGE"' EXIT wasm-bindgen "$HERE/target/wasm32-unknown-unknown/release/tokenling_core.wasm" \ diff --git a/docs/deployment.md b/docs/deployment.md index a4b085f..6d35d53 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -128,7 +128,7 @@ Any static file server or static host works; nothing runs on the server. because those directories never change in place. Serve `sw.js` with `Cache-Control: no-cache` (or a short max-age) so worker updates arrive. - **Compression** is optional; the `.onnx` and runtime `.wasm` files barely - compress. The app's rules module (about 0.6 MB) shrinks to about a third + compress. The app's rules module (about 0.45 MB) shrinks to about a third with gzip. - Allow for sizes: about 97 MB per model and about 85 MB of runtime (a browser fetches only one of the `.wasm` builds; the one transformers.js loads is diff --git a/docs/gotchas.md b/docs/gotchas.md index 9b80e29..dfdc966 100644 --- a/docs/gotchas.md +++ b/docs/gotchas.md @@ -339,6 +339,13 @@ generated glue only works with the CLI of exactly the crate's version. Install the version `core/wasm/Cargo.lock` pins (`cargo install wasm-bindgen-cli --version X --locked`) rather than unpinning the crate. +**The same commit builds a different app hash on another machine or path.** +Rust embeds absolute source paths in panic locations and its symbol names +depend on the package path, so an unremapped WebAssembly build differs by +checkout (even through a symlinked path) and ships the build machine's +paths. `core/wasm/build.sh` remaps those paths and the release profile strips +symbols; keep both when changing the build. + **A Node test throws `document is not defined`.** Some browser modules read the page at import (`web/app/config.ts`). Modules the Node tests import (`web/core.ts`, `web/app/engine.ts`, `storage.ts`, `save-format.ts`) must not diff --git a/docs/testing.md b/docs/testing.md index be8cff1..c253cca 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -310,6 +310,10 @@ speed measurements. progress, both transfer directions preserving identity, offline recovery, a second (loopback alias) host and eventual stop, and 1280/768/360 px. The only console errors were the flow's injected network failures. +- Builds of the same commit from two checkout paths (one through a symlink) + first produced different modules: Rust embedded absolute source paths. + After remapping paths and stripping symbols, both produced identical + files, and the checks above passed again on that build. - Not re-tested for this change: physical phones, Firefox, install prompts, background alert delivery, upgrades between two releases, the 90-second one-thread fallback and CUDA serving.