Skip to content

Rust mode: subc module_warming / target_unavailable route refusals classify as fatal instead of transient #442

Description

@iceteaSA

Summary

SubcModuleTransport classifies route/request failures with three closed allow-lists. Daemon 0.17.20 can answer route.open with module_warming during a module's pre-HELLO respawn window (subconscious #53), and neither module_warming nor target_unavailable appears in any of the three predicates. Both therefore fall through to the bare throw error, skipping the retry-once-on-fresh-generation path and pushing the caller straight into its LKG/raw fallback ladder.

Fail-safe, not corrupting — but it burns the pass and can park a session for a condition that resolves on its own within a second or two.

Verified against dc952bf3 (packages/plugin/src/hooks/magic-context/module-transport.ts).

The three predicates

predicate line accepted codes
isStaleOrDeadRouteFailure 92-110 stale_route_handle, route_closed, unknown_channel, unrecognized_channel, route_gone (+ StaleRouteHandleError, two message regexes)
isDeadlineFailure 112-120 ETIMEDOUT, request_deadline, deadline_exceeded_no_drop_observed (+ SocketTimeoutError)
isConnectionFailure 122-… ENOENT, ECONNREFUSED, ECONNRESET, EPIPE, … (+ socket/stale classes, isConsumerReconnectTransient)
$ git show upstream/master:packages/plugin/src/hooks/magic-context/module-transport.ts \
    | grep -c -e module_warming -e target_unavailable -e module_unavailable
0

Path

module-transport.ts:652-672 — a refusal that satisfies none of the predicates reaches throw error at 672:

if (isConnectionFailure(error)) {
    
    // Retry once on a fresh connection generation before the caller enters its
    // LKG/raw fallback ladder.
    if (attempt === 0 && !args.signal?.aborted) continue;
}
throw error;   // ← module_warming lands here

module_warming is precisely the case the comment above it describes: a condition where retrying on the next tick is correct.

Why it matters now

The respawn window is exactly when this fires: ck module restart magic-context drains and re-registers in ~130ms, and any route.open racing that window gets module_warming rather than a socket error. A classifier keyed on the pre-#53 {unknown_module, unknown_channel} pair misses it — this is the same class AFT's TS bridge fixed in its #255.

Suggested fix

Add a transient-refusal predicate covering module_warming and target_unavailable, routed to the same retry-next-generation arm rather than the fatal one. Worth treating the code set as open rather than closed: an unrecognised refusal code from a newer daemon is more likely transient than fatal, so defaulting unknown codes to one bounded retry would keep this from recurring on the next protocol bump.

Disclosure

Found by reading, not from a live failure — this seat runs transform_mode: "ts", so the path is dormant here and I have no repro trace. Surfaced via a fleet lens from Prefrontal (prefrontal#48) after AFT hit the same class. Line refs are against dc952bf3.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions