@@ -3,6 +3,7 @@ use std::path::{Path, PathBuf};
33use serde:: { Deserialize , Serialize } ;
44use tracedecay_domain:: { BrainId , UserProfileId } ;
55use tracedecay_runtime_core:: errors:: { Result , TraceDecayError } ;
6+ use tracedecay_runtime_core:: path_safety:: canonicalize_existing_prefix;
67use tracedecay_runtime_core:: storage:: PROFILE_IDENTITY_FILENAME ;
78
89const PROFILE_IDENTITY_SCHEMA_VERSION : u32 = 1 ;
@@ -157,6 +158,15 @@ fn random_identity(prefix: &str) -> Result<String> {
157158 Ok ( format ! ( "{prefix}.{}" , hex:: encode( bytes) ) )
158159}
159160
161+ /// Absolutizes `path` and canonicalizes through its deepest existing
162+ /// ancestor.
163+ ///
164+ /// Known divergence, deliberately preserved: the daemon's identically-named
165+ /// resolver additionally applies
166+ /// [`tracedecay_runtime_core::path_safety::collapse_relative_components`] to
167+ /// the result. This one must not — the identity strings it produces are
168+ /// already written into migrated profile records, and collapsing `.`/`..`
169+ /// here would rewrite them. Only the canonicalization algorithm is shared.
160170fn canonical_identity_path ( path : & Path ) -> Result < PathBuf > {
161171 let absolute = if path. is_absolute ( ) {
162172 path. to_path_buf ( )
@@ -165,29 +175,9 @@ fn canonical_identity_path(path: &Path) -> Result<PathBuf> {
165175 . map_err ( |error| profile_identity_io ( "resolve" , path, & error) ) ?
166176 . join ( path)
167177 } ;
168- if let Ok ( canonical) = absolute. canonicalize ( ) {
169- return Ok ( canonical) ;
170- }
171- let mut suffix = Vec :: new ( ) ;
172- let mut existing = absolute. as_path ( ) ;
173- while !existing. exists ( ) {
174- let Some ( name) = existing. file_name ( ) else {
175- return Err ( TraceDecayError :: Config {
176- message : format ! ( "failed to resolve identity path '{}'" , path. display( ) ) ,
177- } ) ;
178- } ;
179- suffix. push ( name. to_os_string ( ) ) ;
180- existing = existing. parent ( ) . ok_or_else ( || TraceDecayError :: Config {
181- message : format ! ( "failed to resolve identity path '{}'" , path. display( ) ) ,
182- } ) ?;
183- }
184- let mut canonical = existing
185- . canonicalize ( )
186- . map_err ( |error| profile_identity_io ( "canonicalize" , existing, & error) ) ?;
187- for component in suffix. iter ( ) . rev ( ) {
188- canonical. push ( component) ;
189- }
190- Ok ( canonical)
178+ canonicalize_existing_prefix ( & absolute) . ok_or_else ( || TraceDecayError :: Config {
179+ message : format ! ( "failed to resolve identity path '{}'" , path. display( ) ) ,
180+ } )
191181}
192182
193183fn invalid_identity ( path : & Path , field : & str , error : impl std:: fmt:: Display ) -> TraceDecayError {
0 commit comments