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)
| 848 | /// produces a `HumanKey` for `::`-separated or all-digit input, so anything |
| 849 | /// else — including `PIMO-1` — arrives here classified as a ULID. |
| 850 | fn normalize_intent_id(&self, id: &str) -> Result<String, RepositoryError> { |
| 851 | use atomic_core::pristine::vault::{parse_intent_reference, IntentRef}; |
| 852 | |
| 853 | let manifest = self.vault_manifest()?; |
| 854 | let project = manifest.project_code().to_string(); |
| 855 | let author = slug_author(&self.resolve_vault_identity().name); |
| 856 | |
| 857 | match parse_intent_reference(id, &project, &author) { |
| 858 | IntentRef::HumanKey(key) => { |
| 859 | // Exact manifest key, or a case-insensitive / legacy match. |
| 860 | if manifest.intents.contains_key(&key) { |
| 861 | return Ok(key); |
| 862 | } |
| 863 | if let Some(k) = manifest |
| 864 | .intents |
| 865 | .keys() |
| 866 | .find(|k| k.eq_ignore_ascii_case(&key) || k.eq_ignore_ascii_case(id)) |
| 867 | { |
| 868 | return Ok(k.clone()); |
| 869 | } |
| 870 | // No entry yet (e.g. freshly composed key): return the composed |
| 871 | // form so callers can still address it. |
| 872 | Ok(key) |
| 873 | } |
| 874 | IntentRef::Uid(uid) => { |
| 875 | // Prefer an exact UID. A prefix is accepted only when it |
| 876 | // identifies exactly one intent. |
| 877 | let mut matches: Vec<_> = manifest |
| 878 | .intents |
| 879 | .values() |
| 880 | .filter(|summary| summary.uid.eq_ignore_ascii_case(&uid)) |
| 881 | .collect(); |
| 882 | if matches.is_empty() { |
| 883 | let prefix = uid.to_ascii_uppercase(); |
| 884 | matches = manifest |
| 885 | .intents |
| 886 | .values() |
| 887 | .filter(|summary| summary.uid.to_ascii_uppercase().starts_with(&prefix)) |
| 888 | .collect(); |
| 889 | } |
| 890 | matches.sort_by(|a, b| a.uid.cmp(&b.uid)); |
| 891 | |
| 892 | if matches.len() == 1 { |
| 893 | let summary = matches[0]; |
| 894 | return Ok(if summary.human_key.is_empty() { |
| 895 | summary.uid.clone() |
| 896 | } else { |
| 897 | summary.human_key.clone() |
| 898 | }); |
| 899 | } |
| 900 | if matches.len() > 1 { |
| 901 | return Err(RepositoryError::AmbiguousIntent { |
| 902 | prefix: id.to_string(), |
| 903 | matches: matches |
| 904 | .into_iter() |
| 905 | .map(|summary| summary.uid.clone()) |
| 906 | .collect(), |
| 907 | }); |