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 (?\\d+\\.\\d+\\.\\d+) \\(zenjpeg (?\\d+\\.\\d+\\.\\d+)\\)" diff --git a/docs/MAINTENANCE.md b/docs/MAINTENANCE.md index 41cebfeac..151c49bce 100644 --- a/docs/MAINTENANCE.md +++ b/docs/MAINTENANCE.md @@ -1189,7 +1189,7 @@ brew install cmake ninja # for the pinned avifenc below ./tools/photos/libavif/build.sh brew install uv && bun run photos:env # Pillow, for gen-pixel-peeper.py only (brew's python3 is PEP 668; pip into it fails) # the JPEG encoder (zenc) builds itself on first pipeline run; needs rust (rustup.rs) -cargo build --release --manifest-path tools/photos/zenc/Cargo.toml +cargo build --release --locked --manifest-path tools/photos/zenc/Cargo.toml bun run wrangler login # Cloudflare auth (deploys + KV + R2 all use it) # the study pages, which are NOT needed to add a photo diff --git a/package.json b/package.json index ec13ce21d..5bf9e0f2b 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,8 @@ "checkpoints:check": "bun tools/check-checkpoints.ts", "checkpoints:sync": "bun tools/check-checkpoints.ts --sync", "inp": "bun tools/inp-lab.ts", - "release": "bun tools/release-status.ts" + "release": "bun tools/release-status.ts", + "zenc:reproducible": "bun tools/photos/zenc-reproducible.ts" }, "comment:check-fast": "Local feedback only: lint, typecheck and test are independent read-only gates, so Bun can run them concurrently. CI keeps them as named sequential steps for legible failures. Do not add build, routes, Lens or perf commands here: several share .build or intentionally run under Node.", "devDependencies": { diff --git a/public/_headers b/public/_headers index d65600210..dbd9a677a 100644 --- a/public/_headers +++ b/public/_headers @@ -78,7 +78,7 @@ Cache-Control: public, max-age=31536000, immutable # OG / Twitter card images (public/og/
-.png), rendered from each -# garage + lwe demo by scripts/gen-og-cards.mjs. The URL is stable and the bytes +# garage + lwe demo by tools/photos/gen-og-cards.ts. The URL is stable and the bytes # change only when a demo's look changes (rare), so NOT immutable — a 30-day # cache clears Lighthouse's "efficient cache lifetimes" bar while a regen + deploy # purges the edge so a refreshed card lands. Social crawlers cache on their own @@ -409,7 +409,7 @@ Cache-Control: public, max-age=0, must-revalidate, s-maxage=60 Service-Worker-Allowed: / -# RSS feeds are build output (scripts/gen-feeds.mjs), regenerated on every deploy +# RSS feeds are build output (tools/gen-feeds.ts), regenerated on every deploy # from site-manifest.json + sitemap lastmod + posts.json. Served as # application/rss+xml rather than the extension's default application/xml so a # reader recognizes the document without sniffing it. Cached like the other diff --git a/src/content/md/terminal.md b/src/content/md/terminal.md index d080c2ce0..bc0b7e5c6 100644 --- a/src/content/md/terminal.md +++ b/src/content/md/terminal.md @@ -132,7 +132,7 @@ So `/radar` does not sense anything. **You bring the signal; it brings the display.** POST readings you have already measured and it draws them: ``` -node tools/photos/radar-sample.mjs --at https://aadhar.sh --anonymize +node tools/photos/radar-sample.ts --at https://aadhar.sh --anonymize curl -X POST aadhar.sh/radar -d '{"samples":[{"name":"AP","rssi":-58}]}' ``` diff --git a/src/pages/garage/workers.html b/src/pages/garage/workers.html index d903d9931..fbfd4740e 100644 --- a/src/pages/garage/workers.html +++ b/src/pages/garage/workers.html @@ -220,9 +220,9 @@

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 @@