mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-09-30 12:39:42 +02:00
Second review round on the #241 follow-ups. Three defects in my own previous commit, each reproduced before and after. 1. The temp path was shared between runs (`${dest}.tmp`), so two concurrent runs fought over it: 4 of 4 concurrent pairs had one run die. Worse than a crash, a sibling's cleanup landing between the esbuild and the alias append makes `appendFileSync` CREATE the file, so the rename publishes a bundle-less file containing only the alias tail, which still satisfies the content check and would be blessed by the cache forever. The name now carries the owning pid. 8 concurrent pairs afterwards: no failures, no strays, aliases intact. 2. The content check only covered the bundle, so a truncated xterm.min.js with a fresh mtime stayed truncated. This script can no longer produce one, but postinstall.js writes the same directory in place, so a Ctrl+C during `npm install` does, and a 200-byte xterm.min.js means `Terminal` is undefined and every mobile test dies on a null. A copy must now match its source byte for byte, and a derived output must clear a floor far below the real ratios (measured 0.97-1.00 minified, 0.51 for the bundle) while a truncation misses by orders of magnitude. Verified: 200-byte and 50-byte poisonings both repaired. 3. The try block ended before the append and rename, so a rename failure leaked its temp behind a raw stack. It now covers both and reports which asset failed. Per-pid names mean a killed run's temp is never reclaimed by a later rebuild, so startup sweeps temps whose owning process is gone, and only those: `kill(pid, 0)` throwing ESRCH. Deleting a live run's temp would recreate the collision fix 1 removes. Verified both directions, plus SIGKILL mid-build leaving no litter. The sweep swallows its own errors, because reclaiming litter must never fail the run: a directory named like a dead temp otherwise crashed the whole prepare step. Security-reviewed: no shell (execFileSync with an array, `shell` unset), every argument from the static asset table plus a numeric pid, all writes confined to the vendor dir under strace, `process.kill` only ever with signal 0 (and pid 0 skipped, since to kill(2) it means this process group), no new dependencies, no network, no eval, nothing published. The emitted browser bundle is byte-identical to the one scripts/build.mjs ships, tail included. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>