For any async workflow that fans out (e.g., Promise.all over providers) or mutates shared session state, apply two rules: 1) Bound/cancel all external async work (timeouts must abort the underlying operation, not only the awaiting caller). 2) Centralize lifecycle transitions for shared mutable state (prefer a state enum + transition helper over ad-hoc “reset fields in parallel”).

How to apply

Example (client-side timeout with defense-in-depth)

const LIVE_MODELS_TIMEOUT_MS = 4000;

function withTimeout<T>(promise: Promise<T>, ms: number, label: string): Promise<T> {
  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), ms);
    promise.then(
      (value) => { clearTimeout(timer); resolve(value); },
      (err) => { clearTimeout(timer); reject(err); }
    );
  });
}

// In fan-out code, ensure each task is bounded so Promise.all can complete.
const liveIds = await withTimeout(
  acpListProviderSupportedModels(providerId),
  LIVE_MODELS_TIMEOUT_MS,
  `live model discovery for ${providerId}`
);

Example (lifecycle state centralized)

enum PromptLifecycle { Idle, AwaitingRun, Running, Succeeded, Failed }

function transitionEntry(entry: Entry, next: PromptLifecycle) {
  // Reset/updates happen in one place to keep concurrent transitions consistent.
  switch (next) {
    case PromptLifecycle.Idle:
      entry.activePromptAttemptId = null;
      entry.activeRunId = null;
      return;
    // other states...
  }
}

This prevents: (a) UI workflows stalling indefinitely due to a single slow dependency, (b) leaked in-flight work when only the client await is timed out, and (c) inconsistent session state caused by partial or parallel field resets.