Context
Async detection (the DetectionWorker) currently uses a fail-once policy: any engine.analyze error sets the run to Failed with no re-enqueue (NATS at-least-once still retries on worker crashes, but not on analyze errors).
This is a deliberate v1 simplification. Analysis failures are often deterministic (malformed document, policy compile error), where retrying just burns LLM/OCR cost. But transient failures do happen — e.g. an LLM/OCR provider returning 503, a timeout, a network blip — and those should be retried.
Ask
Classify detection errors as retryable vs terminal, and only re-enqueue the retryable ones (bounded, with backoff — mirror the ConnectionSyncWorker attempt pattern).
Blocked on: the engine error type (nvisy_engine::Error / elide_core) exposing a reliable retryability signal (e.g. is_retryable() / transient-vs-permanent). Today it doesn't cleanly, so the server can't distinguish them. May need an upstream (runtime) change to surface this.
Acceptance
- Transient analyze failures (provider 5xx, timeout) re-enqueue up to a cap, then
Failed.
- Deterministic failures (bad input, policy error) go straight to
Failed, no retry.
- Retry decision driven by an engine-provided classifier, not a blind attempt counter.
Context
Async detection (the
DetectionWorker) currently uses a fail-once policy: anyengine.analyzeerror sets the run toFailedwith no re-enqueue (NATS at-least-once still retries on worker crashes, but not on analyze errors).This is a deliberate v1 simplification. Analysis failures are often deterministic (malformed document, policy compile error), where retrying just burns LLM/OCR cost. But transient failures do happen — e.g. an LLM/OCR provider returning 503, a timeout, a network blip — and those should be retried.
Ask
Classify detection errors as retryable vs terminal, and only re-enqueue the retryable ones (bounded, with backoff — mirror the
ConnectionSyncWorkerattemptpattern).Blocked on: the engine error type (
nvisy_engine::Error/elide_core) exposing a reliable retryability signal (e.g.is_retryable()/ transient-vs-permanent). Today it doesn't cleanly, so the server can't distinguish them. May need an upstream (runtime) change to surface this.Acceptance
Failed.Failed, no retry.