Fence abandoned Session reconnects before credential cancellation
Cancelling the final native cursor during home-node reconnect aborted its credential request, but the pool could keep that dial in connecting. A cursor opened before the old callback settled could join the abandoned attempt and receive its credential failure.
The credential scope now synchronously fences pending Session attempts before aborting their authentication work. New opens carry the current generation; dispatch discards abandoned dials and their connecting entries before admitting a new open. Late results from an older generation cannot fail or install over the successor.
Decisions
- Keep the shared session pool and TLS channel. Abandon pending handshakes, rather than resetting the cache per cursor. Existing sessions remain owned by their logical interests; cancellation of one of several cursors does not advance the fence.
- Pass the final-interest notification through a synchronous native client bridge so it precedes credential abort callbacks, which may reenter and open a new cursor. This is ephemeral transport cancellation; a volume file cannot represent an in-flight handshake lifetime. No wire message or service is added.
- Use the existing crate-local loom atomic/mutex shim and coalesced wakeup gate. The cache lock is released before notifying the pool. The dispatcher clears the wake flag before reading the generation, so a concurrent abandonment is either observed immediately or leaves a wake.
- Correct the TLS fixture to map its deliberate disconnect to gRPC
Unavailable; an untyped server exception exercised terminal failure instead of reconnect. Product error handling and assertions are unchanged.
Validation
- Windows:
lb.ps1 cargo check --locked -p acyclic-stream -p acyclic-stream-napi --features acyclic-stream/local,acyclic-stream/http --lib --testspasses in 5.47 s. Audited native bridge and changed command/route constructors. - Linux through
bs.ps1: 11 real pool/cache models and properties pass in 9.61 s, including cancellation versus wake registration, a new open versus a stale dial error, and successful successor admission. The broken variant lets the abandoned credential error terminate the new interest and is detected. Existing initialization ownership, node isolation, idle shutdown and accounting controls remain active. - 18 session tests pass in 3.04 s; 10 N-API tests pass in 0.07 s. The native binding was built from the same Rust source.
- 15 TS checks pass in 1.261 s, plus strict native-adapter typechecking. The actual TLS schedule cancels the last cursor mid-reconnect, opens another cursor while the old provider promise is unresolved, and requires the new cursor to receive data through a fresh credential call. It then settles the old promise and verifies continued delivery. The test asserts two Session generations, one HTTP/2 connection, zero actor channels, and zero live Sessions before fixture shutdown.
- All 360 credential schedules include fence-before-abort assertions; an omitted-fence negative control fails. A 64-case shrinking property checks final-interest fences, live request accounting and idempotent cleanup.
- Rust/model batch:
/home/var/log/buildbox/2026-10-16T091257376Z-3290308.log. Resumed typecheck/TS run, reusing the built binding:/home/var/log/buildbox/2026-10-16T091707185Z-3300443.log. Each runtime suite is below 10 seconds. The initial TS command omitted Node type roots and an Actors declaration prerequisite; those setup errors were corrected before the final run.
Live steps
Restack #579, #650 and #644 after this follow-up. Deployed-service latency qualification remains outstanding; these local tests do not establish deployed behavior.
Summary by cubic
Fences abandoned Session reconnects before credential cancellation
Cancelling the last native cursor during home-node reconnect could let a newly opened cursor join the abandoned handshake and receive its credential failure. New opens now carry the current attempt generation, and the pool discards abandoned dials and stale connecting entries before admitting a successor cursor.
- Adds a synchronous
abandon_session_attemptsnative bridge call, invoked before the native credential provider signal is aborted. - Late dial results from an older generation are dropped, so a stale credential error cannot fail or install over the successor.
- Keeps the shared session pool and TLS channel; only pending handshakes are fenced, not existing sessions.
- Extends loom models and TS property schedules to assert fence-before-abort orderingebb and adds a negative control test.