The unsoundness is closed. All four MCP tools now answer correctly over HTTP
(get_running_crons, list_logs, tail_log -> ["info two","error three"],
search_log -> its match) where `tail_log` used to return
{"isError":true,"text":"tool failed: not a text value"}. corpus 71/0,
woc 565/0, wovm gates green, ASan clean on the container fixtures.
- builtin.c: multi_push, map_set (key AND value) and multi_set COPY a TEXT
element into the container. The container's declared kinds already make it
the owner of what it holds, so storing a caller-owned pointer gave one
string two owners — `push(res, e.log_path)` freed a record's field out from
under it. OWNED/GCREF elements still move (not copyable; the @gc escape
keeps their counting), so `set`'s @gc gap is untouched and still recorded
- emit.ml: `drop_fresh_text` — after push/set and the `m[k] = v` / `m[i] = v`
sugar, a value that was freshly BUILT (call result, `..` chain,
interpolation) is dropped here, while a value read out of a place is left to
its owner. That asymmetry is the point: before the copy the borrowed case
double freed and the fresh case leaked
- obj.c: the runtime's output stream is line-buffered. A long-running program
writing progress with `print` was invisible when stdout was a file or a pipe
(full buffering), and a killed one lost its log entirely; byte-exact
fixtures are unaffected
- scripts/log-watcher-accept.sh + `just log-watcher`: the acceptance test for
the sample — compile, watch (alert), run (schedule), and three MCP checks.
Hardened after it lied to me: a per-run port (a stale server on a fixed port
answered for it), a connect-probe that fails loudly when OUR server did not
come up, replies read by Content-Length rather than to EOF (the sample never
closes), and kill -9 on teardown
- docs: the copy rule is in the builtin surface; the status board records the
gap as closed and adds the new one — a blocking accept/read swallows SIGTERM,
which belongs to the shard-actor runtime's event loop, not to a patch here
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>