1use crate::compiler::evidence::{PacketValidationError, validate_packet_sources};
2use crate::schema::{
3 CandidateAction, CompiledFact, Contradiction, EvidenceRecord, HaltSignal, Hypothesis,
4 MYTHOS_SCHEMA_VERSION, NextPassPacket, RecurringFailurePattern, SourceRef, VerifierFinding,
5};
6
7#[derive(Debug, Clone, PartialEq)]
8pub struct CompilerInputBundle {
9 pub objective_id: String,
10 pub run_id: String,
11 pub branch_id: String,
12 pub pass_id: String,
13 pub objective: String,
14 pub evidence: Vec<EvidenceRecord>,
15 pub trusted_facts: Vec<CompiledFact>,
16 pub active_hypotheses: Vec<Hypothesis>,
17 pub contradictions: Vec<Contradiction>,
18 pub recurring_failure_patterns: Vec<RecurringFailurePattern>,
19 pub candidate_actions: Vec<CandidateAction>,
20 pub verifier_findings: Vec<VerifierFinding>,
21 pub open_questions: Vec<String>,
22 pub raw_drilldown_refs: Vec<SourceRef>,
23 pub halt_signals: Vec<HaltSignal>,
24 pub sources: Vec<SourceRef>,
25}
26
27pub fn build_next_pass_packet(
28 input: CompilerInputBundle,
29) -> Result<NextPassPacket, PacketValidationError> {
30 let packet = NextPassPacket {
31 schema_version: MYTHOS_SCHEMA_VERSION.to_string(),
32 objective_id: input.objective_id,
33 run_id: input.run_id,
34 branch_id: input.branch_id,
35 pass_id: input.pass_id,
36 objective: input.objective,
37 evidence: input.evidence,
38 trusted_facts: input.trusted_facts,
39 active_hypotheses: input.active_hypotheses,
40 contradictions: input.contradictions,
41 recurring_failure_patterns: input.recurring_failure_patterns,
42 candidate_actions: input.candidate_actions,
43 verifier_findings: input.verifier_findings,
44 open_questions: input.open_questions,
45 raw_drilldown_refs: input.raw_drilldown_refs,
46 halt_signals: input.halt_signals,
47 sources: input.sources,
48 };
49
50 validate_packet_sources(&packet)?;
51 Ok(packet)
52}
53
54#[cfg(test)]
55mod tests {
56 use super::{CompilerInputBundle, build_next_pass_packet};
57
58 #[test]
59 fn builds_packet_from_compiler_input() {
60 let packet = build_next_pass_packet(CompilerInputBundle {
61 objective_id: "obj-1".to_string(),
62 run_id: "run-1".to_string(),
63 branch_id: "main".to_string(),
64 pass_id: "pass-1".to_string(),
65 objective: "Solve the task".to_string(),
66 evidence: vec![crate::schema::EvidenceRecord {
67 id: "ev-1".to_string(),
68 kind: "observation".to_string(),
69 summary: "shell output".to_string(),
70 source_ids: vec!["src-1".to_string()],
71 source_refs: vec![],
72 observed_at: "2026-04-21T00:00:00Z".to_string(),
73 agent_id: None,
74 lane: None,
75 confidence: None,
76 rationale: None,
77 diff_ref: None,
78 span_before: None,
79 span_after: None,
80 }],
81 trusted_facts: vec![],
82 active_hypotheses: vec![],
83 contradictions: vec![],
84 recurring_failure_patterns: vec![],
85 candidate_actions: vec![],
86 verifier_findings: vec![],
87 open_questions: vec!["What failed?".to_string()],
88 raw_drilldown_refs: vec![crate::schema::SourceRef {
89 source_id: "src-1".to_string(),
90 path: "evidence/log.txt".to_string(),
91 kind: "log".to_string(),
92 hash: "abc".to_string(),
93 hash_alg: "fnv1a-64".to_string(),
94 span: None,
95 observed_at: "2026-04-21T00:00:00Z".to_string(),
96 }],
97 halt_signals: vec![crate::schema::HaltSignal {
98 id: "halt-1".to_string(),
99 kind: "continue".to_string(),
100 contribution: 0.1,
101 rationale: "still unresolved".to_string(),
102 source_ids: vec!["src-1".to_string()],
103 }],
104 sources: vec![crate::schema::SourceRef {
105 source_id: "src-1".to_string(),
106 path: "evidence/log.txt".to_string(),
107 kind: "log".to_string(),
108 hash: "abc".to_string(),
109 hash_alg: "fnv1a-64".to_string(),
110 span: None,
111 observed_at: "2026-04-21T00:00:00Z".to_string(),
112 }],
113 })
114 .expect("valid packet");
115
116 assert_eq!(packet.objective_id, "obj-1");
117 assert_eq!(packet.open_questions, vec!["What failed?".to_string()]);
118 }
119}