diff --git a/src/main/java/com/williamcallahan/javachat/support/RetrievalErrorClassifier.java b/src/main/java/com/williamcallahan/javachat/support/RetrievalErrorClassifier.java index 18958dd6..3ef1be00 100644 --- a/src/main/java/com/williamcallahan/javachat/support/RetrievalErrorClassifier.java +++ b/src/main/java/com/williamcallahan/javachat/support/RetrievalErrorClassifier.java @@ -12,37 +12,25 @@ */ public final class RetrievalErrorClassifier { - /** Owns the stable diagnostic label and vector-store retry policy for each failure category. */ + /** Owns the vector-store retry policy for each failure category. */ private enum RetrievalErrorCategory { - NOT_FOUND("404 Not Found", false), - UNAUTHORIZED("401 Unauthorized", false), - FORBIDDEN("403 Forbidden", false), - RATE_LIMITED("429 Rate Limited", true), - CONNECTION_ERROR("Connection Error", true), - EMBEDDING_SERVICE_UNAVAILABLE("Embedding Service Unavailable", false), - UNKNOWN("Unknown Error", false); + NOT_FOUND(false), + UNAUTHORIZED(false), + FORBIDDEN(false), + RATE_LIMITED(true), + CONNECTION_ERROR(true), + EMBEDDING_SERVICE_UNAVAILABLE(false), + UNKNOWN(false); - private final String errorLabel; private final boolean retryableVectorStoreFailure; - RetrievalErrorCategory(String errorLabel, boolean retryableVectorStoreFailure) { - this.errorLabel = errorLabel; + RetrievalErrorCategory(boolean retryableVectorStoreFailure) { this.retryableVectorStoreFailure = retryableVectorStoreFailure; } } private RetrievalErrorClassifier() {} - /** - * Determines a stable error category from exception types, messages, and causes. - * - * @param failure failure encountered during retrieval - * @return normalized error category label - */ - public static String determineErrorType(Throwable failure) { - return classify(failure).errorLabel; - } - private static RetrievalErrorCategory classify(Throwable failure) { return classifyGrpcStatus(failure).orElseGet(() -> classifyNonGrpcFailure(failure)); } diff --git a/src/test/java/com/williamcallahan/javachat/support/RetrievalErrorClassifierTest.java b/src/test/java/com/williamcallahan/javachat/support/RetrievalErrorClassifierTest.java index c424dfba..735ead5c 100644 --- a/src/test/java/com/williamcallahan/javachat/support/RetrievalErrorClassifierTest.java +++ b/src/test/java/com/williamcallahan/javachat/support/RetrievalErrorClassifierTest.java @@ -26,7 +26,6 @@ class RetrievalErrorClassifierTest { void classifiesDirectTimeoutExceptionAsTransient() { TimeoutException directTimeoutException = new TimeoutException("Future took too long"); - assertEquals("Connection Error", RetrievalErrorClassifier.determineErrorType(directTimeoutException)); assertTrue(RetrievalErrorClassifier.isTransientVectorStoreError(directTimeoutException)); } @@ -35,7 +34,6 @@ void classifiesWrappedTimeoutExceptionAsTransient() { IllegalStateException qdrantTimeoutFailure = new IllegalStateException( "Qdrant operation timed out after 5s", new TimeoutException("Future did not complete")); - assertEquals("Connection Error", RetrievalErrorClassifier.determineErrorType(qdrantTimeoutFailure)); assertTrue(RetrievalErrorClassifier.isTransientVectorStoreError(qdrantTimeoutFailure)); } @@ -44,7 +42,6 @@ void classifiesNullMessageTimeoutExceptionAsTransient() { TimeoutException nullMessageTimeoutException = new TimeoutException(); assertNull(nullMessageTimeoutException.getMessage()); - assertEquals("Connection Error", RetrievalErrorClassifier.determineErrorType(nullMessageTimeoutException)); assertTrue(RetrievalErrorClassifier.isTransientVectorStoreError(nullMessageTimeoutException)); } @@ -53,7 +50,6 @@ void doesNotClassifyTimeoutLookalikeTextAsTransient() { IllegalStateException timeoutConfigurationFailure = new IllegalStateException("Qdrant timeout configuration is invalid"); - assertEquals("Unknown Error", RetrievalErrorClassifier.determineErrorType(timeoutConfigurationFailure)); assertFalse(RetrievalErrorClassifier.isTransientVectorStoreError(timeoutConfigurationFailure)); } @@ -61,7 +57,6 @@ void doesNotClassifyTimeoutLookalikeTextAsTransient() { void classifiesGrpcDeadlineExceededAsTransient() { RuntimeException grpcDeadlineFailure = Status.DEADLINE_EXCEEDED.asRuntimeException(); - assertEquals("Connection Error", RetrievalErrorClassifier.determineErrorType(grpcDeadlineFailure)); assertTrue(RetrievalErrorClassifier.isTransientVectorStoreError(grpcDeadlineFailure)); } @@ -69,7 +64,6 @@ void classifiesGrpcDeadlineExceededAsTransient() { void classifiesGrpcUnavailableAsTransient() { RuntimeException grpcUnavailableFailure = Status.UNAVAILABLE.asRuntimeException(); - assertEquals("Connection Error", RetrievalErrorClassifier.determineErrorType(grpcUnavailableFailure)); assertTrue(RetrievalErrorClassifier.isTransientVectorStoreError(grpcUnavailableFailure)); } @@ -77,7 +71,6 @@ void classifiesGrpcUnavailableAsTransient() { void doesNotRetryGrpcResourceExhaustedFailure() { RuntimeException grpcResourceExhaustedFailure = Status.RESOURCE_EXHAUSTED.asRuntimeException(); - assertEquals("Unknown Error", RetrievalErrorClassifier.determineErrorType(grpcResourceExhaustedFailure)); assertFalse(RetrievalErrorClassifier.isTransientVectorStoreError(grpcResourceExhaustedFailure)); } @@ -87,7 +80,6 @@ void prioritizesGrpcUnavailableOverHttp429Description() { .withDescription("HTTP 429 from upstream proxy") .asRuntimeException(); - assertEquals("Connection Error", RetrievalErrorClassifier.determineErrorType(grpcUnavailableFailure)); assertTrue(RetrievalErrorClassifier.isTransientVectorStoreError(grpcUnavailableFailure)); } @@ -97,7 +89,6 @@ void keepsGrpcResourceExhaustedWithHttp429DescriptionNonRetryable() { .withDescription("HTTP 429 quota exhausted") .asRuntimeException(); - assertEquals("Unknown Error", RetrievalErrorClassifier.determineErrorType(grpcResourceExhaustedFailure)); assertFalse(RetrievalErrorClassifier.isTransientVectorStoreError(grpcResourceExhaustedFailure)); } @@ -105,7 +96,6 @@ void keepsGrpcResourceExhaustedWithHttp429DescriptionNonRetryable() { void doesNotRetryGrpcInvalidArgumentFailure() { RuntimeException grpcInvalidArgumentFailure = Status.INVALID_ARGUMENT.asRuntimeException(); - assertEquals("Unknown Error", RetrievalErrorClassifier.determineErrorType(grpcInvalidArgumentFailure)); assertFalse(RetrievalErrorClassifier.isTransientVectorStoreError(grpcInvalidArgumentFailure)); } @@ -114,7 +104,6 @@ void classifiesWrappedGrpcStatusExceptionAsTransient() { IllegalStateException wrappedGrpcFailure = new IllegalStateException("Qdrant operation failed", Status.UNAVAILABLE.asException()); - assertEquals("Connection Error", RetrievalErrorClassifier.determineErrorType(wrappedGrpcFailure)); assertTrue(RetrievalErrorClassifier.isTransientVectorStoreError(wrappedGrpcFailure)); }