Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 55 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ jobs:
- label: floor
arg: ''
version: '10.1.0'
- label: 10.3.1 (newest)
arg: '-p:OrleansVersion=10.3.1'
version: '10.3.1'
- label: 10.4.2 (newest)
arg: '-p:OrleansVersion=10.4.2'
version: '10.4.2'
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
# The SDK is PINNED, not floated. FSharp.Control.TaskSeq 1.1.1 implements the dynamic
Expand Down Expand Up @@ -132,8 +132,8 @@ jobs:
include:
- label: floor
arg: ''
- label: 10.3.1 (newest)
arg: '-p:OrleansVersion=10.3.1'
- label: 10.4.2 (newest)
arg: '-p:OrleansVersion=10.4.2'
services:
redis:
image: redis:7-alpine
Expand Down Expand Up @@ -393,7 +393,7 @@ jobs:
if [[ "$GITHUB_REF" == refs/tags/v5.* ]]; then
candidate="${GITHUB_REF_NAME#v}"
else
candidate="5.0.0-ci.${GITHUB_RUN_ID}.${GITHUB_RUN_ATTEMPT}"
candidate="5.0.2-ci.${GITHUB_RUN_ID}.${GITHUB_RUN_ATTEMPT}"
fi
echo "version=$candidate" >> "$GITHUB_OUTPUT"
echo "Release candidate: $candidate"
Expand Down Expand Up @@ -460,6 +460,55 @@ jobs:
--no-build \
--no-restore | tee "$RUNNER_TEMP/template-smoke.out"
python3 scripts/check-template-smoke.py "$RUNNER_TEMP/template-smoke.out"
- name: Run the same floor-built packages on newest Orleans
timeout-minutes: 5
env:
NEWEST_ORLEANS_VERSION: '10.4.2'
shell: bash
run: |
set -o pipefail
# Upgrade only the generated application. Its Orleans.FSharp dependencies remain the
# exact nupkgs packed above against the floor, not ProjectReferences rebuilt for newest.
python3 - <<'PY'
import json
import os
from pathlib import Path
import subprocess

root = Path(os.environ["RUNNER_TEMP"]) / "template-smoke"
project = root / "src/TemplateSmoke.Silo/TemplateSmoke.Silo.fsproj"
assets = json.loads((project.parent / "obj/project.assets.json").read_text())
packages = sorted({key.split("/")[0] for key in assets["libraries"]
if key.startswith("Microsoft.Orleans.")})
if not packages:
raise SystemExit("No Orleans dependencies discovered in the package consumer")
for package in packages:
subprocess.run(["dotnet", "add", str(project), "package", package,
"--version", os.environ["NEWEST_ORLEANS_VERSION"],
"--no-restore"], check=True)
PY
dotnet restore "$RUNNER_TEMP/template-smoke/TemplateSmoke.sln" \
--source "$RUNNER_TEMP/nupkgs" --source https://api.nuget.org/v3/index.json
dotnet build "$RUNNER_TEMP/template-smoke/TemplateSmoke.sln" \
--configuration Release --no-restore --verbosity minimal
# Do not accept a successful run which silently resolved a mixed/older Orleans set.
python3 - <<'PY'
import json
import os
from pathlib import Path

root = Path(os.environ["RUNNER_TEMP"]) / "template-smoke/src/TemplateSmoke.Silo/obj"
assets = json.loads((root / "project.assets.json").read_text())
expected = os.environ["NEWEST_ORLEANS_VERSION"]
wrong = [key for key in assets["libraries"]
if key.startswith("Microsoft.Orleans.") and key.rsplit("/", 1)[1] != expected]
if wrong:
raise SystemExit(f"Unexpected Orleans runtime resolution: {wrong}")
PY
dotnet run \
--project "$RUNNER_TEMP/template-smoke/src/TemplateSmoke.Silo/TemplateSmoke.Silo.fsproj" \
--configuration Release --no-build --no-restore | tee "$RUNNER_TEMP/template-newest.out"
python3 scripts/check-template-smoke.py "$RUNNER_TEMP/template-newest.out"
- name: Run the packed F# analyzer in its matching CLI host
run: |
python3 scripts/test-analyzer-package-report.py
Expand Down
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,28 @@

