(
&self,
view_name: &str,
hashes: &[atomic_core::types::Hash],
)
| 138 | } |
| 139 | |
| 140 | fn classify_hashes( |
| 141 | &self, |
| 142 | view_name: &str, |
| 143 | hashes: &[atomic_core::types::Hash], |
| 144 | ) -> Result<ProvenanceSummary, RepositoryError> { |
| 145 | let mut summary = ProvenanceSummary { |
| 146 | view_name: view_name.to_string(), |
| 147 | ..Default::default() |
| 148 | }; |
| 149 | |
| 150 | for hash in hashes { |
| 151 | let change = match self.load_change(hash) { |
| 152 | Ok(c) => c, |
| 153 | Err(_) => { |
| 154 | summary.unreadable_changes += 1; |
| 155 | continue; |
| 156 | } |
| 157 | }; |
| 158 | |
| 159 | let provs = change.provenance(); |
| 160 | if !provs.is_empty() { |
| 161 | summary.ai_changes += 1; |
| 162 | |
| 163 | // Bucket once per unique vendor / tool / model present in this change. |
| 164 | let mut seen_vendors = std::collections::BTreeSet::new(); |
| 165 | let mut seen_tools = std::collections::BTreeSet::new(); |
| 166 | let mut seen_models = std::collections::BTreeSet::new(); |
| 167 | for p in provs { |
| 168 | let v = p.vendor.name().to_string(); |
| 169 | if seen_vendors.insert(v.clone()) { |
| 170 | *summary.by_vendor.entry(v).or_insert(0) += 1; |
| 171 | } |
| 172 | let t = p.tool.description(); |
| 173 | if seen_tools.insert(t.clone()) { |
| 174 | *summary.by_tool.entry(t).or_insert(0) += 1; |
| 175 | } |
| 176 | let m = p.model.clone(); |
| 177 | if seen_models.insert(m.clone()) { |
| 178 | *summary.by_model.entry(m).or_insert(0) += 1; |
| 179 | } |
| 180 | } |
| 181 | continue; |
| 182 | } |
| 183 | |
| 184 | // No provenance — disambiguate by author. |
| 185 | if change.hashed.header.authors.is_empty() { |
| 186 | summary.system_changes += 1; |
| 187 | } else if change |
| 188 | .hashed |
| 189 | .header |
| 190 | .authors |
| 191 | .iter() |
| 192 | .any(author_is_agent_identity) |
| 193 | { |
| 194 | summary.needs_attention_changes += 1; |
| 195 | } else { |
| 196 | summary.human_changes += 1; |
| 197 | } |
no test coverage detected