Normalize a user-supplied intent reference to its manifest key (the human key `PROJECT::author::seq`). Accepts, filling in the current project and author so the common case is just a number: - `3` -> `PROJECT:: ::3` - `alice::3` -> `PROJECT::alice::3` - `PIMO::alice::3` -> exact (project uppercased) - a ULID or prefix -> resolved to the matching intent's huma
(&self, id: &str)
| 1182 | /// produces a `HumanKey` for `::`-separated or all-digit input, so anything |
| 1183 | /// else — including `PIMO-1` — arrives here classified as a ULID. |
| 1184 | fn normalize_intent_id(&self, id: &str) -> Result<String, RepositoryError> { |
| 1185 | use atomic_core::pristine::vault::{parse_intent_reference, IntentRef}; |
| 1186 | |
| 1187 | let manifest = self.vault_manifest()?; |
| 1188 | let project = manifest.project_code().to_string(); |
| 1189 | let author = slug_author(&self.resolve_vault_identity().name); |
| 1190 | |
| 1191 | match parse_intent_reference(id, &project, &author) { |
| 1192 | IntentRef::HumanKey(key) => { |
| 1193 | // Exact manifest key, or a case-insensitive / legacy match. |
| 1194 | if manifest.intents.contains_key(&key) { |
| 1195 | return Ok(key); |
| 1196 | } |
| 1197 | if let Some(k) = manifest |
| 1198 | .intents |
| 1199 | .keys() |
| 1200 | .find(|k| k.eq_ignore_ascii_case(&key) || k.eq_ignore_ascii_case(id)) |
| 1201 | { |
| 1202 | return Ok(k.clone()); |
| 1203 | } |
| 1204 | // No entry yet (e.g. freshly composed key): return the composed |
| 1205 | // form so callers can still address it. |
| 1206 | Ok(key) |
| 1207 | } |
| 1208 | IntentRef::Uid(uid) => { |
| 1209 | // Prefer an exact UID. A prefix is accepted only when it |
| 1210 | // identifies exactly one intent. |
| 1211 | let mut matches: Vec<_> = manifest |
| 1212 | .intents |
| 1213 | .values() |
| 1214 | .filter(|summary| summary.uid.eq_ignore_ascii_case(&uid)) |
| 1215 | .collect(); |
| 1216 | if matches.is_empty() { |
| 1217 | let prefix = uid.to_ascii_uppercase(); |
| 1218 | matches = manifest |
| 1219 | .intents |
| 1220 | .values() |
| 1221 | .filter(|summary| summary.uid.to_ascii_uppercase().starts_with(&prefix)) |
| 1222 | .collect(); |
| 1223 | } |
| 1224 | matches.sort_by(|a, b| a.uid.cmp(&b.uid)); |
| 1225 | |
| 1226 | if matches.len() == 1 { |
| 1227 | let summary = matches[0]; |
| 1228 | return Ok(if summary.human_key.is_empty() { |
| 1229 | summary.uid.clone() |
| 1230 | } else { |
| 1231 | summary.human_key.clone() |
| 1232 | }); |
| 1233 | } |
| 1234 | if matches.len() > 1 { |
| 1235 | return Err(RepositoryError::AmbiguousIntent { |
| 1236 | prefix: id.to_string(), |
| 1237 | matches: matches |
| 1238 | .into_iter() |
| 1239 | .map(|summary| summary.uid.clone()) |
| 1240 | .collect(), |
| 1241 | }); |