use chrono::{DateTime, Utc};
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DriftClassification {
Intentional,
Uncontrolled,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ValidationFailureReason {
None,
ParseFailure,
CoherenceFailure,
MissingLayer,
InvalidTier,
NestingDepth,
SchemaViolation,
}
impl fmt::Display for ValidationFailureReason {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ValidationFailureReason::None => write!(f, "None"),
ValidationFailureReason::ParseFailure => write!(f, "ParseFailure"),
ValidationFailureReason::CoherenceFailure => write!(f, "CoherenceFailure"),
ValidationFailureReason::MissingLayer => write!(f, "MissingLayer"),
ValidationFailureReason::InvalidTier => write!(f, "InvalidTier"),
ValidationFailureReason::NestingDepth => write!(f, "NestingDepth"),
ValidationFailureReason::SchemaViolation => write!(f, "SchemaViolation"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct AvecState {
pub stability: f32,
pub friction: f32,
pub logic: f32,
pub autonomy: f32,
}
impl AvecState {
pub fn psi(self) -> f32 {
self.stability + self.friction + self.logic + self.autonomy
}
pub fn drift_from(self, previous: Self) -> f32 {
self.psi() - previous.psi()
}
pub fn classify_drift(self, previous: Self) -> DriftClassification {
let delta = self.drift_from(previous).abs();
if delta > 0.3 {
DriftClassification::Uncontrolled
} else {
DriftClassification::Intentional
}
}
pub const fn zero() -> Self {
Self {
stability: 0.0,
friction: 0.0,
logic: 0.0,
autonomy: 0.0,
}
}
pub const fn focused() -> Self {
Self {
stability: 0.95,
friction: 0.10,
logic: 0.95,
autonomy: 0.90,
}
}
pub const fn creative() -> Self {
Self {
stability: 0.80,
friction: 0.15,
logic: 0.70,
autonomy: 0.95,
}
}
pub const fn analytical() -> Self {
Self {
stability: 0.90,
friction: 0.20,
logic: 0.98,
autonomy: 0.85,
}
}
pub const fn exploratory() -> Self {
Self {
stability: 0.75,
friction: 0.30,
logic: 0.65,
autonomy: 0.90,
}
}
pub const fn collaborative() -> Self {
Self {
stability: 0.85,
friction: 0.10,
logic: 0.80,
autonomy: 0.70,
}
}
pub const fn defensive() -> Self {
Self {
stability: 0.90,
friction: 0.40,
logic: 0.90,
autonomy: 0.60,
}
}
pub const fn passive() -> Self {
Self {
stability: 0.98,
friction: 0.05,
logic: 0.60,
autonomy: 0.40,
}
}
}
impl Default for AvecState {
fn default() -> Self {
Self::zero()
}
}
#[derive(Debug, Clone)]
pub struct SttpNode {
pub raw: String,
pub session_id: String,
pub tier: String,
pub timestamp: DateTime<Utc>,
pub compression_depth: i32,
pub parent_node_id: Option<String>,
pub user_avec: AvecState,
pub model_avec: AvecState,
pub compression_avec: Option<AvecState>,
pub rho: f32,
pub kappa: f32,
pub psi: f32,
}
#[derive(Debug, Clone)]
pub struct CalibrationResult {
pub previous_avec: AvecState,
pub delta: f32,
pub drift_classification: DriftClassification,
pub trigger: String,
pub trigger_history: Vec<String>,
pub is_first_calibration: bool,
}
#[derive(Debug, Clone)]
pub struct NodeQuery {
pub limit: usize,
pub session_id: Option<String>,
pub from_utc: Option<DateTime<Utc>>,
pub to_utc: Option<DateTime<Utc>>,
}
impl Default for NodeQuery {
fn default() -> Self {
Self {
limit: 500,
session_id: None,
from_utc: None,
to_utc: None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct NumericRange {
pub min: f32,
pub max: f32,
pub average: f32,
}
impl Default for NumericRange {
fn default() -> Self {
Self {
min: 0.0,
max: 0.0,
average: 0.0,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct PsiRange {
pub min: f32,
pub max: f32,
pub average: f32,
}
impl Default for PsiRange {
fn default() -> Self {
Self {
min: 0.0,
max: 0.0,
average: 0.0,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct ConfidenceBandSummary {
pub low: usize,
pub medium: usize,
pub high: usize,
}
#[derive(Debug, Clone, Default)]
pub struct RetrieveResult {
pub nodes: Vec<SttpNode>,
pub retrieved: usize,
pub psi_range: PsiRange,
}
#[derive(Debug, Clone, Default)]
pub struct ListNodesResult {
pub nodes: Vec<SttpNode>,
pub retrieved: usize,
}
#[derive(Debug, Clone, Default)]
pub struct ScopeRekeyResult {
pub source_tenant_id: String,
pub source_session_id: String,
pub target_tenant_id: String,
pub target_session_id: String,
pub temporal_nodes: usize,
pub calibrations: usize,
pub target_temporal_nodes: usize,
pub target_calibrations: usize,
pub applied: bool,
pub conflict: bool,
pub message: Option<String>,
}
#[derive(Debug, Clone, Default)]
pub struct BatchRekeyResult {
pub dry_run: bool,
pub requested_node_ids: usize,
pub resolved_node_ids: usize,
pub missing_node_ids: Vec<String>,
pub scopes: Vec<ScopeRekeyResult>,
pub temporal_nodes_updated: usize,
pub calibrations_updated: usize,
}
#[derive(Debug, Clone, Default)]
pub struct StoreResult {
pub node_id: String,
pub psi: f32,
pub valid: bool,
pub validation_error: Option<String>,
}
#[derive(Debug, Clone)]
pub struct ParseResult {
pub success: bool,
pub node: Option<SttpNode>,
pub error: Option<String>,
}
impl ParseResult {
pub fn ok(node: SttpNode) -> Self {
Self {
success: true,
node: Some(node),
error: None,
}
}
pub fn fail(error: impl Into<String>) -> Self {
Self {
success: false,
node: None,
error: Some(error.into()),
}
}
}
#[derive(Debug, Clone)]
pub struct ValidationResult {
pub is_valid: bool,
pub error: Option<String>,
pub reason: ValidationFailureReason,
}
impl ValidationResult {
pub fn ok() -> Self {
Self {
is_valid: true,
error: None,
reason: ValidationFailureReason::None,
}
}
pub fn fail(error: impl Into<String>, reason: ValidationFailureReason) -> Self {
Self {
is_valid: false,
error: Some(error.into()),
reason,
}
}
}
#[derive(Debug, Clone)]
pub struct MoodCatalogResult {
pub presets: Vec<MoodPreset>,
pub apply_guide: String,
pub swap_preview: Option<MoodSwapPreview>,
}
#[derive(Debug, Clone)]
pub struct MoodPreset {
pub name: String,
pub description: String,
pub avec: AvecState,
}
#[derive(Debug, Clone)]
pub struct MoodSwapPreview {
pub target_mood: String,
pub blend: f32,
pub current: AvecState,
pub target: AvecState,
pub blended: AvecState,
}
#[derive(Debug, Clone)]
pub struct MonthlyRollupRequest {
pub session_id: String,
pub start_utc: DateTime<Utc>,
pub end_utc: DateTime<Utc>,
pub source_session_id: Option<String>,
pub parent_node_id: Option<String>,
pub limit: usize,
pub persist: bool,
}
impl MonthlyRollupRequest {
pub fn new(session_id: impl Into<String>, start_utc: DateTime<Utc>, end_utc: DateTime<Utc>) -> Self {
Self {
session_id: session_id.into(),
start_utc,
end_utc,
source_session_id: None,
parent_node_id: None,
limit: 5000,
persist: true,
}
}
}
#[derive(Debug, Clone)]
pub struct MonthlyRollupResult {
pub success: bool,
pub node_id: String,
pub raw_node: String,
pub error: Option<String>,
pub source_nodes: usize,
pub parent_reference: Option<String>,
pub user_average: AvecState,
pub model_average: AvecState,
pub compression_average: AvecState,
pub rho_range: NumericRange,
pub kappa_range: NumericRange,
pub psi_range: NumericRange,
pub rho_bands: ConfidenceBandSummary,
pub kappa_bands: ConfidenceBandSummary,
}
impl Default for MonthlyRollupResult {
fn default() -> Self {
Self {
success: false,
node_id: String::new(),
raw_node: String::new(),
error: None,
source_nodes: 0,
parent_reference: None,
user_average: AvecState::zero(),
model_average: AvecState::zero(),
compression_average: AvecState::zero(),
rho_range: NumericRange::default(),
kappa_range: NumericRange::default(),
psi_range: NumericRange::default(),
rho_bands: ConfidenceBandSummary::default(),
kappa_bands: ConfidenceBandSummary::default(),
}
}
}