LearnNewsExamplesServices
Frontmatter
id12845
titlecategorizeInvocationError: structural timeout via PROVIDER_TIMEOUT_CODE
stateClosed
labels
enhancementaimodel-experience
assigneesneo-opus-vega
createdAtJun 10, 2026, 6:04 PM
updatedAtJun 10, 2026, 8:02 PM
githubUrlhttps://github.com/neomjs/neo/issues/12845
authorneo-opus-vega
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtJun 10, 2026, 8:02 PM

categorizeInvocationError: structural timeout via PROVIDER_TIMEOUT_CODE

Closed v13.0.0/archive-v13-0-0-chunk-17 enhancementaimodel-experience
neo-opus-vega
neo-opus-vega commented on Jun 10, 2026, 6:04 PM

Context

The deferred sibling-half of the #12837 / #12833 split (with @neo-opus-grace). #12833 added a wall-clock timeout + degrade-on-timeout to SessionService.summarizeSession, and surfaced that consumerFrictionHelper.categorizeInvocationError discriminates a timeout symptom by message-regex (/timeout|aborted|timed[ -]out/i). #12818 exported PROVIDER_TIMEOUT_CODE (ai/provider/createTimeoutError.mjs:61) precisely so callers detect a provider timeout structurally, without per-provider string knowledge. @neo-opus-grace adopted it on the ask-path (SearchService, #12832 / #12844); this is the sibling adoption at the shared consumerFrictionHelper site.

Deferred from #12833's PR to keep that PR scoped, and because touching the file inherits a check-ticket-archaeology grandfathered-ref cleanup (below).

The Problem

categorizeInvocationError returns 'timeout' only when the sanitized message matches the regex. The provider's PROVIDER_TIMEOUT error (both OpenAiCompatible + Ollama, post-#12818) carries error.code === PROVIDER_TIMEOUT_CODE — the authoritative, message-wording-independent signal. The friction consumers (SemanticGraphExtractor, SessionService) therefore mis-bucket a provider timeout whose message ever drifts from "timed out" → 'parse-failure', silently mis-routing the degrade/friction logic. Non-blocking today (the message matches), but brittle.

The Architectural Reality

  • ai/services/memory-core/helpers/consumerFrictionHelper.mjs categorizeInvocationError(err) — add if (err?.code === PROVIDER_TIMEOUT_CODE) return 'timeout'; BEFORE the regex (structural-first, regex fallback). Import PROVIDER_TIMEOUT_CODE from ../../../provider/createTimeoutError.mjs.
  • Precedent to mirror: SearchService.#createDegradedSynthesisResponse (#12832 / #12844) — isTimeout = error?.code === PROVIDER_TIMEOUT_CODE || /timed out/i.test(reason) + a regex-independent test.
  • Husky scoping note: staging consumerFrictionHelper.mjs + consumerFrictionHelper.spec.mjs trips buildScripts/util/check-ticket-archaeology.mjs on ~6 pre-existing #N-in-comment refs (not added by this work). Resolve via the hook-sanctioned // ticket-ref-ok: <reason> markers (or a focused comment-ref cleanup). This is why the change was deferred from #12833 rather than bundled.

Decision Record impact

aligned-with the #12818 PROVIDER_TIMEOUT contract (no ADR governs the provider-error surface).

Acceptance Criteria

  • categorizeInvocationError returns 'timeout' when err.code === PROVIDER_TIMEOUT_CODE, regardless of message wording; the message-regex remains a fallback for non-coded errors.
  • A regex-independent unit test (error carries the code, message does NOT say "timed out" → 'timeout'), mirroring #12832's ask-path test.
  • The grandfathered comment-refs in the touched files are resolved so check-ticket-archaeology passes.
  • The consumerFrictionHelper spec is green.

Out of Scope

  • The SessionService degrade-on-timeout (shipped, #12833) + the ask-path adoption (#12832 / #12844).
  • Re-designing the check-ticket-archaeology whole-file comment scan — a separate friction (it blocks edits to any file with grandfathered comment-refs; worth its own MX look, not bundled here).

Avoided Traps

  • Removing the regex fallback (keep it for non-coded error paths).
  • Rewriting others' grandfathered comments (prefer the sanctioned ticket-ref-ok marker over a prose rewrite).

Related

  • #12833 / #12837 — SessionService stall fix (this is its deferred sibling-half)
  • #12832 / #12844 — ask-path PROVIDER_TIMEOUT_CODE adoption (@neo-opus-grace; the mirror)
  • #12818 / #12814 — the PROVIDER_TIMEOUT_CODE provider contract

Authored by @neo-opus-vega (Claude Opus 4.8).

tobiu referenced in commit b8a705f - "fix(memory-core): structural provider-timeout discrimination in categorizeInvocationError (#12845) (#12847) on Jun 10, 2026, 8:02 PM
tobiu closed this issue on Jun 10, 2026, 8:02 PM