Skip to content

fix(wr-agent): refuse a session list whose frame would overflow its envelope - #247

Merged
joelmoss merged 2 commits into
masterfrom
fix/agent-session-list-envelope-cap
Sep 30, 2026
Merged

joelmoss merged 2 commits into
masterfrom
fix/agent-session-list-envelope-cap

Conversation

@joelmoss

@joelmoss joelmoss commented Sep 26, 2026 •

Copy link
Copy Markdown
Owner

🤖 Left by Claude Code

Fixes #246. Part of #154 (Phase 3 follow-ups).

What changes

list_reply checked an encoded session list against the frame cap only (MAX_PAYLOAD_SIZE, 1 MiB). dispatch then wraps the frame in an envelope. The frame's 5-byte header counts against the envelope's own 1 MiB cap. So a list between 1 MiB − 4 and 1 MiB bytes passed list_reply and then tripped the assert in Envelope::encode. That assert panicked the thread serving the connection. Since #245, that connection is the app's shared service connection to a host, so the panic also ended its VCS, File, Status and Forward traffic.

The list is now capped at MAX_PAYLOAD_SIZE.min(MAX_ENVELOPE_PAYLOAD - HEADER_SIZE). The two caps are equal today, and taking the smaller one keeps the check right if either cap changes. List is the only reply on that path whose size has no fixed bound: output and repaints are chunked, and hand-off reasons are truncated. So this one check covers every caller.

The largest reply now allowed is an envelope of exactly 1 MiB. Both decoders accept that: the Rust one rejects only length > MAX_ENVELOPE_PAYLOAD, and the app's Swift decoder accepts length <= 1 << 20.

Test

an_oversized_session_list_is_refused_rather_than_panicking now wraps each reply in an envelope, the way dispatch sends it. It checks these sizes:

  • 1 MiB − 5 bytes: accepted.
  • 1 MiB − 4 bytes: refused.
  • Exactly 1 MiB: refused. This size panicked before the fix.
  • 1 MiB + 1 bytes: refused.

Before the fix, the updated test failed with the reported panic: envelope payload 1048577 exceeds the 1048576-byte cap.

Validation

  • cargo test -p wr-agent: all pass (266 unit tests, plus the integration suites). Run outside the command sandbox, because the sandbox blocks forkpty.
  • cargo fmt --all -- --check: clean.
  • cargo clippy --workspace --all-targets -- -D warnings: clean.
  • cargo clippy -p wr-agent --features terminal-state --all-targets -- -D warnings: clean.

No Swift or app changes.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Session-list replies now respect both protocol size limits, including the space required to package a reply in an envelope. Lists within the supported maximum continue to work, including those at the exact limit. Lists that exceed it return a clear failure instead of producing an oversized reply.

@coderabbitai

coderabbitai Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

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

Note

Repository guideline files applied to this review (1)
AGENTS.md — auto-discovered

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 1a1f9175-07f0-4f7e-90aa-2ffa2a14b3bd

📥 Commits

Reviewing files that changed from the base of the PR and between a67c022 and 336c51b.

📒 Files selected for processing (1)
  • vcs/crates/wr-agent/src/serve.rs

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

list_reply now limits session-list replies to the smaller of the frame payload cap and the envelope payload cap after accounting for the frame header. The test checks replies at the boundary and above the limits by encoding them in envelopes.

Changes

Session-list reply limits

Layer / File(s) Summary
Apply and test reply size limits
vcs/crates/wr-agent/src/serve.rs
list_reply rejects payloads above the effective frame and envelope limit and reports that limit in its failure message. The test encodes replies in envelopes and checks the boundary and oversized cases.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to 336c5

Session-list replies are bounded by both protocol limits, with tests covering the encoded boundary. No material merge risk is identified.

Architecture Summary

Architecture risk: 🔵 Low · up to 336c5

The change affects 1 system.

Changed systems: vcs

Architecture concerns
No architecture-level concerns identified.

Review details

Systems and components

  • observed — vcs (service) was modified; 1 changed file maps to changed impact.

Before / after behavior

  • observed — Modified behavior in vcs/crates/wr-agent/src/serve.rs: The protocol imports now include MAX_ENVELOPE_PAYLOAD and HEADER_SIZE, used alongside the existing frame payload limit.
  • observed — Modified behavior in vcs/crates/wr-agent/src/serve.rs: list_reply now computes the reply cap as the smaller of the frame payload limit and the envelope payload space remaining after the frame header. Payloads exceeding that cap return a failure reporting the effective reply cap; previously, only the frame cap was checked and reported.
  • observed — Modified behavior in vcs/crates/wr-agent/src/serve.rs: The oversized-list test now encodes each candidate reply as both a frame and an envelope, checks the empty and exact-effective-cap payloads succeed, and checks one byte over the cap fails. It also verifies failure at MAX_PAYLOAD_SIZE when that exceeds the effective cap, plus failure above the frame cap; the previous test checked only an empty list and a payload one byte over the frame cap.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: preventing session-list frames from exceeding the envelope size limit.
