> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mzizi.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# The content-addressed IR

> One architectural decision — every node stored under the hash of its content — answers seven of the eight barriers an agent hits reading a codebase.

RFC-0001 designed the syntax against nine failure modes in **writing** code. RFC-0003 does
the same for **reading a codebase and retaining what was read** — the other half of the
loop, and the half that decides whether a small model can work in a large project at all.

## The eight reading barriers

| ID | Barrier |
| - | - |
| **RB-1** | **Textual addressing only.** Editing requires an exact string match, so a change needs *more* context than the change itself. |
| **RB-2** | **File-granular reads.** Learning one prop's type costs the whole file. No "interface only" primitive exists in the loop. |
| **RB-3** | **Invisible dependency graph.** "What breaks if I change this?" means grepping — false positives from same-name symbols, false negatives from re-exports. |
| **RB-4** | **Diffs conflate moved with changed.** Rename, reformat and real semantic change all arrive as the same noise. |
| **RB-5** | **Generated code is a blind spot.** With macros, the thing that runs is not the thing that was read. |
| **RB-6** | **No stable identity across time.** A summary silently rots, and nothing reports which recorded facts are still true. |
| **RB-7** | **Repeated structure is unavoidable cost.** Hundreds of components with identical prop ceremony, paid for on every read and useless as an edit anchor. |
| **RB-8** | **Understanding cannot be cached.** Every session starts cold, and the hand-written substitute — a `CLAUDE.md` — drifts. |

Content addressing answers seven of the eight from a single decision. That is the entire
argument for it.

| Barrier | What the IR does |
| - | - |
| RB-1 | Nodes are addressed by hash, or by a unique structural path (`connectivity_bar/fn:retry`) — never by line number or string match |
| RB-2 | `mz outline` serves the interface at a fraction of source cost; any single node can be fetched alone |
| RB-3 | Reference edges are explicit in the node, so "who points at this hash" is a lookup, not a search |
| RB-4 | A moved node keeps its hash. Only real change alters a hash, so a diff *is* the semantic diff |
| RB-5 | No macros: the IR is ground truth and is directly inspectable |
| RB-6 | The hash **is** the identity, permanently. A recorded fact is re-verified by asking whether that hash still exists |
| RB-7 | Structural sharing: identical subtrees are one stored node |
| RB-8 | The store is derived and machine-verified — the thing a hand-written `CLAUDE.md` was failing to be |

RB-5 is the exception only in the sense that the syntax already solved it: the view grammar
is native rather than a macro, so the IR inherits the property rather than fixing it.

## The node model

```rust theme={null}
Node {
  kind:     &str            // "component" | "prop" | "enum" | "variant" | "element" | ...
  label:    Option<String>  // the author-visible name, when the kind has one
  fields:   [(String, String)]   // leaf data, sorted by key
  children: [Hash]          // ordered; order is semantic
}
```

A node's hash covers its **canonical serialization**, which includes its children's hashes.
That makes the store a Merkle DAG: change a leaf and every ancestor's hash changes, while
every untouched sibling keeps its own.

### Canonical serialization

Hashing is only stable if serialization is exact, so the form is fully specified and
**length-prefixed rather than delimiter-separated** — a delimiter can appear inside a value
and silently merge two different nodes into one hash:

```text theme={null}
kind_len ":" kind
label_len ":" label            (or "-" when absent)
field_count ":"  for each, in key order:  key_len ":" key value_len ":" value
child_count ":"  for each, in order:      hash_hex
```

Fields are sorted by key so that authoring order cannot change identity. Children are
**not** sorted, because their order is meaning — a view's children are a sequence.

### The hash function

SHA-256, hand-rolled, verified against the published NIST vectors. The house convention is
to hand-roll small, fully-specified things rather than take a dependency, and SHA-256
qualifies precisely because it is completely specified with official test vectors, so
correctness is *verifiable* rather than assumed.

RFC-0003 states the limit of that plainly, and so does this page:

> This is a content-identity function, not a security boundary. Collision resistance
> matters; side channels do not. If a hash ever becomes a trust boundary — signed releases,
> a shared public store — swap in a reviewed crate at that point.

