Conversation
…rt pattern Captures the substrate finding from PR #901 (slice 18 daily-cost-report) Copilot P1 round 2 catch as durable memory. Per Otto-363 substrate-or-it-didn't-happen: this pattern was only living in commit messages and review threads — now indexed + reachable via memory/. Rule: when porting bash `$(... 2>&1)` to spawnSync, merge stdout+stderr at the kernel pipe boundary via `/bin/bash -c "<cmd> 2>&1"`, NOT in JS-space via `result.stdout + result.stderr` concat. Why: kernel pipe preserves the child's chronological write ordering across both streams. JS-space concat glues two pre-segregated buffers in a fixed order, losing the original interleaving. How to apply: documented in the memory file with edge cases (shell-parse-error stacking, defensive `?? ""`, `/bin/bash` over `/bin/sh` for bash-only features). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds a durable memory entry documenting a TS+Bun porting pitfall: preserving mixed stdout/stderr chronological ordering when translating bash $(... 2>&1) to spawnSync.
Changes:
- Added a new
memory/feedback_*.mdwrite-up explaining kernel-pipe (2>&1) vs JS-spacestdout+stderrconcatenation ordering differences. - Added a new top-level index entry in
memory/MEMORY.mdpointing to the new memory file.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| memory/feedback_kernel_pipe_vs_js_space_stream_ordering_ts_bun_port_pattern_2026_04_30.md | New memory capturing the porting pattern + rationale and examples. |
| memory/MEMORY.md | Adds an index bullet linking to the new memory file. |
|
|
||
| **📌 Fast path: read `CURRENT-aaron.md` and `CURRENT-amara.md` first.** <!-- latest-paired-edit: fork-audit R/C/T diff-filter coverage + plumbing-vs-porcelain note (2026-04-29 round-10 Amara). NOTE: this comment is a single-slot "latest paired edit" marker (not a paired-edit log). Per the round-10 Amara framing the slot semantics are now explicit. --> | ||
|
|
||
| - [**Kernel-pipe vs JS-space stream ordering — TS+Bun port pattern (Otto, 2026-04-30)**](feedback_kernel_pipe_vs_js_space_stream_ordering_ts_bun_port_pattern_2026_04_30.md) — TS+Bun port discipline: when porting bash `$(... 2>&1)` to `spawnSync`, merge stdout+stderr via shell-side `bash -c "<cmd> 2>&1"` (preserves chronological ordering at the kernel pipe boundary), NOT `result.stdout + result.stderr` concat in JS-space (loses ordering when child interleaves writes). Origin: PR #901 slice-18 Copilot P1 round 2. Composes with `classifySpawnFailure` 4-case helper + Otto-363 substrate-or-it-didn't-happen. |
There was a problem hiding this comment.
P1: This new MEMORY.md index entry is far longer than the repo’s documented “keep entries terse / ~200 chars” guidance, which makes the index harder to scan and increases the risk of truncation issues. Consider shortening this bullet to a title + very short hook and move the detailed rationale into the linked memory file body (which already contains it).
| - [**Kernel-pipe vs JS-space stream ordering — TS+Bun port pattern (Otto, 2026-04-30)**](feedback_kernel_pipe_vs_js_space_stream_ordering_ts_bun_port_pattern_2026_04_30.md) — TS+Bun port discipline: when porting bash `$(... 2>&1)` to `spawnSync`, merge stdout+stderr via shell-side `bash -c "<cmd> 2>&1"` (preserves chronological ordering at the kernel pipe boundary), NOT `result.stdout + result.stderr` concat in JS-space (loses ordering when child interleaves writes). Origin: PR #901 slice-18 Copilot P1 round 2. Composes with `classifySpawnFailure` 4-case helper + Otto-363 substrate-or-it-didn't-happen. | |
| - [**Kernel-pipe vs JS-space stream ordering — TS+Bun port pattern (Otto, 2026-04-30)**](feedback_kernel_pipe_vs_js_space_stream_ordering_ts_bun_port_pattern_2026_04_30.md) — Port bash `2>&1` to shell-side stderr/stdout merge in `spawnSync`; never concat `stdout` + `stderr` in JS. |
| @@ -0,0 +1,76 @@ | |||
| --- | |||
| name: kernel-pipe vs JS-space stream ordering — TS+Bun port pattern (2026-04-30) | |||
| description: When porting bash command-substitution with `2>&1` to TypeScript via `spawnSync`, must merge stdout+stderr at the kernel pipe boundary (shell-side `2>&1`), NOT in JS-space by concatenating `result.stdout + result.stderr` — JS-space concat loses chronological ordering when child interleaves stdout/stderr writes. | |||
There was a problem hiding this comment.
P1: The frontmatter description reads like an absolute “never concat stdout+stderr in JS-space”, but the body later calls out cases where appending result.stderr is necessary to surface shell-side parse errors. Consider tightening the wording here to clarify the rule is about preserving child stdout/stderr interleaving (kernel-pipe 2>&1) while optionally appending result.stderr for shell diagnostics when relevant.
| description: When porting bash command-substitution with `2>&1` to TypeScript via `spawnSync`, must merge stdout+stderr at the kernel pipe boundary (shell-side `2>&1`), NOT in JS-space by concatenating `result.stdout + result.stderr` — JS-space concat loses chronological ordering when child interleaves stdout/stderr writes. | |
| description: When porting bash command-substitution with `2>&1` to TypeScript via `spawnSync`, preserve child stdout/stderr interleaving by merging at the kernel pipe boundary (shell-side `2>&1`), not by reconstructing child output as `result.stdout + result.stderr` in JS-space; append `result.stderr` separately only when shell-side diagnostics such as parse errors must also be surfaced. |
| const result = spawnSync("/bin/bash", ["-c", `"${path}" 2>&1`], { | ||
| encoding: "utf8", | ||
| stdio: ["inherit", "pipe", "pipe"], | ||
| }); |
There was a problem hiding this comment.
P1: The example interpolates path directly into the bash -c command string. Even if callers usually pass trusted paths, this pattern is easy to cargo-cult into contexts where the value is user-influenced, creating quoting/injection risk. Consider documenting the safer pattern of passing the path as a positional parameter to bash -c (so quoting is handled without string interpolation) and note that interpolation is only acceptable when the value is fully trusted/constructed.
Summary
bash -c \"<cmd> 2>&1\"(preserves chronological ordering) vs JS-spaceresult.stdout + result.stderrconcat (loses ordering)Test plan
lint (markdownlint)passeslint (no conflict markers)passes🤖 Generated with Claude Code