A structured refusal from the exact import-candidate lifecycle.
Candidate refusals are expected operator outcomes, not database failures. The reason is a closed atom vocabulary and the identifiers point at the candidate and attempt that prevented the requested import.
Summary
Types
@type reason() ::
:candidate_mismatch
| :completed
| :failed
| :invalid_catalog_response
| :live_import
| :manifest_changed
| :not_failed
| :not_found
| :not_latest_attempt
| :orphan_candidate
| :protected
| :source_definition_changed
| :stale_import
@type t() :: %GeoGenius.CandidateError{ __exception__: true, message: String.t(), reason: reason(), release_id: Ecto.UUID.t() | nil, run_id: Ecto.UUID.t() | nil }