Share native discovery sessions across cancellation scopes
Concurrent native discovery with credentials and AbortSignals cloned the Rust credential configuration for every cursor, resetting its session cache and opening duplicate Session RPCs. Native follows and discovery now share one Rust client and session pool, with cancellation scoped to logical operations.
Cancelling the first cursor while its Session awaits Welcome no longer cancels a sibling's initialization. When the final interest ends, the pool closes its cached Session RPCs.
Decisions
- The pool owns physical Session initialization. Publishing the shared pool does no I/O; the pool driver owns handshakes and their existing deadlines. Cursor cancellation ends only that cursor's wait.
- Reserve logical interests synchronously when a native open is called, before scheduling its asynchronous worker. Otherwise a queued sibling can be invisible when the first cursor cancels. The existing JS signatures remain unchanged.
- Count queued opens as live interests. On the final release, discard links, readers and pending dials. The reusable pool remains cached, but no Session RPC remains live.
- Resolve credentials afresh for each physical RPC through the existing native callback. Different provider instances retain separate authentication and pools. Abort pending credential work when its final interested operation ends; snapshot pending requests before invoking reentrant abort callbacks.
- These lifetimes are ephemeral transport state. A volume file cannot represent cancellation of an in-flight RPC; no application store, service or protocol message is added.
- README changes remain separate in #677.
Validation
- Windows:
lb.ps1 cargo check --locked -p acyclic-stream -p acyclic-stream-napi --features acyclic-stream/local,acyclic-stream/http --lib --testspasses in 11.02 s after acquiring its build slot. Audited callers of the changed private constructors and native exports. - Linux through
bs.ps1: 9 actual pool/cache models and properties pass in 0.61 s, including initialization ownership, cancellation before a queued sibling open, last-interest shutdown and cache publication. Each broken variant is detected. The models use the crate-local loom synchronization shim. - 32 standalone models/properties pass in 0.13 s, including the real native activation helper, cancellation versus Welcome and worker registration, an omitted-activation negative control, and a shrinking completion property.
- 18 SDK session tests pass in 3.08 s, 2 HTTP checks in 0.05 s, and 10 N-API checks in 0.07 s. The SDK results precede the final N-API scheduling correction; unchanged SDK code was not rebuilt to repeat them. The corrected N-API exports were built and all 10 N-API checks rerun successfully.
- With the freshly built Linux binding, 13 focused TS checks pass in 0.945 s. TLS regressions cover 32 discovery channels plus a sibling follow, moving discovery to a second node, cancellation during credential resolution, and the exact held-Welcome schedule: start A, hold Welcome, start B, abort A, release Welcome. They assert one HTTP/2 connection and one Session RPC per node, continued sibling delivery, zero actor channels, and zero live Sessions before fixture servers are force-closed.
- The real credential-scope code covers all 360 bounded schedules, reentrant cancellation and a 64-case shrinking accounting property. Three broken variants and the existing missing-signal negative control are detected. Strict native-adapter TypeScript checking also passes.
The final Linux batch is logged at /home/var/log/buildbox/2026-10-16T084801908Z-3218248.log. Each runtime suite stays below 10 seconds; prerequisite builds are separate.
Live steps
Deployed-service latency qualification and the 10k-agent scenario remain tracked separately in #644. This PR claims no deployed latency result.