# The model

**Ends.** Surfex scans four kinds of thing, each with an id and a content hash (its
version):
- `spec`: a markdown section (`spec.md#anchor`, or `spec.md#Heading/Path`), a fenced
  block, or a test hint (```` ```test:hint-id ```` in the spec: a claim a test must verify).
- `code`: a module or function (`MyApp.Cart`, `MyApp.Cart.add/2`).
- `test`: one test case (`test:MyApp.CartTest: totals: an empty cart totals nothing`).
  A `describe` group is not an end; each test in it is.
- `class`: a kind of code the spec deliberately doesn't describe (`classes:` in config).

**Relations** have a type and two ends:
- `implements` code → spec · `verifies` test → spec · `tests` test → code (the test calls
  it) · `refines` spec → spec (a unit inside a section) · `depends_on` · `excuses` class → code.

**The log** (`.surfex/`) records each relation as entries, each at its ends' hashes, with
who, when, the commit and a note. The **tip** is the entry no later entry names as its
parent; it is the judgement in force. Nothing is edited or deleted; `mix surfex.log
--verify` detects tampering.

**States**, derived from the tip against the current scan:
- `current`: both ends at the recorded hashes.
- `dangling`: an end changed since; the report names which.
- `orphaned`: an end is no longer scanned (removed or renamed: see `move`).
- `planned`: recorded before its end existed (`relate --planned`).
- `conflicted`: two tips recorded without seeing each other (parallel branches).
- `retired`: put to rest.

**Basis**, how the tip was validated: `evidence` (test runs), `review` (a test judged
against the unit and run green), `judgement` (named by hand with a note; never for
implements), `baseline` (an adopted, trusted suite), `proposed` (a claim nothing has
validated: a citation, a tag before its failing run). A current `implements` or `verifies`
without a validating basis is **unvalidated**.

**Flags** reported beside states: new (in no relation), unmet (`require:` says it must
relate), broken (a tag naming no spec unit), broken citation (the spec names code that
doesn't exist), failed (a relation's test failed in the run, whatever validated it),
unproven (evidence doesn't bear a confirmation out), undeclared (a test no
longer tags the unit it verifies), unrecorded (a test tags a unit the log records no
`verifies` relation to, or only a retired one), moved (a block or hint no longer sits in
the unit its `refines` relation names), triangle gaps (a unit, its tests and its
code don't meet),
impacted (a `depends_on` end isn't current; information only), marks (`mix surfex.info marks`).
