Repository navigation
feat: use valueTask for the feed iterator's MoveNextAsync - #41
Merged
Merged
Conversation
Contributor
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
The focused implementation preserves behavior, follows project guidance, and is covered by existing iterator and builder probes.
Review effort: Balanced
Findings: None
What changed in this PR
Replaces the feed iterator’s hand-built Task-wrapped ValueTask with the approved IcedTasks valueTask computation expression.
Changes:
- Uses
valueTaskinMoveNextAsync. - Adds IcedTasks as a library dependency.
- Documents builder-specific safety requirements and the dependency change.
| File | Description |
|---|---|
.github/copilot-instructions.md |
Defines builder-specific IcedTasks usage gates. |
CHANGELOG.md |
Records the new dependency and implementation change. |
src/Cosmos/FSharp.Azure.Cosmos.fsproj |
Adds the IcedTasks package reference. |
src/Cosmos/IterationExtensions.fs |
Converts MoveNextAsync to valueTask. |
tests/Cosmos.Tests/FSharp.Azure.Cosmos.Tests.fsproj |
Clarifies the direct probe-test dependency. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
xperiandri
force-pushed
the
feat/icedtasks
branch
from
October 3, 2026 01:38
401a582 to
4a1f4ab
Compare
xperiandri
force-pushed
the
feat/valuetask-feed-iterator
branch
from
October 3, 2026 01:38
0af1f4b to
4c87a2e
Compare
xperiandri
force-pushed
the
feat/icedtasks
branch
from
October 4, 2026 23:12
4a1f4ab to
296cc92
Compare
3 of 6 tasks
xperiandri
force-pushed
the
feat/valuetask-feed-iterator
branch
from
October 4, 2026 23:16
4c87a2e to
787df6f
Compare
valueTask for the feed iterator's MoveNextAsync
xperiandri
force-pushed
the
feat/icedtasks
branch
from
October 9, 2026 23:27
296cc92 to
f57bb2b
Compare
xperiandri
force-pushed
the
feat/valuetask-feed-iterator
branch
from
October 9, 2026 23:29
787df6f to
09f1908
Compare
xperiandri
commented
Oct 9, 2026
xperiandri
force-pushed
the
feat/valuetask-feed-iterator
branch
from
October 9, 2026 23:44
09f1908 to
a250667
Compare
FeedIteratorAsyncEnumerator.MoveNextAsync built a Task with task { } and
wrapped it in a ValueTask<bool>, the kind of hand-rolled wrapper the
coding guidelines forbid. It was kept only because library code could
not use IcedTasks yet; valueTask is now allowed, so MoveNextAsync
returns valueTask { } around the same loop.
The XML documentation of MoveNextAsync says why this is safe in Debug
as well: there the pinned SDK leaves every resumable computation
expression to its builder's dynamic implementation (dotnet/fsharp#20466),
each call builds and starts a new value, and every valueTask probe in
IcedTasksProbeTests passes in both Debug and Release.
The library now references IcedTasks, so consumers get it
(>= 0.11.10-beta001) as a transitive dependency, recorded in the
changelog. The enumerator stays hand-written: taskSeq still has no
dynamic implementation.
DisposeAsync keeps returning ValueTask.CompletedTask: it converts
nothing, and valueTaskUnit would only add a state machine around a
synchronous body. No other hand-rolled Task or ValueTask wrapper exists
in src.
The test project keeps its direct IcedTasks reference, as the probes
use IcedTasks themselves; its comment now says why.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DatabaseTestApplicationFactory implemented IAsyncDisposable.DisposeAsync
by piping a task { } into the ValueTask constructor, the kind of
hand-rolled wrapper the coding guidelines forbid. The shared test
infrastructure reached main before IcedTasks did, so it could not use
valueTaskUnit yet. Now that valueTaskUnit is allowed, DisposeAsync
returns valueTaskUnit { } around the same try/finally: the database is
still deleted with the TestContext token read at cleanup time, and the
client is still disposed when that cleanup throws.
It is safe in Debug as well: every valueTaskUnit probe in
IcedTasksProbeTests passes in both Debug and Release, and each call of
DisposeAsync builds and starts a new value, so the dynamic
implementation that Debug builds fall back to (dotnet/fsharp#20466)
never starts one value twice.
The infrastructure project references IcedTasks directly, as it does
Microsoft.Azure.Cosmos, although the library brings it in transitively:
the fixtures use it themselves and must not depend on what the library
happens to reference. No other Task wrapped into a ValueTask is left in
the repository. The AsTask () in IterationExtensionsUnitTests is no
round-trip: it converts the ValueTask<bool> of MoveNextAsync once into
the Task of the Func<Task> that Assert.ThrowsExactlyAsync takes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The documentation of FeedIteratorAsyncEnumerator and of FeedIteratorAsyncEnumerable.GetAsyncEnumerator named the taskSeq builder in <c> tags and the token type in plain words. The contributor guidance keeps <c> for literal values and refers to types and members through <see cref>, so both now do, as the rest of the file already does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
xperiandri
force-pushed
the
feat/valuetask-feed-iterator
branch
from
October 9, 2026 23:44
a250667 to
2d0970e
Compare
xperiandri
added a commit
that referenced
this pull request
Oct 10, 2026
Our TheAngryByrd/IcedTasks#67 fixed the multi-start defect the Phase 0 probes found and shipped in IcedTasks 0.11.10-beta001. With it every probe passes in Debug and Release, so the gate now covers valueTask, valueTaskUnit, cancellableTask and cancellableValueTask, and the risk is resolved except for the prerelease dependency, recorded as an open point: a stable release of this library waits for IcedTasks 0.11.10. The execution section no longer says that Phase 0 did not reach the gate: it names the builders the gate allows and records that #41 converted both hand-rolled wrappers. The Phase 0 result describes the 0.11.9 outcome in the past tense and counts the 30 probes over the four builders they cover; there are no coldTask probes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
xperiandri
added a commit
that referenced
this pull request
Oct 10, 2026
Our TheAngryByrd/IcedTasks#67 fixed the multi-start defect the Phase 0 probes found and shipped in IcedTasks 0.11.10-beta001. With it every probe passes in Debug and Release, so the gate now covers valueTask, valueTaskUnit, cancellableTask and cancellableValueTask, and the risk is resolved except for the prerelease dependency, recorded as an open point: a stable release of this library waits for IcedTasks 0.11.10. The execution section no longer says that Phase 0 did not reach the gate: it names the builders the gate allows and records that #41 converted both hand-rolled wrappers. The Phase 0 result describes the 0.11.9 outcome in the past tense and counts the 30 probes over the four builders they cover; there are no coldTask probes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
xperiandri
added a commit
that referenced
this pull request
Oct 10, 2026
Our TheAngryByrd/IcedTasks#67 fixed the multi-start defect the Phase 0 probes found and shipped in IcedTasks 0.11.10-beta001. With it every probe passes in Debug and Release, so the gate now covers valueTask, valueTaskUnit, cancellableTask and cancellableValueTask, and the risk is resolved except for the prerelease dependency, recorded as an open point: a stable release of this library waits for IcedTasks 0.11.10. The execution section no longer says that Phase 0 did not reach the gate: it names the builders the gate allows and records that #41 converted both hand-rolled wrappers. The Phase 0 result describes the 0.11.9 outcome in the past tense and counts the 30 probes over the four builders they cover; there are no coldTask probes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
xperiandri
added a commit
that referenced
this pull request
Oct 10, 2026
Our TheAngryByrd/IcedTasks#67 fixed the multi-start defect the Phase 0 probes found and shipped in IcedTasks 0.11.10-beta001. With it every probe passes in Debug and Release, so the gate now covers valueTask, valueTaskUnit, cancellableTask and cancellableValueTask, and the risk is resolved except for the prerelease dependency, recorded as an open point: a stable release of this library waits for IcedTasks 0.11.10. The execution section no longer says that Phase 0 did not reach the gate: it names the builders the gate allows and records that #41 converted both hand-rolled wrappers. The Phase 0 result describes the 0.11.9 outcome in the past tense and counts the 30 probes over the four builders they cover; there are no coldTask probes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
xperiandri
added a commit
that referenced
this pull request
Oct 11, 2026
Our TheAngryByrd/IcedTasks#67 fixed the multi-start defect the Phase 0 probes found and shipped in IcedTasks 0.11.10-beta001. With it every probe passes in Debug and Release, so the gate now covers valueTask, valueTaskUnit, cancellableTask and cancellableValueTask, and the risk is resolved except for the prerelease dependency, recorded as an open point: a stable release of this library waits for IcedTasks 0.11.10. The execution section no longer says that Phase 0 did not reach the gate: it names the builders the gate allows and records that #41 converted both hand-rolled wrappers. The Phase 0 result describes the 0.11.9 outcome in the past tense and counts the 30 probes over the four builders they cover; there are no coldTask probes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
xperiandri
added a commit
that referenced
this pull request
Oct 11, 2026
Our TheAngryByrd/IcedTasks#67 fixed the multi-start defect the Phase 0 probes found and shipped in IcedTasks 0.11.10-beta001. With it every probe passes in Debug and Release, so the gate now covers valueTask, valueTaskUnit, cancellableTask and cancellableValueTask, and the risk is resolved except for the prerelease dependency, recorded as an open point: a stable release of this library waits for IcedTasks 0.11.10. The execution section no longer says that Phase 0 did not reach the gate: it names the builders the gate allows and records that #41 converted both hand-rolled wrappers. The Phase 0 result describes the 0.11.9 outcome in the past tense and counts the 30 probes over the four builders they cover; there are no coldTask probes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Proposed Changes
The first use of IcedTasks in library code. #40, now merged, added IcedTasks 0.11.10-beta001 and the tests that check its builders in Debug and Release (the probes); every probe of
valueTask,valueTaskUnit,cancellableTaskandcancellableValueTaskpasses, so the gate in.github/copilot-instructions.mdallows these builders.feat: use valueTask for the feed iterator's MoveNextAsync:FeedIteratorAsyncEnumerator.MoveNextAsyncbuilt aTaskwithtask { }and wrapped it in aValueTask<bool>, a hand-rolled wrapper the coding guidelines forbid. It now usesvalueTask { }around the same loop. The enumerator itself stays hand-written, becausetaskSeqstill has no dynamic implementation. The XML documentation ofMoveNextAsyncsays why this is safe in Debug builds. The package now depends on IcedTasks (>= 0.11.10-beta001), recorded in the CHANGELOG.refactor: use valueTaskUnit for the test fixture's DisposeAsync: thetask { } |> ValueTaskwrapper inDisposeAsyncoftests/Cosmos.Tests.InfrastructurebecomesvalueTaskUnit { }. The infrastructure project references IcedTasks directly.docs: reference taskSeq through see cref in the feed iterator docs: the documentation ofFeedIteratorAsyncEnumeratorand ofFeedIteratorAsyncEnumerable.GetAsyncEnumeratornamed thetaskSeqbuilder in<c>tags and the token type in plain words; it now refers to both through<see cref>, as the rest of the file does.Types of changes
Internal change; the public API is unchanged. The package gains the IcedTasks dependency.
Checklist
Further comments
Behaviour: a check harness compared the old
taskwrapper, the newvalueTaskversion and the built library over these cases, in Debug and Release:All transcripts were identical, and allocation per synchronously completing call is unchanged.
Tests without the emulator on the current head (category
Unit, all 30 probes included): Debug 77/77 and Release 77/77. The full emulator suite last ran before the latest rebase and documentation changes, at the default parallelism: Debug 185/185 and Release 185/185, none skipped; the library and test-infrastructure code it ran are unchanged since. Every commit builds in Release with the same 19 warnings asmain; Fantomas is clean.dotnet packreports NU5104: a stable package should not depend on the prerelease IcedTasks 0.11.10-beta001. It is a warning, and CI packages are prereleases themselves. A stable release of this package should wait for IcedTasks 0.11.10 stable.🤖 Generated with Claude Code