Skip to content

fix(claude): preserve native response-read errno and bound EINTR retries #378

Description

@gnanirahulnutakki

Parent: #364

Problem

The generated native Claude Code daemon client currently collapses every negative response read() into exit code 11 with empty stderr. That makes receive timeout, EINTR, connection reset, and other I/O failures indistinguishable.

The client also ignores the result from setsockopt(..., SO_RCVTIMEO, ...), so it cannot prove that the configured receive timeout was armed.

POSIX specifies that a read() interrupted before transferring data returns -1 with errno=EINTR, and socket reads are equivalent to recv() with no flags. Linux permits either EAGAIN or EWOULDBLOCK for relevant socket conditions, so portable code must handle both.

Primary references, rechecked 2026-07-23:

Scope

In scope:

  • Capture errno immediately after a failed native response read, before cleanup can overwrite it.
  • Emit a stable, sanitized diagnostic containing only operation/stage, numeric errno, and portable symbolic errno name.
  • Retry EINTR without allowing repeated interruptions to extend the configured overall response timeout indefinitely.
  • Treat EAGAIN, EWOULDBLOCK, ETIMEDOUT, and persistent socket/read errors as non-retryable terminal outcomes.
  • Check receive-timeout setup and fail visibly if the timeout cannot be armed.
  • Preserve nonzero, fail-closed native behavior and existing protocol-validation failures.
  • Add a test-only native syscall seam or equivalent deterministic mechanism; do not rely on scheduler timing to manufacture EINTR.

Out of scope:

  • changing latency thresholds;
  • changing .github/workflows/tests.yml;
  • uploading benchmark artifacts;
  • choosing a dedicated or multi-run performance runner;
  • deduplicating push and pull-request runs; and
  • changing branch protection.

Acceptance criteria

  • A failed native response read reports numeric and symbolic errno.
  • Diagnostics never include request bodies, mission passports, tokens, tool arguments, socket paths, temporary paths, environment dumps, or other host-specific data.
  • A single injected EINTR is retried and a subsequent valid daemon response succeeds.
  • Repeated EINTR cannot extend the configured overall response budget without bound.
  • Receive timeout is not retried into success and remains a nonzero native outcome.
  • Persistent injected read errors fail immediately and retain their original errno.
  • Failure to configure SO_RCVTIMEO is visible and nonzero.
  • Existing malformed, truncated, and negative daemon-protocol responses remain rejected.
  • Existing native exit-code consumers retain an explicit, tested compatibility contract.
  • Generated C builds warning-clean with repository compiler flags on supported Linux and macOS test environments.

Targeted tests

  • Deterministic fault injection: EINTR once, then successful read.
  • Deterministic fault injection: repeated EINTR reaches the bounded terminal policy.
  • Deterministic fault injection: persistent EIO or equivalent terminal read error.
  • Real AF_UNIX stalled-server test: timeout, empty stdout, sanitized stderr, nonzero exit.
  • Existing native malformed/truncated response tests.
  • Full focused native/hook test module.
  • Ruff, pre-commit, check-local.sh --quick, and git diff --check.

A base-revision red proof should demonstrate that the new errno and retry assertions fail on unmodified dev.

Security and cost

This is a local Unix-socket correctness change. It requires no cloud credentials, Kubernetes workload, Docker image, external provider, or live model.

The diagnostic format must use an allowlisted field set rather than interpolating user-controlled strings. The implementation must not convert native transport failure into an allow result.

Runtime and CI cost should remain effectively unchanged; tests must use bounded deterministic injection rather than repeated timing loops.

Dependencies and overlap

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingciCI coverage & reliabilitytaskTask belonging to an epictestsTest quality & coverageverificationVerification and reproducibility

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions