use crate::crypto::EventVerificationStatus;
use crate::model::EventId;
pub type Result<T> = std::result::Result<T, ShoreError>;
#[derive(Debug, thiserror::Error)]
pub enum ShoreError {
#[error("{0}")]
Message(String),
#[error("json parse failed: {0}")]
Json(#[from] serde_json::Error),
#[error(
"git command failed: {command}\nstatus: {status}\nstdout:\n{stdout}\nstderr:\n{stderr}"
)]
GitCommand {
command: String,
status: String,
stdout: String,
stderr: String,
},
#[error("invalid event: {message}")]
InvalidEvent { message: String },
#[error("unsupported event schema/version: {schema} v{version}")]
UnsupportedEventSchemaVersion { schema: String, version: u32 },
#[error("unsupported event type: {0}")]
UnsupportedEventType(SchemaBreakRecord),
#[error("unsupported event envelope: {0}")]
UnsupportedEventEnvelope(SchemaBreakRecord),
#[error("unsupported state schema/version: {schema} v{version}")]
UnsupportedStateSchemaVersion { schema: String, version: u32 },
#[error("{reason}")]
WorkflowInputInvalid { reason: String },
#[error("event signature verification rejected event {} with status {}", .event_id.as_str(), .status.as_str())]
EventVerificationRejected {
event_id: EventId,
status: EventVerificationStatus,
},
#[error("unknown claude code session line type `{kind}` at line {line}")]
UnknownClaudeSessionLineType { line: usize, kind: String },
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SchemaBreakRecord {
pub retired: String,
pub broken_at: String,
pub anchor: String,
}
impl std::fmt::Display for SchemaBreakRecord {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{} is no longer supported (broken at {}); see {}",
self.retired, self.broken_at, self.anchor
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn workflow_input_invalid_preserves_display_text() {
let err = ShoreError::WorkflowInputInvalid {
reason: "track is required".to_owned(),
};
assert_eq!(err.to_string(), "track is required");
}
#[test]
fn event_verification_rejected_preserves_display_text() {
let err = ShoreError::EventVerificationRejected {
event_id: crate::model::EventId::new("evt:sha256:abc"),
status: crate::crypto::EventVerificationStatus::Unsigned,
};
assert_eq!(
err.to_string(),
"event signature verification rejected event evt:sha256:abc with status unsigned"
);
}
#[test]
fn schema_break_record_renders_canonical_sentence() {
let record = SchemaBreakRecord {
retired: "review_disposition_recorded".to_owned(),
broken_at: "0.1".to_owned(),
anchor: "docs/assessment-model.md#legacy-disposition-events".to_owned(),
};
assert_eq!(
record.to_string(),
"review_disposition_recorded is no longer supported (broken at 0.1); \
see docs/assessment-model.md#legacy-disposition-events",
);
}
}