The normalized intent id used to key BOTH the tracked vault attestation path and the legacy `.atomic` sidecar dir, so the dual-read fallback lines up (critic #4). Resolution mirrors the repository's private `normalize_intent_id` closely enough that `attest 1`, `attest pimo-1`, and `attest PIMO-1` all collapse to the SAME ` ` on both the tracked and the legacy paths: 1. A case-insensitiv
(repo: &Repository, id: &str)
| 115 | /// manifest stay as the bare number — the same on both paths, so reconciliation |
| 116 | /// still holds). |
| 117 | pub fn normalized_id(repo: &Repository, id: &str) -> CliResult<String> { |
| 118 | // Resolution lives in exactly one place — the repository resolver — which |
| 119 | // fills in the current project + author for a bare number, matches full |
| 120 | // human keys, and resolves ULIDs/prefixes. When nothing resolves (e.g. a |
| 121 | // reference to an intent with no manifest entry yet), fall back to the |
| 122 | // uppercased raw arg so `attest` still produces a deterministic sidecar id. |
| 123 | match repo.resolve_intent_key(id) { |
| 124 | Ok(key) => Ok(key), |
| 125 | Err(_) => Ok(id.to_uppercase()), |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | /// The tracked-vault path for an intent's attestation: |
| 130 | /// `attestations/<sanitized-normalized-id>/attested.md`. |