Changes touching this path
- a ferry refusal reaches a machine consumer as itself, not as a generic error (#867)
Every seam inside `ferry::run` returned `Result<_, String>`, so a pass — which
is mostly other people's failures — flattened all of them before the CLI could
emit them. A typed `RepoError` the engine had already coded, and the reconcile
executor's `Plan::Refuse`, both reached a `--json` consumer as the generic
`error` code. The prose was fine; the machine channel was the loss.
The nine phase signatures now carry `CliError` end to end, which restores the
engine's own slugs for free: engine calls propagate with a bare `?` instead of
`.map_err(|e| e.to_string())`, which is precisely what was flattening them.
Exactly three slugs join the frozen ADR 0023 contract (amendment recorded):
`undescribed_parent` and `foreign_paths` from a new `reconcile::Refusal::code`,
built alongside the unchanged wording by BOTH executors — `apply_plan` and
#866's adopt catch-up — so two verbs sharing one table cannot become two
taxonomies; and `git_mirror` where ferry lifts git2, deliberately coarse
because the bit a consumer acts on is retry-the-environment versus obey.
`git_mirror.rs` stays stringly inside: inventing a loot taxonomy for git2's
errors would be fiction.
`rollback_note` keeps the abort's code and grows only its message — a rollback
is context about that failure, not a different one.
Every refusal's wording is byte-identical; the human channel does not move.
Ferry's own handful of refusals stay honestly generic, and so do the tier's
remaining flatten sites, which graduate one at a time when a consumer needs
them.
The one loot-first line is the seam back out: its orchestrator keeps a String
channel, so `From<CliError> for String` makes that a `?` rather than a
hand-written `.to_string()` at every call.
Found while pinning the codes: the uncaptured-WIP ferry test refuses with
`foreign_paths`, not `undescribed_parent` as it reads. Both wordings offer
`describe -m`, which is why prose was never a taxonomy.
4fc73479 · dbf3dbe6…
Renames are not followed. loot's tree maps a path to an address, so a rename is a delete and an add. This list is the history of the name, not of the bytes.