rustledger_ops/enrichment.rs
1//! Shared types for operation results.
2//!
3//! These types describe the outcome of directive operations — how a
4//! categorization was determined, what alternatives were considered,
5//! and how confident the system is in its result.
6
7/// How a categorization was determined.
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub enum CategorizationMethod {
10 /// Matched a user-defined rule (substring or regex).
11 Rule,
12 /// Matched a built-in merchant dictionary entry.
13 MerchantDict,
14 /// ML model prediction.
15 Ml,
16 /// LLM suggestion via MCP.
17 Llm,
18 /// Fell back to default account (no match found).
19 Default,
20 /// User manually assigned.
21 Manual,
22}
23
24impl CategorizationMethod {
25 /// Returns the string representation used in directive metadata.
26 #[must_use]
27 pub const fn as_meta_value(&self) -> &'static str {
28 match self {
29 Self::Rule => "rule",
30 Self::MerchantDict => "merchant-dict",
31 Self::Ml => "ml",
32 Self::Llm => "llm",
33 Self::Default => "default",
34 Self::Manual => "manual",
35 }
36 }
37}
38
39/// An alternative categorization with its confidence score.
40#[derive(Debug, Clone)]
41pub struct Alternative {
42 /// The account that could have been chosen.
43 pub account: String,
44 /// Confidence score for this alternative (0.0 to 1.0).
45 pub confidence: f64,
46 /// How this alternative was determined.
47 pub method: CategorizationMethod,
48}
49
50/// Enrichment metadata for a single directive, produced by operations.
51#[derive(Debug, Clone)]
52pub struct Enrichment {
53 /// Index of the directive this enrichment applies to.
54 pub directive_index: usize,
55 /// Confidence score for the primary categorization (0.0 to 1.0).
56 pub confidence: f64,
57 /// How the primary categorization was determined.
58 pub method: CategorizationMethod,
59 /// Other possible categorizations, sorted by confidence descending.
60 pub alternatives: Vec<Alternative>,
61 /// Stable fingerprint for deduplication (if computed).
62 pub fingerprint: Option<crate::fingerprint::Fingerprint>,
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68
69 #[test]
70 fn categorization_method_meta_values() {
71 assert_eq!(CategorizationMethod::Rule.as_meta_value(), "rule");
72 assert_eq!(
73 CategorizationMethod::MerchantDict.as_meta_value(),
74 "merchant-dict"
75 );
76 assert_eq!(CategorizationMethod::Ml.as_meta_value(), "ml");
77 assert_eq!(CategorizationMethod::Llm.as_meta_value(), "llm");
78 assert_eq!(CategorizationMethod::Default.as_meta_value(), "default");
79 assert_eq!(CategorizationMethod::Manual.as_meta_value(), "manual");
80 }
81}