Skip to content

fix: empty frame closes path - #1576

Open
rvolosatovs wants to merge 13 commits into
mainfrom
fix/empty-frame-closes-path
Open

rvolosatovs wants to merge 13 commits into
mainfrom
fix/empty-frame-closes-path

Conversation

@rvolosatovs

Copy link
Copy Markdown
Member

No description provided.

An empty frame closes its path, after which no more frames may be sent on it. A pending `future` without a payload type has an empty value encoding, so its resolution is signalled by closing its path.

Assisted-by: claude:claude-opus-5-5
@rvolosatovs
rvolosatovs force-pushed the fix/empty-frame-closes-path branch from 9ec8458 to 76d1cfa Compare October 23, 2026 17:47
@rvolosatovs
rvolosatovs marked this pull request as ready for review October 23, 2026 17:47
Ingress closes the subscription of a path on an empty frame and fails on any further frame for it. `Outgoing::close` sends an empty frame, which `write_future` uses to signal the resolution of a value with an empty encoding, such as that of a `future` without a payload type.

Invocations with no parameters send just the header.

Assisted-by: claude:claude-opus-5-5
@rvolosatovs
rvolosatovs force-pushed the fix/empty-frame-closes-path branch 2 times, most recently from c453b66 to 3b4748f Compare October 23, 2026 18:05
The frame stream reader closes the channel of a path on an empty frame and stops on any further frame for it. Once their path is closed, readers return the error that stopped the frame stream reader, if any, instead of `io.ErrUnexpectedEOF`. Empty writes send no frames, `IndexWriter.ClosePath` sends an empty frame, and invocations with no parameters send just the header.

Assisted-by: claude:claude-opus-5-5
An empty frame closes its sub-stream, and any further frame for it fails the invocation. `Outgoing.write` skips empty data, and `Outgoing.close` sends an empty frame.

Assisted-by: claude:claude-opus-5-5
`Outgoing.write` no longer sends an empty frame for empty data, which is a breaking change.

Assisted-by: claude:claude-opus-5-5
Close the path of a future whose value encodes to no bytes without
skipping the deferred values of it, and construct the closed path set
with `Default`.

Assisted-by: claude:claude-opus-5-5
`Outgoing.write` no longer sends empty frames, so a future whose value
encodes to no bytes was never resolved for the peer. Close its sub-stream
instead, like the Rust implementation does.

Assisted-by: claude:claude-opus-5-5
A path closed cleanly by its peer reported `io.ErrUnexpectedEOF`, the
same as one cut off by the end of transmit, unlike the Rust `Incoming`.

Assisted-by: claude:claude-opus-5-5
`Mux.closed` held the key of every closed path until the end of the
invocation, so it grew with every element of a long stream of futures.
Track closure on the trie nodes and buffered paths instead, which are
forgotten once finished. An empty frame for a forgotten path is accepted,
like the first one.

Assisted-by: claude:claude-opus-5-5
…tream is closed

Wait for the sub-stream of a pending future before decoding its value,
so that a future whose value has an empty encoding is not resolved
before the peer closes its path.

Assisted-by: claude:claude-opus-5-5
`t.future()` describes a bare `future`, whose pending value is resolved
once its sub-stream is closed and decodes to `undefined`.

Assisted-by: claude:claude-opus-5-5
Bare `future` types are generated as `wrpc.Receiver[struct{}]`. A pending
one is resolved once its path is closed and closes its path once
resolved.

Assisted-by: claude:claude-opus-5-5
Exercise the resolution of pending bare futures in both directions across
the Rust, Go and JS implementations.

Assisted-by: claude:claude-opus-5-5
@rvolosatovs
rvolosatovs force-pushed the fix/empty-frame-closes-path branch from 3b4748f to 235ad85 Compare October 24, 2026 08:38

This branch has not been deployed

No deployments
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