jiarung 9944231ff4 fix(file-lock,git-hooks): PID reuse detection, null-payload race, prerelease sort
Three independent fixes bundled here because they came from the same
review pass.

── 1. Record lock owner identity beyond PID (file-lock) ──────────────

Stale-lock detection used only isPidAlive(), but PIDs are reusable.
On systems with small PID namespaces (containers, rapid restarts) a
crashed writer's PID can be reassigned to an unrelated live process,
causing isStaleLock to return false and the lock to appear held
indefinitely.

Fix: record the process start time (field 22 from /proc/{pid}/stat)
alongside pid and createdAt.  On Linux, if the current holder's
startTime differs from the stored value the PID was recycled and the
lock is reclaimed immediately.  On other platforms startTime is omitted
and the existing createdAt age-check (a reused PID inherits the old
timestamp, exceeding staleMs) remains as the fallback.

── 2. Restore mtime fallback for null/unparseable payloads (file-lock) ─

The previous fix treated null payload as immediately stale.  But the
lock file is created (empty) by open('wx') before writeFile fills in
the JSON.  A live writer still in that window has an empty file; marking
it stale immediately allows a second process to steal the lock and both
to enter fn() concurrently.

Fix: when payload is null, fall back to the file's mtime.  A file
younger than staleMs may belong to a live writer and is left alone; a
file older than staleMs was definitely orphaned and is reclaimed.  A
new test asserts that a freshly-created empty lock (recent mtime) is NOT
treated as stale.

── 3. Strip prerelease suffix before printf '%05d' (resolve-node.sh) ──

When an nvm install has a prerelease directory name (e.g.
v22.0.0-rc.1/bin/node), splitting on '.' leaves _pa as '0-rc.1'.
printf '%05d' then fails because '0-rc.1' is not an integer, and
set -euo pipefail aborts the hook before lint/format can run — the
opposite of what the nvm fallback is meant to achieve.

Fix: strip the longest non-digit suffix from each component before
printf: '0-rc.1' → '0', '14' → '14' (no-op for normal releases).
Uses POSIX parameter expansion  so it works on both
GNU bash and macOS bash 3.x.
2026-03-15 07:46:31 +00:00
..