From 7758814b43f1ccf2f2da01e0f5086caecf2df697 Mon Sep 17 00:00:00 2001 From: kjgbot Date: Sat, 5 Sep 2026 21:26:49 +0200 Subject: [PATCH] test(sdk): capture the child stderr these tests deliberately provoke #156 reported an intermittent `ENOENT ... .relayflow/backlog-picker-entry .json` and read it as a flake caused by a relative path racing under vitest parallelism. I could not reproduce a failure, and the stated cause does not hold: every caller of the flow's steps already runs in its own `mkdtempSync` directory with an explicit `cwd`. What is actually happening is simpler and does not fail anything. Several tests here assert a step FAILS -- `select-entry` refusing an unactionable backlog, `emit-package` with no entry to read. `execFileSync` echoes a failing child's stderr into the parent's, so a completely green run prints a full ENOENT stack trace and looks broken. Measured over six consecutive full suites on main before changing anything: 662 passed, 3 skipped, every time -- and the ENOENT text present every time. Never a failure, always the noise. So the defect is the noise, because it is what got misdiagnosed. Child stderr is now captured rather than echoed. It remains on the thrown error for any test that wants to assert on it. with the change, three consecutive runs: Tests 662 passed | 3 skipped (665) | ENOENT lines: 0 Tests 662 passed | 3 skipped (665) | ENOENT lines: 0 Tests 662 passed | 3 skipped (665) | ENOENT lines: 0 with the `stdio` line reverted: Tests 662 passed | 3 skipped (665) | ENOENT lines: 2 Tests pass either way, which is exactly why this was read as a flake: the only signal was output that looked like a failure and was not. I have NOT closed #156 as invalid. Its first run genuinely showed `Test Files 1 failed`, so something failed then; the suite has changed substantially since (#153 widened it from four files to all of them, and several fixes have landed). I cannot reproduce it, and I would rather leave that stated than declare a bug I never saw to be absent. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01FtQSAcGDta5VH9xiZFT4sR Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1 --- sdk/tests/backlog-picker-flow.test.ts | 7 +++++++ sdk/tests/work-package-consumer.test.ts | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/sdk/tests/backlog-picker-flow.test.ts b/sdk/tests/backlog-picker-flow.test.ts index af7ead69..0b938437 100644 --- a/sdk/tests/backlog-picker-flow.test.ts +++ b/sdk/tests/backlog-picker-flow.test.ts @@ -29,6 +29,13 @@ function run(command: string, cwd: string): string { return execFileSync('sh', ['-c', command], { cwd, encoding: 'utf8', + stdio: ['ignore', 'pipe', 'pipe'], + // Capture stderr instead of letting it through to ours. Several tests here + // assert that a step FAILS, and `execFileSync` otherwise echoes the child's + // stack trace into the suite's output -- so a passing run prints + // `ENOENT ... .relayflow/backlog-picker-entry.json` and looks broken. + // #156 was filed on exactly that appearance. The text is still available on + // the thrown error for a test that wants to assert on it. env: { ...process.env, RELAYFLOWS_SDK_DIST: join(__dirname, '..', 'dist') }, }); } diff --git a/sdk/tests/work-package-consumer.test.ts b/sdk/tests/work-package-consumer.test.ts index 46781a0b..aae51acf 100644 --- a/sdk/tests/work-package-consumer.test.ts +++ b/sdk/tests/work-package-consumer.test.ts @@ -77,7 +77,8 @@ describe('the Garden join: picker output feeds the consumer', () => { const flowPath = join(__dirname, '..', '..', 'testdata', 'backlog-picker.flow.yaml'); const flow = load(readFileSync(flowPath, 'utf8')) as { steps: Array<{ id: string; command: string }> }; const step = (id: string) => flow.steps.find((s) => s.id === id)!.command; - const run = (cmd: string, cwd: string) => execFileSync('sh', ['-c', cmd], { cwd, encoding: 'utf8', env: { ...process.env, RELAYFLOWS_SDK_DIST: join(__dirname, '..', 'dist') }, }); + // stdio: stderr captured, not echoed -- see backlog-picker-flow.test.ts. + const run = (cmd: string, cwd: string) => execFileSync('sh', ['-c', cmd], { cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], env: { ...process.env, RELAYFLOWS_SDK_DIST: join(__dirname, '..', 'dist') }, }); const dir = mkdtempSync(join(tmpdir(), 'garden-join-')); try {