> ## 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 — none of it done yet

* **Contract evaluation.** Contract bodies parse and do nothing. With an IR they can be
  evaluated against the tree, which is what finally makes the Phase 0 defect metric
  (compiles clean, behaviourally wrong) measurable by the toolchain rather than by a Rust
  test standing in for it.
* **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 plus the corpus example, so
these are reproducible rather than asserted:

| Claim                    | Measured                                                                                                   |
| ------------------------ | ---------------------------------------------------------------------------------------------------------- |
| Structural sharing       | 127 shared nodes vs 141 isolated — 14 saved across 10 files                                                |
| Outline cost             | Worst case 38% of source (`spinner.mz`); the test fails above 75%                                          |
| Parse + lower, whole set | \~4.3 ms for 10 files; 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 RFC-0003 labels it as such: ten files is a tiny corpus,
  and sharing pays in proportion to repetition. At the scale of the 571-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`.
