diff --git a/compliance-agent/src/pipeline/orchestrator.rs b/compliance-agent/src/pipeline/orchestrator.rs index 84e12d7..2bf4450 100644 --- a/compliance-agent/src/pipeline/orchestrator.rs +++ b/compliance-agent/src/pipeline/orchestrator.rs @@ -625,6 +625,7 @@ impl PipelineOrchestrator { ); let mut new_count = 0u32; + let mut refreshed_count = 0u32; for mut finding in all_findings { finding.scan_run_id = Some(scan_run_id.to_string()); if self @@ -636,8 +637,27 @@ impl PipelineOrchestrator { { self.db.findings().insert_one(&finding).await?; new_count += 1; + } else if !finding.control_refs.is_empty() { + // Re-scan refresh: mirror run_pipeline — persist newly-computed + // control_refs onto a PLC finding first seen before the semantic + // pass ran. The insert path alone never would, so without this a + // PLC re-scan can only pick up mappings via a delete + re-add. + self.db + .findings() + .update_one( + doc! { "fingerprint": &finding.fingerprint }, + doc! { "$set": { "control_refs": finding.control_refs.clone() } }, + ) + .await?; + refreshed_count += 1; } } + if refreshed_count > 0 { + tracing::info!( + target_id, + "Refreshed control_refs on {refreshed_count} existing PLC findings" + ); + } if !all_sbom.is_empty() { if let Err(e) = self