turbovault_git/error.rs
1//! Error type for the git write substrate.
2//!
3//! The crate owns its error domain (git2 / io / invariant violations) so it
4//! stays self-contained — no leakage of `git2` into a consumer crate. Conversion
5//! to the consumer's error type happens at the tool-layer boundary (added when
6//! the substrate is wired into the MCP server, GWS.12).
7
8use std::path::PathBuf;
9
10/// Errors from the git write substrate.
11#[derive(Debug, thiserror::Error)]
12pub enum Error {
13 /// The vault root is not a git repository (feature is git-gated).
14 #[error("not a git repository: {0}")]
15 NotARepo(PathBuf),
16
17 /// A compare-and-swap on a ref failed: the ref moved since we read it.
18 /// The changeset applied nothing; the caller should re-read and retry or
19 /// surface a conflict (the reconsideration domino).
20 #[error("ref CAS conflict on {refname}: expected {expected:?}, found {found:?}")]
21 CasConflict {
22 refname: String,
23 expected: Option<git2::Oid>,
24 found: Option<git2::Oid>,
25 },
26
27 /// A per-file precondition failed: the blob at `path` in the base tree is not
28 /// what the caller read (it changed underneath the changeset). The whole
29 /// changeset aborts with **nothing applied** — the multi-file CAS / the
30 /// reconsideration domino. The caller re-reads the affected paths and
31 /// re-decides.
32 #[error("precondition failed for {path}: expected {expected:?}, found {found:?}")]
33 PreconditionFailed {
34 path: String,
35 expected: Option<git2::Oid>,
36 found: Option<git2::Oid>,
37 },
38
39 /// Underlying libgit2 error.
40 #[error("git error: {0}")]
41 Git(#[from] git2::Error),
42
43 /// Filesystem error (working-tree materialization, etc.).
44 #[error("io error: {0}")]
45 Io(#[from] std::io::Error),
46
47 /// Invariant violation or unsupported state with a description.
48 #[error("{0}")]
49 Other(String),
50}
51
52/// Result alias for the git write substrate.
53pub type Result<T> = std::result::Result<T, Error>;