Conversation
#83 (the net48 leg) and #81 (DeferredEchoQueue and the J1939 rebind probe) were green side by side and merged clean, but neither was ever built against the other: main's Windows leg does not compile. DeferredEchoQueue.cs(46): CS0305 'TaskCompletionSource<TResult>' requires 1 type argument J1939NodeTests.cs(857): CS7036 BitConverter.ToInt32(byte[], int) J1939NodeTests.cs(867): CS0117 BitConverter has no TryWriteBytes The non-generic TaskCompletionSource is polyfilled, next to the Task.WaitAsync shim and for the same reason: DeferredEchoQueue is deliberate test infrastructure that issue #24 will build on, and a shim spares it — and the next file like it — from knowing the net48 leg exists. The surface is reproduced in full rather than trimmed to today's single TrySetResult caller, since a shim missing SetResult would only move the surprise. BitConverter cannot be treated the same way: it is a static BCL class, so the span overloads .NET Framework lacks cannot be added from outside it. The two call sites use the array overloads instead — the same four bytes in the same machine endianness, compiling unchanged on both legs with no #if — and carry a comment so they are not modernised back. Verified on the merged tree: net48 compiles clean (0 warnings), net10.0 runs 409/409 locally, and the netstandard2.0 public surface is still byte-identical to all nine approval files. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
PR SummaryLow Risk Overview Adds In Production / netstandard2.0 surface is unchanged — test-only infrastructure and one test file. Reviewed by Cursor Bugbot for commit e4d7965. Bugbot is set up for automated code reviews on this repo. Configure here. |
|
Superseded by #85, which is already merged. Closing. Both halves of this pull request turned out to be unnecessary once the suite moved to the Polyfill package: The The
That was true of classic extension methods, but not of C# 14 extension members, which can add static members to an existing type. Polyfill 11.3.0 uses exactly that, and its net48 So the Nothing here is lost — the same net48 leg is green on |
mainis currently broken on the Windows leg. This restores it.What happened
#83 (the
net48test leg) and #81 (DeferredEchoQueue, and the J1939 rebind probe) were each green, and merged textually clean. Neither was ever built against the other:strict_required_status_checks_policyisfalseon themainruleset, so GitHub did not re-run #83's checks after #81 landed, and #83's green checkmarks were stale by the time it merged. Since these three checks are now required, a broken Windows leg onmainblocks every subsequent pull request.Reproduced on
main@8c94d51:Three .NET 5+/Core-only APIs on a leg that compiles against netstandard2.0. Only the first was reported initially — the compiler stopped there.
The two fixes, and why they differ
TaskCompletionSource(non-generic) → polyfilled, inInfrastructure/TaskCompletionSourcePolyfill.cs, next to the existingTask.WaitAsyncshim, under#if !NETand in theSystem.Threading.Tasksnamespace. Arity keeps it unambiguous:TaskCompletionSource<T>still resolves to the framework's generic type everywhere, and only the arity-0 spelling — which .NET Framework simply does not have — resolves to the shim.Shimming rather than rewriting the caller, because
DeferredEchoQueueis deliberate test infrastructure that #24 is expected to build on, and a shim spares it (and the next file like it) from having to know thenet48leg exists. That is also why the surface is reproduced in full rather than trimmed to today's singleTrySetResult()caller: a shim missingSetResultwould only move the surprise.It is a thin forwarder over
TaskCompletionSource<bool>. One difference is not reproducible, and is documented in the file:.Taskis statically aTask, as on .NET, but at run time it is aTask<bool>. Awaiting, cancelling, faulting and combining all behave identically; only reflection over its type could tell, and nothing does. .NET 8'sSetFromTask/TrySetFromTaskare left out on purpose — unlike the rest, they have real semantics to get wrong rather than one call to forward.BitConverter→ not polyfillable, so the call sites changed.BitConverteris a static BCL class: the span overloads .NET Framework lacks cannot be added from outside it, by extension method or otherwise. So the two sites inJ1939NodeTestsuse the array overloads:The same four bytes in the same machine endianness, compiling unchanged on both legs with no
#if, and the test's intent is untouched. A comment says why, so they are not modernised back into a broken Windows leg.Verification on the merged tree
dotnet build tests/CanKit.Pro.Tests -f net48 -c Release -p:CanKitProTestNetFrameworkLeg=trueon macOS: clean, 0 warnings (was 3 errors).dotnet build CanKit.Pro.sln -c Release: clean, 0 warnings.dotnet test CanKit.Pro.sln -c Release: 409/409 passed on net10.0.Not verifiable locally (macOS, no Mono): actually executing the
net48leg. That is the Windows CI job's call.Note on process
This is a separate branch because #83 had already merged by the time the collision was found, so there was no branch left to fix. The underlying gap is that
main's ruleset does not require branches to be up to date before merging, which is what let two individually-green PRs combine into a redmain. Worth consideringstrict_required_status_checks_policy: truenow that a Windows-only compile path exists — that class of break cannot happen on the Linux/macOS legs, because they only ever build one TFM.🤖 Generated with Claude Code