The rename path (write new path, then delete old path) is two separate, non-atomic API calls. If a prior partial run's write succeeded but the paired delete failed — plausible under the same infra#179 flakiness resume (#50) exists to work around — a resume would recompute the identical rename and blind-create (no sha) at a path that already exists, hitting a conflict and getting stuck needing another resume cycle just to re-report the same thing. renameEntry now reads the new path first: if it already holds the correct content (prior write succeeded), the write is skipped and only the outstanding delete of the old path runs; if the new path exists but differs, it's updated with the fetched sha instead of blind-created; if the old path is already gone by delete time, that's treated as done, not a failure. Mirrors injectDispatchAllow's (#51) read-before-write idempotency pattern. Test: TestCreateProject_Resume_StrayRenamedOldPath_CompletesCleanly — a stray old path plus an already-correct new path resolves to a single delete, zero redundant writes, no partial_failure. All prior create_project tests unaffected (backward compatible). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>