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)
| 975 | /// produces a `HumanKey` for `::`-separated or all-digit input, so anything |
| 976 | /// else — including `PIMO-1` — arrives here classified as a ULID. |
| 977 | fn normalize_intent_id(&self, id: &str) -> Result<String, RepositoryError> { |
| 978 | use atomic_core::pristine::vault::{parse_intent_reference, IntentRef}; |
| 979 | |
| 980 | let manifest = self.vault_manifest()?; |
| 981 | let project = manifest.project_code().to_string(); |
| 982 | let author = slug_author(&self.resolve_vault_identity().name); |
| 983 | |
| 984 | match parse_intent_reference(id, &project, &author) { |
| 985 | IntentRef::HumanKey(key) => { |
| 986 | // Exact manifest key, or a case-insensitive / legacy match. |
| 987 | if manifest.intents.contains_key(&key) { |
| 988 | return Ok(key); |
| 989 | } |
| 990 | if let Some(k) = manifest |
| 991 | .intents |
| 992 | .keys() |
| 993 | .find(|k| k.eq_ignore_ascii_case(&key) || k.eq_ignore_ascii_case(id)) |
| 994 | { |
| 995 | return Ok(k.clone()); |
| 996 | } |
| 997 | // No entry yet (e.g. freshly composed key): return the composed |
| 998 | // form so callers can still address it. |
| 999 | Ok(key) |
| 1000 | } |
| 1001 | IntentRef::Uid(uid) => { |
| 1002 | // Prefer an exact UID. A prefix is accepted only when it |
| 1003 | // identifies exactly one intent. |
| 1004 | let mut matches: Vec<_> = manifest |
| 1005 | .intents |
| 1006 | .values() |
| 1007 | .filter(|summary| summary.uid.eq_ignore_ascii_case(&uid)) |
| 1008 | .collect(); |
| 1009 | if matches.is_empty() { |
| 1010 | let prefix = uid.to_ascii_uppercase(); |
| 1011 | matches = manifest |
| 1012 | .intents |
| 1013 | .values() |
| 1014 | .filter(|summary| summary.uid.to_ascii_uppercase().starts_with(&prefix)) |
| 1015 | .collect(); |
| 1016 | } |
| 1017 | matches.sort_by(|a, b| a.uid.cmp(&b.uid)); |
| 1018 | |
| 1019 | if matches.len() == 1 { |
| 1020 | let summary = matches[0]; |
| 1021 | return Ok(if summary.human_key.is_empty() { |
| 1022 | summary.uid.clone() |
| 1023 | } else { |
| 1024 | summary.human_key.clone() |
| 1025 | }); |
| 1026 | } |
| 1027 | if matches.len() > 1 { |
| 1028 | return Err(RepositoryError::AmbiguousIntent { |
| 1029 | prefix: id.to_string(), |
| 1030 | matches: matches |
| 1031 | .into_iter() |
| 1032 | .map(|summary| summary.uid.clone()) |
| 1033 | .collect(), |
| 1034 | }); |