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.