mirror of
https://github.com/Jeuners/ECC.git
synced 2026-09-09 15:02:30 +02:00
PR #1983 round 1 introduced unique-suffix tmp paths so two concurrent writers no longer share a single `.tmp` file. That fix is correct under POSIX semantics — `rename(2)` is atomic between source and destination, so each writer renames onto the same target without conflict. Windows `MoveFileExW` is not the same. It fails with EPERM / EACCES / EBUSY when the target is currently being renamed by *another* process — a short race window that fires reliably under this hook's PostToolUse + statusline concurrency. Round 1's CI run made this visible: Test (windows-latest, Node 18.x, npm) — FAILURE Error: EPERM: operation not permitted, rename 'C:\…\ecc-metrics-test-bridge-race-….json.9504.4aef575a.tmp' -> 'C:\…\ecc-metrics-test-bridge-race-….json' at writeBridgeAtomic (scripts/lib/session-bridge.js:79:8) All nine Windows matrix cells (Node 18 / 20 / 22 × npm / pnpm / yarn) hit the same path. POSIX matrices (Linux + macOS) passed unchanged. Fix: extract a `renameWithRetry(tmp, target)` helper that retries `fs.renameSync` up to 5 times on EPERM / EACCES / EBUSY with exponential backoff (20 ms → 320 ms total). Other error codes (ENOENT, ENOSPC, EROFS, …) re-throw on the first attempt — they are not transient. POSIX runs hit the first try and exit immediately. The backoff uses `Atomics.wait` on a throwaway `SharedArrayBuffer` so the retry path does not busy-spin the CPU; verified on Node ≥ 17 that this works on the main thread. There is a `try/catch` fallback to a brief busy-wait for older runtimes where `Atomics.wait` is restricted to workers. `writeBridgeAtomic` calls the helper instead of `fs.renameSync` and keeps its existing best-effort tmp cleanup on terminal failure. `renameWithRetry` is added to `module.exports` so the companion `writeWarnState` in `scripts/hooks/ecc-context-monitor.js` can adopt the same retry policy without duplicating the helper. That adoption lands in the next commit. Local: `node tests/lib/session-bridge.test.js` 14/14, `yarn test` green, `yarn lint` clean. The round-1 test (two concurrent child writers, 200 iterations each) now passes on macOS without retrying at all (POSIX path) and is expected to pass on Windows via the new retry loop. |
||
|---|---|---|
| .. | ||
| install | ||
| install-targets | ||
| session-adapters | ||
| skill-evolution | ||
| skill-improvement | ||
| state-store | ||
| agent-compress.js | ||
| cost-estimate.js | ||
| cursor-agent-names.js | ||
| ecc_dashboard_runtime.py | ||
| github-discussions.js | ||
| harness-adapter-compliance.js | ||
| hook-flags.js | ||
| inspection.js | ||
| install-executor.js | ||
| install-lifecycle.js | ||
| install-manifests.js | ||
| install-state.js | ||
| mcp-config.js | ||
| observer-sessions.js | ||
| orchestration-session.js | ||
| package-manager.d.ts | ||
| package-manager.js | ||
| project-detect.js | ||
| resolve-ecc-root.js | ||
| resolve-formatter.js | ||
| session-aliases.d.ts | ||
| session-aliases.js | ||
| session-bridge.js | ||
| session-manager.d.ts | ||
| session-manager.js | ||
| shell-split.js | ||
| shell-substitution.js | ||
| tmux-worktree-orchestrator.js | ||
| utils.d.ts | ||
| utils.js | ||