From 95e8b71d03f9ba1f5770ab1b0255673ba28a0679 Mon Sep 17 00:00:00 2001 From: Michael Suchacz <203725896+ibetitsmike@users.noreply.github.com> Date: Mon, 10 Aug 2026 11:37:59 +0200 Subject: [PATCH] fix(coderd): start test AI bridge after config in automatic title tests (#27971) Fixes the reopened flake tracked in CODAGT-876 / coder/internal#1629. ## Problem The Aug 10 recurrence was not the previously fixed subtests failing again: the nightly-gauntlet macos run ([job log](https://github.com/coder/coder/actions/runs/31355808516/job/93355150162)) flaked in the sibling test `TestPostChats_AutomaticTitleGenerationPasteOnly`, which the flake investigator matched to the existing issue. Both `TestPostChats_AutomaticTitleGeneration*` tests still used `newChatClientWithAPI`, which starts the in-process AI Gateway daemon before the test creates its provider/model config. The daemon's synchronous initial provider load therefore sees zero providers, and route availability depends on the asynchronous pubsub-driven reload racing the one-shot automatic title generation that `CreateChat` kicks off. When the reload loses (initial load at `.575` with `provider_count=0`, title request at `.907` hitting `route not supported`, reload landing at `1.029`), the title candidate fails without retry and the test times out waiting for the `propose_title` request. ## Fix Convert both tests to the pattern #27564 established for the `TestRegenerateChatTitle`/`TestProposeChatTitle` subtests: `newChatClientWithoutAIBridge`, create the model config, then `aibridgedtest.StartTestAIBridgeDaemon`, so the daemon's synchronous initial load already contains the route. The existing `NoPubsubDelivery` subtest guards that initial-load invariant, so no new guard test is added. ## Validation - Deterministic red-green via the isolated-pubsub technique: old ordering with the pubsub leg removed reproduces the exact CI signature (`provider_count=0`, `route not supported`, timeout at the `titleRequested` wait); the new ordering passes with the pubsub leg still removed, proving the synchronous initial load alone provides the route. - `go test ./coderd -run 'TestPostChats_AutomaticTitleGeneration' -count=10` - `go test ./coderd -run 'TestRegenerateChatTitle|TestProposeChatTitle' -count=1` - `make lint` and `make pre-commit` via hooks. > Opened by Mux on Mike's behalf. --- coderd/exp_chats_test.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/coderd/exp_chats_test.go b/coderd/exp_chats_test.go index 21afca9210..4b6fac6010 100644 --- a/coderd/exp_chats_test.go +++ b/coderd/exp_chats_test.go @@ -9914,9 +9914,10 @@ func TestPostChats_AutomaticTitleGeneration(t *testing.T) { return chattest.OpenAINonStreamingResponse(`{"title": "Generated Title"}`) }) - client, api := newChatClientWithAPI(t) + client, _, api := newChatClientWithoutAIBridge(t) firstUser := coderdtest.CreateFirstUser(t, client.Client) _ = createChatModelConfigWithBaseURL(t, client, baseURL) + aibridgedtest.StartTestAIBridgeDaemon(t.Context(), t, api, nil) chat, err := client.CreateChat(ctx, codersdk.CreateChatRequest{ OrganizationID: firstUser.OrganizationID, @@ -9969,9 +9970,10 @@ func TestPostChats_AutomaticTitleGenerationPasteOnly(t *testing.T) { return chattest.OpenAINonStreamingResponse(`{"title": "Generated Title"}`) }) - client, api := newChatClientWithAPI(t) + client, _, api := newChatClientWithoutAIBridge(t) firstUser := coderdtest.CreateFirstUser(t, client.Client) _ = createChatModelConfigWithBaseURL(t, client, baseURL) + aibridgedtest.StartTestAIBridgeDaemon(t.Context(), t, api, nil) uploadResp, err := client.UploadChatFile( ctx,