Skip to content

Pin late writes on the elided TransformStream path - #7711

Merged
jasnell merged 3 commits into
mainfrom
jasnell/ts-streams-duplicate-consolidaton-3
Oct 14, 2026
Merged

jasnell merged 3 commits into
mainfrom
jasnell/ts-streams-duplicate-consolidaton-3

Conversation

@jasnell

@jasnell jasnell commented Oct 12, 2026

Copy link
Copy Markdown
Collaborator

Settle late elided TransformStream writes consistently with the standard path.

@jasnell
jasnell added this pull request to stack #7710 October 12, 2026 23:43
@jasnell
jasnell requested review from a team as code owners October 12, 2026 23:43
@ask-bonk

ask-bonk Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Since last review: 0 resolved, 0 still open, 0 new.
LGTM!


Reviewed commit: 81650bdb · github run

@codecov-commenter

codecov-commenter commented Oct 12, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 40.90%. Comparing base (88f3aef) to head (81650bd).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #7711   +/-   ##
=======================================
  Coverage   40.90%   40.90%           
=======================================
  Files         985      985           
  Lines      284215   284215           
  Branches    27545    27545           
=======================================
  Hits       116252   116252           
  Misses     151891   151891           
  Partials    16072    16072           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@guybedford guybedford left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Verified locally on the PR head: transform-ts@, transform-cpp@ and //src/wpt:streams-ts@ all pass. Commit 1 is a clean refactor and the #19/#22 pins look right. One suggestion on #23 inline.

Comment thread src/per_isolate/webstreams/transform.ts Outdated
@jasnell
jasnell force-pushed the jasnell/ts-streams-duplicate-consolidaton-3 branch from 1851b26 to 8664e6d Compare October 13, 2026 16:58
Base automatically changed from jasnell/ts-streams-duplicate-consolidaton-2 to main October 14, 2026 00:36
A transformer with no hooks takes the TypeScript implementation's
elided path, whose sink enqueues straight into the readable
controller. Pin how its writes settle in shapes the standard path
guards against, ahead of fixing the divergence:

- writeReachesSinkAfterCancelClearedAlgorithms (ledger #19) adds a
  transformer with no hooks: a write released by a read reaches the
  sink after a same-turn readable.cancel().
- writeAfterCancelSameTurn (ledger #22) writes right after
  readable.cancel(), with room in the readable. C++ and the
  TypeScript hook paths reject the write with the cancel reason.
- readableCancelInsideThrowingSize (ledger #23) has the readable
  side's size() cancel the readable and then throw. C++ fulfills
  the write; the TypeScript hook paths reject it with undefined, as
  the spec does.

The elided path rejects the first two writes at once with the
readable controller's TypeError, and the third with size()'s error.
@jasnell
jasnell force-pushed the jasnell/ts-streams-duplicate-consolidaton-3 branch from 8664e6d to e887395 Compare October 14, 2026 00:36
@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

The generated output of @cloudflare/workers-types matches the snapshot in types/generated-snapshot 🎉

A write that reached the elided path's sink after readable.cancel()
had started found the readable closed, and rejected at once with the
readable controller's TypeError. The standard path rejects it with
the writable's stored error, the cancel reason, once the cancel
settles. C++ does the same for a transformer with no hooks when the
write follows the cancel in the same turn. One such case is a pipe
whose destination errors: pipeTo() cancels the transform's readable
while a producer may still be writing.

The elided sink now checks the finish promise before it enqueues, as
the standard path checks for cleared algorithms. If a finish
operation has started, which at the sink can only be the cancel, it
waits for the finish promise and rejects with the writable's stored
error. Otherwise it enqueues through transformStreamEnqueue, as the
default transform algorithm does, in place of its own copy of the
enqueue and the backpressure mirror. A write that enqueues still
settles after two microtasks.

Enqueueing as the default transform algorithm does also settles a
write whose readable-side size() cancels the readable and then
throws as the hook paths and the spec do (ledger #23): the write
rejects with undefined, the closed readable's stored error, and the
writable is errored with size()'s error. The elided path rejected
the write with size()'s error, and the cancel errored the writable
with its reason; C++ fulfills the write. A size() that throws
without re-entering now errors the writable as the enqueue throws,
as on the standard path, not once the write has rejected.

Flip the pins: ledger #19's case with no hooks, #22 (now parity) and
#23 (now a C++ divergence only). typescript_implemented_streams is
experimental, so this needs no compatibility flag.
The elided and standard constructor paths repeated, token for token,
the writable's construction, the pull source, the readable's
construction and the expectedLength hookup. Each branch now sets up
only what differs, the controller, the algorithms and its sinkWrite,
and the pair is built once after the branch. The start step resolves
the start promise directly when there is no controller.

No behavior change: the sinkWrite bodies are unchanged, every
closure is still created in the constructor's scope, and the
strategies are read in the same order.
@jasnell
jasnell force-pushed the jasnell/ts-streams-duplicate-consolidaton-3 branch from e887395 to 81650bd Compare October 14, 2026 01:44
@jasnell
jasnell requested review from a team and guybedford October 14, 2026 11:53

@guybedford guybedford left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Re-reviewed at 81650bd. The #23 change landed as suggested, and commit 3 is a clean hoist: closure scope, strategy read order and start sequencing are unchanged. transform-ts@, transform-cpp@ and //src/wpt:streams-ts@ pass locally.

Correction to my earlier note: going through transformStreamEnqueue also adds its canCloseOrEnqueue pre-check to every elided write, not just the field read. The standard path pays the same; I don't expect it to show up next to the async sink.

@jasnell
jasnell merged commit fad4c0c into main Oct 14, 2026
50 of 56 checks passed
@jasnell
jasnell deleted the jasnell/ts-streams-duplicate-consolidaton-3 branch October 14, 2026 16:24
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.

3 participants