All files / scripts/mcp-client/error-classification not-indexed.ts

100% Statements 12/12
100% Branches 11/11
100% Functions 2/2
100% Lines 7/7

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53                                                    35x                               25x 24x 14x 45x       8x 4x    
/**
 * @module mcp-client/error-classification/not-indexed
 * @description Classify document-level fetch errors as `not_indexed` vs.
 * transport errors.
 *
 * Adding a new "not-indexed" pattern is a one-file change; the bounded
 * scope avoids accidental coupling with transport-error wording in the
 * MCPClient request stack.
 *
 * @author Hack23 AB
 * @license Apache-2.0
 */
 
import { TRANSPORT_ERROR_RE } from './transport.js';
 
/**
 * Phrases that indicate a document-level indexing gap rather than a
 * transport/operational MCP failure.
 *
 * Bare `404` and bare `not found` are intentionally excluded because they
 * also appear in transport-level errors such as `MCP server error: 404 Not
 * Found` from a wrong endpoint or unavailable route. Treating those as
 * `not_indexed` would mask MCP configuration/server outages as document
 * indexing lag. Use {@link classifyDocumentErrorAsNotIndexed} which combines
 * this list with a transport-error sentinel and a dok_id-aware fallback.
 */
export const NOT_INDEXED_ERROR_PATTERNS = [
  'not indexed',
  'no document',
  'document not found',
  'dok_id not found',
] as const;
 
/**
 * Returns true when the error message matches a known document-level
 * "not indexed" signal AND is not a transport/operational error.
 *
 * The `dokId` argument enables a fallback heuristic: upstream MCP tools that
 * return document-level "not found" responses typically echo the dok_id back
 * in the message, while transport-level failures never do.
 */
export function classifyDocumentErrorAsNotIndexed(message: string, dokId?: string): boolean {
  if (!message) return false;
  if (TRANSPORT_ERROR_RE.test(message)) return false;
  const lower = message.toLowerCase();
  if (NOT_INDEXED_ERROR_PATTERNS.some((p) => lower.includes(p))) return true;
  // Document-level "not found" responses from upstream MCP tools typically
  // echo the dok_id. Transport-level failures never do — so requiring the
  // dok_id to appear in the message disambiguates the two cases.
  if (dokId && lower.includes(dokId.toLowerCase()) && lower.includes('not found')) return true;
  return false;
}