Problem
ai/configBase.mjs ships openAiCompatible.contentionTimeoutMs = 15000 and contentionRetryCount = 2 (lines ~710-712). TextEmbeddingService.embedText (~lines 1838-1845) applies them to every single-input embedding call: 15s timeout → 1s delay → 15s → 1s → 15s ≈ 47s effective giveup, regardless of what the caller declared.
Consumers of the single-input path include the KB and MC embedding canaries. Their declared outer deadlines (300s / 900s) never fire — the inner ladder exhausts first, so the declared deadlines are dead configuration. Measured on a constrained CPU-only plane: provider-activity failures at 47,008-47,022ms, and each aborted attempt logs one engine cancel task row — a saturated serialized lane receives a continuous abort-retry cancel storm (~16s cadence per attempt, paired across the two canaries) that adds load exactly when the lane has none to spare.
The ladder is also unprojected: deployment templates surface NEO_OPENAI_COMPATIBLE_BATCH_EMBEDDING_TIMEOUT_MS but not the contention leaves. That configuration-projection concern is independently owned by #17115; this ticket owns only the runtime deadline mechanism.
Acceptance Criteria
- Under persistent retryable contention, a single-input embed call's effective giveup is governed by its caller's declared deadline; no shorter inner aggregate horizon may silently replace it. Terminal or non-contention errors may still fail fast without waiting for that deadline.
- A canary/probe failing against a saturated lane must not multiply load: deadline-bearing calls do not turn one caller budget into a fixed abort-retry storm.
- Unit/production-path specs prove: (a) KB and MC propagate the declared deadline with the caller signal, (b) a longer caller deadline outlives the former inner ladder without repeat dispatch, (c) a caller deadline can expire while queued with zero provider dispatch, and (d) no retry dispatch occurs after caller abort.
Scope transfer
Contention-leaf projection and operator tuning remain owned by #17115. They are not a close condition for this runtime-mechanism ticket.
Evidence class
Live provider-activity ledger + engine task log on a constrained CPU-only plane, 2026-08-14; source-bound to the leaves and call sites above. Related mechanism history: #16853 (abort semantics), #17049 (clock inversion class).
Part of epic #17072.
Problem
ai/configBase.mjsshipsopenAiCompatible.contentionTimeoutMs = 15000andcontentionRetryCount = 2(lines ~710-712).TextEmbeddingService.embedText(~lines 1838-1845) applies them to every single-input embedding call: 15s timeout → 1s delay → 15s → 1s → 15s ≈ 47s effective giveup, regardless of what the caller declared.Consumers of the single-input path include the KB and MC embedding canaries. Their declared outer deadlines (300s / 900s) never fire — the inner ladder exhausts first, so the declared deadlines are dead configuration. Measured on a constrained CPU-only plane: provider-activity failures at 47,008-47,022ms, and each aborted attempt logs one engine
cancel taskrow — a saturated serialized lane receives a continuous abort-retry cancel storm (~16s cadence per attempt, paired across the two canaries) that adds load exactly when the lane has none to spare.The ladder is also unprojected: deployment templates surface
NEO_OPENAI_COMPATIBLE_BATCH_EMBEDDING_TIMEOUT_MSbut not the contention leaves. That configuration-projection concern is independently owned by #17115; this ticket owns only the runtime deadline mechanism.Acceptance Criteria
Scope transfer
Contention-leaf projection and operator tuning remain owned by #17115. They are not a close condition for this runtime-mechanism ticket.
Evidence class
Live provider-activity ledger + engine task log on a constrained CPU-only plane, 2026-08-14; source-bound to the leaves and call sites above. Related mechanism history: #16853 (abort semantics), #17049 (clock inversion class).
Part of epic #17072.