← Back

Where the reference stands

A short while ago we made a real decision: the Rust compiler stops being a byte-for-byte copy of codexir and becomes the reference for well-typed Codex IR. Being the reference argued that call as a trade — what it frees, what it still binds, what we'd have to replace. This is the reckoning: with the decision made and a batch of work behind it, where do we actually stand?

The one-line answer: the decision is holding, it has already paid for itself once in a way I did not expect, and the safety net we worried about losing is still green.

What the decision actually changed

Before, one oracle judged everything. codexir — the same compiler stopped at the IR wire, built from our own u58 candidate — was the gold, and correctness was byte-identity to it. That is a wonderful regression detector and a terrible ceiling: it means the best we can ever be is exactly as good as the thing we copy, including where that thing leaves a type unresolved.

Now correctness is judged by behavior, through two oracles, and byte-identity is demoted from "the definition of right" to "a regression alarm we expect to trip on purpose sometimes."

digraph {
  rankdir=LR; bgcolor="transparent"; pad=0.2; nodesep=0.4; ranksep=0.7;
  node [shape=box style="rounded,filled" fillcolor="#f4f0e4" color="#c9bfa7"
        fontname="Helvetica" fontsize=12];
  edge [color="#b0a890" arrowsize=0.7];
  src   [label="source\n(.codex)"];
  check [label="check\n(HM, unify-as-you-go)"];
  lower [label="lower + resolve\n+ pipeline"];
  wire  [label="IR wire"];
  src -> check -> lower -> wire;

  val  [label="codexrun  →  value\ncompared to Roc .expected"
        shape=note fillcolor="#dce8f5" color="#5a7fa5"];
  typ  [label="zig plug  →  refuses a hole\n(the type oracle)"
        shape=note fillcolor="#dce8f5" color="#5a7fa5"];
  reg  [label="byte-diff vs codexir\n(regression net, not the judge)"
        shape=note fillcolor="#eef3ea" color="#8aa06f"];

  edge [style=dashed color="#5a7fa5"];
  check -> val [label="run" fontsize=10];
  wire  -> typ [label="build" fontsize=10];
  edge [style=dashed color="#8aa06f"];
  wire  -> reg [label="diff" fontsize=10];
}

Underneath, the machine that does the resolving is the one the node-by-node essay walks through: a shared substitution table, fresh/unify/deep_resolve, and — new on this branch — an explicit, named zonk-and-default phase that defaults a definition's genuinely unconstrained variables at the end of its check, instead of leaving them for something downstream to trip over.

What the discovery loop found

With the two oracles in place, the way to make progress is not to read code and reason — it is to feed the compiler small programs whose answers are unarguable and watch where the oracles disagree. That loop sorted every divergence into three shapes, and the sorting was the finding (the full account is here).

digraph {
  rankdir=LR; bgcolor="transparent"; pad=0.2; ranksep=0.9;
  node [shape=box style="rounded,filled" fontname="Helvetica" fontsize=12];
  edge [style=invis];

  s3 [label="Shape 3 — we were BEHIND\nchecker accepted n + \"hello\"\n→ FIXED (CDX2001)"
      fillcolor="#dce8f5" color="#5a7fa5"];
  s1 [label="Shape 1 — we are AHEAD\norphan sum defaults; plug\nrefuses theirs → LOCKED"
      fillcolor="#e6f0e0" color="#7a9b5e"];
  s2 [label="Shape 2 — a shared FRONTIER\ninlining drops a return-type var;\nboth stop here → OPEN"
      fillcolor="#f0d9a0" color="#c8a13a"];
  s3 -> s2 -> s1;
}

The safety net, in numbers

The thing being the reference was most anxious about was losing the free, total regression detector. We didn't. As it stands on the zonk-and-default branch:

So we bought the freedom to diverge and kept the net. The one place we spent the net deliberately — shape 1 — we replaced with tests, which is exactly the trade the essay said we'd have to make: where you stop grading by byte-identity, you owe a behavioral test in its place.

What being the gold standard demands next

The decision is not a state, it is an obligation, and it has a to-do list.

We set out to stop copying and start being correct. One decision later, the clearest evidence it was right is that the loop it enabled immediately caught the compiler being wrong in a direction we weren't even looking — and the net we were afraid to lose held while we fixed it.