Skip to main content

aristo_core/index/
enums.rs

1//! Enum types for `.aristo/index.toml`.
2
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5
6/// Annotation kind: `intent` (verifiable claim about code) or `assume`
7/// (external invariant the code relies on, taken as given).
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
9#[serde(rename_all = "lowercase")]
10pub enum AnnotationKind {
11    Intent,
12    Assume,
13}
14
15/// Current verification state. The wire form uses kebab-case to keep
16/// `pending-deepen` readable on disk.
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
18#[serde(rename_all = "kebab-case")]
19pub enum Status {
20    /// Verified at the strongest method available; signature is current.
21    Verified,
22    /// Verified via assertion-style testing (mined assertions, free or paid).
23    Tested,
24    /// Verified via neural reasoning (LLM-based).
25    Neural,
26    /// Was verified at a prior code state; current `body_hash` differs from
27    /// the signed outcome. Sig still valid; only the code drifted.
28    Stale,
29    /// `verified_outcome.commit_hash` is not in this repository's history.
30    /// Most likely cause: index entry copied from another repo (B5b).
31    Orphan,
32    /// `verified_outcome` does not verify against any bundled public key —
33    /// either tampered or signed by a revoked/unknown key (B5b).
34    Forged,
35    /// Has not yet been verified, or was reverted to unknown after a rename
36    /// or rebind operation invalidated the prior signature.
37    Unknown,
38    /// Sig is valid but commit ancestry could not be confirmed because the
39    /// outcome's commit falls outside a shallow checkout's window (B5b).
40    PendingDeepen,
41    /// Verification produced a counterexample — the property does NOT
42    /// hold under the cited code/text version. Terminal state: stays
43    /// Counterexample until either `body_hash` drifts (→ Stale) or the
44    /// intent text is rewritten to exclude the refuted case. There is
45    /// NO accept-counterexample flow; counterexamples are loud and
46    /// surface on every `aristo stamp` until the user fixes them.
47    Counterexample,
48    /// Verification was inconclusive — the verifier could not discharge
49    /// the proof's gap and queued one or more suggested annotations the
50    /// user could add to close it. Distinct from Unknown (which means
51    /// "never attempted") so the skip logic can tell "we tried and got
52    /// stuck" from "we haven't tried yet." Stays Inconclusive until
53    /// either the source drifts (→ Stale via the body-drift rule), the
54    /// user adopts a queued suggestion (→ re-verify), or the user
55    /// explicitly re-runs with `--rerun`.
56    Inconclusive,
57}
58
59#[aristo::intent(
60    "The terminal-clean states are exactly Verified, Tested, and Neural — \
61     an intent whose current code IS confirmed to hold under some \
62     verification method. Stale, Counterexample, Inconclusive, Unknown, \
63     and the B5b error states (Orphan / Forged / PendingDeepen) are NOT \
64     clean: each means the property is unproven, refuted, or untrusted for \
65     the current code. This is the single definition every surface — \
66     status counts, the badge rate, and the nudge engine's unverified \
67     backlog — shares, so they can never disagree on what 'verified' means.",
68    verify = "test",
69    id = "status_terminal_clean_is_verified_tested_neural"
70)]
71impl Status {
72    /// True iff this status is a terminal-clean (confirmed-verified) state.
73    pub fn is_terminal_clean(self) -> bool {
74        matches!(self, Status::Verified | Status::Tested | Status::Neural)
75    }
76}
77
78/// `verify` field value. Mixed-type per design (G1):
79///
80/// - `false` (TOML bool): documentation only; no check ever runs.
81/// - `true` (TOML bool): resolves to project default in `aristo.toml [verify] default_method`.
82/// - one of `"neural"`, `"test"`, `"full"` (TOML string): named method.
83#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
84#[serde(untagged)]
85pub enum VerifyLevel {
86    Bool(bool),
87    Method(VerifyMethod),
88}
89
90/// Named verification methods (the string form of [`VerifyLevel`]).
91#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
92#[serde(rename_all = "lowercase")]
93pub enum VerifyMethod {
94    Neural,
95    Test,
96    Full,
97}
98
99/// What syntactic region an annotation covers. Determines the body region
100/// hashed for staleness detection (per B3) and the scope a `"test"`-mode
101/// assertion is injected over.
102#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
103#[serde(rename_all = "snake_case")]
104pub enum CoveredRegion {
105    /// Whole function body (most common; α-form attribute on a fn).
106    Function,
107    /// A single statement (β-form macro before a stmt or loop).
108    Statement,
109    /// Every method in an `impl` block.
110    ImplMethods,
111    /// The inline body of a module item.
112    ModuleInlineBody,
113    /// A struct or enum item.
114    Type,
115    /// A struct field or enum variant.
116    Field,
117    /// The crate root.
118    Crate,
119    /// A trait declaration.
120    Trait,
121}
122
123#[cfg(test)]
124mod tests {
125    use super::*;
126
127    #[test]
128    fn annotation_kind_round_trips_lowercase() {
129        let v = serde_json::to_value(AnnotationKind::Intent).unwrap();
130        assert_eq!(v, serde_json::json!("intent"));
131        let back: AnnotationKind = serde_json::from_value(v).unwrap();
132        assert_eq!(back, AnnotationKind::Intent);
133    }
134
135    #[test]
136    fn status_pending_deepen_is_kebab_case() {
137        let v = serde_json::to_value(Status::PendingDeepen).unwrap();
138        assert_eq!(v, serde_json::json!("pending-deepen"));
139        let back: Status = serde_json::from_value(serde_json::json!("pending-deepen")).unwrap();
140        assert_eq!(back, Status::PendingDeepen);
141    }
142
143    #[test]
144    fn verify_level_accepts_bool_form() {
145        let level: VerifyLevel = serde_json::from_value(serde_json::json!(false)).unwrap();
146        assert_eq!(level, VerifyLevel::Bool(false));
147        let level: VerifyLevel = serde_json::from_value(serde_json::json!(true)).unwrap();
148        assert_eq!(level, VerifyLevel::Bool(true));
149    }
150
151    #[test]
152    fn verify_level_accepts_named_method_form() {
153        let level: VerifyLevel = serde_json::from_value(serde_json::json!("full")).unwrap();
154        assert_eq!(level, VerifyLevel::Method(VerifyMethod::Full));
155    }
156
157    #[test]
158    fn verify_level_rejects_unknown_string() {
159        let result: Result<VerifyLevel, _> = serde_json::from_value(serde_json::json!("partial"));
160        assert!(result.is_err());
161    }
162
163    #[test]
164    fn covered_region_uses_snake_case() {
165        let v = serde_json::to_value(CoveredRegion::ImplMethods).unwrap();
166        assert_eq!(v, serde_json::json!("impl_methods"));
167        let v = serde_json::to_value(CoveredRegion::ModuleInlineBody).unwrap();
168        assert_eq!(v, serde_json::json!("module_inline_body"));
169    }
170
171    #[test]
172    fn unknown_status_value_is_rejected() {
173        let result: Result<Status, _> = serde_json::from_value(serde_json::json!("partial"));
174        assert!(result.is_err());
175    }
176
177    #[test]
178    fn terminal_clean_is_exactly_verified_tested_neural() {
179        for s in [Status::Verified, Status::Tested, Status::Neural] {
180            assert!(s.is_terminal_clean(), "{s:?} should be terminal-clean");
181        }
182        for s in [
183            Status::Stale,
184            Status::Orphan,
185            Status::Forged,
186            Status::Unknown,
187            Status::PendingDeepen,
188            Status::Counterexample,
189            Status::Inconclusive,
190        ] {
191            assert!(!s.is_terminal_clean(), "{s:?} must NOT be terminal-clean");
192        }
193    }
194}