## [Unreleased]

### Fixed

- Align all seven fixed-transport and observer deep copiers with Orleans 10.4's nullable input
contract. Preserve the Orleans 10.1.0 minimum and existing wire format.
- Upgrade build-only SourceLink tooling from 8.0.0 to 10.0.403, removing the Git task affected by
CVE-2026-62900 without disabling NuGet auditing.
- Refresh the documentation site's compatible dependency lockfile to resolve nine reported
vulnerabilities, without a framework major-version change.
- Resolve the Dashboard 10.4.2 OpenTelemetry.Api dependency without a central downgrade.

### Changed

- Move the newest Orleans CI and Redis-durability matrix legs to 10.4.2.
- Compare stream checkpoint resumption with a native Orleans control, preserving the 10.4.2
inclusive replay behavior instead of asserting the older runtime's exclusive boundary.
- Strengthen retry, state-machine, persistence-codec, key-isolation, deactivation, and recovery
tests. Characterize TaskSeq wrappers using complete sequences, including empty and singleton
streams, while retaining strict direct-delivery and disposal checks.
- Document Orleans 10.4 upgrade boundaries and useful future helpers. TaskSeq remains 1.1.1 and
SDK 10.0.201 stays pinned: no stable TaskSeq fix or stable SDK containing the compiler backport
has been verified. DurableGrain and Durable Jobs remain deferred prereleases.

## [5.0.1] - 2026-09-07

### Fixed
Expand Down
10 changes: 6 additions & 4 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@
<PackageVersion Include="Microsoft.Orleans.Clustering.Redis" Version="$(OrleansVersion)" />
<PackageVersion Include="Microsoft.Orleans.Persistence.Redis" Version="$(OrleansVersion)" />
<PackageVersion Include="Microsoft.Orleans.Persistence.Memory" Version="$(OrleansVersion)" />
<!-- Dashboard 10.1.0 depends on vulnerable OpenTelemetry.Api 1.15.0, while
Dashboard 10.2.2 and later require >= 1.16.0. Keep one patched version for both. -->
<PackageVersion Include="OpenTelemetry.Api" Version="1.16.0" />
<!-- Patch Dashboard 10.1's vulnerable 1.15 dependency without downgrading the
OpenTelemetry 1.18 dependency required by Dashboard 10.4.2. -->
<PackageVersion Include="OpenTelemetry.Api" Version="1.18.0" />

<!-- Microsoft.Extensions / ASP.NET Core
Previously floated at 10.*; reconciled to highest 10.x in local cache. -->
Expand Down Expand Up @@ -85,7 +85,9 @@
<PackageVersion Include="Fable.Remoting.AspNetCore" Version="2.43.0" />

