1use serde_json::Value;
5
6pub mod audit;
7pub mod capture_turn;
8pub mod field_names;
9pub mod link;
10pub mod memory;
11pub mod namespace;
12pub mod recall_request;
13pub mod reflection;
14pub mod skill;
15pub mod tag;
16
17#[allow(unused_imports)]
18pub use audit::*;
19pub use capture_turn::*;
20pub use link::*;
21pub use memory::*;
22pub use namespace::*;
23#[allow(unused_imports)]
24pub use recall_request::*;
25#[allow(unused_imports)]
26pub use reflection::*;
27#[allow(unused_imports)]
28pub use tag::*;
29
30pub const MAX_CONTENT_SIZE: usize = 65_536;
31
32pub const PROMOTION_THRESHOLD: i64 = 5;
33pub const SHORT_TTL_EXTEND_SECS: i64 = crate::SECS_PER_HOUR;
35pub const MID_TTL_EXTEND_SECS: i64 = crate::SECS_PER_DAY;
36
37pub fn default_metadata() -> Value {
38 Value::Object(serde_json::Map::new())
39}
40
41#[cfg(test)]
42mod tests {
43 use super::*;
44
45 #[test]
46 fn tier_from_str_valid() {
47 assert_eq!(Tier::from_str("short"), Some(Tier::Short));
48 assert_eq!(Tier::from_str("mid"), Some(Tier::Mid));
49 assert_eq!(Tier::from_str("long"), Some(Tier::Long));
50 }
51
52 #[test]
53 fn tier_from_str_invalid() {
54 assert_eq!(Tier::from_str("invalid"), None);
55 assert_eq!(Tier::from_str(""), None);
56 assert_eq!(Tier::from_str("SHORT"), None); }
58
59 #[test]
60 fn tier_as_str_roundtrip() {
61 for tier in [Tier::Short, Tier::Mid, Tier::Long] {
62 let s = tier.as_str();
63 assert_eq!(Tier::from_str(s), Some(tier));
64 }
65 }
66
67 #[test]
68 fn tier_default_ttl() {
69 assert_eq!(
70 Tier::Short.default_ttl_secs(),
71 Some(6 * crate::SECS_PER_HOUR)
72 );
73 assert_eq!(Tier::Mid.default_ttl_secs(), Some(crate::SECS_PER_WEEK));
74 assert_eq!(Tier::Long.default_ttl_secs(), None);
75 }
76
77 #[test]
78 fn tier_display() {
79 assert_eq!(format!("{}", Tier::Short), "short");
80 assert_eq!(format!("{}", Tier::Mid), "mid");
81 assert_eq!(format!("{}", Tier::Long), "long");
82 }
83
84 #[test]
85 fn constants_valid() {
86 const _: () = assert!(MAX_CONTENT_SIZE > 0);
87 const _: () = assert!(PROMOTION_THRESHOLD > 0);
88 assert_eq!(SHORT_TTL_EXTEND_SECS, 3600);
91 assert_eq!(MID_TTL_EXTEND_SECS, 86400);
92 assert_eq!(SHORT_TTL_EXTEND_SECS, crate::SECS_PER_HOUR);
93 assert_eq!(MID_TTL_EXTEND_SECS, crate::SECS_PER_DAY);
94 }
95
96 #[test]
97 fn tier_rank_ordering() {
98 assert!(Tier::Short.rank() < Tier::Mid.rank());
99 assert!(Tier::Mid.rank() < Tier::Long.rank());
100 assert_eq!(Tier::Short.rank(), 0);
101 assert_eq!(Tier::Mid.rank(), 1);
102 assert_eq!(Tier::Long.rank(), 2);
103 }
104
105 #[test]
108 fn attest_level_from_str_canonical_strings() {
109 assert_eq!(
116 AttestLevel::from_str("unsigned"),
117 Some(AttestLevel::Unsigned)
118 );
119 assert_eq!(
120 AttestLevel::from_str("self_signed"),
121 Some(AttestLevel::SelfSigned)
122 );
123 assert_eq!(
124 AttestLevel::from_str("peer_attested"),
125 Some(AttestLevel::PeerAttested)
126 );
127 assert_eq!(
128 AttestLevel::from_str("signed_by_peer"),
129 Some(AttestLevel::SignedByPeer)
130 );
131 assert_eq!(
132 AttestLevel::from_str("daemon_signed"),
133 Some(AttestLevel::DaemonSigned)
134 );
135 }
136
137 #[test]
138 fn attest_level_as_str_exact_wire_strings() {
139 assert_eq!(AttestLevel::Unsigned.as_str(), "unsigned");
145 assert_eq!(AttestLevel::SelfSigned.as_str(), "self_signed");
146 assert_eq!(AttestLevel::PeerAttested.as_str(), "peer_attested");
147 assert_eq!(AttestLevel::SignedByPeer.as_str(), "signed_by_peer");
148 assert_eq!(AttestLevel::DaemonSigned.as_str(), "daemon_signed");
149 }
150
151 #[test]
152 fn attest_level_from_str_unknown_returns_none() {
153 assert_eq!(AttestLevel::from_str(""), None);
154 assert_eq!(AttestLevel::from_str("Unsigned"), None); assert_eq!(AttestLevel::from_str("self-signed"), None); assert_eq!(AttestLevel::from_str("attested"), None);
157 }
158
159 #[test]
160 fn attest_level_as_str_round_trips_through_from_str() {
161 for lvl in [
162 AttestLevel::Unsigned,
163 AttestLevel::SelfSigned,
164 AttestLevel::PeerAttested,
165 AttestLevel::SignedByPeer,
166 AttestLevel::DaemonSigned,
167 ] {
168 let s = lvl.as_str();
169 assert_eq!(
170 AttestLevel::from_str(s),
171 Some(lvl),
172 "round-trip failed for {lvl:?}"
173 );
174 }
175 }
176
177 #[test]
178 fn attest_level_display_matches_as_str() {
179 assert_eq!(format!("{}", AttestLevel::Unsigned), "unsigned");
180 assert_eq!(format!("{}", AttestLevel::SelfSigned), "self_signed");
181 assert_eq!(format!("{}", AttestLevel::PeerAttested), "peer_attested");
182 assert_eq!(format!("{}", AttestLevel::SignedByPeer), "signed_by_peer");
183 assert_eq!(format!("{}", AttestLevel::DaemonSigned), "daemon_signed");
184 }
185
186 #[test]
187 fn attest_level_serde_wire_shape_matches_db_column() {
188 let json = serde_json::to_string(&AttestLevel::PeerAttested).unwrap();
191 assert_eq!(json, "\"peer_attested\"");
192 let back: AttestLevel = serde_json::from_str("\"self_signed\"").unwrap();
193 assert_eq!(back, AttestLevel::SelfSigned);
194 assert!(serde_json::from_str::<AttestLevel>("\"bogus\"").is_err());
196 }
197
198 #[test]
201 fn depth_flat_namespace() {
202 assert_eq!(namespace_depth("global"), 1);
203 assert_eq!(namespace_depth("ai-memory"), 1);
204 assert_eq!(namespace_depth("under_score"), 1);
205 }
206
207 #[test]
208 fn depth_hierarchical() {
209 assert_eq!(namespace_depth("a/b"), 2);
210 assert_eq!(namespace_depth("alphaone/engineering"), 2);
211 assert_eq!(namespace_depth("alphaone/engineering/platform"), 3);
212 assert_eq!(
213 namespace_depth("a/b/c/d/e/f/g/h"),
214 8,
215 "max depth of 8 counts each segment"
216 );
217 }
218
219 #[test]
220 fn depth_empty_is_zero() {
221 assert_eq!(namespace_depth(""), 0);
222 }
223
224 #[test]
225 fn parent_hierarchical() {
226 assert_eq!(
227 namespace_parent("alphaone/engineering/platform"),
228 Some("alphaone/engineering".to_string())
229 );
230 assert_eq!(
231 namespace_parent("alphaone/engineering"),
232 Some("alphaone".to_string())
233 );
234 }
235
236 #[test]
237 fn parent_flat_is_none() {
238 assert_eq!(namespace_parent("global"), None);
239 assert_eq!(namespace_parent("ai-memory"), None);
240 assert_eq!(namespace_parent(""), None);
241 }
242
243 #[test]
244 fn ancestors_three_levels() {
245 let a = namespace_ancestors("alphaone/engineering/platform");
246 assert_eq!(
247 a,
248 vec![
249 "alphaone/engineering/platform".to_string(),
250 "alphaone/engineering".to_string(),
251 "alphaone".to_string(),
252 ],
253 "ancestors ordered most-specific-first"
254 );
255 }
256
257 #[test]
258 fn ancestors_flat_namespace() {
259 assert_eq!(namespace_ancestors("global"), vec!["global".to_string()]);
260 assert_eq!(
261 namespace_ancestors("ai-memory"),
262 vec!["ai-memory".to_string()]
263 );
264 }
265
266 #[test]
267 fn ancestors_empty_input() {
268 assert!(namespace_ancestors("").is_empty());
269 }
270
271 #[test]
272 fn ancestors_single_level() {
273 assert_eq!(namespace_ancestors("a"), vec!["a".to_string()]);
274 }
275
276 #[test]
277 fn ancestors_max_depth() {
278 let a = namespace_ancestors("a/b/c/d/e/f/g/h");
279 assert_eq!(a.len(), 8);
280 assert_eq!(a[0], "a/b/c/d/e/f/g/h");
281 assert_eq!(a[7], "a");
282 }
283
284 #[test]
287 fn governance_default_policy() {
288 let p = GovernancePolicy::default();
289 assert_eq!(p.core.write, GovernanceLevel::Any);
290 assert_eq!(p.core.promote, GovernanceLevel::Any);
291 assert_eq!(p.core.delete, GovernanceLevel::Owner);
292 assert_eq!(p.core.approver, ApproverType::Human);
293 assert!(p.core.inherit);
297 }
298
299 #[test]
300 fn governance_inherit_field_defaults_true_on_partial_payload() {
301 let json = r#"{"write":"approve"}"#;
305 let p: GovernancePolicy = serde_json::from_str(json).unwrap();
306 assert_eq!(p.core.write, GovernanceLevel::Approve);
307 assert!(p.core.inherit, "missing `inherit` must deserialize as true");
308 }
309
310 #[test]
311 fn governance_inherit_field_explicit_false_round_trip() {
312 let json = r#"{"write":"any","inherit":false}"#;
315 let p: GovernancePolicy = serde_json::from_str(json).unwrap();
316 assert!(!p.core.inherit);
317 let back = serde_json::to_value(&p).unwrap();
318 assert_eq!(back["inherit"], false);
319 }
320
321 #[test]
322 fn governance_level_serde_snake_case() {
323 for (level, expected) in [
325 (GovernanceLevel::Any, "any"),
326 (GovernanceLevel::Registered, "registered"),
327 (GovernanceLevel::Owner, "owner"),
328 (GovernanceLevel::Approve, "approve"),
329 ] {
330 let json = serde_json::to_string(&level).unwrap();
331 assert_eq!(json, format!("\"{expected}\""));
332 let back: GovernanceLevel = serde_json::from_str(&json).unwrap();
334 assert_eq!(back, level);
335 }
336 }
337
338 #[test]
339 fn approver_type_serde_shapes() {
340 let json = serde_json::to_string(&ApproverType::Human).unwrap();
342 assert_eq!(json, "\"human\"");
343
344 let a = ApproverType::Agent("alice".to_string());
346 let json = serde_json::to_string(&a).unwrap();
347 assert_eq!(json, r#"{"agent":"alice"}"#);
348 let back: ApproverType = serde_json::from_str(&json).unwrap();
349 assert_eq!(back, a);
350
351 let c = ApproverType::Consensus(3);
353 let json = serde_json::to_string(&c).unwrap();
354 assert_eq!(json, r#"{"consensus":3}"#);
355 let back: ApproverType = serde_json::from_str(&json).unwrap();
356 assert_eq!(back, c);
357 }
358
359 #[test]
360 fn governance_policy_full_roundtrip() {
361 let p = GovernancePolicy {
362 core: CorePolicy {
363 write: GovernanceLevel::Registered,
364 promote: GovernanceLevel::Approve,
365 delete: GovernanceLevel::Owner,
366 approver: ApproverType::Agent("maintainer".to_string()),
367 inherit: true,
368 max_reflection_depth: None,
369 },
370 ..Default::default()
371 };
372 let json = serde_json::to_string(&p).unwrap();
373 let back: GovernancePolicy = serde_json::from_str(&json).unwrap();
374 assert_eq!(back, p);
375 }
376
377 #[test]
378 fn governance_from_metadata_missing() {
379 let meta = serde_json::json!({"agent_id": "alice"});
380 assert!(GovernancePolicy::from_metadata(&meta).is_none());
381 }
382
383 #[test]
384 fn governance_from_metadata_null() {
385 let meta = serde_json::json!({"governance": null});
386 assert!(GovernancePolicy::from_metadata(&meta).is_none());
387 }
388
389 #[test]
390 fn governance_from_metadata_default_shape() {
391 let default = GovernancePolicy::default();
392 let meta = serde_json::json!({"governance": serde_json::to_value(&default).unwrap()});
393 let parsed = GovernancePolicy::from_metadata(&meta)
394 .expect("present")
395 .expect("valid");
396 assert_eq!(parsed, default);
397 }
398
399 #[test]
400 fn governance_from_metadata_invalid_returns_err() {
401 let meta = serde_json::json!({
402 "governance": {"write": "bogus", "promote": "any", "delete": "any", "approver": "human"}
403 });
404 let result = GovernancePolicy::from_metadata(&meta).expect("present");
405 assert!(result.is_err(), "unknown enum value must fail deserialize");
406 }
407
408 #[test]
413 fn governance_partial_policy_write_only_uses_defaults() {
414 let json = serde_json::json!({"write": "owner"});
415 let parsed: GovernancePolicy = serde_json::from_value(json).expect("write-only parses");
416 assert_eq!(parsed.core.write, GovernanceLevel::Owner);
417 assert_eq!(parsed.core.promote, GovernanceLevel::Any);
418 assert_eq!(parsed.core.delete, GovernanceLevel::Owner);
419 assert_eq!(parsed.core.approver, ApproverType::Human);
420 }
421
422 #[test]
423 fn governance_partial_policy_write_and_promote() {
424 let json = serde_json::json!({"write": "any", "promote": "registered"});
425 let parsed: GovernancePolicy = serde_json::from_value(json).expect("parses");
426 assert_eq!(parsed.core.promote, GovernanceLevel::Registered);
427 assert_eq!(parsed.core.delete, GovernanceLevel::Owner);
429 assert_eq!(parsed.core.approver, ApproverType::Human);
430 }
431
432 #[test]
433 fn governance_missing_write_still_errors() {
434 let json = serde_json::json!({"promote": "owner"});
437 let err = serde_json::from_value::<GovernancePolicy>(json);
438 assert!(err.is_err(), "missing write must fail deserialize");
439 }
440
441 #[test]
442 fn governance_level_as_str_tags() {
443 assert_eq!(GovernanceLevel::Any.as_str(), "any");
444 assert_eq!(GovernanceLevel::Registered.as_str(), "registered");
445 assert_eq!(GovernanceLevel::Owner.as_str(), "owner");
446 assert_eq!(GovernanceLevel::Approve.as_str(), "approve");
447 }
448
449 #[test]
450 fn approver_type_kind_tags() {
451 assert_eq!(ApproverType::Human.kind(), "human");
452 assert_eq!(ApproverType::Agent("a".into()).kind(), "agent");
453 assert_eq!(ApproverType::Consensus(3).kind(), "consensus");
454 }
455
456 #[test]
461 fn default_metadata_is_empty_object() {
462 let v = default_metadata();
463 assert!(v.is_object());
464 assert!(v.as_object().unwrap().is_empty());
465 }
466
467 #[test]
468 fn governed_action_as_str_pinned() {
469 assert_eq!(GovernedAction::Store.as_str(), "store");
470 assert_eq!(GovernedAction::Delete.as_str(), "delete");
471 assert_eq!(GovernedAction::Promote.as_str(), "promote");
472 }
473
474 #[test]
475 fn governance_decision_equality() {
476 use crate::governance::GovernanceRefusal;
477 assert_eq!(GovernanceDecision::Allow, GovernanceDecision::Allow);
478 assert_ne!(
482 GovernanceDecision::Deny(GovernanceRefusal::new(
483 GovernedAction::Store,
484 GovernanceLevel::Owner,
485 "ai:x",
486 "a",
487 )),
488 GovernanceDecision::Deny(GovernanceRefusal::new(
489 GovernedAction::Store,
490 GovernanceLevel::Owner,
491 "ai:x",
492 "b",
493 )),
494 );
495 assert_eq!(
496 GovernanceDecision::Pending("p1".into()),
497 GovernanceDecision::Pending("p1".into())
498 );
499 }
500
501 #[test]
502 fn vector_clock_observe_monotonic() {
503 let mut vc = VectorClock::default();
504 vc.observe("peer-a", "2026-04-01T00:00:00+00:00");
505 vc.observe("peer-a", "2026-05-01T00:00:00+00:00");
506 vc.observe("peer-a", "2026-03-01T00:00:00+00:00");
508 assert_eq!(vc.latest_from("peer-a"), Some("2026-05-01T00:00:00+00:00"));
509 }
510
511 #[test]
512 fn vector_clock_latest_from_unknown_is_none() {
513 let vc = VectorClock::default();
514 assert!(vc.latest_from("never-seen").is_none());
515 }
516
517 #[test]
518 fn vector_clock_serde_roundtrip() {
519 let mut vc = VectorClock::default();
520 vc.observe("p1", "2026-04-01T00:00:00+00:00");
521 vc.observe("p2", "2026-04-02T00:00:00+00:00");
522 let json = serde_json::to_string(&vc).unwrap();
523 let back: VectorClock = serde_json::from_str(&json).unwrap();
524 assert_eq!(back.entries.len(), 2);
525 assert_eq!(back, vc);
526 }
527
528 #[test]
529 fn namespace_parent_with_trailing_slash() {
530 assert_eq!(namespace_parent("a/"), Some("a".to_string()));
533 }
534
535 #[test]
536 fn namespace_depth_skips_empty_segments() {
537 assert_eq!(namespace_depth("a//b"), 2);
539 assert_eq!(namespace_depth("/a"), 1);
540 assert_eq!(namespace_depth("a/"), 1);
541 }
542
543 #[test]
544 fn namespace_ancestors_two_levels() {
545 assert_eq!(
547 namespace_ancestors("a/b"),
548 vec!["a/b".to_string(), "a".to_string()]
549 );
550 }
551
552 #[test]
553 fn memory_serde_roundtrip_minimal() {
554 let m = Memory {
555 id: "abc".into(),
556 tier: Tier::Mid,
557 namespace: "global".into(),
558 title: "t".into(),
559 content: "c".into(),
560 tags: vec!["x".into()],
561 priority: 5,
562 confidence: 0.9,
563 source: "api".into(),
564 access_count: 0,
565 created_at: "2026-04-01T00:00:00+00:00".into(),
566 updated_at: "2026-04-01T00:00:00+00:00".into(),
567 last_accessed_at: None,
568 expires_at: None,
569 metadata: default_metadata(),
570 reflection_depth: 0,
571 memory_kind: MemoryKind::Observation,
572 entity_id: None,
573 persona_version: None,
574 citations: Vec::new(),
575 source_uri: None,
576 source_span: None,
577 confidence_source: ConfidenceSource::CallerProvided,
578 confidence_signals: None,
579 confidence_decayed_at: None,
580 version: 1,
581 };
582 let json = serde_json::to_string(&m).unwrap();
583 let back: Memory = serde_json::from_str(&json).unwrap();
584 assert_eq!(back.id, m.id);
585 assert_eq!(back.tier, Tier::Mid);
586 }
587
588 #[test]
589 fn approver_type_kind_for_each_variant() {
590 assert_eq!(ApproverType::Human.kind(), "human");
593 assert_eq!(ApproverType::Agent(String::new()).kind(), "agent");
594 assert_eq!(ApproverType::Consensus(0).kind(), "consensus");
595 }
596
597 #[test]
598 fn governance_partial_policy_with_approver() {
599 let json = serde_json::json!({
601 "write": "owner",
602 "approver": {"agent": "alice"}
603 });
604 let parsed: GovernancePolicy = serde_json::from_value(json).expect("parses");
605 assert_eq!(parsed.core.write, GovernanceLevel::Owner);
606 assert_eq!(
607 parsed.core.approver,
608 ApproverType::Agent("alice".to_string())
609 );
610 assert_eq!(parsed.core.promote, GovernanceLevel::Any);
611 assert_eq!(parsed.core.delete, GovernanceLevel::Owner);
612 }
613}