LIVE https://todo-rust.bfj.oncarlos.com f78a916

## What's there

- Rust: axum 0.8 on tokio, maud templates, rusqlite with bundled SQLite,
  mimalloc. A static linux-arm64 musl binary of about 3 MB, built with
  `cargo zigbuild`.
- `make test`: 10 in-process HTTP tests, all passing.
- Shared suite on a local run: 67 passed, 3 skipped (the skips are the
  JS-only tests in the JS-off run). Against
  [https://todo-rust.bfj.oncarlos.com](https://todo-rust.bfj.oncarlos.com),
  67 passed, 3 skipped after the review-fix deploy (`f78a916`).
- `scripts/boot-check.sh dist/app-linux-arm64`: healthz 200, version 200,
  clean exit on SIGTERM.

## Worth knowing

On the first live run, one test failed: a cross-origin POST got 502
from the edge instead of 403. It reproduced reliably: 19 of 60
cross-origin POSTs and 13 of 40 POSTs to an unknown path came back 502.
Both responses were sent before the app had read the request body, and
that drops the connection to the edge. The app now reads the whole body
(up to 1 MiB) before it answers anything. Afterwards, 120 of 120 of
those requests answered correctly (403 and 404). Any other app that
rejects a request without reading its body may hit the same thing on
Carloku.

## Review fixes (`f78a916`)

1. **An edit was lost when another action's response arrived.**
   `static/app.js` used to replace the whole list on every response. If
   an item is being edited and its edit hasn't been sent yet, the list is
   now patched around that item instead. Its draft, focus and edit state
   stay, and only its view (label, checkbox) is refreshed. Checked with a
   Playwright script that delayed POST responses by 1.5 s: toggle one
   item, start editing another and type a draft. When the toggle response
   arrived, the toggle was applied and the draft, focus and edit state
   were all still there. Pressing Enter then saved the draft.
2. **`clean-deps` left Zig's compiled libraries in its shared cache.**
   The Makefile now points `ZIG_GLOBAL_CACHE_DIR` and
   `ZIG_LOCAL_CACHE_DIR` at `apps/rust/.cache/zig`, and `clean-deps`
   removes that directory. A cold `make build-arm64` after `clean-deps`
   took 1 min 29 s and refilled `.cache/zig` (79 MB).

## Review findings not fixed

None.