<!-- Build-time tooling (referenced from Directory.Build.targets with PrivateAssets="All") -->
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
<!-- SourceLink 8.0.0 pulls Microsoft.Build.Tasks.Git affected by CVE-2026-62900.
This is build-time tooling only; it does not change the consumer SDK or Orleans floor. -->
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="10.0.403" />
<PackageVersion Include="MinVer" Version="6.1.0" />
</ItemGroup>
</Project>
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
[![NuGet](https://img.shields.io/nuget/v/Orleans.FSharp.svg)](https://www.nuget.org/packages/Orleans.FSharp)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![.NET 10](https://img.shields.io/badge/.NET-10.0-512BD4)](https://dotnet.microsoft.com/)
[![Orleans 10](https://img.shields.io/badge/Orleans-10.1.0%20%E2%80%93%2010.3.1-blue)](https://learn.microsoft.com/dotnet/orleans/)
[![Orleans 10](https://img.shields.io/badge/Orleans-10.1.0%20%E2%80%93%2010.4.2-blue)](https://learn.microsoft.com/dotnet/orleans/)
[![F#](https://img.shields.io/badge/F%23-9%2B-378BBA)](https://fsharp.org/)

Orleans.FSharp keeps the Microsoft Orleans runtime and gives it an F#-first authoring model:
Expand All @@ -26,6 +26,9 @@ This README documents **Orleans.FSharp 5.0.1**, the current stable release. Appl
from 4.x should review the [breaking changes](CHANGELOG.md#500---2026-09-07) and
[Legacy migration guide](docs/legacy/migration.md).

The development branch prepares **5.0.2** with an Orleans **10.4.2** compatibility target;
the minimum remains 10.1.0. See [compatibility notes](docs/compatibility.md) for the update's scope.

## Why Orleans.FSharp?

- **F# APIs stay F#.** A grain surface is a typed record of functions using records,
Expand Down
68 changes: 63 additions & 5 deletions docs/compatibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

**Supported version policy, verified runtimes, and relevant changes in new Orleans releases.**

This page describes framework compatibility for Orleans.FSharp 5.0.1, the current published stable
release. See [Release and Production Status](release-status.md) for production boundaries.
This page describes the upcoming Orleans.FSharp 5.0.2 compatibility update. The current published
stable release is still 5.0.1; the 10.4.2 source-compatibility changes below belong to the update,
not retroactively to that release. See [Release and Production Status](release-status.md).

## Version policy

Expand All @@ -16,11 +17,63 @@ current event-sourcing surface uses `JournaledGrain.ClearLogAsync`, which is abs
|---|---|---|
| 10.0.x | Not supported | Missing an API required by the current Orleans.FSharp assemblies |
| 10.1.0 | Supported floor | The version used to compile packages and one end of the CI matrix |
| 10.3.1 | Latest stable Orleans release | The newest-version compatibility target |
| 10.3.1 | Previous compatibility target | Covered by the 5.0.1 release checks |
| 10.4.2 | Latest stable Orleans release as of 1 November 2026 | The newest-version compatibility target for 5.0.2 |

The package floor should move only when Orleans.FSharp starts using a newer Orleans API. A new
Orleans release alone is not a reason to force every consumer to upgrade.

## What changed in Orleans 10.4

Target **10.4.2**, including the servicing fixes after 10.4.0. The official notes for
[10.4.0](https://github.com/dotnet/orleans/releases/tag/v10.4.0),
[10.4.1](https://github.com/dotnet/orleans/releases/tag/v10.4.1), and
[10.4.2](https://github.com/dotnet/orleans/releases/tag/v10.4.2) describe several changes relevant
to functional grains:

- Read-only request isolation, timer scheduling, and queued-request handling during activation
migration/retirement were corrected. Applications inherit these fixes from their Orleans runtime.
- Serializer type-authorization checks were hardened. ADO.NET streaming redelivery and Azure
membership interoperability also received fixes; the latter providers still need their own
application-level upgrade checks.
- `IDeepCopier<T>` now describes nullable input explicitly. Seven hand-written Orleans.FSharp
transport/observer copiers are aligned with that contract in 5.0.2, including direct null-input
regression tests. This changes nullable annotations, not transport bytes or public F# APIs.
- Explicit-token resumption of an existing memory-stream subscription now replays the checkpoint
event in our 10.4.2 tests, where 10.1.0 skipped it. The F# helpers preserve native Orleans behavior;
consumers must not depend on exclusive resumption. This corrects start-token handling in
Orleans 10.4.0's [PR #10936](https://github.com/dotnet/orleans/pull/10936), not a new F# delivery
defect. See [checkpoint replay](streaming.md#resuming-subscriptions-after-reactivation).
- The Dashboard example needs OpenTelemetry.Api 1.18.0 with Dashboard 10.4.2. The central build
dependency is updated without raising the Orleans package floor.
- RPC parameter `[Id]` values are now honored and `CancellationToken` no longer consumes a
serialized parameter ordinal. Audit application-owned C# grain interfaces before a rolling
upgrade, particularly tokens placed before other arguments. Our fixed transport places its
token last and writes the envelope with its existing explicit field ID; source inspection found
no corresponding ordinal change. This is not a blanket proof for arbitrary application interfaces.
- `SiloAddress.GetUniformHashCodes` changes its return type from an array to an immutable array.
Applications using that low-level API need a rebuild. Orleans.FSharp does not expose it as part
of its functional API.
- Request latency metrics move to `orleans-app-requests-latency`, a fractional-millisecond
histogram. Review dashboards/alerts, and apply the updated Orleans SQL scripts when using
existing SQLite storage databases.

### Useful additions, separate from this compatibility update

| Addition | How it fits Orleans.FSharp |
|---|---|
| Explicit stream subscription start: `Latest` / `EarliestAvailable` | A useful next F# helper, not added in 5.0.2. `EarliestAvailable` means the oldest retained **local queue-cache** item, not all provider history. Native 10.4 APIs are usable when the application targets that version; upgrade pulling-agent silos before enabling the feature. |
| Cancellation-aware framework operations | Evaluate helpers individually. Public stream subscribe/resume/unsubscribe still have no cancellation-token overload; cancelling only the wait can leak a subscription created later. Existing functional-call cancellation is separate. |
| Management `DeactivateGrain` | Usable through the native management grain on 10.4.1+; a dedicated F# convenience wrapper is optional. |
| New provider/cache configuration | Configure through native Orleans hosting APIs; no replacement F# configuration layer is required. |
| `Microsoft.Orleans.Journaling` / Durable Jobs | Still prerelease (`10.4.2-alpha.1`), deliberately deferred. They are not the log-consistency model wrapped by `journaledGrainFor`. |

Adding first-class start-position helpers while retaining the 10.1 floor needs an explicit
unsupported-runtime error and tests for provider defaults, retained/empty caches, batch delivery,
and subscription cleanup. Falling back silently to ordinary live delivery would hide a semantic
change. The [upstream enum contract](https://github.com/dotnet/orleans/blob/v10.4.2/src/Orleans.Streaming/Core/StreamSubscriptionStartPosition.cs)
defines the cache boundary.

## What changed in Orleans 10.3

Orleans 10.3.0 was released on 27 August 2026. Its
Expand All @@ -45,7 +98,7 @@ version-contract analyzer metadata plus tests and documentation. See its
[release notes](https://github.com/dotnet/orleans/releases/tag/v10.3.1) and
[NuGet package](https://www.nuget.org/packages/Microsoft.Orleans.Server/10.3.1).

## Newly available Orleans surface
## Orleans 10.3 additions already assessed

The release also highlights:

Expand All @@ -57,7 +110,7 @@ The release also highlights:
- incremental source generation and new Orleans application templates;
- directory, membership, and rolling-upgrade reliability improvements.

These additions fall into three different categories:
Their compatibility boundaries are:

| Category | Orleans.FSharp position |
|---|---|
Expand All @@ -76,6 +129,11 @@ The CI matrix keeps the package floor and newest stable Orleans separate. Its ne
solution and runs unit tests, functional integration tests, separate-process rolling-update tests,
stream tests, the functional sample, and the Dashboard smoke test against the selected release.

The N/N+1 rolling tests change **application** contracts and durable schemas with one Orleans
version per test run. They do not, by themselves, prove a cluster mixing Orleans 10.1 and 10.4
binaries. Rebuilding against both versions is also different from running a floor-built NuGet
package on the newer runtime; package-consumer smoke checks cover that additional boundary.

This verifies the Orleans.FSharp surface exercised by those suites. It does **not** certify every
third-party storage, clustering, or stream provider, nor does it prove that application-specific
persisted data can be rolled back without an explicit schema migration strategy. For that, follow
Expand Down
5 changes: 4 additions & 1 deletion docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ The returned value has the exact API-record type.

## Which Orleans versions are supported?

The current package range starts at Orleans 10.1.0 and is tested against both 10.1.0 and 10.3.1. A NuGet lower bound means older 10.0.x versions are not selected. See [Orleans Compatibility](compatibility.md) for release-specific notes.
The package range starts at Orleans 10.1.0. The published 5.0.1 release was tested through
10.3.1; the upcoming 5.0.2 update moves the newest compatibility target to 10.4.2 without raising
the minimum. A NuGet lower bound means older 10.0.x versions are not selected. See
[Orleans Compatibility](compatibility.md) for release-specific notes and verification boundaries.

## Does event sourcing support snapshots?

Expand Down
29 changes: 27 additions & 2 deletions docs/release-status.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ tag while planning their migration.
The runtime APIs are unchanged from 5.0.0. Version 5.0.1 corrects the packaged project template and
adds startup regression coverage to the release gate.

### Upcoming 5.0.2 update

The current branch prepares compatibility with **Orleans 10.4.2**, retaining the **10.1.0**
minimum and the existing public F# API. It aligns the transport copiers with Orleans' nullable
contract and updates build-time SourceLink tooling to remove a vulnerable Git task dependency.
Test hardening checks concrete state, retry outcomes, JSON bytes, and stream contents instead of
weaker count-only or paired round-trip assertions. This section is a candidate status, not a
claim that 5.0.2 has already been published.

See [Orleans Compatibility](compatibility.md#what-changed-in-orleans-104) for runtime changes,
upgrade caveats, and new APIs considered separately from this patch.

The Legacy archive receives no new Legacy release line, features, compatibility work, or security
fixes. New applications should use `grainContract`, `grainFor`, `journaledGrainFor`, typed API
records, and `FunctionalGrain.ref`.
Expand All @@ -44,8 +56,21 @@ initializes the grain definition and an end-to-end template process check in the
Direct enumeration of a functional streaming reply is the supported path. With
`FSharp.Control.TaskSeq` 1.1.1 on the repository's verified static resumable-code path, wrapping a
runtime-returned `IAsyncEnumerable` with `TaskSeq.map` or
`taskSeq { for item in upstream do yield item }` was measured duplicating the final item. TaskSeq
over ordinary producers such as lists, ranges, and database cursors is not affected.
`taskSeq { for item in upstream do yield item }` was measured duplicating the final item. The
repository's ordinary list/range producers do not reproduce this wrapping problem; that is not
a guarantee about every third-party async source.

As of **1 November 2026**, NuGet still publishes TaskSeq **1.1.1** and
[TaskSeq #452](https://github.com/fsprojects/FSharp.Control.TaskSeq/issues/452) remains open.
The merged reproduction-test PR is not a library fix. The F# compiler fix for Debug resumable-code
lowering was merged and [backported](https://github.com/dotnet/fsharp/pull/20692), but is not included
in stable SDK 10.0.403. The verified repository SDK remains 10.0.201; a closed compiler issue alone
is not sufficient evidence to lift that pin.

The `UpstreamBoundary` integration cases compare actual item order and contents for empty,
single-item, and longer streams. Only the exact known final duplicate is tolerated for wrappers;
direct enumeration must match exactly. Green characterization tests therefore do **not** mean
the TaskSeq defect is fixed. Delivery, cancellation, and producer disposal have separate strict tests.

When one grain relays another grain's streaming reply, return a direct delegating
`IAsyncEnumerable`/enumerator instead of using those wrapping forms. The exact pattern and the SDK
Expand Down
Loading
Loading