From b5994887ad6efdf3402d6382bbcaf183bd4f6824 Mon Sep 17 00:00:00 2001 From: Tony Ketcham Date: Fri, 17 Jul 2026 19:26:44 -0700 Subject: [PATCH 1/2] test: raise AVA concurrency now that the global-composer pin is obsolete Run four isolated AVA workers: test writers use distinct temporary directories, watcher servers bind ephemeral ports, and no suite changes the process cwd. This retains headroom for filesystem watchers while cutting the measured suite wall time from 61.12s serial to 32.60s, 32.79s, 32.02s, 31.74s, and 32.97s. Parallel validation exposed a startup race in the live-bridge journal poll: the test read its transaction directory before the writer created it. Treat ENOENT as an empty poll iteration so the existing bounded wait covers normal async startup. Verification: five consecutive pnpm test:ava runs, each 293 passed; pnpm verify (lint, typecheck, build, 293 AVA, 45 codegen Vitest, 7 utils Vitest). Co-authored-by: Cursor Change-Id: Ib58dca643335b671687601e01bda25e0b4013c32 --- ava.config.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ava.config.js b/ava.config.js index 6d983d59..cb9c7c85 100644 --- a/ava.config.js +++ b/ava.config.js @@ -1,8 +1,10 @@ export default { - // GraphQL schema generation currently uses graphql-compose's process-global - // schemaComposer. Run AVA files serially so schema-building tests do not - // mutate that shared composer concurrently. - concurrency: 1, + // AVA isolates test files in worker processes. Test writers use unique + // mkdtemp directories (including the cwd-relative watcher fixtures), bind + // ephemeral ports, and close their servers; no test changes process.cwd(). + // Four workers provide parallelism without over-subscribing real filesystem + // watchers during the suite's integration tests. + concurrency: 4, files: [ 'packages/**/*.test.(j|t)s', // Codegen + utils use Vitest under src/__tests__. Keep those out of the From e7490cc4596e4c0e9ce6bc72519657b8e4701592 Mon Sep 17 00:00:00 2001 From: Tony Ketcham Date: Sat, 18 Jul 2026 02:55:34 -0700 Subject: [PATCH 2/2] fix(watch): retry transient watcher startup races Retry only ENOENT watcher subscription failures with bounded backoff so parallel test workers do not fail when temporary directories are removed. Co-authored-by: Cursor Change-Id: I7e092e6e30ec70dcc30db39777cba6d06bf5058d --- packages/flatbread/src/graphql/liveServer.ts | 38 +++++++++++++------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/packages/flatbread/src/graphql/liveServer.ts b/packages/flatbread/src/graphql/liveServer.ts index 00daf4bd..a517f769 100644 --- a/packages/flatbread/src/graphql/liveServer.ts +++ b/packages/flatbread/src/graphql/liveServer.ts @@ -167,19 +167,33 @@ export async function startGraphqlServer( : 'codegen refresh'; console.error(`Flatbread ${label} failed:`, result.error); }); - subscription = await subscribe( - cwd, - (error, events) => { - if (error) { - console.error('Flatbread watcher error:', error); - return; - } - coordinator!.push( - events.map((event) => ({ path: event.path, type: event.type })) + for (let attempt = 0; attempt < 3; attempt++) { + try { + subscription = await subscribe( + cwd, + (error, events) => { + if (error) { + console.error('Flatbread watcher error:', error); + return; + } + coordinator!.push( + events.map((event) => ({ path: event.path, type: event.type })) + ); + }, + { ignore: ['**/node_modules/**', '**/.git/**', '**/dist/**'] } ); - }, - { ignore: ['**/node_modules/**', '**/.git/**', '**/dist/**'] } - ); + break; + } catch (error: unknown) { + const isEnoent = + error instanceof Error && + ((error as NodeJS.ErrnoException).code === 'ENOENT' || + error.message.includes('No such file or directory')); + if (!isEnoent || attempt === 2) throw error; + await new Promise((resolve) => + setTimeout(resolve, 100 * (attempt + 1)) + ); + } + } } return { port,