Release SharpLink 2.0.0: merge dev into main - #671
Merged
Conversation
* perf(stack4): 端点随机序号直接映射 * perf(stack4): 真实组包入口精确清零 * perf(stack4): 合法 decimal 校验短路径 * perf(stack4): 大 bool 集合规范值批量验证 * perf(codec): transfer uniquely decoded DateTimeOffset array ownership --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* perf(stack4): 端点随机序号直接映射 * perf(stack4): 真实组包入口精确清零 * perf(stack4): 合法 decimal 校验短路径 * perf(stack4): 大 bool 集合规范值批量验证 * perf(codec): transfer uniquely decoded DateTimeOffset array ownership * perf(codec): reuse validated offset ticks during collection decoding --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* perf(stack4): 端点随机序号直接映射 * perf(stack4): 真实组包入口精确清零 * perf(stack4): 合法 decimal 校验短路径 * perf(stack4): 大 bool 集合规范值批量验证 * perf(codec): transfer uniquely decoded DateTimeOffset array ownership * perf(codec): reuse validated offset ticks during collection decoding * perf(server): reuse validated metadata after inline request decoding * fix(server): isolate metadata reuse from the default inline decode path * test(server): declare LINQ import explicitly for repository test compilation * test(server): format metadata reuse regression coverage * chore(maintainability): document compressed dispatch allowance --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…rmits (#642) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* feat(server): add atomic call capacity publication unit * feat(server): expose runtime call capacity update * feat(server): publish call capacity under lifecycle gate * feat(server): resize existing call admission targets atomically * fix(server): keep deadline scans valid after capacity growth * fix(server): report and stop against runtime call capacity * test(server): cover runtime call capacity resize semantics * fix(server): grow deadline scheduler ceiling with call capacity * fix(server): grow deadline scan ceiling before call admission * test(server): cover deadline growth and stop sealing
Restack the two measured hot-path recovery changes onto current dev: globally queued send-pump continuation scheduling and immutable NoDecode request-permit ownership. Keep only focused deterministic regressions; drop unrelated ConnectAsync and historical test-synchronization changes from this performance PR.
* feat(client): define redacted support snapshot contract * feat(runtime): expose on-demand session support facts * feat(client): capture bounded support snapshots on demand * fix(runtime): read existing session queue diagnostics * test(client): cover support snapshot redaction and bounds * docs: add redacted client support snapshot workflow * fix(client): capture cluster support facts through owner API * docs(client): document support snapshot enum surface * test(client): expand support snapshot acceptance coverage * fix(test): add support snapshot acceptance imports * fix(test): make support acceptance states deterministic * test(client): negotiate metadata in support snapshot capacity case * fix(client): make support JSON export NativeAOT-safe * fix(client): capture cluster-owned support state * fix(client): expose dynamic owned connections to support capture * fix(client): capture bounded cluster support state * refactor(client): keep support capture off cluster interface * fix(client): preserve cluster support topology semantics * fix(client): capture static cluster support state * fix(client): capture dynamic cluster support state * refactor(client): delegate support capture to cluster owner * refactor(client): materialize owner-captured support DTOs * fix(client): publish dynamic resolver failures to support snapshot * test(client): cover support snapshot review gaps * refactor(client): split cluster support capture from routing owners * refactor(client): split static support capture * refactor(client): split dynamic support capture * refactor(client): group static support reads * refactor(client): keep static routing file within LOC gate * test(client): import LINQ for support review assertions
* test(client): make emission deadline boundary deterministic * test(runtime): keep phase-gate flush off the scheduler clock * test: drain connect output before tracked unary hook
* feat(client): separate public lifecycle and readiness API * feat(client): add runtime lifecycle state * feat(client): add cluster connectivity state * feat(client): add public readiness state * feat(client): implement non-blocking runtime startup * feat(client): expose multi-cluster lifecycle readiness API * feat(client): separate multi-cluster runtime lifecycle * fix(hosting): start client runtime without readiness wait * fix(hosting): start multi-cluster runtime without readiness wait * docs(hosting): clarify client accessor startup boundary * docs(hosting): clarify multi-cluster accessor startup boundary * docs(hosting): separate hosted runtime from remote health * fix(client): start runtime mutation candidates before connect * test(client): cover runtime lifecycle independent of readiness * test(client): cover multi-cluster partial readiness lifecycle * test(hosting): align startup assertions with runtime lifecycle * test(hosting): wait explicitly for readiness publication * fix(client): export lifecycle domains in support snapshot * test(client): cover support lifecycle domains * style(client): preserve final newline in support tests * test(client): assert support snapshot v2 state schema
Make StartAsync/WaitForShutdownAsync/StopAsync the canonical Server lifecycle, preserve runtime-vs-connection failure domains, and explicitly observe the shared terminal cleanup task for fatal runtime paths.
* feat(api): add multi-cluster status snapshot * feat(api): add non-throwing cluster status query * feat(client): query cluster status without absence exceptions * test(client): cover non-throwing cluster status query * docs(api): define control-plane result contract * docs(api): index control-plane result contract * fix(api): preserve independent cluster status domains * fix(api): capture canonical cluster readiness * fix(api): avoid guessing legacy missing-cluster exceptions * test(api): cover canonical readiness and legacy fallback * docs(api): clarify status domains and custom fallback * fix(test): import abstraction types for legacy status regression * fix(test): import SharpLink SDK contract types
Define MaxConcurrentClusterConnects as a shared cap on physical child transport ConnectAsync attempts across initial connectivity, reconnect, pool expansion, runtime Add/Replace candidates, and dynamic endpoint generations. Preserve running Add publication/readiness decoupling and add deterministic concurrency and shutdown coverage. Closes #661
* feat(health): return structured probe outcomes * fix(test): configure multi-cluster request timeout policy * fix(test): allow dynamic-only health cluster * fix(health): honor canonical client lifecycle * test(health): cover lifecycle domain races
* api: add structured runtime configuration result * client: add non-throwing runtime configuration publication paths * client: expose structured runtime configuration APIs * client: add structured topology runtime updates * server: add structured runtime configuration publication paths * server: expose structured runtime configuration APIs * client: document structured runtime configuration APIs * test: cover structured runtime configuration results * test: import SDK contract types in fallback coverage * fix: prioritize lifecycle seal over runtime mode conflicts * fix: address runtime configuration review feedback
* ci: make PR Quick manual-only * ci: split package smoke from PR Quick
* feat(protocol): define session refresh control signal * feat(protocol): negotiate session refresh capability * feat(protocol): advertise session refresh support * feat(protocol): encode session refresh requests * feat(runtime): send session refresh control frames * feat(api): define desired session configuration * feat(api): expose desired session publication * feat(server): publish desired session generations * feat(server): pin desired snapshot at accept boundary * feat(server): carry desired snapshot through accepted session * feat(server): negotiate from pinned desired session snapshot * feat(runtime): dispatch negotiated session refresh requests * feat(runtime): consume session refresh control frames * fix(protocol): gate session refresh negotiation by transport * fix(server): defer stale refresh until session ready * feat(client): attach session refresh ownership at ready publication * feat(client): route session refresh to topology owner * feat(client): blue-green replace fixed sessions on refresh * feat(client): blue-green replace static endpoint sessions * feat(client): blue-green replace dynamic endpoint sessions * fix(server): supervise stale session refresh catch-up * docs(session): define desired generation and rolling refresh contract * docs(index): link session refresh contract * test(protocol): cover session refresh payload contract * test(server): cover desired session publication semantics * fix(test): build desired-session server with existing test primitives * test(protocol): cover session refresh capability fallback * fix(runtime): avoid by-ref parameter on async refresh send * fix(server): key desired session pins by session identity * fix(server): supervise refresh catch-up as finite work * style: restore final newline in server API * style: restore final newline in protocol surface * style: restore final newline in desired-session API * style: restore final newline in protocol rules * style: restore final newline in refresh codec * style: restore final newline in server accept loop * test(client): cover session refresh replacement invariants * test(client): pin refresh capacity and improve diagnostics * fix(protocol): recognize session refresh control frames * test(protocol): cover session refresh frame parsing * fix(protocol): accept refresh while session drains * test(runtime): allow session refresh while draining * perf(server): remove ambient desired session state * refactor(server): pass desired snapshot into handshake * refactor(server): thread desired snapshot through lifecycle * fix(session): address rolling refresh review races * fix(api): restore runtime extension documentation * test: fix desired session review definite assignment * fix(client): keep refresh reservations out of active-call load * style: restore dynamic refresh final newline * fix(client): reconcile reconnect after refresh publication race * test(client): expose exact refresh eligibility cut * fix(client): restore expansion load trigger and tighten refresh tests * test(client): make refresh review races deterministic * fix(server): rescan same-generation rolling refresh requests * docs: align refresh admission and rescan semantics * fix(client): route disconnect cleanup through topology owner * fix(client): abort refresh cut when replacement already failed * test(client): synchronize refresh cut assertions * fix(client): linearize refresh cut and bound refresh redirects The blue-green eligibility cut reserved replacement admission but did not freeze the replacement's fatal transition, so a replacement that failed after the reservation and before the source admission closure still let the cut proceed against a dead target. Linearize the cut on a connection-level commit CAS: the admission reservation stays in TryReserveSessionRefreshCommit, the separate TryCommitSessionRefreshRetirement claims the cut, and ObserveFatalFailureForAdmission (including Fail) rejects an unclaimed commit. A failure published first rolls the replacement back, keeps the source selectable, and retries the refresh debt; a failure after the claim follows ordinary post-cut semantics. Fixed, static, and dynamic cut sites all use the same claim. Replace the fixed 32-hop predecessor chain with one shared SessionRefreshRedirect per refresh lineage. Every retired generation points at the same indirection and it holds only the newest Ready replacement, so a pinned long-lived source no longer retains disposed predecessors and stale admission resolves in constant depth regardless of how many rolling refreshes completed. Regressions cover the post-reservation pre-cut replacement failure for fixed/static/dynamic, and more than 32 successful refreshes pinned by a long-lived server-streaming call. * fix(session): bound refresh enqueue waits and account control frames * fix(client): make refresh publication the admission cut * fix(session): honor publication snapshots and fixed refresh bounds * fix(session): bound idle cluster refresh and scope snapshot pins * fix(session): preserve advanced refresh debt and admission eligibility
* chore(release): calibrate 2.0 versions and prepare five-hour CI soak * Finalize 2.0 public API, package boundaries and release validation * Install ripgrep for the release architecture guard * Align protocol fixture with explicit timeout policy and bound macOS test workers * Document the non-loopback TCP migration requirements
This was referenced Sep 12, 2026
* Capture bounded Windows chaos hang diagnostics before runner timeout * fix(client): detach supervised cleanup from topology locks * fix(client): release cluster topology lock before stop teardown * fix(runtime): join send-pump publication during session teardown * fix: share safe handles for local anonymous pipe clients * ci: align quick test concurrency with release validation
…673) * test: synchronize replacement routing and warm allocation probes * test: await supervised connection cleanup after heartbeat expiry * ci: fail the required release summary when any dependency fails
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.
Merge the complete SharpLink 2.0 release from dev into main. This major release introduces Generated API 4, Protocol v2 minor 4 TimeBudget semantics, explicit client timeout policy, supervised Client/Server lifecycles, runtime configuration/refresh results, isolated codec ownership and the separate Zstd compression package. All eight shipping packages have reviewed API snapshots, calibrated version boundaries, package validation and source migration documentation.
The integration branch retains both main and dev ancestry. Its final tree is byte-for-byte identical to dev at 9d1653a, including both dependency upgrades (#566/#567), release preparation #670 ownership fixes #672 and test/gate completion corrections #673. The latter resolve disconnect/registration lock cycles, send-pump publication versus teardown, and same-process anonymous-pipe handle ownership. Quick and full test workflows now consistently bound inter-test concurrency at eight while preserving each race test's own concurrency.
Validation of the included runtime source: Release Gate 34713374851 passed all three full test matrices, NativeAOT, eight-package API/version/architecture checks, six desktop compatibility identities and Chaos. Windows completed three separate chaos attempts with final reports and zero unexpected failures. Full unit count is 1815, generator 264, load-tool 60 and integration 451 per platform. The CI-only follow-up passed fresh PR checks at 6ab4d96. Follow-up #673 waits for the actual replacement routing cut and supervised heartbeat connection cleanup, warms the exact allocation probe, and makes the required release summary fail on any unsuccessful prerequisite. Its fresh PR checks passed at bb8d7a2. The current integration head must pass its own full Release Gate before this PR merges.
The ordinary production admission reservation/release BDN comparison is 6.317 ns before → 3.889 ns after (ratio 0.62), with zero managed B/op in both; this is a focused hot-path measurement, not end-to-end RPC throughput. After merge, the exact final-main commit must pass Release Gate again, and its actual packages must complete the published-NuGet 1.1.1 → final-main 2.0 → published-1.1.1 ABA matrix on the four-physical-core server with VM/Mac clients before tagging/publishing.
Browser/Mono/WASM remains investigational under #253; only the six desktop CoreCLR compatibility identities are blocking and supported by that matrix. Five-hour Actions soak runs in parallel under the user's explicit release exception, with its exact SHA/link/status recorded and a follow-up on completion. Pending is never reported as passed. Release evidence and #86/#67/#572 closure follow final validation and publication.