Skip to content

Treat a connection the peer closed as a dropped stream - #179

Merged
adityak74 merged 4 commits into
mainfrom
fix/dropped-connection-is-a-dropped-stream
Sep 5, 2026
Merged

Treat a connection the peer closed as a dropped stream#179
adityak74 merged 4 commits into
mainfrom
fix/dropped-connection-is-a-dropped-stream

Conversation

@adityak74

Copy link
Copy Markdown
Contributor

Why

Six of 35 benchmark trials on OpenRouter's free providers ended with peer closed connection without sending TLS close_notify, each after 25 to 58 tool calls of good work. rustls reports it as an UnexpectedEof on the body read, and nothing retried it because the retry rule was written about status codes. It is the same event as the provider's own mid-stream 504, seen from our side.

What

  • zorp::connection_dropped recognises a closed connection by the io error kind in the chain (UnexpectedEof, ConnectionReset, ConnectionAborted, BrokenPipe) and refuses when a timeout is underneath.
  • At send time, send_json_retrying re-sends a dropped connection under the same Retrying bound and backoff, saying so on stderr. One bound, one count of sends.
  • During the body, stream_sse reports a dropped connection as InStreamError::Dropped (now DroppedBy::Provider or DroppedBy::Transport), so the existing loop re-ask handles it after deltas and the existing Retrying path handles it before any. Provider Display unchanged.
  • A read timeout stays loud and fatal; read_error's clock rule is untouched.
  • Stub gains Reset { after }, ResetBeforeHeaders and Quiet { after }. Tests count connections: two deltas then a reset then an answer (two connections, one assistant message, the "asking again" line); reset before headers then an answer (two connections); reset on every connection (exactly ZORP_RETRY_ATTEMPTS connections, error names the bound); a read timeout is not re-sent.
  • docs/DECISIONS.md gets a 2026-09-05 entry and the 2026-08-23 entry an Amended by line. CLAUDE.md and AGENTS.md updated in sync.

Tests

cargo test -p zorp 59 to 60, cargo test -p zorp-agent 607 to 611, with research 804 to 808. fmt, clippy -D warnings and cargo build --workspace pass.

https://claude.ai/code/session_01ADjombyM8oH114zG9FnMxo

Six of 35 benchmark trials died on "peer closed connection without
sending TLS close_notify", each after 25 to 58 calls of good work. It is
the provider's mid-stream 504 seen from our side of the socket. Before
any delta it is sent again under the one existing bound; after a delta
the stream reports it as dropped and the loop asks again. A timeout is
still not retried anywhere.

Claude-Session: https://claude.ai/code/session_01ADjombyM8oH114zG9FnMxo
…n-is-a-dropped-stream

# Conflicts:
#	docs/DECISIONS.md
@adityak74
adityak74 merged commit eca23be into main Sep 5, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant