From 4bb56c2dc465c86fc8e3ef1ed6f8605984fc6367 Mon Sep 17 00:00:00 2001 From: jdalton Date: Sun, 19 Apr 2026 12:32:25 -0400 Subject: [PATCH] docs(claude): add Promise.race handler-stacking rule Documents the leak anti-pattern so future concurrency code in socket-cli does not reintroduce it. See nodejs/node#17469. Prompted by fixes in sibling repos (socket-sdk-js #600, socket-lib #184) where the pattern had crept in. --- CLAUDE.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CLAUDE.md b/CLAUDE.md index 098dec654..0ab0583ef 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -86,6 +86,7 @@ If user repeats instruction 2+ times, ask: "Should I add this to CLAUDE.md?" - Backward Compatibility: 🚨 FORBIDDEN to maintain — actively remove when encountered - Safe Deletion: Use `safeDelete()` from `@socketsecurity/lib/fs` (NEVER `fs.rm/rmSync` or `rm -rf`) - HTTP Requests: NEVER use `fetch()` — use `httpJson`/`httpText`/`httpRequest` from `@socketsecurity/lib/http-request` +- `Promise.race` / `Promise.any`: NEVER pass a long-lived promise (interrupt signal, pool member) into a race inside a loop. Each call re-attaches `.then` handlers to every arm; handlers accumulate on surviving promises until they settle. For concurrency limiters, use a single-waiter "slot available" signal (resolved by each task's `.then`) instead of re-racing `executing[]`. See nodejs/node#17469 and `@watchable/unpromise`. Race with two fresh arms (e.g. one-shot `withTimeout`) is safe. - File existence: ALWAYS `existsSync` from `node:fs`. NEVER `fs.access`, `fs.stat`-for-existence, or an async `fileExists` wrapper. Import: `import { existsSync, promises as fs } from 'node:fs'`. ### Documentation Policy