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.suggestlists 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 Nrecords them. Accepting validates nothing: animplementsfrom a citation isproposeduntil evidence or a review.mix surfex.relate FROM TO --type T --note N: one relation by hand,proposed.--plannedrecords 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/2tocode: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'simplementsto 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.funnames 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.--acceptrecords 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 ormix surfex.validate); once it holds, the next--acceptormix surfex.suggest --acceptretires the section's, noting the claim.--code ID --to CLAIMrecords 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 basisbaselineon 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.