What the m0 wheel promises — 2026-09-29
A design note from the engineering record. D54 and D55 are the decisions;
SPEC G9 and M14 move to out of scope. D56 joined them on 2026-09-30,
under "libm0core" below.
The question
The m0 wheel ships the framework as source: every tracked file of
m0-core, m0-http, the fork, the host, m0-datastar, m0-sqlite and
m0-postgres (D39). A name in one of those trees is something an application
can import, so it reads as something the packages promise. The 2026-09-28
review went through them asking what uses each, and found a set of names
that nothing in the tree calls — not m0serve, not the Mojo host, not an
application under apps/, not a scaffold template — each with tests of its
own and, in two cases, a place in the documentation:
RequestContext(request_context.mojo), a carrier frombefore_requesttoafter_responsethat no handler built.check_api_key(auth.mojo), and with itAppConfig.api_keyandM0_API_KEY. The configuration read the variable and nothing read the field, so no request was ever refused by it; the host's doctor went out of its way to leave the key out of its report.ResponseCache(response_cache.mojo), a URL-keyed cache.PatchJournalandJournalResult(sse/journal.mojo), a per-URL patch journal.DatastarStream's own replay journal is a different thing and stays (SPEC I10, I30).negotiate_encodingandnegotiate_language, and the free functionswants_htmlandwants_event_streamincontent_negotiation.mojo.AcceptResultand its fields stay; applications readaccept.wants_html.- FNV-1a and xxHash32 in m0-core's
hashing.mojo, with the 32-bit hex formatter that printed them, and their C-ABI exportsm0_fnv1a,m0_xxhash32andm0_format_hash.libm0corestays, becausem0pubnumbers its events through its one other export,m0_shared_fetch_add. run_benchmarks.mojo, m0-core's benchmark, which the review found no longer compiled, and itsbench-coretask.m0_sqlite.stats_intsand its siblings (reduce.mojo), whose one user wasbench_sqlite.mojo.
ResponseCache and PatchJournal are the supports of a Siren/GRAIL
server, and sibling repositories still use copies of them. The owner's
decision of 2026-09-29 is that Siren/GRAIL on m0 is not a product aim.
What was decided
The packages ship what the application layer and m0serve use. Each
name above left the tree, with its tests. One moved rather than left:
stats_ints, with ColumnStats, went into bench_sqlite.mojo, so the
aggregate figure in docs/SQLITE_PERFORMANCE.md stays reproducible, and
the bench refuses to time an answer that differs from SQLite's own, which
is the check that mattered. SPEC G9, API-key authentication, moved to out of scope: an
application authenticates in its own views, with the layer's signed
session and CSRF check (N13, N43) or a grant (I21), and a key checked in
front of the server is a proxy's.
Nothing served changes. m0serve never acted on M0_API_KEY, and none
of the removed names was reachable from it or from the Mojo host. What
changes is what an application built with the m0 wheel can import, and
the wheel is a 0.x preview (D43): an application that imported one of
these names keeps a copy of its own.
The client
m0_http.Client (client.mojo), an HTTP/1.1 client over the fork's own
connect, encode and parse, went the same way, with its end-to-end check
and its smoke (SPEC M14). No application called it. It spoke no TLS, so it
could reach almost nothing outside a private network. And it blocked: a
view that runs on the loop and makes a call stalls every connection that
loop holds until the answer comes back, and where a call should run — a
pool thread, or the loop without blocking it — was never decided. A gate
kept it compiling and answering, which is not the same as it being usable.
Outbound calls are designed later, as a phase of their own (D55), not kept alive by a gate on a client nobody used. That design answers TLS, where the call runs, and connection reuse. The fork is untouched: the pieces the client assembled stay where they were.
libm0core, 2026-09-30
D54 kept libm0core for m0_shared_fetch_add, the call m0pub makes
through ctypes to number the events it publishes. Every release still
attached it as a standalone download, bare and as a self-contained bundle,
though no caller outside m0serve was known. It is m0serve's private
runtime and not a published artifact (D56). The release workflow stopped
attaching it, poe bundle-ffi and its CI step left, and the library ships
inside the m0serve wheel only, in _lib/ beside the binary, where the
wheel's launcher points m0pub at it. Nothing changes for an m0serve user.
The evidence: across 32 releases its 114 assets were downloaded 32 times,
and 0 times on each of the seven releases from v1.2.0 to v1.8.0; no project
outside this repository names it, apart from a vendored copy of this
repository; and m0pub is the only caller of its only export.
docs/FFI_DISTRIBUTION.md has the history of the bundle and what carried
over to the wheel's copy, including the self-containment check.
What would retire it
For D54: Siren/GRAIL returning as a product aim on m0, which brings its supports back with it; or an application on the layer that needs one of these names and cannot keep its own copy. For D55: an application on the layer that needs outbound calls. For D56: a named caller outside this repository that asks for a C ABI, at which point publishing resumes with a versioned ABI.