| 1 | LIVE https://todo-spinel.bfj.oncarlos.com 6692def |
| 2 | |
| 3 | ## Where it stands |
| 4 | |
| 5 | - The shared suite passes on the live host: 67 passed, 3 skipped (the two |
| 6 | JS-only edit tests with JS off, and the screenshot test with JS off). |
| 7 | It passes locally too, against the x86-64 build and against the arm64 |
| 8 | binary under qemu, both with `SPINEL_GC_STRESS=1`. |
| 9 | - `make test` (test/run.sh, 86 checks of the contract over curl and raw |
| 10 | sockets, run plain and again under GC stress) passes, against the x86-64 |
| 11 | build and against the arm64 binary under qemu. |
| 12 | - `scripts/boot-check.sh dist/app-linux-arm64` passes. |
| 13 | - `dist/app-linux-arm64` is a static aarch64 ELF, 8.8 MB, no shared |
| 14 | libraries. |
| 15 | |
| 16 | ## Worth knowing |
| 17 | |
| 18 | - **Build route.** The host Spinel compiles Ruby to C; only the C compile |
| 19 | and static link run in the emulated arm64 root (`scripts/spinel-cross`, |
| 20 | `scripts/arm64-cc`). Running the arm64 Spinel itself under emulation |
| 21 | also works but took 14 minutes for hello-world, against about 3 to 5 |
| 22 | minutes this way. Both Spinels are the same commit (`abf54280`). |
| 23 | - **A GC bug, fixed in the tep patch.** spinelkit's `Url.parse_query` |
| 24 | holds a decoded key in an unrooted temporary while it decodes the |
| 25 | value. On arm64 a collection in between dropped every todo title longer |
| 26 | than about a thousand characters (the first live deploy, 947e5fe, |
| 27 | failed the long-title test for this reason). On x86-64 it only shows |
| 28 | under `SPINEL_GC_STRESS=1`. `patches/2-tep-bakeoff.patch` decodes forms |
| 29 | in C instead. Worth reporting upstream to spinelkit/tep. |
| 30 | - **tep rewrites words inside string literals.** Its translator turns |
| 31 | `request` into `req` even inside strings, so a 403 message reading |
| 32 | "cross-origin request refused" came out as "cross-origin req refused". |
| 33 | The app's strings avoid those words. |
| 34 | - **The arm64 root** now has `libssl-dev` installed (tep's HTTP layer |
| 35 | links OpenSSL, and the static link needs `libssl.a`; it also pulls in |
| 36 | `-lz -lzstd`). |
| 37 | - **One worker.** tep's server here is a single blocking process that |
| 38 | closes each connection after its response. Each request has a 10-second |
| 39 | deadline for the whole exchange, so a slow or idle client can't hold it. |
| 40 | |
| 41 | ## Review findings (all four fixed, deployed as 6692def) |
| 42 | |
| 43 | 1. **Per-read timeout.** Replaced by one 10-second deadline per request: |
| 44 | before every read and write, the socket timeouts are set to the time |
| 45 | left. A test trickles one byte a second and is cut off within 12 s. |
| 46 | 2. **Bodies capped at 64 KiB.** tep's C shim now reads bodies whole, up to |
| 47 | 256 KiB, into a growing buffer. Above that the answer is 413. A body |
| 48 | short of its `Content-Length`, carrying a NUL, or sent chunked gets 400 |
| 49 | before any handler runs, so nothing changes. tep's SQLite column |
| 50 | buffer grew from 64 KiB to 256 KiB to match. A 10,000-emoji title |
| 51 | (about 120 KB encoded) round-trips locally and on the live host. |
| 52 | 3. **Unissued cookies accepted.** A new `visitors` table records every |
| 53 | token the server issues. A cookie that isn't in it gets a fresh random |
| 54 | token. A migration backfills the tokens of lists that already existed, |
| 55 | so current visitors keep their lists (checked against a database at the |
| 56 | old schema). |
| 57 | 4. **`--listen` on any address.** The binary now accepts only loopback |
| 58 | (`127.0.0.0/8`, `::1`, `localhost`) and exits with status 2 for any |
| 59 | other address, a missing port, or neither `--socket` nor `--listen`. |
| 60 | tep's every-interface fallback is gone. |
| 61 | |
| 62 | ## Review findings not fixed |
| 63 | |
| 64 | None. |
| 65 | |