Follow-up to #66, #493 and #499. The unchanged pinned regression test/js/bun/spawn/spawn-pipe-stale-fd-unregister.test.ts fails in native Home with a five-second timeout. Extracting its exact fixture reveals panic: attempt to use null value during teardown after a registered stdout fd is deliberately closed and its number reused. This also reproduces before the #499 input changes. Installed Bun 1.3.14 fails this newer regression too (empty output instead of OK), so it is not a passing control.
The native FilePoll still feeds positive kevent error values through Maybe.errnoSys, which decodes a syscall return code, and then unwraps null. The selected current Bun Rust implementation has direct kevent_change_error decoding, preserves global syscall failures separately, and treats ENOENT/EBADF during deregistration as already removed so registration flags are cleared. Home's Linux/FreeBSD deregistration paths also need the corresponding already-removed handling.
Port the actual error conventions and flag cleanup; preserve the unchanged fixture's fd close/reuse, pending read, cancellation, child cleanup and OK/exit assertions. Verify repeated teardown and adjacent timer/spawn/watchers to catch stale registration or event-loop lifetime regressions. Darwin is locally executable; Linux/FreeBSD behavior needs its own validation and must not be counted as proven merely by compiling guarded code.
Source pin: 4982b91e3702094330f3be3883354c52b8c01323. This is distinct from Blob/stream input validation and rejected-payload cleanup in #499 and raw extra socket ownership in #495.