# ADR 0012: Reference Resolution Folds Into `TypstCompile` (Taxonomy 7 → 6)

## Status

Accepted. **Corrects ADR-0010**, which fixed the diagnostic taxonomy at *seven*
classes including a separate `DanglingReference`. This ADR retires
`DanglingReference`, folding reference-resolution failures into `TypstCompile`, so
the taxonomy is now *six* classes. ADR-0010 stays the record of the original
decision; this one records the correction.

## Context

ADR-0010 named two distinct external-facility diagnostics for reference problems:

- `DanglingReference` — "a relative import outside the import boundary, or an
  unresolved cross-reference."
- `TypstCompile` — "the assembled typst source fails to compile (syntax error,
  **unresolved `@ref`**, etc.)."

The unresolved cross-reference (`@ref`) was listed under **both** — a genuine
contradiction in the contract. And on inspection, the *other* `DanglingReference`
case (an out-of-boundary relative import) is **also** a typst compile-time error:
typst resolves `import`/`include` paths at runtime (ADR-0011's *Correction*), so a
path escaping the import boundary fails as `"cannot access file system from
here"` — a `TypstCompile` diagnostic. Both of `DanglingReference`'s cases are
therefore detected by, and surface as, the typst compiler's own output.

The implementation reflected this from the start: `cph-typst` maps **every** typst
`SourceDiagnostic` to `DiagCode::TypstCompile` (`crates/cph-typst/src/diag.rs`), and
**no** code path ever emits `DanglingReference`. The Lean `Oracle` likewise had a
`refsResolve` field separate from `compiles`, but `compiles t` already entails that
target `t`'s references resolve (the source would not compile otherwise) — so
`refsResolve` was redundant in the `Legal` conjunction.

`DanglingReference` was thus a contract class with no distinct verdict, no distinct
emitter, and a definition overlapping `TypstCompile`. It diluted the taxonomy
rather than carving a real boundary.

## Decision

### `TypstCompile` owns reference resolution

`TypstCompile` is the single external-facility diagnostic for the assembled typst
source failing to compile — **including** an unresolved cross-reference (`@ref`)
and a relative `import`/`include` that escapes the import boundary or names a
missing file. There is no separate reference-resolution diagnostic.

### `DanglingReference` is retired; the taxonomy is six classes

The diagnostic taxonomy is now:

| Code | Meaning | Severity | Kind |
|------|---------|----------|------|
| `PartPathMissing` | A manifest `[[parts]]` entry points at a non-existent folder (or escapes the root via `..`). | error | structural |
| `UnknownKind` | A part declares a kind not in the known set (or a part/`element.toml` kind mismatch). | error | structural |
| `MissingContentFile` | A `content` field required by the kind schema has no `<field>.typ`. | error | structural/schema |
| `SchemaViolation` | Instance data violates its kind's JSON Schema; also the malformed-`manifest`/`element.toml` fallback. | error | schema / external |
| `TypstCompile` | The assembled typst source fails to compile — syntax error, unresolved `@ref`, out-of-boundary or missing `import`/`include`. | error | external |
| `RenderIgnored` | A used kind a target does not cover; the element is omitted from that export. | **warning** | semantic |

`RenderIgnored` alone is a `warning`; the other five are `error`. The
structural / external / semantic boundary from ADR-0010 is unchanged.

### `Oracle.refsResolve` is removed

The `Legal`-predicate oracle drops its `refsResolve` field. Reference resolution is
subsumed by `compiles` (per target): `compiles t` already requires `t`'s assembled
source to compile, which requires its references to resolve. `Legal` becomes
`dataConforms ∧ contentFilesPresent ∧ (∀ declared t, compiles t)`.

## Consequences

- The contract no longer contradicts itself on where an unresolved `@ref` is
  reported: it is a `TypstCompile` diagnostic, full stop.
- The implementation needs no behavioral change — it already routed all reference
  failures to `TypstCompile` and never emitted `DanglingReference`. The
  correction *removes* the unused `DiagCode::DanglingReference` variant, closing
  the spec↔impl gap (a named-but-unemitted code) rather than leaving it as a
  permanent MVP-deferred stub.
- The `Oracle` / `Legal` definitions in the Lean master shrink by one redundant
  conjunct, with no change to which lessons are legal.

## Open Questions / Deferred

- **Finer reference diagnostics.** Should a future checker want to distinguish an
  out-of-boundary import from a missing file from an unresolved `@ref` — with
  reference-specific fix hints better than typst's generic message — that is a
  *new* diagnostic class, introduced deliberately when the need is real (ADR-0010's
  "taxonomy is open to growth" still holds). This ADR removes the redundant class;
  it does not forbid a genuinely distinct one later.
