Files
docker-agent/pkg/modelerrors
Arnaud Héritier 445fd38023 fix: add bounded jittered backoff to StartableToolSet retry path
Refs #4060 (partial): RAG semantic-embeddings indexing triggered a
rate-limit retry storm — repeated toolset-start attempts had no pacing
after a 429 from the embedding provider (the 15s/5min gate is the partial
fix; DefaultStartTimeout and chunk-level checkpointing are deferred).

Implementation:
- modelerrors.RetryableHTTPStatus(err): HTTP-status classifier that
  recognises 429, 408, and 5xx via *StatusError first, then falls back
  to statusCodeRegex. The toolset gate pre-filters to *StatusError via
  errors.As before calling it, so port numbers and chunk counts in
  plain error strings cannot arm the gate.
- pkg/tools/startable_backoff.go: bounded exponential backoff with
  additive 0-20% jitter (base=15s, cap=5min, delay∈[d,1.2d]).
- Gate in tryStartLocked (TryStart/TryStartWithTimeout only): blocking
  Start() bypasses it so mcpcatalog enable and skill startup are
  immediate.
- Gate adopts a live StartReporter after /toolset-restart without
  waiting for the window to expire.
- Wrap embedding errors via oaistream.WrapOpenAIError at openai/client.go
  and dmr/embed.go so a 429 from the embedding provider surfaces as
  *StatusError and correctly arms the gate.
- WithStartRetryJitter / WithStartRetryClock options via variadic
  NewStartable for deterministic test control.
- Stale 'retry on next turn' log messages updated in agent.go/mcp.go.
- Partial-start exemption documented (code-mode composites remain
  unpaced; follow-up at issue #4067).

Tests (same commit, covering the above):
- startable_backoff_test.go: unit tests for the gate (gate fires on
  429/408/5xx StatusError, not on plain text / context errors,
  blocking Start() ungated, concurrency, jitter bounds)
- startable_backoff_regression_test.go: consumer-shaped regression
  suite (RAG/MCP/LSP error shapes, no-goroutine/timer leak, latch)
- rag_backoff_test.go: real-toolset integration test via rag.New +
  fake clock

Docs:
- docs/tools/rag/index.md: 'Indexing failures, retries and backoff'
  section with trigger table, parameters, and troubleshooting.
- docs/tools/mcp/index.md, docs/tools/lsp/index.md: lifecycle notes
  confirming local startup failures fail fast.

Scope: DefaultStartTimeout (30s) unchanged — deferred.
2026-09-01 13:20:38 +02:00
..