Known differencesalpha
Where does moxzi differ from moc or from a real replica, and why?
A difference is a place where moxzi's behaviour is deliberately not the reference's, with a reason that survives being written down. Everything on this page is intended and gated; anything not on this page and not obviously a limit is a bug worth reporting.
Differences from moc, the reference compiler#
The output bytes are the thing that must match, and they do — 221 corpus programs, byte-identical across independent builds. The differences are in what the compiler says.
| Difference | moc | moxzi | Why |
|---|---|---|---|
| Non-toplevel actor | M0069 plus M0037 and M0038 | M0069 alone | one cause, one message. Gated by scripts/nontoplevel_actor_matrix.sh |
| Parse errors | M0001 | M0000 | moxzi's M0000 is a catch-all; match the text as well as the code |
| Warnings | many, with -A/-W/-E leveling | eight (M0089, M0145, M0146, M0173, M0194, M0198, M0254, M0265, M0266 among them), no leveling | M0145/M0146 pattern coverage is a faithful port of moc's checker; M0194/M0198 unused-identifier covers blocks, match arms and loops (function parameters, top-level program ids and object fields do not warn yet). As measured against moc, warnings from --package libraries are suppressed; errors never are |
| Legacy actors | accepted | rejected with M0220 | persistent is how a program says its state survives; silence is the bug. --default-persistent-actors rewrites bare actors |
| Unimplemented front-end forms | n/a | M9000 unimplemented: … | moxzi names its own gaps at the point they are hit rather than miscompiling |
Three corpus programs are known to be classified under a different code by each compiler and are recorded as such in the parity harness: moc M0106 → moxzi M0220, moc M0086 → moxzi M0220, moc M0076 → moxzi M0077.
Differences from a real replica, off-chain#
These apply to moxzid and to the browser runtime. Each is a property the Internet Computer gets from having a subnet, and none of them is faked.
| Difference | What actually happens | Why not faked |
|---|---|---|
| No certificates | ic0.data_certificate_present returns 0 | a certificate is a subnet threshold signature. A forged one would be verified and believed — worse than none. @dfinity/agent's Actor is therefore unsupported; the generated idlFactory path is |
raw_rand is derived, not drawn | SHA-256 over (host seed, canister, counter) | the runtime replays a write-ahead log to recover; fresh entropy would make a replayed message take a different branch than the one journalled. Honest property: unpredictable without the host seed, entirely predictable with it |
ic0.time is journalled | the clock value a message saw is recorded and replayed | same reason: recovery must reproduce the state that was lost, not a new one |
| Outcall responses are journalled | recorded in their own file, replayed on recovery | a network response is not the same twice; without this an actor that called out could not be recovered at all |
| Ingress caller | the anonymous principal [4] by default; an authenticated client names one per request with x-caller: <principal> | claiming a caller is an operator capability, like dfx minting identities against a local replica — the WAL records it, so replay reproduces the identities that spoke. Signed ingress envelopes are a later milestone |
| Trap text | IC0503 for explicit ic0.trap, IC0502 only for a recognised wasm trap (currently just stack overflow) | the IC's first line is reproduced; its version-dependent second sentence is not |
| Stable-type compatibility | moxzid pre-flights through moxzi stable-compatible and refuses a proven incompatibility, as the replica does; ?force=true skips the pre-flight (the RTS's memory check still has the final word) | with no moxzi binary on the machine (MOXZI_BIN), moxzid cannot ask and falls back to a loud warning |
| HTTP verbs | moxzid's gateway forwards every verb | mainnet's boundary nodes do not. This is why an actor can speak WebDAV off-chain; the REST subset of the same actor runs unchanged on-chain |
Differences specific to the browser#
| Difference | Detail |
|---|---|
| Per-instruction metering in a browser is opt-in | V8 has no fuel, so moxzi-web instruments a module at install time to count its own. With meter: true an instruction limit is enforced as it is in moxzid and on the IC; without it, only creation and message fees are charged |
| Preemption is wall-clock | a runaway message is killed by a worker deadline, not an instruction count |
| Preemption rewinds coarsely | to the last completed message, not the trapping one — a terminated worker cannot report where it got to. Autosave makes the window one message wide |
| Lower nesting ceiling for the compiler | a guest frame on V8's stack costs far more than one on wasmtime's; ~60 chained operators compile in a tab, and past ~400 the limit moves into parsing |
None of these changes what a program computes: 149 corpus programs run zero-diverging against the native runtime, which was itself validated against a real replica.
Differences that only exist on-chain#
| Difference | Detail |
|---|---|
| An on-chain build returns an unlinked artifact | by design. moxzi link is a real step; validation failing on the unlinked module is expected, not a symptom |
| Builds serialize per canister | one compiler canister is one job queue. Parallelism means more canisters |
| Actor-class libraries | a remote build cannot pre-build an imported actor class library; build the library first or compile locally |
| The operator can read uploaded source | the VFS is canister state. Build from a mops tag — which uploads zero bytes — or accept the disclosure |
Differences that are not differences#
Three things that look like divergences and are not, recorded because each one cost time:
| Looks like | Actually |
|---|---|
| Query output missing on a replica | query prints are not replicated |
| An actor's log truncated | the IC log is a ring buffer |
| A sweep reporting many new failures | very often a stale binary or an orphaned server process — check what is actually running before believing a divergence |
Next#
- The differential corpus — the sweeps that establish the parity these differences sit inside.
- Limits — the numbers behind the browser and on-chain rows.
- Open questions — the differences that are not yet decisions.