CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl-labs/graceful-degradation

Every external call needs a timeout, every timeout needs a fallback — resilience patterns for HTTP, databases, and third-party services

88

4.72x
Quality

90%

Does it follow best practices?

Impact

85%

4.72x

Average score across 5 eval scenarios

SecuritybySnyk

Passed

No known issues

Overview
Quality
Evals
Security
Files

criteria.jsonevals/scenario-4/

{
  "context": "Tests whether the agent proactively applies graceful degradation when building a travel search aggregator that calls four external travel provider APIs in parallel. The task is purely a business requirement -- no mention of timeouts, fallbacks, resilience, or error handling strategy. The agent should recognize that four external APIs need resilience patterns.",
  "type": "weighted_checklist",
  "checklist": [
    {
      "name": "timeouts-on-all-fetches",
      "description": "Every HTTP request to Skyscanner, Booking.com, Rentalcars, and Viator APIs includes an explicit timeout (AbortSignal.timeout, axios timeout, or equivalent). No bare fetch() calls.",
      "max_score": 15
    },
    {
      "name": "parallel-with-isolation",
      "description": "All four provider APIs are called in parallel using Promise.allSettled() or individual try/catch wrappers, NOT Promise.all(). One slow or failing provider does not block or crash the others.",
      "max_score": 15
    },
    {
      "name": "partial-results-returned",
      "description": "When one or more providers fail, the endpoint returns a 200 response with available results and empty arrays or null for failed providers, rather than returning a 500 error.",
      "max_score": 15
    },
    {
      "name": "fallback-values-per-provider",
      "description": "Each provider has a defined fallback (empty array, null, or cached results) returned when it fails. The catch block returns a meaningful fallback, not a re-throw.",
      "max_score": 10
    },
    {
      "name": "warnings-for-unavailable-providers",
      "description": "The response includes a warnings or metadata field indicating which providers failed or returned no results, so the frontend can show appropriate messages.",
      "max_score": 10
    },
    {
      "name": "structured-error-logging",
      "description": "Provider failures are logged with structured context: provider name, error details, search parameters, and fallback used. Not just console.log(error).",
      "max_score": 10
    },
    {
      "name": "retry-with-backoff-on-transient",
      "description": "At least one provider call includes retry logic with exponential backoff and jitter for transient errors (429, 502, 503, 504). Fixed delays or blind retries are a failure.",
      "max_score": 10
    },
    {
      "name": "per-provider-timeout-config",
      "description": "Providers can have different timeout values (e.g., flights search may need more time than activities search). Timeouts are configurable per provider.",
      "max_score": 8
    },
    {
      "name": "circuit-breaker-for-providers",
      "description": "A circuit breaker pattern is implemented for at least one provider, tracking failures over time and short-circuiting to fallback after a threshold.",
      "max_score": 7
    }
  ]
}

evals

tile.json