Skip to content

fix: use stream idle deadline after reply handle arrives - #23

Merged
senamakel merged 1 commit into
tinyhumansai:mainfrom
senamakel:stream-reply-idle-deadline
Sep 24, 2026
Merged

senamakel merged 1 commit into
tinyhumansai:mainfrom
senamakel:stream-reply-idle-deadline

Conversation

@senamakel

@senamakel senamakel commented Sep 24, 2026 •

Copy link
Copy Markdown
Member

Summary

Scope call_streaming_with_timeout to receipt of the reply handle, as its contract states. The streamed body now uses a per-chunk idle deadline from StreamLimits, so a progressing transfer may exceed the handle timeout while a stalled sender still fails.

Validation

  • cargo fmt --all -- --check
  • cargo test -p tinybus a_streamed_reply -- --nocapture (3 passed)
  • cargo test --workspace --all-features --quiet (all passed)

Context

CodeRabbit raised the same source-level issue on the OpenHuman module refresh PRs for TinyJuice, TinyMCP, TinyRuntime, and TinyWallet. Those repositories will advance their TinyBus gitlinks after this lands.

Summary by CodeRabbit

  • Improvements
    • Streaming replies can continue beyond the overall call deadline when data keeps arriving, so active streams are not cut off prematurely.
    • Reads now fail with a stream-idle error if no data arrives within the configured idle limit, instead of waiting indefinitely. This preserves protection against stalled streams while allowing ongoing streams more time to complete.

@coderabbitai

coderabbitai Bot commented Sep 24, 2026

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 10a43573-d8c4-40dd-97d9-55d32d6b5bef

📥 Commits

Reviewing files that changed from the base of the PR and between b436e09 and 4c02dbd.

📒 Files selected for processing (2)
  • crates/tinybus/src/connection.rs
  • crates/tinybus/src/stream/mod.rs
 _____________________________________________________________________________________________________
< Write code that writes code. Code generators increase your productivity and help avoid duplication. >
 -----------------------------------------------------------------------------------------------------
  \
   \   (\__/)
       (•ㅅ•)
       /   づ

Comment @coderabbitai help to get the list of available commands.

@tinysweeper

tinysweeper Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Tiny Sweeper review

Tiny Sweeper reviewed this change across 6 lane(s) and found 3 active actionable finding(s). Detailed lane evidence and any incomplete work are listed below.

State: Changes requested
Priority: high
Reviewed head: 4c02dbd4c5a6
Updated: 1790269497 (Unix time)

Review snapshot

Change surface Files Review signal Count
Production 2 Active findings 3
Tests 0 Noted findings 0
Documentation 0 Resolved findings 0
Configuration 0 Pending checks/questions 0

Completeness: Complete
Test assessment: No supported feature-to-test mapping was available; this does not mean tests are absent or passed.

What changed

The review could not produce a supported behavioral summary; inspect the cited changed surface and lane details below.

Features

None identified with supported citations.

Tests

No supported feature-to-test mapping was produced. Test execution is not inferred.

Findings

  • medium · critique · Retain an absolute deadline for streamed replies — This awaits the entire streamed response using only `StreamReader`'s per-read idle timeout. A peer can send a small chunk just before each idle timeout and keep the call alive inde (crates/tinybus/src/connection\.rs:993)
  • high · security · Preserve the overall deadline for streamed replies — This removes the caller-supplied call deadline from streamed-reply consumption. `read_to_end_capped` can continue returning chunks indefinitely, and the per-read idle timeout reset (crates/tinybus/src/connection\.rs:993)
  • medium · security · Use deterministic synchronization instead of sleeping — This test uses a fixed sleep to coordinate the delayed writer, which violates the repository rule against sleep-based synchronization and can become flaky under scheduler or CI loa (crates/tinybus/src/connection\.rs:1428)

Before merge

  • Address Preserve the overall deadline for streamed replies (crates/tinybus/src/connection\.rs).

How this fits together

flowchart LR
  n0["Connection<br/>changed<br/>3 findings"]:::blocking
  n1["StreamLimits<br/>changed"]:::changed
  n2["StreamRegistry<br/>changed"]:::changed
  n3["StreamWriter<br/>changed"]:::changed
  n4["new"]:::impacted
  n5["Err"]:::impacted
  n6["send_streamed_reply"]:::impacted
  n7["open"]:::impacted
  n8["write"]:::impacted
  n9["pair"]:::impacted
  n2 -->|uses| n1
  n3 -->|uses| n0
  n6 -->|uses| n0
  n6 -->|calls| n4
  n7 -->|calls| n5
  n8 -->|calls| n5
  n9 -->|uses| n0
  n9 -->|calls| n4
  n9 -->|tests| n4
  classDef changed fill:#0d4429,stroke:#238636,color:#e6edf3
  classDef impacted fill:#161b22,stroke:#6e7681,color:#c9d1d9
  classDef flagged fill:#5a1e02,stroke:#d93f0b,color:#ffffff
  classDef blocking fill:#67060c,stroke:#f85149,color:#ffffff
Loading
Agent review details

critique

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: The change correctly makes streamed reads fail when no progress occurs, but it removes the call's absolute deadline and leaves the overall streamed operation potentially unbounded. It is not safe to merge without retaining an absolute deadline in addition to the idle-progress timeout. (1 observation(s) grouped into shared inline comments) _The code index is behind this pull request (indexed at `5a0ae736132d`), so retrieved context may be out of date._ _Memory was unavailable (model: cortex: v1/recall: timed out after 10s), so this review ran without it._
  • Evidence: crates/tinybus/src/connection\.rs — Retain an absolute deadline for streamed replies

