package processing import "errors" // Sentinel errors returned by the processing pipeline. Handlers should use // errors.Is and expose only these (or wrapped forms) to clients. var ( ErrRateLimited = errors.New("rate limit: too many processing jobs started; retry shortly") ErrRawIDsRequired = errors.New("raw_product_ids required") ErrTooManyProducts = errors.New("too many products") ErrNoMatchingProducts = errors.New("no matching products for company") ErrRawProductsNotFound = errors.New("one or more raw products not found for this company") ErrJobNotCancellable = errors.New("job not cancellable") ErrJobStillActive = errors.New("job still active") ErrJobNotRetryable = errors.New("job not retryable") // Orphan cleanup confirm gates (fail-closed). ErrOrphanCleanupEmpty = errors.New("no orphans to delete") ErrOrphanCleanupA1Protected = errors.New("refusing orphan cleanup that touches A1 cohort") ) // ClientError reports whether err is a known client-facing processing error // and returns a stable public message (preserves wrap details when present). func ClientError(err error) (msg string, ok bool) { switch { case err == nil: return "", false case errors.Is(err, ErrRateLimited), errors.Is(err, ErrRawIDsRequired), errors.Is(err, ErrTooManyProducts), errors.Is(err, ErrNoMatchingProducts), errors.Is(err, ErrRawProductsNotFound), errors.Is(err, ErrJobNotCancellable), errors.Is(err, ErrJobStillActive), errors.Is(err, ErrJobNotRetryable), errors.Is(err, ErrOrphanCleanupEmpty), errors.Is(err, ErrOrphanCleanupA1Protected): return err.Error(), true default: return "", false } }