mati_core/hooks/decide/
instructions_loaded.rs1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
14pub struct InstructionsLoadedPayload {
15 pub session_id: String,
16 pub transcript_path: String,
17 pub cwd: String,
18 pub hook_event_name: String,
19 pub file_path: String,
20 pub memory_type: String,
21 pub load_reason: String,
22}
23
24pub fn parse_instructions_loaded(input: &serde_json::Value) -> Option<InstructionsLoadedPayload> {
29 let payload: InstructionsLoadedPayload = serde_json::from_value(input.clone()).ok()?;
30 (payload.hook_event_name == "InstructionsLoaded").then_some(payload)
31}
32
33#[cfg(test)]
34mod tests {
35 use super::*;
36 use serde_json::json;
37
38 fn payload() -> serde_json::Value {
39 json!({
40 "session_id": "session-123",
41 "transcript_path": "/tmp/transcript.jsonl",
42 "cwd": "/repo",
43 "hook_event_name": "InstructionsLoaded",
44 "file_path": "/repo/.claude/CLAUDE.md",
45 "memory_type": "Project",
46 "load_reason": "session_start"
47 })
48 }
49
50 #[test]
51 fn parses_captured_platform_shape() {
52 let parsed = parse_instructions_loaded(&payload()).expect("payload should parse");
53 assert_eq!(parsed.file_path, "/repo/.claude/CLAUDE.md");
54 assert_eq!(parsed.load_reason, "session_start");
55 }
56
57 #[test]
58 fn rejects_other_hook_events() {
59 let mut value = payload();
60 value["hook_event_name"] = json!("SessionStart");
61 assert!(parse_instructions_loaded(&value).is_none());
62 }
63
64 #[test]
65 fn rejects_missing_or_wrongly_typed_fields() {
66 let mut missing = payload();
67 missing.as_object_mut().unwrap().remove("file_path");
68 assert!(parse_instructions_loaded(&missing).is_none());
69
70 let mut wrong_type = payload();
71 wrong_type["load_reason"] = json!(42);
72 assert!(parse_instructions_loaded(&wrong_type).is_none());
73 }
74
75 #[test]
77 fn accepts_unknown_fields() {
78 let mut value = payload();
79 value["future_platform_field"] = json!(true);
80 let parsed = parse_instructions_loaded(&value).expect("unknown fields must not reject");
81 assert_eq!(parsed.file_path, "/repo/.claude/CLAUDE.md");
82 }
83}