Wall of the pi TUI bring-up (gate 3, tracker #6564). On first run pi downloads the fd tool via node-fetch, whose writeToStream does:
pipeline = promisify(Stream3.pipeline); // bundle line 67176
...
await pipeline(body, dest); // bundle line 67372
Under perry this throws TypeError: The "streams" argument must be specified (Node's ERR_MISSING_ARGS), thrown when stream.pipeline receives zero streams. Caught once ("Failed to download fd"), then a second occurrence is UNCAUGHT and crashes pi. Node completes the download fine.
So promisify(stream.pipeline)(body, dest) reaches perry's stream.pipeline with no/undefined stream args. Two hypotheses to check:
- promisify.custom not honored: Node defines
stream.pipeline[util.promisify.custom] (the real promise impl from stream/promises). If perry's promisify ignores that symbol, it falls back to generic promisify; verify perry's generic promisify of a variadic (...streams, callback) function forwards all leading args (a common bug is capturing only fixed params and dropping the rest before the appended callback).
- pipeline variadic arg collection: perry's
stream.pipeline may mis-collect its arguments/rest when the last arg is a callback appended by promisify.
Repro (minimal): const {promisify}=require('util'); const {pipeline}=require('stream'); const {Readable,Writable}=require('stream'); const p=promisify(pipeline); await p(Readable.from(['a','b']), new Writable({write(c,e,cb){cb()}})); — diff perry vs node v26.3.0 (node: resolves; perry: ERR_MISSING_ARGS). Also test stream/promises pipeline directly (bundle also imports it) and promisify(pipeline) with a transform in the middle.
Real parity bug (promisify + variadic + promisify.custom), matters well beyond pi. Peripheral to TUI rendering but blocks first-run. Repro binary: secret-tests/pi-target/dist/pi-native; PTY harness scratchpad/pty_cap.py.
Wall of the pi TUI bring-up (gate 3, tracker #6564). On first run pi downloads the
fdtool via node-fetch, whosewriteToStreamdoes:Under perry this throws
TypeError: The "streams" argument must be specified(Node'sERR_MISSING_ARGS), thrown whenstream.pipelinereceives zero streams. Caught once ("Failed to download fd"), then a second occurrence is UNCAUGHT and crashes pi. Node completes the download fine.So
promisify(stream.pipeline)(body, dest)reaches perry'sstream.pipelinewith no/undefined stream args. Two hypotheses to check:stream.pipeline[util.promisify.custom](the real promise impl fromstream/promises). If perry'spromisifyignores that symbol, it falls back to generic promisify; verify perry's generic promisify of a variadic(...streams, callback)function forwards all leading args (a common bug is capturing only fixed params and dropping the rest before the appended callback).stream.pipelinemay mis-collect itsarguments/rest when the last arg is a callback appended by promisify.Repro (minimal):
const {promisify}=require('util'); const {pipeline}=require('stream'); const {Readable,Writable}=require('stream'); const p=promisify(pipeline); await p(Readable.from(['a','b']), new Writable({write(c,e,cb){cb()}}));— diff perry vs node v26.3.0 (node: resolves; perry: ERR_MISSING_ARGS). Also teststream/promisespipelinedirectly (bundle also imports it) andpromisify(pipeline)with a transform in the middle.Real parity bug (promisify + variadic + promisify.custom), matters well beyond pi. Peripheral to TUI rendering but blocks first-run. Repro binary:
secret-tests/pi-target/dist/pi-native; PTY harnessscratchpad/pty_cap.py.