Skip to content

fix(release): drain base-reds r7 of v3.8.51 — connection-test operator-disable race, two vitest teardown leaks - #15130

Merged
diegosouzapw merged 3 commits into
release/v3.8.51from
fix/release-v3.8.51-basereds-r7
Sep 29, 2026
Merged

diegosouzapw merged 3 commits into
release/v3.8.51from
fix/release-v3.8.51-basereds-r7

Conversation

@diegosouzapw

Copy link
Copy Markdown
Owner

Drains two reds from the release PR #11442 CI (run 36601097731, head fc8e91b).

1. Unit Tests (6/8): connection-test-respects-operator-disable (2 tests)

Cause — a real production race, not DNS. testSingleConnection() reads the connection (cached) before the probe and decided whether to activate on that snapshot after the probe returned. POST /api/providers fires a background testSingleConnection() on create, so in the test (and in production) this interleaving happens:

  1. create → background auto-test reads snapshot isActive:false, no marker ("never activated"), starts probing;
  2. operator disables (PUT / bulk PATCH stamps operatorDisabledAt);
  3. background probe passes → isOperatorDisabled(staleSnapshot) is false → writes isActive:true. recoverKeyHealth() also rebuilt providerSpecificData from the stale copy, which could drop the marker.

The ENOTFOUND proxy.operator-disable.example.com lines are noise: the undici dispatcher falls back to the stubbed fetch. They only change the probe's timing. The test has been intermittent since it landed with #14941. It failed on ed664fc, 0816f62 and 6f665f3, and passed on 4f65ef3 and 4796624, so it is not a #15101/#15064/#15045 regression.

Fix (src/app/api/providers/[id]/test/route.ts): re-read the row uncached right before the write and use it for the operator-disable check (both the skipped and the valid paths) and as the recoverKeyHealth base.

Proof: new test an operator disable during an in-flight probe is not undone when the probe passes holds the probe on a gate, disables the connection mid-probe, then releases it. It was red on the tip (1 !== 0) and is green with the fix. The file passed 4/4 three times, and all 19 neighbouring files that exercise testSingleConnection passed (159/159).

2. Vitest UI: 2 unhandled errors (all 431 files passed)

  • Unhandled Rejection: window is not defined (RawJsonPanel.tsx:85), from tests/unit/translator-friendly-raw-json-panel.test.tsx. The suite never unmounted its React roots. Removing the container does not run effect cleanups, so the 600 ms auto-detect debounce stayed armed and fired after jsdom teardown. The component itself is correct because it clears the timer on unmount. Fix: a mountRoot() helper unmounts every root on cleanup. The new test cleanup leaves no debounced auto-detect running after the test was red before the harness fix (the detect fetch was called 3 times after cleanup) and is green after.
  • EnvironmentTeardownError: Cannot load partialWithoutDefaults.ts … after the environment was torn down, from tests/unit/ui/playground-studio.test.tsx. The next/dynamic mock started each tab import without awaiting it. A probe showed all 3 imports still pending when afterAll started ([false,false,false] in 3/3 runs). Fix: the imports are tracked and awaited in afterAll. Unhandled-error detection is unchanged.

Both files passed 3/3 (22 tests).

Gates

typecheck:core OK · check:open-sse-typecheck OK (0) · eslint on the changed files OK · check-file-size OK after commit (the route was tightened back under its 1252-line ceiling).

Note: tests/unit/monitoring-health-cached-credential.test.ts › "returns the stale cached summary immediately" failed once locally at 2262 ms against a 2000 ms budget. That is cold-import timing: it passed 3/3 with this change (1.1 to 1.7 s) and does not touch the connection-test route. It is not addressed here.

…ot the pre-probe snapshot

testSingleConnection() read the connection (cached) before the probe and
decided whether to activate on that snapshot after the probe returned. The
probe can take seconds, and POST /api/providers fires one in the background
on create, so an operator disable landing mid-probe was undone: the stale
snapshot still read 'never activated' and the passing test wrote
isActive:true (and could overwrite providerSpecificData with the stale copy,
dropping the operator-disable marker). This race made the two
connection-test-respects-operator-disable tests flaky in CI (#14941).

Re-read the row uncached right before the write and use it for the
operator-disable check and the key-health recovery base. New test holds a
probe in flight, disables the connection, and asserts it stays off.
…down

The vitest UI job passed every file but failed on two unhandled errors:

- translator-friendly-raw-json-panel: roots were never unmounted, so the
  RawJsonPanel 600 ms auto-detect debounce stayed armed and fired after the
  environment was torn down ('window is not defined'). Cleanup now unmounts
  each root; a new test proves no auto-detect runs after cleanup.
- playground-studio: the next/dynamic mock started each tab import without
  awaiting it; all three were still loading when the tests finished
  (EnvironmentTeardownError on BuildTab's import graph). The imports are now
  tracked and awaited in afterAll.
… size

Tighten the fresh-row read and two nearby comments so the route stays under
its check-file-size ceiling (1252 lines).
@diegosouzapw
diegosouzapw merged commit ce0d215 into release/v3.8.51 Sep 29, 2026
6 of 7 checks passed
Jaani2634 pushed a commit to Jaani2634/OmniRoute that referenced this pull request Sep 29, 2026
… to the provider test route (diegosouzapw#15134)

Release-captain base-red fix: classify diegosouzapw#15130's uncached connection re-read in the hard-lease inventory (class C state read). Inventory 3/3.
@diegosouzapw diegosouzapw mentioned this pull request Sep 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant