From c9d49386160c83d8a6c454b4dae4b8df4e128df6 Mon Sep 17 00:00:00 2001 From: Patrick O'Reilly Date: Fri, 2 Oct 2026 05:47:10 -0700 Subject: [PATCH] docker.yml: assert the server survives writes through every POV flavour (#578) The v0.1.0 arm64 image passed the MCP smoke, the in-container orlyc compile and the REPL check while segfaulting just after the first write through a POV. Each of those smokes stops looking as soon as its write answers, and #578's crash landed a moment later. After the MCP smoke, write through safe/fast x shared/private, five fresh POVs each, wait five seconds, and require the container to still be running with exit 0 and no restarts. Checked locally against the published images: v0.1.0 arm64 dies under the step (exit 139); v0.1.1 arm64 answers all 20 writes and stays up. --- .github/workflows/docker.yml | 26 ++++++++++++++++++++++++ changelog.d/578-image-survives-writes.md | 1 + 2 files changed, 27 insertions(+) create mode 100644 changelog.d/578-image-survives-writes.md diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 4df452a8..778fd167 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -153,6 +153,32 @@ jobs: (cd clients/mcp && npm install --silent && npx tsc) ORLY_URL=ws://127.0.0.1:8082/ node clients/mcp/smoke/smoke.mjs + # The MCP smoke writes, but it exits as soon as each write answers. The + # v0.1.0 arm64 image passed it while segfaulting just AFTER the first + # write through a POV (#578), so a smoke that never looks back cannot + # see that shape. Write through every POV flavour, five fresh POVs + # each, wait, and assert the server is still the same running process. + - name: Server survives writes through every POV flavour + run: | + pip3 install --break-system-packages --quiet websocket-client + PYTHONPATH=clients/python python3 - <<'PY' + import orly + c = orly.connect("ws://127.0.0.1:8082/") + c.new_session() + c.install("sample", 1) + n = 0 + for _ in range(5): + for kind in ("safe shared", "safe private", "fast shared", "fast private"): + n += 1 + pov = c.send(f"new {kind} pov;") + c.call(pov, "sample", "write_val", {"n": 1000 + n, "x": n}) + print(f"{n} writes answered") + PY + sleep 5 + state=$(docker inspect orly --format '{{.State.Status}} exit={{.State.ExitCode}} restarts={{.RestartCount}}') + echo "container after writes: $state" + test "$state" = "running exit=0 restarts=0" + # The image also claims in-container package compiles (orlyc + g++ + # ORLY_SRC_ROOT). Gate that claim: compile a from-scratch user package # to a loadable .so inside the running container. (This caught a diff --git a/changelog.d/578-image-survives-writes.md b/changelog.d/578-image-survives-writes.md new file mode 100644 index 00000000..d290e627 --- /dev/null +++ b/changelog.d/578-image-survives-writes.md @@ -0,0 +1 @@ +- **Added**: the docker workflow now checks that the server *survives* writes, not just that writes answer. After the MCP smoke, it writes through all four POV flavours (five fresh POVs each) against the running container, waits, and asserts the container is still running with exit 0. The `v0.1.0` arm64 image passed every existing smoke while segfaulting just after the first write (#578). Run locally against the published images, the new step fails on `v0.1.0` arm64 (exit 139) and passes on `v0.1.1`.