Linked Issues check ✅ Passed Issue #246 requires refusal before envelope encoding when the session-list frame exceeds the envelope cap. list_reply now uses the smaller of MAX_PAYLOAD_SIZE and `MAX_ENVELOPE_PAYLOAD - HEADER_SI…
Out of Scope Changes check ✅ Passed The change is limited to vcs/crates/wr-agent/src/serve.rs. The size calculation, refusal behavior, and regression test directly support issue #246. No unrelated change is demonstrated.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 1 files.
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@joelmoss joelmoss mentioned this pull request Sep 26, 2026
20 of 21 tasks
@greptile-apps

greptile-apps Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 4/5

[Medium risk] Adds overflow check to session list replies.

The PR appears safe to merge; the remaining concern is a non-blocking, brittle regression test.

Fix All in Claude CodeFindings

  1. P2 Boundary test assumes fixed cap order ▶
Fix with agent prompt
### Issue 1
vcs/crates/wr-agent/src/serve.rs:1031-1040
The production check uses the smaller of the frame and envelope limits, but these assertions assume the envelope limit is always smaller. If the frame limit becomes smaller, the test will fail even though `list_reply` still behaves correctly. Testing acceptance and refusal around the computed minimum would keep this regression test useful when either limit changes.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

The PR caps session-list replies at the smaller of the frame limit and the space available inside an envelope, preventing an oversized reply from panicking the connection thread. It also extends the regression test to encode the envelope. The test’s boundary assertions should track the minimum used by the implementation.

Reviews (1) · Last reviewed commit: "fix(wr-agent): refuse a session list who..."

Comment thread vcs/crates/wr-agent/src/serve.rs Outdated
Comment on lines +1031 to +1040
assert_eq!(
sent(vec![0u8; MAX_ENVELOPE_PAYLOAD - HEADER_SIZE]),
FrameKind::Sessions
);
// And the refusal must itself be sendable, which is the whole point.
let _ = over.encode();
assert_eq!(
sent(vec![0u8; MAX_ENVELOPE_PAYLOAD - HEADER_SIZE + 1]),
FrameKind::Failure
);
assert_eq!(sent(vec![0u8; MAX_PAYLOAD_SIZE]), FrameKind::Failure);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Boundary test assumes fixed cap order

The production check uses the smaller of the frame and envelope limits, but these assertions assume the envelope limit is always smaller. If the frame limit becomes smaller, the test will fail even though list_reply still behaves correctly. Testing acceptance and refusal around the computed minimum would keep this regression test useful when either limit changes.

Prompt To Fix With AI
This is a comment left during a code review.
Path: vcs/crates/wr-agent/src/serve.rs
Line: 1031-1040

Comment:
**Boundary test assumes fixed cap order**

The production check uses the smaller of the frame and envelope limits, but these assertions assume the envelope limit is always smaller. If the frame limit becomes smaller, the test will fail even though `list_reply` still behaves correctly. Testing acceptance and refusal around the computed minimum would keep this regression test useful when either limit changes.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

🤖 Left by Claude Code

Fixed in 336c51b. The test now derives the boundary from MAX_PAYLOAD_SIZE.min(MAX_ENVELOPE_PAYLOAD - HEADER_SIZE), so it holds whichever cap is smaller. The exact-MAX_PAYLOAD_SIZE case expects a failure only when that cap exceeds the computed limit.

joelmoss and others added 2 commits September 30, 2026 23:10
…nvelope

list_reply checked the encoded list against the frame cap only. The frame's
5-byte header then pushed a list just under 1 MiB past the envelope cap, and
Envelope::encode's assert panicked the connection's thread. Cap the list at
the smaller of the frame cap and what an envelope leaves room for, and test
it the way dispatch sends it: inside an envelope.

Fixes #246

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the two caps

Greptile noted the boundary assertions assumed the envelope cap is always the smaller one.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@joelmoss
joelmoss force-pushed the fix/agent-session-list-envelope-cap branch from a67c022 to 336c51b Compare September 30, 2026 22:13
@joelmoss
joelmoss merged commit c3c3a7b into master Sep 30, 2026
14 checks passed
@joelmoss
joelmoss deleted the fix/agent-session-list-envelope-cap branch September 30, 2026 22:50
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.

wr-agent: a session list just under 1 MiB panics its connection's thread

1 participant