Concurrent or repeated move requests for the same model raced each other:
the first move succeeded, the rest failed with FileNotFoundError, leaving
the model card pointing at stale/empty paths.
- Serialize moves per source file with an asyncio.Lock keyed on the
normalized source path
- When the source file is already gone, reconcile instead of failing:
locate the model via the hash index or the expected target paths, repair
the metadata sidecar and cache entry, and reuse the stale cache entry
when no sidecar exists at the new location
- Avoid duplicate cache entries when the cache already tracks the moved
file; only drop the stale source entry
- Move via business paths (abspath) instead of realpath, matching every
other file mutation and the containment check; realpath stays reserved
for scanner dedup per project convention