fix: make upstream sync crash recoverable - #2
Conversation
Adversarial review (multi-agent, post-merge)Ran three independent adversarial reviews against cb771be — (1) concurrency/crash-recovery correctness, (2) security/input validation, (3) cross-platform + test quality — including live experiments: 8-way concurrent lock races on fresh/stale/stale+guard locks, ~40-payload path-validator fuzzing, NTFS junction escapes, a crafted-journal recovery tampering attempt, and crash simulations at each commit point. Bottom line: the transaction core holds up — mutual exclusion is airtight, readers never see a torn tree (the independent Findings1. [P1] Staleness is PID-liveness only; PID reuse wedges lock takeover and transaction recovery. 2. [P1] Crash in the commit window + external target drift = permanent wedge with circular advice. 3. [P2] Directory fsync is a silent no-op on Windows — durability is process-crash-grade only. 4. [P2] Lock-initializer scanner misclassifies takeover-guard temp files. 5. [P2] The lock provides no mutual exclusion across the Windows↔WSL boundary the PR claims to support. 6. [P2] Read-only commands now serialize on the exclusive lock. 7. [P3] Hardlink-based lock creation fails raw on filesystems without hardlinks. FAT32/exFAT/many SMB shares → every command, including 8. [P3] Recovery trusts the on-disk journal as authorization for deletes. Demonstrated end-to-end: a crafted journal ( 9. [P3] Minor: Suggested follow-ups
None of these lose data — every observed failure mode fails stop with state retained — but findings 1–2 make the "next |
Problem
scripts/sync-upstream.mjs --applypreviously wrote and removed managed files directly. A filesystem error or process crash could leave a partially refreshed checkout with an old manifest.Change
--applycheck-upstreamhold the same lock and refuse pending recovery stateThis provides mutual exclusion, rollback before returning an ordinary error, and recovery after hard exits. It does not claim instantaneous multi-file visibility for readers that ignore the lock.
Verification
npm teston Windows: 68 passed, 1 existing Unix-only skipnpm run check-packagegit diff --checkAgent: GPT-6 via Codex