LIVE https://todo-zig.bfj.oncarlos.com e5042a9

## What's live

- `todo-zig` on account `bfj`, one instance on channel `edge`, build probe
  `/api/version`. The deployed version is `e5042a9`; `/api/version` and
  `X-Carlos-Version` both report it.
- The shared behaviour suite passed locally (67 passed, 3 skipped) and
  again against [https://todo-zig.bfj.oncarlos.com](https://todo-zig.bfj.oncarlos.com)
  (67 passed, 3 skipped). The skips are the suite's own: blur and Escape
  with JavaScript off, and the screenshot comparison with JavaScript off.
- `scripts/boot-check.sh dist/app-linux-arm64` passed: `/healthz` and
  `/api/version` answer 200 on a unix socket under qemu, and SIGTERM exits 0.
- `make test`: 11 Zig unit tests pass (view, routing, form and cookie
  parsing, title trimming, origin check, store scoping).

## Notes

- Binary: static aarch64 musl, 1.9 MB, stripped, CSS and JS embedded.
- Cold `make build-arm64` after `make clean-deps` took 8m06s on docs-t1,
  with Zig compiling its build runner, musl and the SQLite amalgamation
  from scratch (other builders were compiling at the same time).
- Zig 0.17 unpacks fetched packages into a project-local directory; the
  Makefile points it (and both Zig caches) into `.cache/`, so
  `clean-deps` keeps the downloaded SQLite sources (`.cache/zig/p`,
  `.cache/pkg`) and drops everything compiled.
- Nothing in the contract seemed wrong.

## Review fixes (576c3b8)

Both findings are fixed. After the fixes, the shared suite passed
locally and against the live site (67 passed, 3 skipped each time), and
`boot-check.sh` passed on the new arm64 binary.

1. **An open editor was lost when an earlier response arrived.**
   `static/app.js` now leaves an item being edited in place when it applies
   a response. It never detaches that item, so the editor keeps its focus
   and unsaved text. It replaces the items around it and refreshes the
   item's checkbox, label and classes. If the response no longer contains
   that item (deleted, or filtered out), the list is replaced as before.
   I checked this in a browser: I delayed a toggle by 1 s and opened
   another item's editor while it was pending. When the answer arrived,
   the editor kept its text and focus and the counter updated. Enter then
   saved the edited text.
2. **Titles were trimmed of ASCII whitespace only.** Adding and editing
   now trim Unicode White_Space characters (U+00A0, U+2003, U+3000 and
   the rest) and U+FEFF from both ends (`trimTitle` in `src/app.zig`, with
   a unit test). A whitespace-only add creates nothing, and editing an
   item to whitespace only deletes it. Both were checked with curl.

## Review findings not fixed

None.

## Second review round

The second review request listed no findings, so the code is unchanged
and nothing was redeployed: rebuilding and redeploying the same commit
would change nothing. The live site still reports `576c3b8`, and the
shared suite run against it again passed (67 passed, 3 skipped).

## Third review round (e5042a9)

1. **[security] Malformed UTF-8 in a title aborted the server.** Fixed.
   The backward scan in `trimTitle` (`src/app.zig`) passed every byte
   after a lead byte to `std.unicode.utf8Decode`. That function asserts
   it gets exactly one sequence, so `title=a%80%80%80%80` reached
   `unreachable` and the ReleaseSafe build aborted. I reproduced the
   abort on the previous binary. The scan now checks that the lead
   byte's sequence length matches the bytes found before it decodes;
   anything else is treated as non-whitespace and ends the trim, so a
   malformed title is stored as sent, untrimmed at that end.
   Regression cases are in the `trimTitle` unit test.
   Verified: locally the four malformed payloads answer 303 and
   `/healthz` stays 200, and the live site answers 303 to the reported
   payload. The shared suite passed locally and against the live site
   (67 passed, 3 skipped each time), and `boot-check.sh` passed on the
   new arm64 binary.

No findings from this round were left unfixed.
