Describe the bug
The lock-file subsystem (internal/platform/lock_unix.go, lock_windows.go, AcquireLock/Release) is fully implemented — flock on POSIX, LockFileEx on Windows, stale-PID detection — but has zero call sites anywhere in internal/cli, internal/config, internal/packages, or cmd/.
README states as fact: "Concurrent runs are blocked via a lock file at ~/.nodeup/nodeup.lock." This is currently false.
Concrete impact
- Two concurrent
nodeup upgrade invocations can snapshot/install/migrate at the same time with no protection whatsoever.
- Two concurrent
nodeup config set invocations race: each does an independent read-modify-write, and the second writer's atomic rename silently clobbers the first writer's change (a lost update, not a crash).
Suggested fix
Wire platform.AcquireLock()/Release() into runUpgrade (around the snapshot/install/migrate critical section) and into internal/config's Save() path (or at least config set/init). Also fix the incidental doc bug while here: README says the lock lives at ~/.nodeup/nodeup.lock; the real path is <DataDir>/nodeup.lock, which resolves to OS-specific XDG/AppData locations per CLAUDE.md's on-disk layout table, never literally ~/.nodeup/ on any of the three supported OSes.
Severity
High — advertised safety feature does not exist in the wired product.
Describe the bug
The lock-file subsystem (
internal/platform/lock_unix.go,lock_windows.go,AcquireLock/Release) is fully implemented — flock on POSIX,LockFileExon Windows, stale-PID detection — but has zero call sites anywhere ininternal/cli,internal/config,internal/packages, orcmd/.README states as fact: "Concurrent runs are blocked via a lock file at
~/.nodeup/nodeup.lock." This is currently false.Concrete impact
nodeup upgradeinvocations can snapshot/install/migrate at the same time with no protection whatsoever.nodeup config setinvocations race: each does an independent read-modify-write, and the second writer's atomic rename silently clobbers the first writer's change (a lost update, not a crash).Suggested fix
Wire
platform.AcquireLock()/Release()intorunUpgrade(around the snapshot/install/migrate critical section) and intointernal/config'sSave()path (or at leastconfig set/init). Also fix the incidental doc bug while here: README says the lock lives at~/.nodeup/nodeup.lock; the real path is<DataDir>/nodeup.lock, which resolves to OS-specific XDG/AppData locations per CLAUDE.md's on-disk layout table, never literally~/.nodeup/on any of the three supported OSes.Severity
High — advertised safety feature does not exist in the wired product.