Skip to content

feat(Async): RunSynchronouslyImmediate#19804

Open
bartelink wants to merge 21 commits into
dotnet:mainfrom
bartelink:run-synchronously-immediate
Open

feat(Async): RunSynchronouslyImmediate#19804
bartelink wants to merge 21 commits into
dotnet:mainfrom
bartelink:run-synchronously-immediate

Conversation

@bartelink

@bartelink bartelink commented May 25, 2026

Copy link
Copy Markdown

Implements RunSynchronouslyImmediate per fsharp/fslang-suggestions#1042

See also fsharp/fslang-suggestions#1467

Heavily revises the xmldoc for RunSynchronously in order to convey the tradeoffs involved in selecting between the new and the old.

Updated RunSynchronously:
image

NEW RunSynchronouslyImmediate:
image

NOTE xmldocs are intended to convey a nuanced message as explained in detail in #19804 (comment):

  • RunSychronously is still fine and reasonable to use
  • RSI offers the following key benefit:
    • until the first suspension point, you're directly on the same call stack so:
      • a breakpoint pause in a debugger will show a clean and simple call stack as for any synchronous call
      • an exception will show a single exception trace without any nesting
  • aside: you never pay for a thread hop (slight perf benefit; potentially significant in tight loops, but you're way off the beaten path if you have strong expectations of performance from RunSynchronously)
  • aside: a stack trace for an exception from RSI has two less frames [with wierd names like AsyncResult.Commit and QueueAsyncAndWaitForResultSynchronously

Checklist

  • Test cases added
    • validate absence of thread hops
    • contrast with Async.RunSynchronously
  • xmldoc updated
    • mention RSI in RS
    • mention RS in RSI
    • mention fact SynchronizationContext is not honored in RSI
    • mention RS ensures you're on a threadpool thread
    • DONT mention RSI does not force you onto a threadpool thread - my assumption is that RS does that for esoteric reasons we don't need to bother users of RSI with?
  • Release notes entry updated

@github-actions

github-actions Bot commented May 25, 2026

Copy link
Copy Markdown
Contributor

❗ Release notes required

You can open this PR in browser to add release notes: open in github.dev


✅ Found changes and release notes in following paths:

Change path Release notes path Description
src/FSharp.Core docs/release-notes/.FSharp.Core/11.0.100.md
src/Compiler docs/release-notes/.FSharp.Compiler.Service/11.0.100.md

@bartelink bartelink force-pushed the run-synchronously-immediate branch 2 times, most recently from d6a0470 to 69e41a2 Compare May 25, 2026 22:07
@bartelink bartelink marked this pull request as ready for review May 25, 2026 22:19
@bartelink bartelink requested a review from a team as a code owner May 25, 2026 22:19
Copilot AI review requested due to automatic review settings May 25, 2026 22:19

Copilot AI 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.

Pull request overview

Adds Async.RunSynchronouslyImmediate to FSharp.Core to allow running an Async<'T> synchronously while always executing the initial step on the calling thread (aimed at improved diagnostics/stack traces in FSI/tests), with accompanying API surface updates, documentation, unit tests, and release notes.

Changes:

  • Add public API Async.RunSynchronouslyImmediate and wire it through Async primitives.
  • Add unit tests characterizing basic behavior and key differences vs Async.RunSynchronously.
  • Update FSharp.Core surface area baselines and release notes; extend XML docs for RunSynchronously/RunSynchronouslyImmediate.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncModule.fs Adds unit tests for RunSynchronouslyImmediate and contrasts with RunSynchronously.
tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl Records new public surface area entry for RunSynchronouslyImmediate.
tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl Records new public surface area entry for RunSynchronouslyImmediate.
tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl Records new public surface area entry for RunSynchronouslyImmediate.
tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl Records new public surface area entry for RunSynchronouslyImmediate.
src/FSharp.Core/async.fsi Adds XML docs for the new API and revises RunSynchronously docs to reference it.
src/FSharp.Core/async.fs Implements the new API by exposing an “immediate” synchronous runner and refactoring RunSynchronously internals.
docs/release-notes/.FSharp.Core/11.0.100.md Adds release note entry for Async.RunSynchronouslyImmediate.
Comments suppressed due to low confidence (1)

tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncModule.fs:527

  • This test uses a raw Thread but doesn’t capture exceptions from the thread body. Any unexpected exception inside the thread (including from Async.RunSynchronously) will be unhandled and may crash the test process rather than reporting a normal xUnit failure. Capture exceptions in the thread and rethrow/assert after Join.
        let t = Thread(fun () ->
            callerThreadId <- Thread.CurrentThread.ManagedThreadId
            async { runSyncThreadId <- Thread.CurrentThread.ManagedThreadId }
            |> Async.RunSynchronously
            async { immThreadId <- Thread.CurrentThread.ManagedThreadId }
            |> Async.RunSynchronouslyImmediate)

Comment thread tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncModule.fs Outdated
Comment thread src/FSharp.Core/async.fsi Outdated
Comment thread src/FSharp.Core/async.fsi Outdated
Comment thread src/FSharp.Core/async.fsi Outdated
@github-actions github-actions Bot added the AI-Tooling-Check-Scanned-Clean Tooling check: diff analyzed, no interesting infrastructure files label May 25, 2026
Comment thread src/FSharp.Core/async.fsi Outdated
Comment thread src/FSharp.Core/async.fsi Outdated
@bartelink

bartelink commented May 26, 2026

Copy link
Copy Markdown
Author

@T-Gro I've implemented as per OP of fsharp/fslang-suggestions#1042

Firstly, in a debugger context a first chance exception breakpoint has more direct causation vs having to disentangle an adjacent thread waiting, which tooling may or may not be able to convey unaided.

However, while the exception stack trace has less noise, it's not significantly better AFAICT:

image

It seems the TL;DR value prop is:

  • in a debugger breakpoint there's an obvious call stack
  • stack traces have 2/3 less noise layers
  • default perf is better as no egregious thread hops (though for many real world cases, there may be a root RunSynchronously that pays the hop price and then nested calls don't pay?)

But its not a slam dunk as:

  • potential deadlocks
  • confusion about a longstanding thing that people's fingers and thousands of tutorials had

This is making me think I should dial back the xmldoc from where I have it trying to set a "use the new RunSynchronouslyImmediate in FSI from now on" vibe (as I've tried to do with AwaitTask vs Await where it is a slam dunk)

Final stacktrace comparison:
image

cc @majocha @dsyme

Comment thread src/FSharp.Core/async.fs Outdated
@bartelink bartelink force-pushed the run-synchronously-immediate branch from 75fed30 to f9e0383 Compare May 26, 2026 15:40
Comment thread src/FSharp.Core/async.fs
@bartelink bartelink requested review from T-Gro and Copilot May 26, 2026 21:31

Copilot AI 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.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 9 comments.

Comment thread tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncModule.fs Outdated
Comment thread tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncModule.fs Outdated
Comment thread tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncModule.fs Outdated
Comment thread tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncModule.fs Outdated
Comment thread tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncModule.fs Outdated
Comment thread src/FSharp.Core/async.fsi Outdated
Comment thread src/FSharp.Core/async.fsi Outdated
Comment thread src/FSharp.Core/async.fs
Comment thread src/FSharp.Core/async.fs Outdated
Comment thread src/FSharp.Core/async.fs
/// Run the asynchronous workflow and wait for its result.
[<DebuggerHidden>]
let QueueAsyncAndWaitForResultSynchronously (token: CancellationToken) computation timeout =
let QueueAsyncAndWaitForResultSynchronously computation (token: CancellationToken) timeout =

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

can revert this, but trying to get arg order consistent across most involved functions

Comment thread src/FSharp.Core/async.fs
trampolineHolder
(fun res -> resultCell.RegisterResult(AsyncResult.Ok res, reuseThread = true))
(fun edi -> resultCell.RegisterResult(AsyncResult.Error edi, reuseThread = true))
(fun exn -> resultCell.RegisterResult(AsyncResult.Canceled exn, reuseThread = true))

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

old behavior resulting in OperationCanceledException

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.

does it change RunSynchronously implementation?

@bartelink bartelink May 27, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@majocha in the PR as it stands, the core impl of RunSynchronouslyImmediate is:
https://github.com/bartelink/fsharp/blob/013acc1fca33bdfcd6f978d531bc0c6e1e34c199/src/FSharp.Core/async.fs#L1157

  1. that new code is based on OP of Add Async.RunImmediate fsharp/fslang-suggestions#1042 (comment)
  2. RunSynchronously used to delegate to https://github.com/dotnet/fsharp/pull/19804/changes#diff-7045116fe4610c3375ffcdd7df2ee411e71879bdf25890c8d3cf047c1b5208e2L1141 where conditions allow (no thread hop required)
  3. RunSynchronously now delegates to 1

The key diff is that:

  • the old way with the ResultCell Commit would result in OperationCanceledException being observed by caller if cancellation happened during running
  • the new way is tcs.Task.GetAwaiter().GetResult(), which results in a TaskCanceledException (which, to the best of my knowledge does not provide a way to wire in the CT info)

The pros from my perspective are:

Not an easy call, which is why I'm looking for someone else to vouch for it!

Comment thread src/FSharp.Core/async.fs
computation
|> unfake

[<DebuggerHidden>]

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

moved up as required by RunSynchronously

note the whole PR could be made much shorter by having the Async layer call Async.FromContinuations

However, as mentioned in other places, I believe its for the best that RunSynchronouslyImmediate and the immediate path of RunSychronously should have strong clear ties in the lower layer as this PR does

@bartelink

Copy link
Copy Markdown
Author

The open review comments and Don's comment here fsharp/fslang-suggestions#1042 (comment) make me think:

  1. implementing RunSynchronouslyBackground (fka RunImmediateExceptOnUI) might make it easier to explain the overall set of APIs, i.e.

    RSI guarantees inline running (but also potentially introduces synccontext deadlock)
    RSB = RSI + offloads iff necessary to avoid synccontext deadlock

    But, there's only one consumer of RSB atm, so what is the cut and dried use case. i.e. what would the summary/release notes say to convey who needs this API and when?

  2. if you had RSI+RSB and leave RS as-is (changing its behavior or guarantees is presumably not tenable), what new APIs with individual orthogonal behaviors would you add with a view to having better alternatives and then effectively deprecating RS?

    • Perhaps a RunSynchronouslyTimeout with a mandatory timeout parameter?
      • runs in threadpool unconditionally
      • provides some clear semantics that resolves the puzzle of what is being achieved / silently left unhandled in
        let timeout, cancellationToken =
        match cancellationToken with
        | None -> timeout, defaultCancellationTokenSource.Token
        | Some token when not token.CanBeCanceled -> timeout, token
        | Some token -> None, token
        +
        match res with
        | None -> // timed out
        // issue cancellation signal
        if innerCTS.IsSome then
        innerCTS.Value.Cancel()
        // wait for computation to quiesce; drop result on the floor
        resultCell.TryWaitForResultSynchronously() |> ignore
        // dispose the CancellationTokenSource
        if innerCTS.IsSome then
        innerCTS.Value.Dispose()
        raise (TimeoutException())
        | Some res ->
        match innerCTS with
        | Some subSource -> subSource.Dispose()
        | None -> ()
        res.Commit()
        +
        match SynchronizationContext.Current, Thread.CurrentThread.IsThreadPoolThread, timeout with
        | null, true, None -> RunImmediate cancellationToken computation
        | _ -> QueueAsyncAndWaitForResultSynchronously cancellationToken computation timeout
      • should the API take an outer CT and/or defaults to DefaultCancellationToken?
      • what happens if the token is cancelable and you wanted a timeout?
      • can the default one not be cancelable

In general I think one PR that adds one API is a perfectly fine outcome for now, but if someone out there (@dsyme ?) has a really clear picture of all the use cases, it may be worth at least speccing out in full the orthogonal elements of what only the current impl of RunSynchronously provides that are not covered by RSI+RSB

In short, if someone is convinced that RSI + RSB and/or some complementary APIs makes it possible to deprecate and eventually move away from from a complected RunSynchronously, I'm happy to do the work, but I don't feel I understand it deeply enough atm.

@majocha

majocha commented May 27, 2026

Copy link
Copy Markdown
Contributor

FWIW my limited experience with internal RunImmediate implemented in a few places in this repo: It can cause problems in unexpected places, IIRC there were some deadlocks when trying to parallelize tests. As noted, it only improves debugger call stacks. Exception stack traces - not that much.

Comment thread src/FSharp.Core/async.fs
@T-Gro T-Gro added the AI-reviewed PR reviewed by AI review council label May 27, 2026
@T-Gro

T-Gro commented Jun 4, 2026

Copy link
Copy Markdown
Member

@bartelink :
re: RunSynchronously - Deprecating it now would be I guess too early, but maybe we can at least start with a "See also .." remark in the XML docs (which then make it to the published docs).

And consider marking it obsolete later in a separate PR.

What RunSynchronously provides is the automated decision-making based on inputs+context. Even though it can be handy when writing library code (that does not know where/how it will be run), it does go against the "Pit of success" spirit.

@bartelink

Copy link
Copy Markdown
Author

but maybe we can at least start with a "See also .." remark in the XML docs (which then make it to the published docs).

Will double check we have an xmldoc cross reference (think we do already)

I don't think it's practical to actually make RunSynchronously literally Obsolete in even the medium term (esp considering that blind replacement will lead to deadlocks, and per Murphy's Law, those will be in lots of low traffic places like try ... with handling etc.

Let me know if there's anything else to do to get this completely ready for whenever merge makes sense.

What RunSynchronously provides is the automated decision-making based on inputs+context. Even though it can be handy when writing library code (that does not know where/how it will be run), it does go against the "Pit of success" spirit.

See also fsharp/fslang-suggestions#1042 (comment) - maybe a pathway can be that there is a camelCase Async.* helper that uses RSI and shouts "pick me" for fsi/tests cases?

@bartelink bartelink force-pushed the run-synchronously-immediate branch from 013acc1 to 5074cab Compare June 5, 2026 19:25
@bartelink bartelink force-pushed the run-synchronously-immediate branch from 331b0b6 to 71c8638 Compare June 5, 2026 20:48
@bartelink bartelink force-pushed the run-synchronously-immediate branch from 71c8638 to d1c658a Compare June 5, 2026 20:50

@T-Gro T-Gro left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

one last review round

Comment thread src/FSharp.Core/async.fs Outdated
(fun edi -> tcs.SetException edi.SourceException)
// NOTE In this case, cancellation will surface as a TaskCanceledException (with CT.None) from GetResult()
// (as opposed to the OperationCanceledException that RegisterResult cancellation ends up mapping to)
(fun _operationCanceledExn -> tcs.SetCanceled())

@T-Gro T-Gro Jul 11, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This ccont also backs RunSynchronously's inline fast-path (L1175), so the token gets stripped there:

try Async.RunSynchronously(comp, cancellationToken = myTok)
with
| :? OperationCanceledException as e when e.CancellationToken = myTok -> fallback
| :? OperationCanceledException -> reraise ()
  • inline (thread-pool caller): token stripped -> reraise() -- wrong branch
  • queued (other caller): token kept -> fallback
  • same call, thread-dependent
- (fun _operationCanceledExn -> tcs.SetCanceled())
+ (fun operationCanceledExn -> tcs.SetException operationCanceledExn)

Then the test at AsyncModule.fs:470 flips: Assert.Throws<TaskCanceledException> -> Assert.Throws<OperationCanceledException>.

  • this leaves the internal tcs.Task Faulted not Canceled — invisible here (immediately GetResult()'d, only the thrown exception escapes)
  • SetCanceled(token) (keeps both) is .NET 5+, absent on ns2.0/2.1, so SetException is the only token-preserving option

@bartelink bartelink Jul 11, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

applied this change
See also clones in 8422a23 (all call sites identical, though obviously there's potential for effects from the breaking nature of the change)

see also related comment thread #19804 (comment)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

(All impls of RSI, and the RS shortcut path are now identical, and the test documenting the behavior change has become a pinning test validating that it's OperationCanceledException with the triggering token)

open Xunit
open FSharp.Test.Utilities

#if !FSHARPCORE_USE_PACKAGE // TODO For 11.x, remove shimming to rely fully on shipped FSharp.Core variant

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Guard is inverted (illib.fs defines the shim when the package lacks the member).

async { return 42 } |> Async.RunSynchronouslyImmediate  // FSHARPCORE_USE_PACKAGE=true (BUILDING_USING_DOTNET default)
  • package = shipped 10.0.101, no such member
  • shim also excluded by the ! -> FS0039
  • green CI only builds the in-repo config
-#if !FSHARPCORE_USE_PACKAGE
+#if FSHARPCORE_USE_PACKAGE

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

applied this change but it breaks MacOS build so have temporarily reinstated

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@T-Gro I have not managed to get to the bottom of this as to be honest I don't understand the full array of build scenarios.

(Not saying you don't have a point; it's just that in practice my programming-by-coincidence had a purpose!)

Bottom line is I applied it and it broke the build, and reverting it made it green

I'm happy for you to either try to resolve it by working in this branch or providing me some more suggestions

// This file mimics how Roslyn handles their compilation references for compilation testing
module Utilities =

#if !FSHARPCORE_USE_PACKAGE // TODO For 11.x, remove shimming to rely fully on shipped FSharp.Core variant

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same inverted guard as Common.fs:19 -> breaks package-mode build (FSHARPCORE_USE_PACKAGE=true, the BUILDING_USING_DOTNET default) with FS0039.

-#if !FSHARPCORE_USE_PACKAGE
+#if FSHARPCORE_USE_PACKAGE

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Applied and then reverted as per common.fs:19

Comment thread src/FSharp.Core/async.fsi
///
/// The timeout parameter is given in milliseconds. A value of -1 is equivalent to
/// <see cref="F:System.Threading.Timeout.Infinite"/>.
/// <summary><p>Runs the asynchronous computation on a threadpool thread, honoring the ambient

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

SynchronizationContext.SetSynchronizationContext ctx
async { return 1 } |> Async.RunSynchronously   // ctx.Post called 0 times; runs inline
  • "on a threadpool thread" -- false (fast-path is inline)
  • "honoring the ambient SynchronizationContext" -- false (never posts)
- /// <summary><p>Runs the asynchronous computation on a threadpool thread, honoring the ambient
- /// <see cref="T:System.Threading.SynchronizationContext"/>.</p>
+ /// <summary><p>Runs the computation and blocks the caller until it completes. Runs inline on the
+ /// calling thread when it is a thread-pool thread with no ambient SynchronizationContext and no
+ /// timeout; otherwise runs on the thread pool.</p>

@bartelink bartelink Jul 11, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Your wording feels much better (I was aware that my wording was technically not 100% correct - my aim was to emphasize the core difference vs RSI: even if you are doing something tiny, you'll incur a thread hop more often than you might expect from the name).

Also wanted to be pedantic on some specifics:

on a threadpool thread" -- false (fast-path is inline)

but fast path requires you to already be on a thread pool thread. So RunSynchronously didnt need to do a hop, but the code is run on a thread pool thread?

"honoring the ambient SynchronizationContext" -- false (never posts)

I think this is due to special casing triggered by the reuseThread = true parameter to RegisterResult (async.fs: 1004)

But I may well have missed the point you're trying to make.

Happy to apply your summary assuming all the above tallies with your understanding/intent.

Comment thread src/FSharp.Core/async.fsi
/// </p>
/// <p>Does not support a timeout; see
/// <see cref="M:Microsoft.FSharp.Control.FSharpAsync.RunSynchronously`1"/> if one is desired.</p>
/// <p>Does not ensure execution takes place on a threadpool thread; see

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

async { return 1 } |> Async.RunSynchronously   // also runs inline -- not a threadpool guarantee
  • cross-ref to RunSynchronously here implies a threadpool guarantee it doesn't provide
- /// <p>Does not ensure execution takes place on a threadpool thread; see
- /// <see cref="M:Microsoft.FSharp.Control.FSharpAsync.RunSynchronously`1"/> or
- /// <see cref="M:Microsoft.FSharp.Control.FSharpAsync.SwitchToThreadPool"/> if this is required.</p>
+ /// <p>Does not ensure execution takes place on a threadpool thread; see
+ /// <see cref="M:Microsoft.FSharp.Control.FSharpAsync.SwitchToThreadPool"/> if this is required.</p>

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

The key driver for me referring to both was to try to explain the key behavioral difference of consequence between RS and RSI in terms of other concrete methods as a pedagogical mechanism.

AIUI (but I may very well be wrong) RunSynchronously does provide this guarantee, as which:

  1. stays on current thread until the first asynchronous suspension if all these things are true:
  • the current thread is a threadpool thread
  • and SynchronizationContext.Current is null
  • and we're not trying to apply a timeout
  1. in all other cases it posts the work into the thread pool and uses the calling thread to await

Note I renamed the internal impl to RunSynchronouslyBackgroundThreadPool to try to convey the above semantics in shorthand.

All of that said, clearly my wording didn't get the point across as intended.

Hence I feel it may make more sense to reword it and/or remove it entirely as the proposed change turns it into a non-sequitur as the sentence no longer enables people to triangulate/bridge the concepts as intended?

@T-Gro

T-Gro commented Jul 11, 2026

Copy link
Copy Markdown
Member

Sorry for the late replies. Decisions:

what is the cut and dried use case [for RSB]?

It's internal-only — replace its single call site with RunSynchronously. No new API.

a camelCase Async.* helper that shouts "pick me"?

Third name is too much here, let's avoid it.

Ship RSI alone, RS unchanged + "see also". Merge-ready once the two blockers in my review land (inverted #if guard; cancellation dropping the token).

@bartelink

Copy link
Copy Markdown
Author

@T-Gro I believe this is ready for re-review; feel free to mark comment threads as resolved as you read them.

Happy to address any follow-ups later and/or tomorrow

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI-reviewed PR reviewed by AI review council AI-Tooling-Check-Scanned-Clean Tooling check: diff analyzed, no interesting infrastructure files

Projects

Status: New

Development

Successfully merging this pull request may close these issues.

4 participants