| 1 | LIVE https://todo-ocaml.bfj.oncarlos.com a24ca85 |
| 2 | |
| 3 | ## Checks |
| 4 | |
| 5 | - `make test`: 16 Alcotest tests pass (form parsing, Unicode trimming, |
| 6 | escaping, and the request handler against an in-memory database). |
| 7 | - Shared suite against `dist/app --listen 127.0.0.1`: 67 passed, 3 skipped |
| 8 | (the two JS-only edit tests with JS off, and the screenshot with JS off). |
| 9 | - `scripts/boot-check.sh dist/app-linux-arm64`: /healthz and /api/version |
| 10 | 200, clean exit on SIGTERM. |
| 11 | - Deployed with `make deploy`; `/api/version` reports `a24ca85`. |
| 12 | - Shared suite against https://todo-ocaml.bfj.oncarlos.com: 67 passed, |
| 13 | 3 skipped. |
| 14 | |
| 15 | ## Review fixes (a24ca85) |
| 16 | |
| 17 | 1. **Unbounded request heads.** `bin/main.ml` now runs cohttp-eio's |
| 18 | per-connection loop itself instead of `Cohttp_eio.Server.run` (which |
| 19 | hard-codes `max_size:max_int`). Each connection reads through a byte |
| 20 | budget: 64 KiB for a request line plus headers, then 1 MiB + 64 KiB |
| 21 | per request after that, with at most 256 connections. Checked locally: |
| 22 | a 10 MB header line and 100,000 small headers both get |
| 23 | `431 Request Header Fields Too Large`, and the process stays at about |
| 24 | 17 MB RSS. |
| 25 | 2. **Edits lost on re-render.** `app.js` keeps an open editor across a |
| 26 | response: the same item stays in edit mode with its unsaved text, |
| 27 | focus and selection, and losing focus during the swap doesn't count |
| 28 | as a save. Checked in Chromium with a toggle response held back while |
| 29 | another item was being edited. |
| 30 | 3. **Unicode whitespace.** `Form.trim` strips Unicode White_Space (plus |
| 31 | U+FEFF) and is used for both adding and editing. A title of only |
| 32 | non-breaking spaces adds nothing, and editing to one deletes the item. |
| 33 | 4. **SQLite from source.** `tools/sqlite.sh` downloads the SQLite 3.54.1 |
| 34 | amalgamation once into `.cache/src` (checked against sqlite.org's |
| 35 | SHA3-256) and compiles it into `.cache/sqlite-<arch>`. The `sqlite3` |
| 36 | opam package finds it through `pkg-config`. `make clean-deps` deletes |
| 37 | those builds and keeps the tarball. The shipped binary contains SQLite |
| 38 | 3.54.1 (source id 2026-10-16), not the arm64 root's 3.46.1. |
| 39 | |
| 40 | ## Notes |
| 41 | |
| 42 | - The shipped binary is static glibc (aarch64), built in the emulated |
| 43 | arm64 root with Debian's OCaml 5.3.0 as `ocaml-system`. The linker |
| 44 | warns about `getpwnam`, `gethostbyname` and the like (pulled in by |
| 45 | OCaml's `unix` library). The app never calls them. |
| 46 | - `make clean-deps && make build-arm64` took 20.5 minutes here: SQLite |
| 47 | and every OCaml library compiled under qemu. After that, a rebuild of |
| 48 | the app alone takes about 15 seconds. |
| 49 | - docs-t1 has no `pkg-config`, so the x86 build unpacks Debian's |
| 50 | `pkgconf` into `.cache/` with `apt-get download` (see README). |
| 51 | |