Repository navigation
[2.0] Split the SDK into Ably.PubSub.Core and Device/Server door packages - #1340
Merged
Merged
Conversation
Per PDR-091b plan decisions 5b and 6: - delete the `IO.Ably.Android` (monoandroid) and `IO.Ably.iOS` (Xamarin.iOS) platform heads. They were 30-line `Platform.cs` heads whose only functional difference from the netstandard2.0 head was reporting the agent runtime as `xamarin`, no test workflow covered them, and they are what pinned the packaging workflow to windows-2022 plus a legacy Xamarin VS installer. Classic Xamarin / .NET for Android+iOS / MAUI consumers now receive the netstandard2.0 asset. - delete the `IO.Ably.Push.Android` / `IO.Ably.Push.iOS` satellites, their nuspecs and the `package-push` scripts. `ably.io.push.android` / `ably.io.push.ios` 1.x continue from the 1.x maintenance line; a modern net8.0-android/net8.0-ios port is a post-GA 2.x follow-up. - delete the `AndroidSample` and `DotnetPush` examples (they target the removed heads and satellites; they live on in the 1.x maintenance line). - delete `IO.Ably.PackagePush.sln`, `IO.Ably.Xamarin.sln` and `IO.Ably.DotNetPush.sln`, which only existed for the removed projects, and drop the removed projects from the remaining solutions. - drop the ILRepack `_Package_Merge_All` task, the `PushPackage` target and the Xamarin build tasks from the Cake build. The ILRepack helper itself stays: `Update.AblyUnity` still uses it to build the Unity plugin assembly. - drop the Android SDK and legacy Xamarin installer steps and the whole `package-push` job from `.github/workflows/package.yml`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Per PDR-091b plan decision 2: the package/assembly identity changes, the code namespace does not. `namespace IO.Ably` and every public type name are untouched; the compiled assembly becomes `Ably.PubSub.Core.dll`. The distinct assembly name is the load-bearing half of the decision: with `IO.Ably.dll` kept, an app that transitively pulled both `ably.io` and the new core would have MSBuild pick the higher version with only an MSB3277 warning and fail at runtime. With a distinct assembly name and a shared namespace, mixing the two produces loud CS0433 compile errors instead. Moves (via `git mv`, so history follows): src/IO.Ably.NETStandard20 -> src/Ably.PubSub.Core src/IO.Ably.NETFramework -> src/Ably.PubSub.Core.NETFramework src/IO.Ably.Shared -> src/Ably.PubSub.Shared src/IO.Ably.Shared.MsgPack -> src/Ably.PubSub.Shared.MsgPack src/IO.Ably.Tests.Shared -> src/Ably.PubSub.Tests.Shared src/IO.Ably.Tests.DotNET -> src/Ably.PubSub.Tests.DotNET src/IO.Ably.Tests.NETFramework -> src/Ably.PubSub.Tests.NETFramework src/IO.Ably.sln -> src/Ably.PubSub.sln src/IO.Ably.Package.sln -> src/Ably.PubSub.Package.sln src/IO.Ably.NetStandard.sln -> src/Ably.PubSub.NetStandard.sln src/IO.Ably.NetFramework.sln -> src/Ably.PubSub.NetFramework.sln Target frameworks are unchanged: `netstandard2.0;net6.0;net7.0` plus the `net462` head (decision 5). Also updated: every project/solution/shared-project import path, the `AssemblyName` and XML documentation file names on both heads, the `InternalsVisibleTo` entries for the renamed test assemblies, `AssemblyTitle`, the Cake paths/targets and the test-assembly names they look for, and `tools/list-test-categories.fsx`. `IO.Ably.ruleset`, `IO.Ably.Tests.ruleset`, `stylecop.json` and `IO.Ably.snk` keep their names: the strong-name key must stay byte-identical and renaming the rulesets buys nothing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`ably.io` is never published from this branch again — 1.x fixes ship from the 1.x maintenance line — so `nuget/io.ably.nuspec` is deleted rather than retargeted, and `nuget/ably.pubsub.core.nuspec` takes its place. - `<id>Ably.PubSub.Core</id>`, same `$version$` token, authors/owners/license/ icon/readme/repository metadata as before, copyright year bumped to 2026. - The `<description>` states plainly that this is an internal implementation package for Ably's own `Ably.PubSub.Device` / `Ably.PubSub.Server` packages and is not intended for direct use (PDR-091b §1). NuGet consumers receive it transitively, so "internal" is a statement in metadata and docs, not something the dependency graph can enforce. - Dependency groups: netstandard2.0 / net6.0 / net7.0 / net46, each declaring Newtonsoft.Json 13.0.1 and System.Threading.Channels. The monoandroid / Xamarin.iOS / monotouch groups are gone with their heads. - The net46 assets now come from the plain build output rather than an ILRepack-merged `Packaged/` directory, hence Newtonsoft.Json is a declared net46 dependency instead of a merged-in one. - `IO.Ably.DeltaCodec.*` now needs explicit `files` entries: the old `IO.Ably.*` glob happened to pick the delta codec up, and `Ably.PubSub.Core.*` does not. `_Package_Create_NuGet` now packs a list of nuspecs so stack PR 2 can add the device and server nuspecs to it, and `package.cmd` / `package-unity.sh` no longer name `ably.io`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`Ably.PubSub.Core` starts at 2.0.0 and, from stack PR 2 on, releases in lockstep with `Ably.PubSub.Device` and `Ably.PubSub.Server`. Bump the single source of the runtime version (`src/CommonAssemblyInfo.cs`, read back by `Defaults.GetVersion()`) and the Unity package version, and move the copyright year to 2026. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The Unity package ships a single ILRepack-merged plugin assembly. Point everything that names it at the new assembly name: the `Update.AblyUnity` Cake task (input and output), `link.xml`'s `<assembly fullname>`, the `precompiledReferences` of the AblySandbox / EditMode / PlayMode asmdefs, and the `unity/CONTRIBUTING.md` note. The stale `unity/Assets/Ably/Plugins/IO.Ably.dll` is removed rather than regenerated: ILRepack needs Mono or Windows, neither of which is available in the environment this branch was prepared in, so the merged `Ably.PubSub.Core.dll` has to be produced by running `unity-plugins-updater.sh 2.0.0` (or the `.cmd`) on a machine that has Mono. The plugin's `.meta` is renamed in place so the importer settings and asset GUID survive; the regenerated dll drops straight into it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Minimal docs pass only; the full README rewrite and the migration guide are a later phase of the plan. - README: a "2.0 is in development" note at the top describing the new package set (`Ably.PubSub.Device` / `Ably.PubSub.Server` in the next PR, `Ably.PubSub.Core` internal), the unchanged `IO.Ably` namespace, the never-mix rule, and that `ably.io` 1.x continues from a maintenance branch. The "Supported platforms" table drops the Xamarin.Android/iOS/Mac rows for ".NET for Android, .NET for iOS and MAUI via netstandard2.0", and the MAUI `TrimmerRootAssembly` snippet now names `Ably.PubSub.Core`. Install and usage sections still describe 1.x and say so. - CONTRIBUTING: the "working from source" project paths, and the release-step artifact names. - cake-build/README: new project names, the `Build.Xamarin` target is gone, and the packaging section documents `package.cmd` producing `Ably.PubSub.Core.*.nupkg` from the nuspec list plus `package-unity.sh`. - PushNotifications.md: a note that it describes the 1.x push-receive packages, which are not in the 2.0 set, and that push admin is unaffected. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`IoC`'s static constructor located the platform head's `IO.Ably.Platform` type by loading an assembly literally named "IO.Ably". After the assembly rename that load throws `FileNotFoundException`, which the ctor swallows, leaving `Platform` null. Every platform service then silently degraded: the transport factory and `PlatformId` fell back (so the agent string lost its `dotnetN` / OS entries), and `IoC.MobileDevice` threw `NullReferenceException` because only `NotImplementedException` is caught there — which is what 18 `RestInitSpecs` tests hit. `Platform.cs` is compiled into the same assembly as this shared code by every head, so look the type up in this assembly instead. That is also immune to any later rename. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`FindTestAssemblies` defaults to a filename pattern, which still looked for `IO.Ably.Tests.*.dll` and so found nothing after the test assemblies were renamed. The Cake helper only warns when it finds no assemblies and the task then returns early, so the .NET Framework test legs would have gone green without running a single test. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- D9: remove the committed 1.6 MB test-results .trx artifact and ignore *.trx and test-results/ - D27: add a pinned root nuget.config (nuget.org only, with source mapping) and drop the four solutions' dangling .nuget\NuGet.Config solution item - D29: align built-against System.Threading.Channels to 4.6.0 (matching the nuspec) and System.Threading.Tasks.Extensions to 4.5.2 (matching the net46 head) - D11: document the transitive ably.io/Ably.PubSub.* mixed-graph failure (CS0433, type identity) plus the dotnet-nuget-why detection and extern alias isolation recipe - D32: replace the false "rewritten later in this stack" Installation/Usage promise with an honest before-2.0-GA sequencing note - D33: discourage the direct core AblyRealtime/AblyRest constructors in XML docs (summary one-liner plus remarks rationale), pointing at the door factories - D34: drop the stale 1.x ably.io NuGet badge from the README - D35: fix stale doc cross-references (PushNotifications.md Dart link, unity/README.md dead anchor, past-dated protocol-v1 deprecation line) - D17 (change 1): sign the net46 core head under package builds only, matching the SDK-style core - D8 (guard): fail _Package_Unity packaging when the committed Unity plugin Ably.PubSub.Device.dll is missing PubSub device/server split rollout (PDR-091b2) review follow-ups.
The core stamped `ably-dotnet/<version>` as its RSC7d1 family identifier. At the Pub/Sub package split (PDR-091b) it becomes `ably-pubsub-dotnet/<version>`, registered in ably-common#361 as a versioned `sdk` entry. The flip is the point: with the 1.x maintenance branch keeping the old identifier, the string alone partitions legacy traffic from new-package traffic, so no version correlation is needed to tell them apart. Updates the four spec files that assert on the token: the shared realtime connection-parameter specs, the shared REST HTTP client specs, and the Unity EditMode/PlayMode specs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Ports the ably-js `packages/shared/side.ts` contract (ably-js#2293,
ably-java#1233).
`src/Ably.PubSub.Side/Side.cs` is a single shared source file compiled
into both door assemblies by a `<Compile Include>` item rather than
published as a third package - the .NET analogue of ably-js's
`shared/side.ts` and ably-java's `shared/.../Side.java`. It holds both
side identifiers, with the load-bearing-suffix warning, and
`WithSideAgent`, which:
- builds a new `Agents` dictionary from the caller's entries, so the
caller's own dictionary instance is never mutated;
- applies the side entry last with a null value, so the flag is
versionless (`Agent.AddAgentIdentifier` already emits a bare token
for a null version) and wins a collision on its own key.
`PubSubServer` (`CreateRealtimeClient` / `CreateHttpClient`) and
`PubSubDevice` (`CreateClient`) each take the three shapes the core
constructors accept - key or token string, `ClientOptions`,
`Action<ClientOptions>` - and return the concrete `AblyRealtime` /
`AblyRest`. One device door by design: device-side connectionless
operations stay available on that client, so there is no device HTTP
door.
Both doors are strong-named in every configuration, so a consumer of
the signed core never mixes signed and unsigned Ably assemblies, and
both target the core's `netstandard2.0;net6.0;net7.0`. Server also gets
an old-style `net462` head mirroring the core's, so the package has a
`lib/net46` asset; there is deliberately no `net462` Device.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`ably.pubsub.device.nuspec` and `ably.pubsub.server.nuspec` carry the same authors/licence/icon/repository metadata as the core's, and each declares an exact pin on the core (`[$version$]`) per target-framework group - the NuGet analogue of ably-js's exact `peerDependencies`, so a consumer can never resolve two core versions. Server ships net46 (from its .NET Framework head), netstandard2.0, net6.0 and net7.0; Device ships the same minus net46. `_Package_Create_NuGet` packs core, then device, then server, matching the publish order stack PR 3 will need. The `[$version$]` substitution inside a dependency version attribute is marked TODO to verify on the release dry run - no nuget.exe or Mono locally to check it. Stack PR 3 adds the pre-flight that asserts the packed pin equals the version. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Thirteen specs in Ably.PubSub.Tests.DotNET/PubSub/PubSubPackageSpecs.cs.
They live in the .NET test head rather than Ably.PubSub.Tests.Shared
because Ably.PubSub.Device has no net462 asset, so the shared project
cannot reference it from the .NET Framework head.
What they pin, using the existing MockHttp/FakeHttpMessageHandler
capture for the header and the fake transport factory for the realtime
connection params, so nothing here opens a network connection:
- the `Ably-Agent` header a door-created REST client actually puts on
the wire contains the bare side flag, no versioned form of it, the
versioned `ably-pubsub-dotnet/<version>` family identifier, and not
the other side's flag;
- the same for the realtime connection params from
`TransportParams.GetParams()`;
- caller `Agents` entries survive alongside the flag; a caller entry
under the side's own key is overridden; the caller's own dictionary
instance is untouched;
- null options and a null configure action throw
ArgumentNullException from every door;
- all three overload shapes return the concrete core types;
- the string overload's key-versus-token colon rule.
The identifiers are written out as literals, not read from `Side`, so a
rename of the constant fails here instead of passing silently.
Verified by mutation: giving the flag a version fails 8 of the 13.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Replaces the "added in the next PR in this stack" placeholders in the 2.0-in-development note with install commands and the door snippets for both sides, and states plainly that the doors are the supported entry points and Ably.PubSub.Core is internal. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…evice door - D3: add ClientOptions.Clone() to the core (member-wise copy; fresh dictionaries for Agents/AuthHeaders/AuthParams/TransportParams; private write-only host fields carried from inside the class) and make Side.WithSideAgent stamp a clone, never the caller's instance; rewrite the mutation-ratifying spec and add a cross-door reuse regression spec - D4: add PubSubDoorSandboxSpecs (type=integration) - one sandbox publish/subscribe round-trip per realtime door and one REST call through the HTTP door - D14: pin the unclassified-core promise - directly-constructed AblyRest/AblyRealtime emit neither side flag (while carrying the family identifier) - D16: exception-parity spec - the no-credentials HTTP door fails with exactly the core's own 40106, proving it neither requires nor injects auth - D28: fix Ably.PubSub.Package.sln shared-project metadata (drop phantom GUID, register the real Core consumer) - D1: merge the Ably.PubSub.Device door into the Unity plugin - MergeDLLs gains an internalize-exclude-file parameter, cake-build/unity-internalize-exclude.txt keeps IO.Ably.PubSub.Device.* public, the merge output is renamed Ably.PubSub.Device.dll (.meta GUID preserved, link.xml, three test asmdefs, unity CONTRIBUTING/README synced), and the Unity sample constructs through PubSubDevice.CreateClient - D36: route the NotificationsPublisher example through PubSubServer.CreateRealtimeClient with a server-door project reference - D33: soft-[Obsolete] the five public core AblyRealtime/AblyRest constructors pointing at the door factories; scoped CS0618 suppressions at the sanctioned door call sites; NoWarn 618 on the two test heads that deliberately exercise the constructors - D17 (changes 2-3): make door signing Package-conditional in lockstep with the core (all three door heads) and delete the ruleset CS8002 suppression so any future signed-vs-unsigned mix fails the build - D32: rewrite the README Installation/Usage sections onto the door packages and drop the now-satisfied interim sequencing note; the transport-buffer example moves to the server door alongside the constructor obsoletion - D15: verified locally with nuget.exe 6.3.1 (Mono) that $version$ substitutes inside dependency version attributes (packed pins read [2.0.0]); settled the TODO comments in both door nuspecs - MergeDLLs also gains a Mono-facades /lib fallback (appended only when the facades directory exists on disk, so Windows invocations are bit-for-bit unchanged): under Mono, /targetplatform:v4 cannot resolve the netstandard facade the netstandard2.0 inputs reference Includes the regenerated Unity plugin, produced by the sanctioned ./unity-plugins-updater.sh 2.0.0 pass under local Mono with the facades-lib robustness fix; merged-assembly surface verified with monodis: assembly Ably.PubSub.Device 2.0.0, door public, core public, Newtonsoft/DeltaCodec internalized (D8, D1 dry-run items executed). Unity EditMode/PlayMode smoke remains for the Windows/Unity pass. PubSub device/server split rollout (PDR-091b2) review follow-ups.
Three packages ship at one version and both doors pin the core with an
exact version range. Nothing in the build enforced any of that, so a
loose pin, a stale build or a version-file skew would first become
visible to a consumer after the version had been published and could
never be changed again.
cake-build/tasks/release.cake adds three tasks that bracket the pack:
_Release_Preflight source-only assertions: the --version input
equals all three attributes in
src/CommonAssemblyInfo.cs and
unity/Assets/Ably/version.txt; nuget/ holds
exactly the lockstep set with the expected
ids and the $version$ token; every dependency
group of every door pins Ably.PubSub.Core as
[$version$]; nothing depends on ably.io or
the 1.x push satellites.
_Release_Verify_Files every <file src> glob resolves to a real
file. nuget silently omits a files entry it
cannot resolve, so this is the last point at
which an empty or partial package can be
caught.
_Release_Verify_Packages post-pack assertions against the produced
.nupkg files: id, version, one lib/<tfm>
assembly per declared target, and the packed
door -> core pin.
The pre-flight is a dependency of _Version rather than of
_Package_Build_All because _Version overwrites CommonAssemblyInfo.cs
with the --version input; running after it would make the version
assertion a tautology. Package now fails loudly without --version
instead of silently producing nothing.
The packed-pin assertion is what proves the open question from the door
packages PR: NuGet does substitute $version$ inside a dependency's
version attribute, and the packed pin comes out as [2.0.0]. Both door
nuspecs lose their TODO and say so.
The same source-level assertions are duplicated as xunit specs in
Ably.PubSub.Tests.DotNET/PubSub/PackagingSpecs.cs, so a PR that edits a
nuspec fails the ordinary unit run without waiting for a packaging job.
They locate nuget/ by walking up from the test assembly rather than by
counting directories.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The lockstep invariants live in the version files and the nuspecs, none of which the compiler reads, and a NuGet version once published can never be changed. This packs all three packages from every PR commit and runs the pre-flight and the post-pack assertions over them, so a version-file skew, a loosened pin, a renamed id or a nuspec files entry that no longer resolves fails on the PR that introduced it rather than on release day. Windows, not Linux, because the core and server packages carry a lib/net46 asset built by an old-style MSBuild head. `dotnet pack -p:NuspecFile=...` does pack a nuspec Mono-free, so packing is not what needs Windows - the net462 build is - and _Release_Verify_Files fails loudly rather than letting a Linux run ship packages silently missing that asset. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Today's release is a human downloading an artifact zip and running
`dotnet nuget push` by hand. With three packages that must land in
dependency order, at one version, and where a half-finished release
cannot be undone, that is not a process anyone should be asked to
execute correctly under pressure.
publish.yml is dispatch-only, takes `version` and `dry_run` (default
true), and:
- runs the pre-flight before anything is built, so a mismatched
version or a loosened pin aborts the run with nothing produced;
- builds, packs and creates the .unitypackage in one job from one
build, so the Unity asset and the .nupkg files can never come from
different builds of the same version;
- pushes core -> device -> server, and waits for the core version to
be listed on nuget.org before the doors that pin it go out, because
nuget.org validates and indexes asynchronously;
- queries the flat container before each push and skips a version
already published, so a run that fails partway is completed by
re-running it with the same version rather than by hand;
- creates the tag and GitHub release, with all four artifacts
attached, from a separate job so that contents: write is scoped to
the only step that needs it;
- prints the unlist guidance on every run, because NuGet cannot
delete and the moment it is needed is the moment nobody wants to be
reading a workflow file.
Authentication is nuget.org Trusted Publishing: GitHub OIDC exchanged
by NuGet/login for an API key valid for one hour, requested immediately
before the push, so the repository holds no long-lived NuGet
credential. The fallback to a NUGET_API_KEY secret is documented in a
comment at the step, and the registry-side setup in CONTRIBUTING.md.
Because the pre-flight demands the 2.0 nuspec set, this workflow is
inert on a 1.x checkout: it can be cherry-picked to the default branch
(which is where `gh workflow run` reads workflow files from) and
dispatched against integration refs without being able to release 1.x.
package.yml is deleted rather than kept alongside: it built the same
artifacts by the same Cake targets and then asked a human to push them,
which is now `dry_run=true` with assertions. package.cmd,
package-unity.sh and build.sh are unchanged.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
CONTRIBUTING.md's release process was ten manual steps ending in a hand-run `dotnet nuget push` of an artifact zip. It is now: bump one version in two files, PR, merge, dispatch publish.yml with dry_run=true, dispatch it again with dry_run=false. The tag, the GitHub release and the .unitypackage attachment are the workflow's job. The changelog and Headway steps are unchanged, and the re-run-to-complete and unlist-to-abandon behaviours are written down where someone mid-incident will find them. Adds the nuget.org Trusted Publishing setup as its own section: what the policy binds (owner, repository, the workflow file name only), that its scope has to allow new packages if a brand-new id is being claimed, that a private-repo policy is provisional for 7 days until the first publish gives nuget.org the repository ids, that it matches by repository name and so must be created after any rename, and how to fall back to an API key. cake-build/README.md documents Release.Preflight and Release.VerifyPackages, the three packages that package.cmd now produces, --packageOutput, and the `--` separator that Cake's reserved --version flag forces. README gains a paragraph on why the exact core pin means all Ably.PubSub.* references in a project move together. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…tooling - D17 follow-up (composition break surfaced by the release dry run): under Package builds the signed core references the unsigned submodule-built DeltaCodec on the SDK TFMs - a pre-existing mix the deleted global ruleset suppression had been masking. Scope a CS8002 NoWarn to the core's Package-conditional signing group only (the doors compile clean and get nothing); the plain-Release guard stays fully live; proper cure is signing the submodule build (follow-up) - D25: make 2.0.0-beta.N buildable and publishable - _Version stamps numeric identity into AssemblyVersion/AssemblyFileVersion (CS7034 otherwise) and the full string into AssemblyInformationalVersion; ReleaseAssertVersionFilesAgree asserts per-attribute expectations and its success message reworded; gh release create gains --prerelease for hyphenated versions; PackagingSpecs.TheTwoVersionFiles_Agree mirror-patched to the same split; README exact-pin paragraph gains the prerelease-pinning sentence - D26: publish.yml gains a workflow-level concurrency group keyed on the version (never cancel in-progress) and the publish job runs in the `release` environment as the required-reviewer gate - D7: new pre-flight assertion ReleaseAssertUnityPluginVersion - the committed unity/Assets/Ably/Plugins/Ably.PubSub.Device.dll must exist and carry the release's numeric identity and full informational version, so a stale merged plugin can never ship inside the .unitypackage - D1 (CI): publish.yml regenerates the Unity plugin from the release checkout before UnityPackage and cross-checks identity/informational version against the committed DLL, which stays canonical and ships (it is what the Unity test pass validated) - D12: nuspec projectUrl/releaseNotes/repository URLs moved to ably-pubsub-dotnet in all three nuspecs (metadata freezes per version at push time) - D13: CHANGELOG gains the 2.0.0 entry and UPDATING.md is added as the 1.x -> 2.0 migration guide (door factories, mixed-graph rule, exact pinning, MAU forcing function, Xamarin push-receive gap, Unity door usage) - D30: the five run-tests workflows also trigger on pushes to integration/** branches (previously only release-dry-run.yml did) - D31: RestoreSolution stops swallowing restore failures - Windows NuGetRestore throws; the non-Windows nuget CLI path probes for the tool, warns-and-skips when absent (Mono-less macOS/Linux legs) and throws when present-and-failing; DotNetRestore now throws unconditionally - D5: features.yml repository-name updated to ably-pubsub-dotnet - the check stays red regardless until the ops-side AWS IAM trust-policy re-bind allows the renamed repo - D18 (optional polish, included - builds clean): Microsoft.SourceLink.GitHub 8.0.0 with PublishRepositoryUrl/EmbedUntrackedSources on the three SDK csprojs Deferred/ops notes: the Windows-pack halves remain for CI (net46 pack/install check, sn -v on packed assemblies, the publish.yml regenerate/cross-check dry run); the `release` GitHub environment must be created and given required reviewers plus a deployment-branch restriction in repo Settings - referencing it auto-creates it unprotected; D13's entry needs its release date and compare link when the release is cut; D25's wire-agent consequence (a beta build reports ably-pubsub-dotnet/2.0.0 without the label via Defaults.GetVersion()) needs rollout-owner sign-off; Unity EditMode/PlayMode smoke of the committed plugin remains for the Windows/Unity pass. PubSub device/server split rollout (PDR-091b2) review follow-ups.
Bring the main-side changes now on integration/v2 (RTN23 connection fixes, ably-dotnet -> ably-pubsub-dotnet rename references, the 1.2.19 release commits and the package-push runner fix) into the split-1 Core restructure. Rename-aware resolution: main's edits to the old src/IO.Ably.* paths land in the renamed src/Ably.PubSub.* files via git rename detection (verified: TransportParams RTN23b heartbeats change is byte-identical to main in the renamed Ably.PubSub.Shared file). Conflict resolutions: - .github/workflows/package.yml: keep restructure (the package-push Xamarin job was removed in the 2.0 layout; main's runner fix targets that now-deleted job). - CONTRIBUTING.md, README.md: keep the 2.0 restructure content; main's ably-dotnet -> ably-pubsub-dotnet URL swaps are cosmetic and slated for a post-merge docs pass. - src/CommonAssemblyInfo.cs, unity/Assets/Ably/version.txt: keep 2.0.0 (main's 1.2.19 bump is superseded, not a downgrade of the 2.0 branch). - nuget/io.ably*.nuspec, unity/Assets/Ably/Plugins/IO.Ably.dll: keep the restructure deletions (renamed to ably.pubsub.* / Ably.PubSub.Device).
Propagate the integration/v2 sync (RTN23 fixes, rename references, 1.2.19 release commits) up the stack via the split-1 Core branch. Clean auto-merge, no conflicts.
Propagate the integration/v2 sync (RTN23 fixes, rename references, 1.2.19 release commits) to the top of the stack. Conflict resolutions: - .github/workflows/features.yml: both sides set repository-name: ably-pubsub-dotnet; keep the incoming explanatory comment about the IAM OIDC role binding. - CHANGELOG.md: both sides added a section at the top; keep both, the hand-written 2.0.0 section above the generated 1.2.19 section.
M18: the door factory PubSubDevice.CreateClient clones the options it is given, where new AblyRealtime(options) used to store them by reference. The dashboard sample created its client at startup and assigned _clientOptions.ClientId in the connect handler, so the typed ClientId mutated only the caller's copy and was silently ignored by the already-created client - the sample's ClientId input became a no-op. Restructure the sample so ClientId is set before the options are cloned, and recreate the client on each connect so a ClientId changed between sessions is captured: - InitializeAbly() now only constructs _clientOptions. - New CreateAblyClient() creates the client, wires the existing Connection.On handler unchanged, and closes any client it replaces. - ConnectClickHandler() closes when connected; otherwise it sets ClientId, recreates the client, and connects. Scope extension over the planned AblyMain.cs-only change: AblyChannel and AblyPresence captured the client reference in readonly fields at startup, so recreate-on-connect requires them to accept an updated reference - they gain an internal UpdateClient(AblyRealtime) which AblyMain calls (null-conditionally) after each recreation. unity/README.md's simpler sample (no connect handler) gets the minimal faithful mapping: InitializeAbly split into options construction plus CreateAblyClient, with a comment on the clone semantics.
Merge the door-packages branch (M18 sample fix) so the release-tooling tip stays consistent with the layer below. Clean auto-merge.
[Split 3/3] Lockstep release pre-flight, release dry-run CI job, and publish workflow
Review follow-ups (M-IDs from the review-response plan): - M5: FindTestAssemblies now throws when a pattern matches zero test assemblies instead of warning and returning green - a glob typo can no longer pass as a successful run with zero tests. - M40: features.yml gains the integration/** push trigger the other six workflows already have. - M7: the core nuspec lists the lib/net46 files explicitly (dll + xml + DeltaCodec dll) so the old glob no longer sweeps in the .dll.config and .pdb. - M34: the net46 Server head cannot host the SourceLink analyzer (legacy packages.config project); the limitation is documented in the csproj header alongside the same-shaped core head rather than half-wired in. - M32: CONTRIBUTING no longer claims the publish workflow uses no GitHub environment - it documents the release environment as the human approval gate and the optional nuget.org policy Environment pin. - M37: release steps note that the hand-written 2.0.0 CHANGELOG section must be merged with the generator output, not duplicated. - M38: the Unity regenerate-and-cross-check step documents its limit (identity/version comparison, not byte identity - ILRepack output is nondeterministic; the committed, Unity-tested copy stays canonical). - M39: the same step documents why the pack step must stay ordered before it (Build.NetStandard depends on _Clean, which wipes bin/). - M1 hardening: the committed Unity plugin path is defined once, in paths.cake (UnityPluginDll), and referenced by the build task, the packaging guard and the release pre-flight so the sites cannot drift. - M2 residual: remaining ably-dotnet URLs and package-name mentions in README updated to ably-pubsub-dotnet. - README usage sample: add the missing 'using IO.Ably;' - the block uses core types (ConnectionEvent, IRealtimeChannel) that the door namespace alone does not import, so it did not compile as copied. (UPDATING.md samples already carry both usings.) Validation: cake graph compiles (dry run of the Package target); FindTestAssemblies exercised both ways via a scratch cake script (real pattern finds 1 assembly, wrong pattern throws); both workflow files YAML-parse; nuspec and csproj XML-parse; NetStandard solution builds with 0 warnings / 0 errors.
M21: ClientOptions.Clone() is a hand-maintained public API of the core (the door factories copy options through it on entry), so it silently drops the first property someone adds and forgets to copy. Guard against that rot with a reflection spec that stamps a distinct, non-default value on every public settable property (including the inherited AuthOptions members), clones, and asserts the clone matches the original. Design notes: - Compares the clone against the ORIGINAL's getter, not the stamped value, so a deliberately no-op setter (UseBinaryProtocol discards its value in non-MSGPACK builds) compares default-to-default and passes, while a forgotten copy still fails (original carries the stamp, clone the default). - Write-only host fields (RestHost/RealtimeHost/FallbackHosts) are asserted through their private backing fields. - Deep-copied dictionaries (Agents/AuthHeaders/AuthParams/TransportParams) are asserted NotBeSameAs + BeEquivalentTo (Clone rebuilds them). - ChannelDefaults (internal setter) is asserted BeSameAs separately. - Obsolete members are pragma-618 guarded; the value factory throws on an unhandled property type so a new property of a new shape fails here too. - A separate block covers the internal Logger/NowFunc (by reference) and SkipInternetCheck (by value) via InternalsVisibleTo. Validation: the spec passes; verified non-vacuous by temporarily dropping the ClientId copy in Clone() and confirming the spec fails, then reverting. NetStandard solution builds 0 warnings / 0 errors.
M26: the SDK-style door projects Ably.PubSub.Device and
Ably.PubSub.Server carried the legacy project-type GUID
{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} in every solution that lists
them; give them the SDK-style {9A19103F-16F7-4668-BE54-9A1E7A4F7556}.
The net46 heads (Core.NETFramework, Server.NETFramework,
Tests.NETFramework) and IO.Ably.DeltaCodec are genuinely non-SDK and
keep the legacy GUID. Also unify each door's per-project GUID across
solutions (Device -> {ADD94C3B-...}, Server -> {882D22FB-...}) so one
project no longer has three identities; no csproj ProjectReference keys
off these GUIDs, so the change is self-contained to the solutions.
M26 (config): in Ably.PubSub.NetFramework.sln, Ably.PubSub.Server.NETFramework
{7B3C1F42-...} mapped its solution-level and
configurations to Debug|Any CPU, so a solution-level Package build would
produce and consume Debug bits for the net46 Server asset. Map both
configurations (ActiveCfg + Build.0, all four platforms) to Release|Any CPU,
matching the sibling Ably.PubSub.Core.NETFramework {2D265650-...} precedent in
the same solution. (Ably.PubSub.Package.sln, the solution the packaging
pipeline actually builds, declares no package/package_netstandard solution
configs and already maps Release->Release, so it was correct.)
M10: RootNamespace hints pointed at the assembly names
(Ably.PubSub.Shared, Ably.PubSub.Tests.NETFramework) while the code
namespace is IO.Ably; a contributor adding a file in VS got the wrong
namespace seeded. Set them to IO.Ably and IO.Ably.Tests. Presentation
only - RootNamespace does not affect compiled output here.
M25: the Device csproj comment said '.NET Framework is not a supported
device target', which is wrong - a .NET Framework 4.6.2+ WPF/WinForms app
is a device target and consumes the netstandard2.0 asset, as MAUI does.
Reword to say why there is no separate .NET Framework Device head.
Validation: all four solutions parse (balanced Project/EndProject, BOM
and LF line endings preserved, diff symmetric); FAE04EC0 now appears only
on the net46 heads and DeltaCodec; NetStandard solution builds 0W/0E;
targeted PubSub + Clone specs pass (32/32).
M33: Defaults.GetVersion() read AssemblyFileVersion, which D25 stamps numeric-only (2.0.0) while the full SemVer including any prerelease label lives in AssemblyInformationalVersion. A prerelease such as 2.0.0-beta.1 therefore identified on the wire as 2.0.0, indistinguishable from GA. Read AssemblyInformationalVersion instead and strip the SourceLink '+<commit>' build-metadata suffix via a new internal NormalizeInformationalVersion helper, keeping the SemVer core and the prerelease label. The old numeric file-version path (first three parts) stays as a fallback when no informational version is present; the .Take(3) truncation is deliberately not applied to the informational version, which would corrupt a prerelease label. This does NOT include the RTN2g realtime wire-key change (M16), which is still gated on realtime-team confirmation. Validation: NetStandard solution builds 0 warnings / 0 errors; new normalizer theory covers the beta+metadata, GA+metadata, prerelease and plain cases, plus a spec asserting GetVersion() carries no '+' suffix in this SourceLink-enabled build; targeted Defaults/Agent/HTTP tests pass (31/31).
A JSON object returned from AuthCallback is also treated as a serialized TokenDetails when it has an issued field (TokenDetails.IsToken), not only when it has a string token field.
Keep realtime retrieval from changing the options of HTTP channels
A realtime channel decoded received messages with a decoding context built once from the options it was created with, so SetOptions and Channels.Get(name, options) never changed the cipher used for them (RTL16, RTS3c). Presence, annotations and publishing already used the current options. Update the context's options whenever the channel's options change, rather than replacing the context, which also holds the delta base payload that must survive the change (RTL19).
Conflicts resolved: - AnnotationsRequestParams.cs: keep the RSAN3b querystring sentence, take the HttpAnnotations cref and drop the "experimental" wording. - CHANGELOG.md: take the rewritten 2.0 breaking-change bullets and add the FallbackHosts getter note; keep the ExtraParameters bullet next to the new Fixed bugs section. - UPDATING.md: drop "Experimental." from the Annotations row and keep the GetAsync parameters sentence. Follow-on fixes for the merged API: - AnnotationsTests asserts HttpAnnotations (RestAnnotations was renamed). - The RTL10b ChannelHistoryTests use the restored public HistoryAsync(untilAttach: true); drop the internal-API adaptation and its deviations.md entry. - Un-gate AuthCallbackTests.RSA8d_CallbackReturnsJwt and TokenDetailsTests.RSA16b_TokenStringFromCallback, now that an AuthCallback may return a token string or JWT; drop their deviations.md entry. - Integration and proxy JWT auth callbacks, and the oversized-token RSA4f test, return the string as the spec does, instead of wrapping it in TokenDetails. - Align the uts-to-csharp skill references with HttpAnnotations, the public channel untilAttach overloads and string AuthCallback results. - Move the fatal ERROR + close bullet from the released 1.2.19 CHANGELOG section to 2.0.0 Behaviour changes.
Move the fatal ERROR followed by socket close entry to Fixed bugs, since it describes a bug that 2.0 fixes. Drop the AnnotationsRequestParams limit-exception entry: the annotations API is new in 2.0, so there is no earlier behaviour to compare with.
Add UTS test infrastructure, realtime and REST UTS-derived tests, and the uts-to-csharp skill
Decode live messages with the channel's current options
ttypic
approved these changes
Nov 2, 2026
Brings in the two main-only changes since the merge base, so the 2.0 line can merge back into main without conflicts. - RealtimeChannels.cs: keeps the 2.0 RTS4e behaviour (release throws 90011 unless the channel is Initialized, Detached or Failed). Main's RTS4b deprecation warning is the 1.x counterpart and doesn't apply. - ChannelsSpecs.cs: keeps the 2.0 RTS4c-e tests. Main's RTS4b tests merged cleanly but use the 1.x AblyRealtime type and assert the deprecated 1.x behaviour, so they are dropped. - AblySandboxFixture.cs: ports main's race fix (one Lazy provisioning task per endpoint in a ConcurrentDictionary, evicted on failure) onto the 2.0 endpoint-based fixture, keeping MutableMessagesNamespace.
Merged
sacOO7
force-pushed
the
integration/v2
branch
from
November 2, 2026 17:39
d492808 to
482de5d
Compare
sacOO7
force-pushed
the
integration/v2
branch
from
November 2, 2026 17:40
482de5d to
0feb7bd
Compare
Test-only changes; no product code. - ConnectionAwaiter (behind WaitForState) checked the connection state before subscribing, so a change landing between the two was missed and the wait timed out. It now subscribes first, then checks, removes its listener on every exit path, uses TrySetResult, runs continuations asynchronously and cancels its timeout delay. New ConnectionAwaiterTests cover the already-there, reached, timeout and listener-removal cases; the concurrency test disposes the client each of its 200 iterations creates. - LocalDeviceTests registered ProcessingEventCallback after the call that raises the second GotPushDeviceDetails on a background task, so it could miss it. The callback is now registered first. - Test classes that read or reset the process-wide LocalDevice.Instance (LocalDeviceTests, the ActivationStateMachineTests classes, PushChannelTests and PushRealtimeTests) now share one non-parallel xUnit collection, and PushRealtimeTests clears LocalDevice.Instance after its base teardown, as the others do. - TaskCompletionAwaiter.Tick decrements atomically, so two concurrent ticks can't lose one. - PresenceSandboxSpecs.Presence_ShouldHaveInternalMapForCurrentConnectionId waits on each channel for the specific expected presence event instead of the first event of any kind, and names the missing one on timeout. An assertion that could never fail is removed.
UtsRecord.ConnectionStates and ConnectionStateChanges only see changes made after they subscribe. ConnectionStaysFailedWhenTheServerClosesAfterAFatalError created an AutoConnect client and subscribed afterwards, and its mock answers the first attempt with a fatal ERROR at once. On a slow runner the client could reach FAILED, and stay there, before the recorder subscribed, so the poll for FAILED timed out after 10 seconds. The failure reproduced locally under CPU load. Create the client with AutoConnect off, subscribe, then connect. The test still checks the same race across 20 clients. Two smoke tests in RealtimeUnitSmokeTests, and MockWebSocketTests' event-order test (which subscribed after triggering a disconnect whose retry is refused at once), had the same pattern and could lose the DISCONNECTED or first CONNECTING change they read, so they now subscribe first too.
Fix races in test helpers that made tests flaky
Remove the old-style Ably.PubSub.Server.NETFramework project and the lib/net46 asset and dependency group it fed into the Server package. A .NET Framework app now gets Server's netstandard2.0 asset with Core's net46 asset, the same pairing Ably.PubSub.Device already uses. The net46 core already grants Ably.PubSub.Server InternalsVisibleTo (keyless and keyed), and Server compiles the same sources with no platform-specific code, so nothing else changes. - Drop the project from the three solutions and the nuspec. - Package consumption: the ServerApp net462/net48 rows now expect Server lib/netstandard2.0 with Core lib/net46; ServerApp also constructs a client through the CreateHttpClient(string) overload, offline. - _Package_Verify_NuGet fails if a door package contains lib/net46 or a .NET Framework dependency group; PackagingSpecs asserts both door nuspecs ship exactly netstandard2.0, net6.0 and net7.0. - Update CONTRIBUTING.md, cake-build/README.md and related comments.
Use the netstandard2.0 build of Ably.PubSub.Server on .NET Framework
….Core The net46 Ably.PubSub.Core.dll is strong-name signed in Package builds, but it referenced, and shipped next to, the unsigned IO.Ably.DeltaCodec.dll. A strong-named assembly should reference only strong-named assemblies. - Add a _Package_Merge_NetFramework Cake task, which _Package_Create_NuGet depends on. Like 1.x's _Package_Merge_All, it uses ILRepackHelper to merge only IO.Ably.DeltaCodec.dll into the net46 core, internalized and signed with Ably.PubSub.snk, and writes the result and the core's XML docs to bin/Release/Packaged. Newtonsoft.Json is not merged. - Pack lib/net46 from Packaged in the core nuspec, and drop the separate net46 IO.Ably.DeltaCodec.dll. The netstandard2.0, net6.0 and net7.0 cores still ship it as a separate file. - Use the tracked tools/ILRepack.exe name in ILRepackHelper. The lowercase name only works on case-insensitive file systems, and every pack now runs ILRepack. - Add a "Newtonsoft.Json on .NET Framework" section to UPDATING.md, and note that DeltaCodec isn't shared with ably.io on .NET Framework.
Merge DeltaCodec into the .NET Framework build of Ably.PubSub.Core and document Newtonsoft.Json on .NET Framework
This branch was successfully deployed
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.
Summary
This PR merges
integration/v2intomain. It is Ably Pub/Sub .NET 2.0: the singleably.iopackage is split into an internal core and two "door" packages (PDR-091b), so every client is classified as device-side or server-side on the wire. Ably's platform behaviour and MAU-based billing depend on that classification.2.0 also moves the root namespace to
Ably.PubSub, renames the REST client types to HTTP, removes the 1.x[Obsolete]members, adds protocol v6 support (publish results, message updates/deletes/appends, annotations, message retrieval) and replacesEnvironment/RestHost/RealtimeHostwithEndpoint.The branch is 167 commits ahead of
main. Merge it only on the release owner's go, once every item in "Before merging" is done.Packages
Ably.PubSub.DevicePubSubDevice.CreateClient(...), which adds theably-pubsub-deviceagent flagAbly.PubSub.ServerPubSubServer.CreateRealtimeClient(...),PubSubServer.CreateHttpClient(...), which add theably-pubsub-serveragent flagAbly.PubSub.Coreably.io(1.x)v1branch cut from tag1.2.19: security and critical fixes for one year from the 2.0 release. No moreably.ioreleases frommain.[$version$]), and the three packages are released together at one version.ably-pubsub-dotnet/<version>. The side flags are versionless agent entries.Ably.PubSub.Device.dll.What's included
Package split (stacked PRs, each reviewed separately, followed by review-feedback commits on
integration/v2):Ably.PubSub.Core: [Split 1/3] Restructure into Ably.PubSub.Core (assembly rename, drop Xamarin heads and push satellites, version 2.0.0) #1333Ably.PubSub.DeviceandAbly.PubSub.Serverdoor packages and the side-declaring agents: [Split 2/3] Add Ably.PubSub.Device and Ably.PubSub.Server door packages with side-declaring agents #1334publish.yml, Trusted Publishing setup and release pre-flight were later removed (see "Release process" below).Namespace and renames:
RESTnaming becomesHTTP(AblyRestis nowPubSubHttpClient,AblyRealtimeis nowPubSubRealtimeClient): Rename the REST naming to HTTP across the SDK #1341IO.AblytoAbly.PubSub: Move the root namespace from IO.Ably to Ably.PubSub #1342IO.Ably-named build artifacts are retired: Retire the remaining IO.Ably-named build artifacts #1343Protocol v6 (ECO-5754):
/statsendpoint stays pinned to the v2 response format: [ECO-5754] Pin the stats endpoint to the protocol v2 response format #1347Other API changes:
EndpointreplacesEnvironment,RestHostandRealtimeHost(REC1/REC2): Replace Environment, RestHost and RealtimeHost with Endpoint #1359HistoryAsync(untilAttach)overloads are restored;AuthCallbackcan return a token string again.Platform and packaging:
Ably.PubSub.Deviceworks on .NET Framework, and a test now installs the packed packages: Fix Ably.PubSub.Device on .NET Framework and add a package-consumption test #1373Release process:
package.ymlis restored, andpublish.yml,release-dry-run.ymlandrelease.cakeare removed: Return to the manual release process: restore package.yml, remove the publish automation #1375Docs:
UPDATING.mdcorrected: Rewrite the README for 2.0 and correct UPDATING.md #1372Tests:
uts-to-csharpskill: Add UTS test infrastructure, realtime and REST UTS-derived tests, and the uts-to-csharp skill #1362FallbackHostsgetter).authorize()waiting).Breaking changes for users
The full list is in the 2.0 section of
CHANGELOG.md, and migration steps are inUPDATING.md. In short:Ably.PubSub.DeviceorAbly.PubSub.Server, notably.io, and create clients through the door factories.IO.AblytoAbly.PubSub;Endpointreplaces the old host options;PublishResult.Request()/RequestV2()without anX-Ably-Versionheader now get protocol-6 response shapes.IHttpChannelandIRealtimeChannelgain members, so code that implements them (such as test fakes) must add them.Push.Activate()/Deactivate()throw an error that links Re-introduce device push notification support (FCM/APNs) for modern .NET Android/iOS and MAUI #1360. The decision record isPushNotifications.md.Push.Admin) is available in both packages. It is documented as server-side use that needs thepush-admincapability.IO.Ably.*) and v2 (Ably.PubSub.*) types no longer collide, apart fromIO.Ably.DeltaCodec. A mixed dependency graph compiles, butUPDATING.mdsays to keep it temporary.Still open into
integration/v2Before merging
main. GitHub reports this PR as CONFLICTING.src/Ably.PubSub.Shared/Realtime/RealtimeChannels.cs(from Deprecate releasing a realtime channel that isn't detached (RTS4b) #1357, the RTS4b deprecation) andsrc/Ably.PubSub.Tests.Shared/Infrastructure/AblySandboxFixture.cs(from Provision each sandbox test environment once, atomically #1337).RealtimeChannels.cs.mainbefore merging:integration/v2. If it merges tomainfirst, it adds a conflict here. Port it, or close it.v1maintenance branch from tag1.2.19. It doesn't exist on origin yet.package.ymlandnuget/io.ably.nuspec, with thepackage-pushjob moved off the retired macOS 14 runners (macos-14at the tag,macos-14-largeonmain).main'spackage.ymlis the 2.0 one, and 1.x patches are packed by dispatchingpackage.ymlagainstv1.v1also takes themaincommits after the tag: Fix package-push: macOS-13-era Xcode/Xamarin toolchain no longer exists on hosted runners #1339, 1337 and 1357.ably-pubsub-dotnet,ably-pubsub-device,ably-pubsub-server): Register the Pub/Sub split agent identifiers: per-side flags and per-language families ably-common#361. It is still open.Ably-Agentquery param, but RTN2g specifiesagent. Confirm with the realtime team and land any fix onintegration/v2.deb6659f, the UTSunit (net6.0)job failed onStateWaitTests.ConnectionStaysFailedWhenTheServerClosesAfterAFatalError. All other jobs passed.integration/v2. Features doesn't run on pushes tointegration/v2(only on pull requests and pushes tomain), so confirm it on this PR once the conflicts are resolved. It is green on recent PRs intointegration/v2.Merge mechanics
Squash-merge only. The branch history contains a 1.6 MB test-results file (
test-results/tests-netstandard-unit.trx, added and later removed) and several superseded builds of the Unity plugin DLL. Squashing keeps them out ofmain.After the merge, release by hand per the "Release process" section of
CONTRIBUTING.md. Publish only once this PR is onmain: the README andCHANGELOG.mdlink toblob/main/UPDATING.md, which doesn't exist onmainuntil then.src/CommonAssemblyInfo.cs,unity/Assets/Ably/version.txtand the README examples. It is already2.0.0, so this is needed only for a prerelease such as2.0.0-rc.1.Ably.PubSub.Device.dllfrom the release commit (the updater builds fromCommonAssemblyInfo.cs). Then check it for duplicate attributes withmonodisand run the Unity EditMode/PlayMode smoke tests.package.yml.Ably.PubSub.Corefirst. Once nuget.org lists it, pushAbly.PubSub.Device, thenAbly.PubSub.Server.After release
ably.iodeprecation: 2.0 NuGet release readiness: new Ably.PubSub.* packages, ably.io deprecation, and pre-GA blockers #1356*.WithRetrytargets exit 0 on test failure: Cake *.WithRetry test targets exit 0 when a test fails on both the run and the retry #1369untilAttachremoved,AuthCallbacktoken strings #1370 (2.0 findings) is addressed by PRs 1371 and 1372. Update it once 2.0 ships.v1: since 1.2.15, anAuthCallbackthat returns a token string or JWT fails with 80019. 2.0 has the fix (PR 1371).Reviewer notes
src/Ably.PubSub.Device,src/Ably.PubSub.Server,src/Ably.PubSub.Side/Side.csandsrc/Ably.PubSub.Shared/Agent.cs: classification and agent flags.nuget/*.nuspec: exact core pin and package contents..github/workflows/package.ymland theCONTRIBUTING.mdrelease section.CHANGELOG.md2.0 andUPDATING.mdfor accuracy.