Hashes display as the first 12 hex characters.

## Names are metadata, which is what makes renames free

The store maps `Hash → Node`. A **separate** namespace maps `name → Hash`. Nothing inside a
node records the name of anything it references — only hashes.

* **A rename touches one namespace entry.** No call site changes, because no call site ever
  held the name. That removes the whole class of exhaustive multi-site refactor, which is
  precisely what small models perform worst at.
* **Source carries no import lines.** This is the mechanism underneath the syntax-level
  rule: source says *what*, the namespace says *which*.
* **Two components can be compared for identity, not similarity.** Same hash means
  genuinely the same logic, wherever it came from.

## What is implemented, and what is designed

<CardGroup cols={2}>
  <Card title="Implemented" icon="check">
    `mz hash` — the root hash and node count after sharing.

    `mz outline` — the interface form.

    `mz ir` — the flat node listing with hashes and structural paths.
  </Card>

  <Card title="Designed, not built" icon="circle-dashed">
    `mz refs <hash>` — every node referencing this one (RB-3).

    `mz path <hash>` — the structural path.

    `mz patch <path> <source>` — the write half of RB-1.

    `mz diff <hash-a> <hash-b>` — node-level added / removed / changed, with moves reported
    as moves.
  </Card>
</CardGroup>

The store is **in-memory only**. On-disk format, and whether the store is shared between
projects, is an open question with a caching payoff and a trust question attached.

## A correction the implementation forced

This is worth reading because it is the shape of the whole project in one paragraph: a
claim was made, a measured test caught it, and the claim was narrowed rather than defended.

RFC-0003's first draft called structural paths *"stable across edits"*. Two `row` siblings
inside `alert`'s view collided on the same path, which would have made a patch address
ambiguous. Two things came out of it. Paths now disambiguate same-named siblings — by `slot`
where one exists (`alert/view/element:notice/element:row@alert-title`, readable, and `slot`
is already the design system's identity attribute), by ordinal otherwise. And the claim was
cut back to what is true:

> **Paths are unique and readable and survive reformatting; the permanently stable identity
> is the hash.** Inserting a sibling can shift an ordinal-disambiguated path, so anything
> holding a reference across edits should hold the hash, not the path.

## What the IR unlocks — not done yet

Contract evaluation is no longer on this list: `mz contract` evaluates a component's
contract block against the component's own declarations (RFC-0006). RFC-0006 §6 also
settles that contracts participate in the IR hash, so changing a contract changes the
component's identity.

* **Incremental compilation keyed on hashes.** Only changed hashes and their ancestors
  recompile — the cheapest route to the sub-second check loop the charter names as a Phase 0
  success metric.
* **A cache that cannot lie.** The store is derived, not authored, so it cannot drift from
  the code the way prose documentation does.

## Measured

From `compiler/tests/ir_measured.rs`, over the nine primitives and the two component
examples, run at `6da2170` (services have no IR yet, so the example service is left out).
They are reproducible rather than asserted:

| Claim | Measured |
| - | - |
| Structural sharing | 242 shared nodes vs 248 isolated — 6 saved across 11 files |
| Outline cost | Worst case 38% of source (`spinner.mz`); the test fails above 75% |
| Parse + lower, whole set | About 10 ms for 11 files in a debug build; budget 400 ms |
| Identity stability | Same source → same root hash; blank-line changes do not alter it; a variant column change reaches the root |
| Rename cost | Renaming every component in the store changes **zero** nodes |

<Note>
  The sharing number is small, and smaller than when the corpus had ten files. RFC-0003
  labels it as such: eleven files is a tiny corpus, and sharing pays in proportion to
  repetition. At the scale of the 577-component registry
  the ratio should improve substantially — *"but that is a prediction, and it stays labelled
  as one until the registry is lowered."*
</Note>

## Still open

1. **Local state.** Signal semantics must survive content addressing.
2. **The patch API's conflict model.** Two agents patching sibling nodes should compose;
   patching the same node must not silently pick a winner.
3. **Store persistence.** In-memory today.
4. **Contract evaluation semantics** — the subject language for assertions like
   `every button_size height at_least 48`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.