History

fix: preserve pre-advisory provider status during compatibility advisory removal

When applyCompatibilityAdvisory overwrites a provider's status/message with compatibility information, the original values (e.g. from a genuine probe failure) were permanently lost. When a subsequent advisory removal or replacement occurred, removeExistingCompatibilityAdvisory would reset status to 'ready' instead of the original pre-advisory status. Fix by recording preAdvisoryStatus and preAdvisoryMessage in the advisory object when it is applied. removeExistingCompatibilityAdvisory now restores these saved values instead of unconditionally resetting to 'ready'/'disabled'. For old advisories without these fields, the fallback behavior is unchanged.

Cursor Agent committed 6 months ago

Commit fad51d11 parent 5f9dc673 files · +64 −2Browse files

Unified · Split

3 files
  1. apps/server/src/provider/providerCompatibility.test.ts +46 −0
  2. apps/server/src/provider/providerCompatibility.ts +16 −2
  3. packages/contracts/src/server.ts +2 −0
apps/server/src/provider/providerCompatibility.test.ts+46−0
@@ -327,6 +327,52 @@ describe("provider compatibility", () => { · 326 unmodified lines
327327 });
328328 });
329329
330+ it.effect("preserves genuine probe errors when the remote map relaxes a bundled advisory", () => {
331+ const bundledMessage =
332+ "This provider harness version 0.130.0 is known to be incompatible with this T3 Code release. Use 0.129.0.";
333+ const probeErrorMessage = "CLI health-check failed: process exited with code 1";
334+ const remoteDocument = {
335+ version: 1,
336+ policies: [
337+ {
338+ t3CodeRange: ">=0.0.0",
339+ driver: "codex",
340+ recommendedRange: ">=0.130.0",
341+ recommendedVersion: "0.130.0",
342+ ranges: [{ status: "supported", range: ">=0.130.0" }],
343+ },
344+ ],
345+ };
346+
347+ return Effect.gen(function* () {
348+ const enriched = yield* enrichProviderSnapshotWithCompatibilityAdvisory({
349+ ...baseProvider,
350+ status: "error",
351+ message: bundledMessage,
352+ compatibilityAdvisory: {
353+ status: "broken",
354+ severity: "error",
355+ currentVersion: "0.130.0",
356+ message: bundledMessage,
357+ recommendedRange: "<0.130.0",
358+ recommendedVersion: "0.129.0",
359+ ranges: [{ status: "broken", range: ">=0.130.0" }],
360+ preAdvisoryStatus: "error",
361+ preAdvisoryMessage: probeErrorMessage,
362+ },
363+ }).pipe(
364+ Effect.provideService(
365+ HttpClient.HttpClient,
366+ jsonHttpClient(() => ({ payload: remoteDocument })),
367+ ),
368+ );
369+
370+ expect(enriched.status).toBe("error");
371+ expect(enriched.message).toBe(probeErrorMessage);
372+ expect(enriched.compatibilityAdvisory).toMatchObject({ status: "supported" });
373+ });
374+ });
375+
330376 it.effect("falls back to the bundled map when the remote compatibility fetch fails", () =>
331377 Effect.gen(function* () {
332378 const enriched = yield* enrichProviderSnapshotWithCompatibilityAdvisory({
apps/server/src/provider/providerCompatibility.ts+16−2
@@ -325,13 +325,19 @@ function applyCompatibilityAdvisory<Snapshot extends ProviderCompatibilitySnapsh · 324 unmodified lines
325325 ? "warning"
326326 : baseSnapshot.status;
327327
328+ const advisoryWithPreState: ServerProviderCompatibilityAdvisory = {
329+ ...compatibilityAdvisory,
330+ preAdvisoryStatus: baseSnapshot.status,
331+ ...(baseSnapshot.message ? { preAdvisoryMessage: baseSnapshot.message } : {}),
332+ };
333+
328334 return {
329335 ...baseSnapshot,
330336 status,
331337 ...(compatibilityMessage || baseSnapshot.message
332338 ? { message: compatibilityMessage ?? baseSnapshot.message }
333339 : {}),
334− compatibilityAdvisory,
340+ compatibilityAdvisory: advisoryWithPreState,
335341 } as Snapshot;
336342 }
337343
@@ -349,11 +355,19 @@ function removeExistingCompatibilityAdvisory<Snapshot extends ProviderCompatibil · 11 unmodified lines
349355 : undefined;
350356 if (compatibilityMessage && baseSnapshot.message === compatibilityMessage) {
351357 const { message: _message, ...snapshotWithoutCompatibilityMessage } = baseSnapshot;
358+ const restoredStatus =
359+ existingCompatibilityAdvisory.preAdvisoryStatus ?? (snapshot.enabled ? "ready" : "disabled");
352360 return {
353361 ...snapshotWithoutCompatibilityMessage,
354− status: snapshot.enabled ? "ready" : "disabled",
362+ status: restoredStatus,
363+ ...(existingCompatibilityAdvisory.preAdvisoryMessage
364+ ? { message: existingCompatibilityAdvisory.preAdvisoryMessage }
365+ : {}),
355366 } as Snapshot;
356367 }
368+ if (existingCompatibilityAdvisory.preAdvisoryStatus !== undefined) {
369+ return { ...baseSnapshot, status: existingCompatibilityAdvisory.preAdvisoryStatus } as Snapshot;
370+ }
357371 return baseSnapshot as Snapshot;
358372 }
359373
packages/contracts/src/server.ts+2−0
@@ -163,6 +163,8 @@ export const ServerProviderCompatibilityAdvisory = Schema.Struct({ · 162 unmodified lines
163163 ranges: Schema.Array(ServerProviderCompatibilityRange).pipe(
164164 Schema.withDecodingDefault(Effect.succeed([])),
165165 ),
166+ preAdvisoryStatus: Schema.optionalKey(ServerProviderState),
167+ preAdvisoryMessage: Schema.optionalKey(TrimmedNonEmptyString),
166168 });
167169 export type ServerProviderCompatibilityAdvisory = typeof ServerProviderCompatibilityAdvisory.Type;
168170

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t