# Master Data Relations

This document defines master-to-master references. The `ref<M>` field also drives the per-field Join builder on the source query — see [Join Operator](schema.md#join-operator). Richer relation contracts (cardinality, cascade behavior) will be defined in future revisions of this document.

## Reference Type

A `ref<M>` value identifies one row of a master `M` by its primary key.

```mst
master A {
  record {
    primary id: int,
    primary name: string,
  }
}

master B {
  record {
    primary id: int,
    aRecord: ref<A>,
  }
}
```

`ref` is a built-in generic type with one type argument. The argument must be a master type; any other argument is reported as `masterbelt.checker.ref_non_master_target`.

## Field Expansion

A field whose type is `ref<M>` is expanded into the target master's primary-key fields. The expanded fields are introduced at the parent record's top level, named by joining the original field name and the target's primary-key field name with `_`.

For the example above, master `B`'s effective record shape is:

```
B.id          : int
B.aRecord_id  : int
B.aRecord_name: string
```

The expansion is observable at every consumer of the schema:

- **CSV import**: source files must provide one column per expanded field. The example expects `id, aRecord_id, aRecord_name`.
- **Code generation**: the target language emits one field per expanded entry on the generated record type, and emits a per-field Join builder that resolves the ref's expanded primary-key columns against the target master's relation through `FindBy` (see [Join Operator](schema.md#join-operator)).

The original `ref` field name does not appear as a single nested field at any consumer in the current revision.

## Post-Filter Collections in Validation

The same post-filter record collection that source programs reach through `Master.toList()` also appears as the `table` binding (and its alias `self`) of a master's [validation](validation.md) `all` rule, iterated with `for row in table`. The only source-level relation terminal is `toList()`; `findBy` and the other terminals stay codegen/runtime-level. The relation **stage** operators (`where`, `orderBy`, `thenBy`, `skip`, `take`) are reachable from source only inside a [scope body](query.md#source-level-relation-queries), where a validation `all` rule may also call the master's scopes on `table`.

## Reserved Keywords

The identifier `ref` is not reserved: it is matched only when written as a generic type argument application `ref<M>`. Using `ref` as an ordinary identifier elsewhere remains allowed.
