fix(runtime): claim blocked select cases atomically - #180
Merged
Conversation
Signed-off-by: Christian Stewart <christian@aperture.us>
Contributor
There was a problem hiding this comment.
🔵 Needs a closer look
It changes core channel/select concurrency semantics and scheduling behavior in the runtime, which is high-impact and warrants final human verification beyond automated review.
Pull request overview
This PR fixes a race in the GoScript runtime select implementation where blocked branches could consume multiple channel values before Promise.race resolved, by claiming selection synchronously at the channel transfer point, aborting/withdrawing losing cases immediately, and preventing a select from rendezvousing with itself.
Changes:
- Extend
selectReceive/selectSendwith anonCommithook and use anAbortControllerto cancel/withdraw losing cases atomically at commit time. - Adjust channel rendezvous/wakeup scheduling to avoid extra microtask deferrals that allowed other transfers to slip in before commit.
- Add regression coverage in both runtime contract tests and the select compliance fixture (plus expected output), and document the updated
selectStatementbehavior.
File summaries
| File | Description |
|---|---|
gs/builtin/channel.ts |
Implements atomic commit for blocked select cases via onCommit + abort/withdrawal, and enforces “no self-rendezvous” within a single select. |
gs/builtin/runtime-contract.test.ts |
Adds targeted runtime contract tests covering losing-branch preservation, send withdrawal, and self-rendezvous prevention. |
tests/tests/select_statement/select_statement.go |
Extends the Go compliance fixture with concurrent send/select scenarios to detect value loss/double-consumption. |
tests/tests/select_statement/select_statement.gs.ts |
Updates the compiled TypeScript fixture to match the new Go test and validate runtime behavior end-to-end. |
tests/tests/select_statement/expected.log |
Adds the new expected compliance output line for the added test case. |
design/DESIGN.md |
Documents the updated blocked-select claiming/cancellation behavior and self-rendezvous rule. |
Review details
- Files reviewed: 5/6 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Blocked select branches could consume multiple channel values before Promise.race chose a winner. Claim selection synchronously at channel transfer, cancel losing cases before further transfers, and prevent a select from rendezvousing with itself.
Validation: 33 runtime contract tests, compiled select compliance fixture, TypeScript typecheck, and JavaScript lint pass. The formerly intermittent downstream WebKit recovery test passes 50 repetitions in Chromium and WebKit. Go lint could not read the installed Go 1.27 export format; its binary supports an older format.