trace_share_core/
models.rs1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct ToolInfo {
6 pub name: String,
7 pub args_json: Option<String>,
8 pub result_json: Option<String>,
9}
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct EventMeta {
13 pub cwd: Option<String>,
14 pub repo: Option<String>,
15 pub exit_code: Option<i32>,
16 pub model: Option<String>,
17 pub tags: Vec<String>,
18}
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct CanonicalEvent {
22 pub source: String,
23 pub session_id: String,
24 pub ts: DateTime<Utc>,
25 pub kind: String,
26 pub text: String,
27 pub tool: Option<ToolInfo>,
28 pub meta: Option<EventMeta>,
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct ChunkMetadata {
33 pub source: String,
34 pub session_id: String,
35 pub chunk_index: usize,
36 pub ts_start: String,
37 pub ts_end: String,
38 pub tool_names: Vec<String>,
39 pub error_types: Vec<String>,
40 pub repo_fingerprint: Option<String>,
41 pub language: Option<String>,
42 pub policy_version: String,
43 pub sanitizer_version: String,
44 pub content_hash: String,
45}
46
47#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct ChunkDocument {
49 pub id: String,
50 pub text: String,
51 pub metadata: ChunkMetadata,
52}
53
54pub fn normalize_text(input: &str) -> String {
55 input
56 .lines()
57 .map(str::trim_end)
58 .collect::<Vec<_>>()
59 .join("\n")
60 .trim()
61 .to_string()
62}
63
64pub fn content_hash(normalized_sanitized_text: &str) -> String {
65 blake3::hash(normalized_sanitized_text.as_bytes())
66 .to_hex()
67 .to_string()
68}
69
70pub fn doc_id(source: &str, session_id: &str, chunk_index: usize, content_hash: &str) -> String {
71 let seed = format!("{source}|{session_id}|{chunk_index}|{content_hash}");
72 blake3::hash(seed.as_bytes()).to_hex().to_string()
73}
74
75#[cfg(test)]
76mod tests {
77 use super::{content_hash, doc_id, normalize_text};
78
79 #[test]
80 fn deterministic_hash_and_id() {
81 let normalized = normalize_text("hello\nworld\n");
82 let h1 = content_hash(&normalized);
83 let h2 = content_hash(&normalized);
84 assert_eq!(h1, h2);
85
86 let d1 = doc_id("codex_cli", "abc", 1, &h1);
87 let d2 = doc_id("codex_cli", "abc", 1, &h1);
88 assert_eq!(d1, d2);
89 }
90}