diff --git a/CLAUDE.md b/CLAUDE.md
index bd73113bf..fd5ec5313 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -215,7 +215,7 @@ bun run photos:env
# build the JPEG thumbnail encoder (zenc = zenjpeg hybrid+scan). the pipeline
# scripts auto-build it on first run; this is the explicit form.
-cargo build --release --manifest-path tools/photos/zenc/Cargo.toml
+cargo build --release --locked --manifest-path tools/photos/zenc/Cargo.toml
# bust caches via wrangler (RN_KV namespace ID hardcoded in scripts).
# NB: the photo manifest is NOT a cache anymore — the worker bundles
diff --git a/config/tools.json b/config/tools.json
index 8690a0e38..a179ab5a2 100644
--- a/config/tools.json
+++ b/config/tools.json
@@ -147,12 +147,12 @@
"match": "cargo (\\d+\\.\\d+\\.\\d+)"
},
"bytes": false,
- "bytes_why": "builds zenc, and zenjpeg's encode is deterministic for a given pin, which dependabot owns in tools/photos/zenc/Cargo.toml. A compiler bump does not move a JPEG"
+ "bytes_why": "builds zenc, and zenjpeg's encode is deterministic for a given pin, which dependabot owns in tools/photos/zenc/Cargo.toml. A compiler bump does not move a JPEG, and it does not move a HISTOGRAM either, which is the half that was doubted: `bun run zenc:reproducible` bakes all 165 stems under three rustc versions and diffs them"
},
{
"bin": "zenc",
"path": "tools/photos/zenc/target/release/zenc",
- "install": "cargo build --release --manifest-path tools/photos/zenc/Cargo.toml",
+ "install": "cargo build --release --locked --manifest-path tools/photos/zenc/Cargo.toml",
"optional": true,
"why": "the JPEG encoder for every shipped tier, plus the square/resize geometry and the histogram bake. It decides the bytes of the JPG half of /i/ exactly the way avifenc decides the AVIF half, and it was the one encoder here with no entry: `cargo` was declared as its BUILD prerequisite, which is a different question from which encoder baked the library",
"required_by": [
@@ -165,7 +165,7 @@
"tools/photos/onestep-probe.sh",
"tools/photos/reencode-thumbnails.sh"
],
- "optional_why": "`optional` here means BUILT ON DEMAND rather than degrades: every caller runs `cargo build --release` when the binary is missing, so an absent zenc on a fresh checkout is a state the pipeline repairs itself rather than a prerequisite anybody has to go install. A missing `cargo` is the blocking failure, and cargo is declared above",
+ "optional_why": "`optional` here means BUILT ON DEMAND rather than degrades: every caller runs `cargo build --release --locked` when the binary is missing, so an absent zenc on a fresh checkout is a state the pipeline repairs itself rather than a prerequisite anybody has to go install. A missing `cargo` is the blocking failure, and cargo is declared above",
"version": {
"flag": "--version",
"match": "zenc (?The real unlock: configuration as code
with ! carves that path back out to serve straight from the edge:
{
"name": "aadhar-sh",
- "main": "www/_worker.js/index.js",
+ "main": ".build/src/worker/index.ts",
"assets": {
- "directory": "www",
+ "directory": ".build/public",
"binding": "ASSETS",
"run_worker_first": ["/*", "!/nav.js", "!/garage/*", "!/images/*.avif", ...]
},
@@ -266,7 +266,7 @@ 2 · Durable Objects, in-house (already shipped)
odometer at the bottom of the front page) had to reach across to a separate
Worker, cf-garage, and borrow its Counter
class by cross-script binding. On Workers the class lives right here, in
- www/_worker.js/counter.js, exported from the entry, with its
+ src/worker/counter.ts, exported from the entry, with its
migration in the same config. To keep the number honest across the move, the new object
self-seeds once from the count it had on the old one (about 2,375) instead of resetting to
zero. Same odometer, now wired into its own dashboard.
@@ -462,7 +462,7 @@ The honest scorecard
{
"t": "Its Durable Object class moved in-house, exported from this worker's entry with its migration in the same config.",
"ok": true,
- "why": "Right. Pages could host no Durable Object, so the counter borrowed the Counter class from the separate cf-garage worker by cross-script binding. Now it lives in www/_worker.js/counter.js."
+ "why": "Right. Pages could host no Durable Object, so the counter borrowed the Counter class from the separate cf-garage worker by cross-script binding. Now it lives in src/worker/counter.ts."
},
{
"t": "It moved out of a Durable Object into KV, which Workers ships built in.",
diff --git a/src/pages/lwe/vigenere.html b/src/pages/lwe/vigenere.html
index a63899ae6..0a48700af 100644
--- a/src/pages/lwe/vigenere.html
+++ b/src/pages/lwe/vigenere.html
@@ -547,13 +547,13 @@