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)
| 1159 | /// produces a `HumanKey` for `::`-separated or all-digit input, so anything |
| 1160 | /// else — including `PIMO-1` — arrives here classified as a ULID. |
| 1161 | fn normalize_intent_id(&self, id: &str) -> Result<String, RepositoryError> { |
| 1162 | use atomic_core::pristine::vault::{parse_intent_reference, IntentRef}; |
| 1163 | |
| 1164 | let manifest = self.vault_manifest()?; |
| 1165 | let project = manifest.project_code().to_string(); |
| 1166 | let author = slug_author(&self.resolve_vault_identity().name); |
| 1167 | |
| 1168 | match parse_intent_reference(id, &project, &author) { |
| 1169 | IntentRef::HumanKey(key) => { |
| 1170 | // Exact manifest key, or a case-insensitive / legacy match. |
| 1171 | if manifest.intents.contains_key(&key) { |
| 1172 | return Ok(key); |
| 1173 | } |
| 1174 | if let Some(k) = manifest |
| 1175 | .intents |
| 1176 | .keys() |
| 1177 | .find(|k| k.eq_ignore_ascii_case(&key) || k.eq_ignore_ascii_case(id)) |
| 1178 | { |
| 1179 | return Ok(k.clone()); |
| 1180 | } |
| 1181 | // No entry yet (e.g. freshly composed key): return the composed |
| 1182 | // form so callers can still address it. |
| 1183 | Ok(key) |
| 1184 | } |
| 1185 | IntentRef::Uid(uid) => { |
| 1186 | // Prefer an exact UID. A prefix is accepted only when it |
| 1187 | // identifies exactly one intent. |
| 1188 | let mut matches: Vec<_> = manifest |
| 1189 | .intents |
| 1190 | .values() |
| 1191 | .filter(|summary| summary.uid.eq_ignore_ascii_case(&uid)) |
| 1192 | .collect(); |
| 1193 | if matches.is_empty() { |
| 1194 | let prefix = uid.to_ascii_uppercase(); |
| 1195 | matches = manifest |
| 1196 | .intents |
| 1197 | .values() |
| 1198 | .filter(|summary| summary.uid.to_ascii_uppercase().starts_with(&prefix)) |
| 1199 | .collect(); |
| 1200 | } |
| 1201 | matches.sort_by(|a, b| a.uid.cmp(&b.uid)); |
| 1202 | |
| 1203 | if matches.len() == 1 { |
| 1204 | let summary = matches[0]; |
| 1205 | return Ok(if summary.human_key.is_empty() { |
| 1206 | summary.uid.clone() |
| 1207 | } else { |
| 1208 | summary.human_key.clone() |
| 1209 | }); |
| 1210 | } |
| 1211 | if matches.len() > 1 { |
| 1212 | return Err(RepositoryError::AmbiguousIntent { |
| 1213 | prefix: id.to_string(), |
| 1214 | matches: matches |
| 1215 | .into_iter() |
| 1216 | .map(|summary| summary.uid.clone()) |
| 1217 | .collect(), |
| 1218 | }); |