# Recording relations

Every write appends an entry to `.surfex/` at both ends' current hashes, with a note.
Create the log once with `mix surfex.log --init` (it also sets git's union merge).

- `mix surfex.suggest` lists relations the source already states: a spec section citing
  code by name (`implements`), test tags (`verifies`), what each test calls (`tests`),
  units inside sections (`refines`), and moves (a renamed heading, anchor, test module or
  describe at the same version). `--accept --note N` records them. Accepting validates
  nothing: an `implements` from a citation is `proposed` until evidence or a review.
- `mix surfex.relate FROM TO --type T --note N`: one relation by hand, `proposed`.
  `--planned` records an end that doesn't exist yet (the code you're about to write).
- `mix surfex.retire FROM TO --type T --note N`: the relation no longer holds. On a pair
  never related it declines a suggestion (the note is required), and suggest skips it.
- `mix surfex.move OLD NEW --note N`: an id was renamed; carries every relation, keeping
  each basis. Headings with an id written for them (`<!-- surfex: totals -->` on the line
  after, spec §11) keep their id across renames. A test moved to a renamed module,
  describe or file brings its red→green and baseline
  records when its version is unchanged; the task lists any it leaves behind. A function
  renamed or re-aritied moves too (`code:Mod.f/2` to `code:Mod.f/3`); suggest proposes it
  when the arity changed. The moved relations dangle until judged again.
- `mix surfex.resolve FROM TO --type T --pick TIP`: two branches recorded the same relation
  without seeing each other; pick the tip (by id prefix) to keep.
- `mix surfex.history ID`: every relation an id has had.
- `mix surfex.migrate SECTION [--within]`: moving a section's `implements` to the claims
  inside it, one section at a time (spec §14.1). Each code item related to the section is
  listed with the claims that could own it: a row whose key names it (`Mod.fun` names every
  arity), a claim whose test calls it, or failing those reaches it. **none** comes first
  (write its claim, or it doesn't belong), then **several** (yours to judge), then
  **single**. Arities of one definition are one proposal. It writes nothing.
  `--report [SECTION…]`: what migrating buys: relations an edit dangles now and after, the
  marking a prose section needs first, each item's dangle width; with no section, every
  section worst first, split into those whose claims are units and prose ones.
  `--accept` records each single proposal, proposed, as **migrating**: it doesn't fail
  while the section keeps its relation, so a section can move over several commits.
  Validate the claim's relation (evidence or `mix surfex.validate`); once it holds, the
  next `--accept` or `mix surfex.suggest --accept` retires the section's, noting the claim.
  `--code ID --to CLAIM` records your choice for several, or for none once its claim is
  written. The walkthrough: the guide "Migrating to claim grain".
  A section relation on the baseline (`mix surfex.info adoption`) keeps basis `baseline`
  on the claim when the same baselined test verifies the claim and exercises the code,
  and the section's retires at once.

Types: `implements`, `verifies`, `tests`, `refines`, `depends_on`, `excuses`.
Ids: `spec.md#anchor` or `spec.md#Heading/Path`, a bare hint id, `Mod`, `Mod.fun/2`,
`test:Mod: describe: name`.

Validating is separate: `mix surfex.info validation`.
