Skip to main content

feagi_evolutionary/genome/schema/
version.rs

1// Copyright 2025 Neuraville Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Genome schema version primitives.
5//!
6//! See `crates/feagi-evolutionary/src/genome/README.md` and
7//! `feagi-core/docs/GENOME_SCHEMA_VERSIONING.md` for the design rationale,
8//! invariants, and the procedure for adding a new schema version.
9
10use serde::{Deserialize, Serialize};
11use std::fmt;
12
13/// Integer schema version of a genome.
14///
15/// Serializes as a bare integer on the wire so it can be queried directly
16/// from MongoDB and so diffs are obvious. The legacy human-readable
17/// `version` string field on a genome is unrelated and MUST NOT be used
18/// to drive code dispatch.
19#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Serialize, Deserialize)]
20#[serde(transparent)]
21pub struct GenomeSchemaVersion(pub u32);
22
23impl GenomeSchemaVersion {
24    pub const fn new(version: u32) -> Self {
25        Self(version)
26    }
27
28    pub const fn as_u32(self) -> u32 {
29        self.0
30    }
31}
32
33impl fmt::Display for GenomeSchemaVersion {
34    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35        write!(f, "v{}", self.0)
36    }
37}
38
39/// Lowest schema version recognized by this crate.
40///
41/// The integer space starts at 2. There is no `v1`: the project never
42/// persisted a genome at that integer in any production database or in
43/// the offline `g0/` corpus. The chain registry is contiguous starting
44/// at this constant.
45pub const MIN_SCHEMA_VERSION: GenomeSchemaVersion = GenomeSchemaVersion(2);
46
47/// Latest schema version. New genomes are produced at this version, and
48/// `Validator(CURRENT_SCHEMA_VERSION)` is the only blocking validator.
49pub const CURRENT_SCHEMA_VERSION: GenomeSchemaVersion = GenomeSchemaVersion(3);
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54
55    #[test]
56    fn ordering_follows_integer_value() {
57        assert!(GenomeSchemaVersion(2) < GenomeSchemaVersion(3));
58        assert!(MIN_SCHEMA_VERSION <= CURRENT_SCHEMA_VERSION);
59    }
60
61    #[test]
62    fn current_is_at_or_above_min() {
63        assert!(CURRENT_SCHEMA_VERSION >= MIN_SCHEMA_VERSION);
64    }
65
66    #[test]
67    fn min_is_two() {
68        assert_eq!(MIN_SCHEMA_VERSION.as_u32(), 2);
69    }
70
71    #[test]
72    fn current_is_three() {
73        assert_eq!(CURRENT_SCHEMA_VERSION.as_u32(), 3);
74    }
75
76    #[test]
77    fn serializes_as_bare_integer() {
78        let v = GenomeSchemaVersion(3);
79        let json = serde_json::to_string(&v).unwrap();
80        assert_eq!(json, "3");
81    }
82
83    #[test]
84    fn deserializes_from_bare_integer() {
85        let v: GenomeSchemaVersion = serde_json::from_str("3").unwrap();
86        assert_eq!(v, GenomeSchemaVersion(3));
87    }
88
89    #[test]
90    fn round_trips_through_serde() {
91        let v = GenomeSchemaVersion(42);
92        let json = serde_json::to_string(&v).unwrap();
93        let back: GenomeSchemaVersion = serde_json::from_str(&json).unwrap();
94        assert_eq!(v, back);
95    }
96
97    #[test]
98    fn display_uses_v_prefix() {
99        assert_eq!(format!("{}", GenomeSchemaVersion(3)), "v3");
100    }
101
102    #[test]
103    fn const_constructor_matches_field_constructor() {
104        const VIA_CONST: GenomeSchemaVersion = GenomeSchemaVersion::new(5);
105        assert_eq!(VIA_CONST, GenomeSchemaVersion(5));
106        assert_eq!(VIA_CONST.as_u32(), 5);
107    }
108}