security

  • Conclusion: Failure
  • Scope reviewed: all assigned evidence
  • Lane summary: The change removes the overall deadline from streamed replies and replaces it with only an inactivity timeout. This allows a peer to keep a call alive indefinitely by sending periodic chunks, so it is not safe to merge under the repository's mandatory-deadline rule. (1 finding added by a second pass) _The code index is behind this pull request (indexed at `5a0ae736132d`), so retrieved context may be out of date._ _Memory was unavailable (model: cortex: v1/recall: timed out after 10s), so this review ran without it._
  • Evidence: crates/tinybus/src/connection\.rs — Preserve the overall deadline for streamed replies
  • Evidence: crates/tinybus/src/connection\.rs — Use deterministic synchronization instead of sleeping

tests

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: Removes the total timeout on streamed reply reads, relying instead on the per-chunk idle timeout added to `StreamReader::next_chunk`. This allows a reply to progress past the call's original deadline while still bounding waits on a stalled sender. Added tests cover both successful continued reads and per-chunk timeout errors. The change is consistent with the repository's concurrency rules and is well-tested. _The code index is behind this pull request (indexed at `5a0ae736132d`), so retrieved context may be out of date._ _Memory was unavailable (model: cortex: v1/recall: timed out after 10s), so this review ran without it._

commits

  • Conclusion: Neutral
  • Scope reviewed: all assigned evidence
  • Lane summary: Nothing sensitive found in what this pull request commits.

description

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: Change moves the streaming reply timeout from call-level to per-chunk idle timeout from StreamLimits, allowing progressing streams to continue beyond the original deadline while still timing out stalled ones. Tests verify both cases; code adheres to repository rules. Merge safe. _The code index is behind this pull request (indexed at `5a0ae736132d`), so retrieved context may be out of date._ _Memory was unavailable (model: cortex: v1/recall: timed out after 10s), so this review ran without it._

e2e

  • Conclusion: Neutral
  • Scope reviewed: all assigned evidence
  • Lane summary: No end-to-end harness in this repository: no e2e test files and no e2e workflow.
Evidence and run details
  • Models: ladder/vectors, gpt-5.6-luna, deepseek-v4-flash
  • Spend: $0.004069
  • Tokens: 129415 input · 17144 output · 6024 cached · 357 embedding
Head State Pass summary
4c02dbd4c5a6 changes requested 3 active finding(s), 0 resolved finding(s) (at 1790269497)

tinysweeper 0.1.0

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes: 1 lane(s) blocking, worst finding is high.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

             $0.0041 · 129,415 in / 17,144 out · 6,024 cached (5%)  · ladder/vectors, gpt-5.6-luna, deepseek-v4-flash · 357 embedded
critique:    $0.0016 · 48,273 in  / 4,795 out  · 2,110 cached (4%)  · gpt-5.6-luna, deepseek-v4-flash
security:    $0.0017 · 58,337 in  / 3,002 out  · 1,866 cached (3%)  · gpt-5.6-luna
tests:       $0.0004 · 13,908 in  / 4,050 out  · 1,024 cached (7%)  · deepseek-v4-flash
description: $0.0002 · 5,165 in   / 3,197 out  · 1,024 cached (20%) · deepseek-v4-flash

member: MemberName::new("StreamReply").expect("literal member name is valid"),
timeout_ms: timeout.as_millis() as u64,
})??;
let bytes = reader.read_to_end_capped(limit).await?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority high security confident

Preserve the overall deadline for streamed replies

This removes the caller-supplied call deadline from streamed-reply consumption. read_to_end_capped can continue returning chunks indefinitely, and the per-read idle timeout resets after every chunk, so a peer that sends data periodically can keep the call and its resources alive without bound. Retain the overall call deadline while using the idle timeout only to detect stalled progress.


Additional critique observation

priority medium confident

Retain an absolute deadline for streamed replies

[RULE] missing-deadline

This awaits the entire streamed response using only StreamReader's per-read idle timeout. A peer can send a small chunk just before each idle timeout and keep the call alive indefinitely (for example, one byte every 19ms with a 20ms idle timeout), even though the original call deadline has elapsed. The streamed body is part of the call and must retain an absolute deadline; apply the original deadline to the full read, or carry a separate absolute deadline alongside the progress timeout.

[RULE] missing-deadline ·

.unwrap();
let stream = writer.stream_ref();
let send = tokio::spawn(async move {
tokio::time::sleep(Duration::from_millis(30)).await;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority medium security confident

Use deterministic synchronization instead of sleeping

This test uses a fixed sleep to coordinate the delayed writer, which violates the repository rule against sleep-based synchronization and can become flaky under scheduler or CI load. Coordinate the writer with an explicit in-memory signal or another awaitable synchronization primitive, and use a timeout only as the test deadline.

[RULE] no-sleep-synchronization ·

@tinysweeper tinysweeper Bot added the priority: p1 Next. Wrong behaviour a user will hit, or a security weakness behind a condition. label Sep 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: p1 Next. Wrong behaviour a user will hit, or a security weakness behind a condition.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant