diff --git a/compliance-agent/src/pipeline/orchestrator.rs b/compliance-agent/src/pipeline/orchestrator.rs index 8f038ea..84e12d7 100644 --- a/compliance-agent/src/pipeline/orchestrator.rs +++ b/compliance-agent/src/pipeline/orchestrator.rs @@ -586,7 +586,21 @@ impl PipelineOrchestrator { let Some(path) = ingest_set.get(&a.id).and_then(|ia| ia.working_path.clone()) else { continue; }; - all_findings.extend(crate::pipeline::plc::analyze_tree(&path, target_id)); + let mut source_findings = crate::pipeline::plc::analyze_tree(&path, target_id); + // Control mapping for the PLC path (run_plc_scan is separate from + // run_pipeline, which does its own mapping). PLC findings carry + // file_path/line/cwe, so the semantic pass reads each region under this + // source's `path` and stamps master-control refs. The LUT + grounded + // surface passes are code-pattern / CRA-specific and don't apply to + // IEC 61131-3 control logic, so only the semantic pass runs here. + crate::controls::semantic_stamp_findings( + &self.config, + self.llm.clone(), + &path, + &mut source_findings, + ) + .await; + all_findings.extend(source_findings); // Control-application SBOM: CODESYS libraries + runtime from a // `.projectarchive` (uploaded, or committed in the working tree). let archive = a