moxzi
Docs / Reference / Open questions

Open questionsalpha

What design problems are still unresolved?

These are problems moxzi has not solved, as distinct from decisions it has made. A known limit with a stated reason belongs on the limits page; this page is for the things that are genuinely still arguments. Everything here is verifiable in the repository, and none of it is chased in the alpha.

Correctness#

QuestionWhere it stands
Some warnings are still missing. Pattern coverage (M0145/M0146) and unused identifiers (M0194/M0198) landed 2026-08-26 — a faithful port of moc's coverage.ml plus a use-count scope discipline. Still absent: M0155 (operator may trap), M0244 (never-reassigned var), M0240/M0241, and unused warnings for function parameters, top-level ids and object fields.The gap is measured, not guessed: on the compiler's own 177 sources moc reports 15 warnings, all in codes we do not yet emit, and we report zero false positives. The remaining codes are a parity gap like any other.
Mutable data cannot cross Candid — and that is moc's design, not a gap. to_candid on [var T] or {var f} is a TYPE ERROR in both compilers (measured: moc M0173; ours now reports the same code, region and rendered type). The unimplemented write_alias path guards only classical (pre-EOP) stabilization — and a disassembly of moc 1.14.1's own EOP output shows it emits no write-side alias functions either: there is nothing to be byte-identical WITH. The read side (read_alias, for upgrading FROM classical state) is fully implemented here.The serializer trap stays as a named sentinel in a path EOP cannot reach; if a classical-stabilization mode is ever added, write_alias comes with it (moc's design is documented in Note [mutable stable values], and the protocol is understood — buffer_size marks StableSeen, serialize rewrites tags to stream offsets).
The compiler's nesting ceiling in V8. A guest frame on V8's stack costs far more than one on wasmtime's, so a tab compiles ~60 chained operators where the CLI is untroubled. A frame diet took the requirement from ~13,759 JS-frame-equivalents to ~8,426 against a tab's ~11,154 — enough for ordinary programs, not a fix for nesting.The designed fix is to move codegen's expression descent onto an explicit heap work-stack, so native frame depth stops tracking input nesting. Prior work is on the workstack-fullpipe branch and is not landed; byte parity is its absolute gate.

Operations#

QuestionWhere it stands
moxzid is one process with one actor thread. Messages execute one at a time across the whole server; per-actor queues and round-robin give fairness, not parallelism (moxzi/server/src/main.rs:14, scripts/moxzid_fairness.sh).Horizontal scale means more moxzids, and nothing coordinates two of them. A shared-runtime design is not attempted because the runtime is not yet safe to share.
Recovery is serial and blocking. Every actor is installed first, then each one's journal is replayed in turn, because a replayed message may call another actor and a half-populated registry turns a real call into "no actor at …".The server binds and answers /health throughout, and /health/ready reports progress — but a large state directory means a long, sequential start.
Auth is one shared bearer token, checked in constant time, with TLS delegated to a reverse proxy. Roles and per-user keys are post-alpha (main.rs:144).Honest rather than half-RBAC, but it means every client of a moxzid is the same client.
Browser preemption rewinds coarsely. A terminated worker cannot report where it got to, so the rewind is to the last completed message, not the trapping one.Autosave narrows the window to one message. Making it exact needs a preemption mechanism that survives the termination, which a worker does not provide.
No certificates off-chain, by design. ic0.data_certificate_present returns 0 in every off-chain runtime.This one is settled — a forged certificate would be verified and believed, which is worse than none — but it leaves certified-data programs with no off-chain test path at all, and that consequence is not solved.

Trust and economics#

QuestionWhere it stands
On-chain build operators can read uploaded source. The VFS is canister state; whoever controls the canister can read it.Building from a mops tag uploads zero bytes and avoids the disclosure entirely. Otherwise the disclosure is printed and accepted. There is no confidential-build design.
Escrow pricing rests on three measurements. escrowCyclesPerByte is 750,000, three times the worst rate observed (200,657 cycles per source byte, the compiler compiling itself); escrowCyclesFloor is 0.5 T.instructionsUsed under-reports real spend by 2.3×–3.4× and the ratio is not constant across phases, so there is no formula — only a worst case with margin. Both constants are operator-settable precisely because they are estimates.
Storage is capped, not metered. The build canister bounds each store (VFS 64 MiB per caller and 1 GiB total, blobs 256 MiB, build cache 200 MiB, artifacts 100 MiB) instead of charging rent.The argument is that all four stores saturated together cost about 2.2 T cycles a year, which one build covers — so the liability is a number that can be stated. If the storage rate moves an order of magnitude, that argument needs redoing.
raw_rand is predictable to anyone holding the host seed. It is derived from (seed, canister, counter) so that log replay reproduces it.Stated plainly in the source. There is no off-chain design that is both replayable and unpredictable, and this is not treated as solvable — only as something a program must not confuse with the IC's guarantee.

Process#

QuestionWhere it stands
The registry sweep proves compiling, not correctness. scripts/mops_sweep.py compiles the top-40 mops packages (391 modules) with both compilers and compares function bodies; the 2026-08-26 run against moc 1.14.1: moc built 384, moxzi 383, differing function bodies 1.56% — one real finding: a module bound by destructuring (let { Buffer } = Utils) does not carry its type namespace, so Buffer.Buffer<Nat8> in type position is M0026 (test/fixtures/destructured-module-type-path.mo).The genuinely open half is FUNCTIONAL: running each package's own test suite against the moxzi-built artifact. Compiling is not the bar — a miscompile builds cleanly and computes the wrong answer. That harness is not built.
The corpus sweeps do not run in CI. Per-PR jobs run the native tests and the gates; the weekly corpus-sweeps job is a reminder until a corpus mirror exists in CI (docs/ci.md).The sweeps run in make alpha-check before a tag, so a release is covered and a pull request is not.
No invocation-ID deduplication on /call. A client retry after a timeout can execute an update twice; the IC dedups by request id, moxzid does not yet.Documented at the endpoint and in the server skill. The durable fix (invocation envelopes with IDs, a dedup window over the WAL seq) is scoped in .plan/host-gap.md §3 (spec §47).
Documented counts drift. Prose figures in README/CHANGELOG lag the tree the moment a gate lands.Resolved by policy: those documents now point at scripts/alpha_check.sh instead of quoting numbers. That prose figures can drift while gate figures cannot is exactly the argument for executable claims.
A remote build cannot pre-build an imported actor-class library. The CLI refuses with an explicit message (moxzi/src/remote.rs:188).Build the library first, or compile locally. The dependency ordering a remote build would need is not designed.

Next#

On this pageCorrectnessOperationsTrust and economicsProcessNext