Skip to main content

liminal_server/server/connection/
supervisor.rs

1use std::collections::HashMap;
2#[cfg(test)]
3use std::collections::VecDeque;
4use std::net::{SocketAddr, TcpStream};
5use std::os::fd::RawFd;
6#[cfg(test)]
7use std::sync::Barrier;
8use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
9use std::sync::mpsc::{Receiver, RecvTimeoutError, Sender, TryRecvError, channel};
10use std::sync::{Arc, Condvar, Mutex, MutexGuard, PoisonError, Weak};
11use std::thread;
12use std::time::{Duration, Instant};
13
14use beamr::atom::{Atom, AtomTable};
15use beamr::module::ModuleRegistry;
16use beamr::native::native_process::NativeHandlerFactory;
17use beamr::process::ExitReason;
18use beamr::scheduler::{
19    ExitEvent, ExitEventSubscription, ReadinessToken, Scheduler, SchedulerConfig, SchedulerServices,
20};
21use beamr::timer::TimerRef;
22
23use liminal::protocol::WorkerRegistration;
24use liminal_protocol::wire::ConnectionIncarnation;
25
26use super::incarnation::ConnectionIncarnationAuthority;
27use super::notifier::ConnectionNotifier;
28use super::process::ConnectionProcess;
29use super::services::{
30    ConnectionServices, LiminalConnectionServices, ProductionSubsystems, SubsystemFactory,
31    build_connection_services_via,
32};
33use crate::ServerError;
34use crate::config::types::{LimitsConfig, ServerConfig};
35use crate::server::participant::{
36    ConnectionFateClass, InstalledParticipantService, ParticipantSemanticHandler,
37    ParticipantServiceFatal,
38};
39use crate::server::shutdown::ShutdownHandle;
40
41const CONNECTION_SCHEDULER_THREADS: usize = 4;
42const CONNECTION_SHUTDOWN_CONTROL_ATOM: &str = "liminal_server_connection_shutdown_control";
43/// R6 (§1.2(4)): the single `READY` wake vocabulary for a connection. One atom;
44/// any marker (or N coalesced) triggers one full slice servicing all sources.
45const CONNECTION_READY_ATOM: &str = "liminal_server_connection_ready";
46
47#[cfg(test)]
48#[path = "supervisor_fate_tests.rs"]
49mod fate_tests;
50#[cfg(test)]
51#[path = "supervisor_tests.rs"]
52mod tests;
53
54/// Supervisor that owns the beamr scheduler for per-connection processes.
55#[derive(Clone, Debug)]
56pub struct ConnectionSupervisor {
57    inner: Arc<SupervisorInner>,
58}
59
60impl ConnectionSupervisor {
61    /// Creates a connection supervisor backed by the services the config's
62    /// `[services]` profile selects: the full liminal channel/conversation stack
63    /// (the default) or the capability-scoped worker front door. Profile
64    /// enforcement is [`build_connection_services`](super::services::build_connection_services)'s,
65    /// so this constructor can never build full services for a worker-front-door
66    /// config.
67    ///
68    /// # Errors
69    /// Returns [`ServerError`] when service construction or scheduler startup fails.
70    pub fn from_config(config: &ServerConfig) -> Result<Self, ServerError> {
71        Self::from_config_via(config, &ProductionSubsystems)
72    }
73
74    /// [`Self::from_config`] with the §9 D2 subsystem factory injected.
75    ///
76    /// The factory is the only route to every scheduler-owning subsystem the
77    /// services construction builds, so a recording factory observes exactly what
78    /// was constructed; the connection scheduler itself (built below for BOTH
79    /// profiles) is the census baseline, not a census entry.
80    fn from_config_via(
81        config: &ServerConfig,
82        subsystems: &dyn SubsystemFactory,
83    ) -> Result<Self, ServerError> {
84        let services = build_connection_services_via(config, subsystems)?;
85        // The configured token (if any) is carried opaquely as bytes for a
86        // constant-time comparison against the handshake's `auth_token`. Absent
87        // `[auth]` leaves it `None`, so the connection stays open-access.
88        let auth_token = config
89            .auth
90            .as_ref()
91            .map(|auth| auth.token.clone().into_bytes());
92        SupervisorInner::new(services, None, auth_token, config.limits, None).map(|inner| Self {
93            inner: Arc::new(inner),
94        })
95    }
96
97    /// Creates a connection supervisor with no configured channels.
98    ///
99    /// # Errors
100    /// Returns [`ServerError`] when scheduler startup fails.
101    pub fn new() -> Result<Self, ServerError> {
102        Self::with_services(Arc::new(LiminalConnectionServices::empty()?))
103    }
104
105    /// Creates a connection supervisor using an explicit service adapter.
106    ///
107    /// # Errors
108    /// Returns [`ServerError`] when scheduler startup fails.
109    pub fn with_services(services: Arc<dyn ConnectionServices>) -> Result<Self, ServerError> {
110        SupervisorInner::new(services, None, None, LimitsConfig::default(), None).map(|inner| {
111            Self {
112                inner: Arc::new(inner),
113            }
114        })
115    }
116
117    /// Creates a connection supervisor with an explicit service adapter and the
118    /// configured connection auth token.
119    ///
120    /// This is the production constructor for callers that build services
121    /// themselves (the runtime needs the shared channel cluster before the
122    /// supervisor takes ownership) and therefore cannot use
123    /// [`Self::from_config`]: without it the configured `[auth]` token would be
124    /// silently dropped and the server would run open-access.
125    ///
126    /// # Errors
127    /// Returns [`ServerError`] when scheduler startup fails.
128    pub fn with_services_and_auth(
129        services: Arc<dyn ConnectionServices>,
130        auth_token: Option<Vec<u8>>,
131    ) -> Result<Self, ServerError> {
132        Self::with_services_auth_and_limits(services, auth_token, LimitsConfig::default())
133    }
134
135    /// Creates a connection supervisor with explicit services, authentication,
136    /// and operational limits.
137    ///
138    /// Production runtime construction uses this form so the durable
139    /// incarnation stream's complete-reference bound is the same signed
140    /// `max_connections` bound enforced by connection admission.
141    ///
142    /// # Errors
143    /// Returns [`ServerError`] when incarnation startup or scheduler startup fails.
144    pub fn with_services_auth_and_limits(
145        services: Arc<dyn ConnectionServices>,
146        auth_token: Option<Vec<u8>>,
147        limits: LimitsConfig,
148    ) -> Result<Self, ServerError> {
149        Self::with_services_auth_limits_and_fatal_shutdown(services, auth_token, limits, None)
150    }
151
152    /// Production composition with the process-wide shutdown activation that a
153    /// post-Open participant fatal must join.
154    pub(crate) fn with_fatal_shutdown(
155        services: Arc<dyn ConnectionServices>,
156        auth_token: Option<Vec<u8>>,
157        limits: LimitsConfig,
158        fatal_shutdown: ShutdownHandle,
159    ) -> Result<Self, ServerError> {
160        Self::with_services_auth_limits_and_fatal_shutdown(
161            services,
162            auth_token,
163            limits,
164            Some(fatal_shutdown),
165        )
166    }
167
168    fn with_services_auth_limits_and_fatal_shutdown(
169        services: Arc<dyn ConnectionServices>,
170        auth_token: Option<Vec<u8>>,
171        limits: LimitsConfig,
172        fatal_shutdown: Option<ShutdownHandle>,
173    ) -> Result<Self, ServerError> {
174        SupervisorInner::new(services, None, auth_token, limits, fatal_shutdown).map(|inner| Self {
175            inner: Arc::new(inner),
176        })
177    }
178
179    /// Creates a connection supervisor with an explicit service adapter and a
180    /// connection-keyed worker-registration notifier.
181    ///
182    /// The `notifier` is invoked when a worker registers on a connection and when
183    /// such a connection closes. Supervisors built via [`Self::with_services`],
184    /// [`Self::from_config`], or [`Self::new`] carry no notifier, so liminal still
185    /// runs standalone; a `WorkerRegister` frame is then accepted without any
186    /// application callback.
187    ///
188    /// # Errors
189    /// Returns [`ServerError`] when scheduler startup fails.
190    pub fn with_services_and_notifier(
191        services: Arc<dyn ConnectionServices>,
192        notifier: Arc<dyn ConnectionNotifier>,
193    ) -> Result<Self, ServerError> {
194        SupervisorInner::new(
195            services,
196            Some(notifier),
197            None,
198            LimitsConfig::default(),
199            None,
200        )
201        .map(|inner| Self {
202            inner: Arc::new(inner),
203        })
204    }
205
206    /// Spawns one supervised beamr process that owns `stream`.
207    ///
208    /// # Errors
209    /// Returns [`ServerError`] when stream configuration or beamr spawn fails.
210    pub fn spawn_connection(&self, stream: TcpStream) -> Result<ConnectionHandle, ServerError> {
211        self.inner.spawn_connection(stream)
212    }
213
214    /// Returns the underlying beamr scheduler.
215    #[must_use]
216    pub fn scheduler(&self) -> Arc<Scheduler> {
217        Arc::clone(&self.inner.scheduler)
218    }
219
220    /// Reaps connection processes that have exited outside the normal handler path.
221    #[must_use]
222    pub fn reap_crashed_connections(&self) -> usize {
223        self.inner.runtime.reap_crashed(&self.inner.scheduler)
224    }
225
226    /// Returns true when `pid` is still tracked by the supervisor.
227    #[must_use]
228    pub fn is_tracked(&self, pid: u64) -> bool {
229        self.inner.runtime.contains(pid)
230    }
231
232    /// Returns the number of tracked live connections.
233    #[must_use]
234    pub fn active_connection_count(&self) -> usize {
235        self.inner.runtime.active_count()
236    }
237
238    /// Parks until every tracked connection has been removed or `deadline`
239    /// elapses, returning `true` when the drain completed and `false` when the
240    /// single admitted deadline won.
241    ///
242    /// The TOLD drain-completion replacement (W4 leg 3, §4.3): the waiter is woken
243    /// by the one `remove()` funnel every connection exit reaches — never by a
244    /// reap/count timer. Both the graceful drain and the force-close settle call
245    /// this same waiter, each with its own one-shot deadline; there is no second
246    /// settle poll loop.
247    #[must_use]
248    pub(crate) fn wait_for_connections_drained(&self, deadline: Instant) -> bool {
249        self.inner
250            .runtime
251            .wait_for_active_connections_drained(deadline)
252    }
253
254    /// Returns the first latched post-Open participant fatal, if any.
255    ///
256    /// The production runtime reads this after its existing shutdown handle wakes,
257    /// then returns the typed fatal after the ordinary drain and durable flush.
258    pub(crate) fn participant_service_fatal(
259        &self,
260    ) -> Result<Option<ParticipantServiceFatal>, ServerError> {
261        self.inner.runtime.participant_service_fatal()
262    }
263
264    /// Returns the beamr process ids of the currently tracked live connections.
265    ///
266    /// Useful for addressing a specific connection — e.g. as the `pid` argument to
267    /// [`push_to_connection`](Self::push_to_connection) when the caller knows there
268    /// is a single connected client.
269    #[must_use]
270    pub fn active_connection_pids(&self) -> Vec<u64> {
271        self.inner
272            .runtime
273            .active_connections()
274            .into_iter()
275            .map(|connection| connection.pid)
276            .collect()
277    }
278
279    /// Broadcasts a best-effort shutdown notification to active connections.
280    ///
281    /// Connections with no active subscriptions ignore the notification. Failures
282    /// to enqueue the control message are logged and skipped; they are not retried.
283    pub fn notify_shutdown_subscribers(&self) {
284        self.inner
285            .broadcast_control(&ConnectionControl::NotifyShutdown);
286    }
287
288    /// Sends a force-close control message to every tracked connection process.
289    ///
290    /// Each live process attempts one shutdown notification before closing its
291    /// stream and exiting normally. Enqueue failures are logged and skipped.
292    pub fn force_close_active_connections(&self) {
293        for connection in self.inner.runtime.active_connections() {
294            tracing::warn!(
295                connection_pid = connection.pid,
296                peer_addr = ?connection.peer_addr,
297                "forcefully closing connection after drain timeout"
298            );
299            if !self
300                .inner
301                .enqueue_control(connection.pid, ConnectionControl::ForceClose)
302            {
303                tracing::warn!(
304                    connection_pid = connection.pid,
305                    peer_addr = ?connection.peer_addr,
306                    "failed to request forceful connection close; process is not live"
307                );
308            }
309        }
310    }
311
312    /// Pushes an opaque payload to a specific connected client over that client's
313    /// existing connection and returns an awaiter for the client's correlated reply.
314    ///
315    /// This is the server-initiated leg (server-to-client), the inverse of every
316    /// other request frame. It allocates a correlation id, registers a one-shot
317    /// reply slot keyed by that id, and enqueues a [`ConnectionControl::Push`] for
318    /// the connection process owning `pid`; that process writes a [`Frame::Push`]
319    /// out on its socket. When the client answers with a `PushReply` carrying the
320    /// same correlation id, the connection process resolves the awaiter's slot. The
321    /// returned [`PushReplyAwaiter`] blocks (bounded) for that reply.
322    ///
323    /// The reply's lifetime belongs to the push, not to any one
324    /// [`PushReplyAwaiter::receive`] call: this no-deadline push reserves a slot
325    /// that is reclaimed only by (a) the reply being consumed or (b) the
326    /// connection closing. An elapsed `receive` poll is a benign re-arm, never a
327    /// failure and never a cancellation. The §5
328    /// `max_pending_pushes_per_connection` cap bounds abandonment; use
329    /// [`push_to_connection_with_deadline`](Self::push_to_connection_with_deadline)
330    /// when the reply must have an explicit expiry.
331    ///
332    /// # Errors
333    /// Returns [`ServerError`] when the correlation id cannot be allocated, the
334    /// reply slot cannot be registered, or the control message cannot be enqueued
335    /// for the (possibly already-gone or concurrently-closing) connection
336    /// process. PUBLICATION INVARIANT: an `Err` guarantees no `Push` control was
337    /// published — the client never sees a `Push` frame for a failed call.
338    /// Conversely `Ok` promises ADMISSION, not delivery: the awaiter's outcome
339    /// is the delivery truth (a push admitted just as its connection closes
340    /// resolves to the truthful disconnected outcome, never to a lost reply).
341    pub fn push_to_connection(
342        &self,
343        pid: u64,
344        payload: Vec<u8>,
345    ) -> Result<PushReplyAwaiter, ServerError> {
346        self.push_with_deadline(pid, payload, None)
347    }
348
349    /// Like [`push_to_connection`](Self::push_to_connection) but attaches an
350    /// explicit reply deadline to the reserved slot: `deadline` is a DURATION
351    /// FROM NOW bounding the reply's lifetime — a property of THIS push rather
352    /// than of any [`PushReplyAwaiter::receive`] wait quantum.
353    ///
354    /// Deadline expiry is evaluated HOST-SIDE and LAZILY — at the next `receive`
355    /// touch, and at connection close at the latest. It never wakes the connection
356    /// process, adds no timer thread, and runs no periodic sweeper: a push that is
357    /// abandoned and never polled resolves at the next host-side touch (connection
358    /// close). At expiry the slot resolves to [`ServerError::PushReplyExpired`],
359    /// is removed, and its §5 `max_pending_pushes_per_connection` cap admission is
360    /// released. An elapsed `receive` poll BEFORE the deadline is still a benign
361    /// re-arm. A `receive` call in flight when the deadline falls due returns
362    /// the terminal expiry PROMPTLY — it waits the earlier of its quantum and
363    /// the deadline, so a large quantum can never extend the reply's lifetime
364    /// and the terminal outcome is quantum-independent.
365    ///
366    /// The deadline is evaluated at OBSERVATION POINTS, not enforced against the
367    /// wall clock: a reply that arrives before expiry is observed is delivered
368    /// normally, even if it arrives after the deadline instant. The deadline
369    /// bounds waiting and slot occupancy; it is not a delivery-freshness
370    /// guarantee. (This is deliberate — a reply is checked for at every
371    /// observation point before the deadline is, so an answer in hand always
372    /// beats an expiry.)
373    ///
374    /// # Errors
375    /// Returns [`ServerError`] when `deadline` is not representable on the
376    /// monotonic clock (an extreme duration is refused, never a panic), the
377    /// correlation id cannot be allocated, the reply slot cannot be registered,
378    /// or the control message cannot be enqueued for the (possibly already-gone
379    /// or concurrently-closing) connection process. PUBLICATION INVARIANT: an
380    /// `Err` guarantees no `Push` control was published — the client never sees
381    /// a `Push` frame for a failed call. Conversely `Ok` promises ADMISSION,
382    /// not delivery: the awaiter's outcome is the delivery truth.
383    pub fn push_to_connection_with_deadline(
384        &self,
385        pid: u64,
386        payload: Vec<u8>,
387        deadline: Duration,
388    ) -> Result<PushReplyAwaiter, ServerError> {
389        self.push_with_deadline(pid, payload, Some(deadline))
390    }
391
392    /// Shared body for the no-deadline and explicit-deadline push paths. With
393    /// `deadline == None` this is byte-for-byte the historical
394    /// `push_to_connection` behaviour (no per-slot deadline); with `Some`, the
395    /// slot carries an absolute expiry evaluated lazily at `receive`.
396    fn push_with_deadline(
397        &self,
398        pid: u64,
399        payload: Vec<u8>,
400        deadline: Option<Duration>,
401    ) -> Result<PushReplyAwaiter, ServerError> {
402        // S5: an extreme `Duration` must surface as this fallible API's typed
403        // error, not an `Instant` addition panic. Checked BEFORE any slot is
404        // registered so a refused deadline leaves nothing to roll back.
405        let deadline_at = match deadline {
406            None => None,
407            Some(window) => {
408                Some(
409                    Instant::now()
410                        .checked_add(window)
411                        .ok_or_else(|| ServerError::ListenerAccept {
412                            message: format!(
413                                "cannot push to connection process {pid}: reply deadline of {window:?} overflows the monotonic clock"
414                            ),
415                        })?,
416                )
417            }
418        };
419        let correlation_id = self.inner.runtime.next_push_correlation_id();
420        let receiver = self
421            .inner
422            .runtime
423            .register_push(pid, correlation_id, deadline_at)?;
424        // S3+S7 close-vs-register wall, ordered INSERT -> CONFIRM -> PUBLISH.
425        // The confirmation runs BEFORE the control is enqueued, which yields the
426        // PUBLICATION INVARIANT: an `Err` from this method guarantees no `Push`
427        // control was published — the client never sees a Push for a failed
428        // call. (Confirming after the enqueue was S7's non-linearizable race: a
429        // close could sweep, the published Push could already be answered and
430        // resolved, and the failed confirmation then returned `Err` for a push
431        // the client had received.) A close landing AFTER a successful confirm
432        // linearizes after push admission: the enqueue either fails (process
433        // gone — rollback below, `Err` truthful, nothing delivered) or succeeds
434        // with the slot already swept, and the awaiter then reads the truthful
435        // DISCONNECTED while a late client reply is the pinned harmless no-op.
436        // The exactly-one-side-observes argument lives at
437        // `confirm_push_registration`.
438        if !self
439            .inner
440            .runtime
441            .confirm_push_registration(pid, correlation_id)
442        {
443            return Err(ServerError::ListenerAccept {
444                message: format!(
445                    "cannot push to connection process {pid}: the connection closed during push registration"
446                ),
447            });
448        }
449        let control = ConnectionControl::Push {
450            correlation_id,
451            payload,
452        };
453        if self.inner.enqueue_control(pid, control) {
454            Ok(PushReplyAwaiter {
455                correlation_id,
456                receiver,
457                deadline: deadline_at,
458                runtime: Arc::downgrade(&self.inner.runtime),
459            })
460        } else {
461            // The process is gone AND the control provably never reached a
462            // consumer: `enqueue_control` returns false only when its failed-wake
463            // rollback REMOVED the queued control (S8 — an entry a drain already
464            // consumed counts as published and returns true, with the slot
465            // lifecycle carrying the delivery truth). Dropping the now-unreachable
466            // reply slot here therefore keeps the publication invariant exact on
467            // every `Err` path.
468            self.inner.runtime.cancel_push(correlation_id);
469            Err(ServerError::ListenerAccept {
470                message: format!("cannot push to connection process {pid}: process is not live"),
471            })
472        }
473    }
474
475    /// Flushes durable channel state through the configured liminal services.
476    ///
477    /// # Errors
478    /// Returns [`ServerError::ShutdownFlush`] when the underlying service flush fails.
479    pub fn flush_durable_state(&self) -> Result<(), ServerError> {
480        self.inner.runtime.services().flush_durable_state()
481    }
482
483    /// LP-WS-TRANSPORT R1.3 sibling-transport spawn seam (ADDITIVE ONLY).
484    ///
485    /// Admits, allocates a durable connection incarnation for, spawns, and
486    /// registers a connection process whose handler is built by `build_factory`
487    /// over this supervisor's shared [`ConnectionRuntime`]. The WebSocket
488    /// sibling acceptor uses this so its connections share the ONE §5
489    /// `max_connections` admission bound, the one incarnation authority, the
490    /// one registry (controls, pushes, crash reap, drain, forced close), and the
491    /// one `apply_frame` seam with TCP connections. The TCP accept path above
492    /// (`spawn_connection`) is byte-for-byte untouched and never calls this.
493    ///
494    /// `fd_guard` is a host-held duplicate of the connection's underlying
495    /// socket, exactly like the TCP path's: it keeps the fd alive until the
496    /// single record-removal path has synchronously deregistered readiness.
497    ///
498    /// This method exists because Rust module privacy makes the runtime,
499    /// admission counter, incarnation authority, and registry unreachable from
500    /// the sibling `websocket` module family; it is the narrow additive seam
501    /// that shares them without generalizing any TCP hot path.
502    ///
503    /// # Errors
504    /// Returns [`ServerError`] when admission is refused
505    /// ([`ServerError::ConnectionLimitReached`]), incarnation allocation fails,
506    /// or beamr spawn/registration fails.
507    pub(super) fn spawn_transport_connection(
508        &self,
509        peer_addr: Option<SocketAddr>,
510        fd_guard: TcpStream,
511        build_factory: &dyn Fn(
512            Arc<ConnectionRuntime>,
513            Option<ConnectionIncarnation>,
514        ) -> NativeHandlerFactory,
515    ) -> Result<ConnectionHandle, ServerError> {
516        self.inner
517            .spawn_transport_connection(peer_addr, fd_guard, build_factory)
518    }
519
520    /// Stops the beamr scheduler used by connection processes.
521    pub fn shutdown(&self) {
522        // Remove every host record while the readiness owner is still live. The
523        // removal path ACKs deregistration and only then releases each fd guard;
524        // scheduler shutdown subsequently drops the process-owned handles.
525        for connection in self.inner.runtime.active_connections() {
526            self.inner.runtime.finish(connection.pid);
527        }
528        self.inner.scheduler.shutdown();
529    }
530
531    /// R7 test instrument: slices serviced by connection `pid` since spawn.
532    #[cfg(test)]
533    pub(crate) fn slice_count(&self, pid: u64) -> u64 {
534        self.inner.runtime.slice_count(pid)
535    }
536
537    /// Installs a one-use readiness marker for the next serviced slice of `pid`.
538    #[cfg(test)]
539    pub(crate) fn observe_next_slice(&self, pid: u64) -> Receiver<u64> {
540        self.inner.runtime.observe_next_slice(pid)
541    }
542
543    /// Installs a one-use readiness marker for the next genuine scheduler park of
544    /// `pid`. The delivered value is the process's slice count at the final probe
545    /// that selected `Wait`.
546    #[cfg(test)]
547    pub(crate) fn observe_next_park(&self, pid: u64) -> Receiver<u64> {
548        self.inner.runtime.observe_next_park(pid)
549    }
550
551    /// Returns a marker for the current park when `pid` is already settled, or
552    /// the next park when a coalesced readiness event has started another slice.
553    #[cfg(test)]
554    pub(crate) fn observe_settled_park(&self, pid: u64) -> Receiver<u64> {
555        self.inner.runtime.observe_settled_park(pid)
556    }
557
558    /// Queues an explicit outbound capacity for the next TCP process constructed.
559    #[cfg(test)]
560    pub(crate) fn queue_next_outbound_capacity(&self, capacity: usize) {
561        self.inner.runtime.queue_next_outbound_capacity(capacity);
562    }
563
564    #[cfg(test)]
565    pub(crate) fn install_participant_holdback_pause(&self, pid: u64) -> Receiver<()> {
566        self.inner.runtime.install_participant_holdback_pause(pid)
567    }
568
569    #[cfg(test)]
570    pub(crate) fn resume_test_process(&self, pid: u64) -> bool {
571        self.inner.runtime.ready_waker(pid).is_some_and(|waker| {
572            waker.fire();
573            true
574        })
575    }
576
577    /// Reserved push reply slots outstanding (test observability for the public
578    /// push paths — lets e2e tests assert slot reclamation and cap accounting).
579    #[cfg(test)]
580    pub(super) fn pending_push_count(&self) -> usize {
581        self.inner.runtime.pending_push_count()
582    }
583
584    /// R6 test seam: a [`ReadyWaker`](super::wake::ReadyWaker) for `pid` — the same
585    /// handle a subscription-inbox or reply-availability notifier fires.
586    #[cfg(test)]
587    pub(super) fn ready_waker(&self, pid: u64) -> Option<super::wake::ReadyWaker> {
588        self.inner.runtime.ready_waker(pid)
589    }
590
591    /// Registered readiness tokens held in host records (test observability).
592    #[cfg(test)]
593    pub(super) fn readiness_registration_count(&self) -> usize {
594        self.inner.runtime.readiness_registration_count()
595    }
596
597    /// Kernel fd registered for `pid` (test observability for fd-reuse races).
598    #[cfg(test)]
599    pub(super) fn readiness_fd(&self, pid: u64) -> Option<RawFd> {
600        self.inner.runtime.readiness_fd(pid)
601    }
602
603    /// The readiness token registered for `pid` (test observability). Lets the
604    /// fd-reuse successor oracle capture a stale token before reclamation and
605    /// replay its deregister afterwards, proving it is a keyed no-op.
606    #[cfg(test)]
607    pub(super) fn readiness_token(&self, pid: u64) -> Option<ReadinessToken> {
608        self.inner.runtime.readiness_token(pid)
609    }
610
611    /// Installs the pid-specific reclamation gate (oracle 26) and returns its
612    /// `(reached, release, done)` endpoints.
613    #[cfg(test)]
614    pub(super) fn install_reclaim_barrier(
615        &self,
616        pid: u64,
617    ) -> (Arc<Barrier>, Arc<Barrier>, Arc<Barrier>) {
618        self.inner.runtime.install_reclaim_barrier(pid)
619    }
620
621    /// A weak handle to the connection runtime (test observability): lets a
622    /// lifetime test assert the runtime — and transitively the durable store's
623    /// writer lock — is released synchronously at supervisor drop rather than
624    /// held by the detached reclaim reactor.
625    #[cfg(test)]
626    pub(super) fn runtime_weak(&self) -> Weak<ConnectionRuntime> {
627        Arc::downgrade(&self.inner.runtime)
628    }
629
630    /// Installs a one-use observation for the process-owned stream at `fd` being
631    /// dropped. External scheduler termination removes the process-table entry
632    /// before an executing native handler is destroyed, so table absence is not
633    /// sufficient evidence that the descriptor is reusable.
634    #[cfg(test)]
635    pub(super) fn observe_process_stream_drop(&self, fd: RawFd) -> Receiver<()> {
636        self.inner.runtime.observe_process_stream_drop(fd)
637    }
638
639    /// Installs a one-use arm-to-probe barrier and returns its test endpoints.
640    #[cfg(test)]
641    pub(super) fn install_pre_wait_barrier(&self) -> (Arc<Barrier>, Arc<Barrier>) {
642        self.inner.runtime.install_pre_wait_barrier()
643    }
644
645    /// Barrier-staged final probes that observed newly arrived work.
646    #[cfg(test)]
647    pub(super) fn pre_wait_probe_hits(&self) -> u64 {
648        self.inner.runtime.pre_wait_probe_hits()
649    }
650
651    /// Installs the one-use drain-park gate (oracles 18, 19) and returns its
652    /// `(armed, release)` endpoints.
653    #[cfg(test)]
654    pub(super) fn install_drain_park_barrier(&self) -> (Arc<Barrier>, Arc<Barrier>) {
655        self.inner.runtime.install_drain_park_barrier()
656    }
657
658    /// Drain waiter wakes that observed a real connection removal (oracle 12).
659    #[cfg(test)]
660    pub(super) fn drain_exit_wakes(&self) -> u64 {
661        self.inner.runtime.drain_exit_wakes()
662    }
663
664    /// Drain waiter deadline expirations (oracles 12, 16).
665    #[cfg(test)]
666    pub(super) fn drain_deadline_hits(&self) -> u64 {
667        self.inner.runtime.drain_deadline_hits()
668    }
669}
670
671/// Handle for one supervised connection process.
672#[derive(Clone, Debug)]
673pub struct ConnectionHandle {
674    pid: u64,
675    peer_addr: Option<SocketAddr>,
676    connection_incarnation: Option<ConnectionIncarnation>,
677    supervisor: Arc<SupervisorInner>,
678}
679
680impl ConnectionHandle {
681    /// Returns the beamr process id for this connection.
682    #[must_use]
683    pub const fn pid(&self) -> u64 {
684        self.pid
685    }
686
687    /// Returns the peer address if it was available from the accepted stream.
688    #[must_use]
689    pub const fn peer_addr(&self) -> Option<SocketAddr> {
690        self.peer_addr
691    }
692
693    /// Returns the durable participant connection incarnation, when this
694    /// supervisor has a complete participant service installed.
695    ///
696    /// `None` identifies a services adapter that does not advertise participant
697    /// lifecycle semantics.
698    #[must_use]
699    pub const fn connection_incarnation(&self) -> Option<ConnectionIncarnation> {
700        self.connection_incarnation
701    }
702
703    /// Returns whether the beamr process is still live.
704    #[must_use]
705    pub fn is_live(&self) -> bool {
706        self.supervisor
707            .scheduler
708            .process_table()
709            .get(self.pid)
710            .is_some()
711    }
712
713    /// Requests an error exit for tests and supervisor control paths.
714    ///
715    /// # Errors
716    /// Returns [`ServerError`] when the process is no longer live.
717    pub fn request_crash(&self) -> Result<(), ServerError> {
718        if self
719            .supervisor
720            .scheduler
721            .enqueue_atom_message(self.pid, Atom::ERROR)
722        {
723            Ok(())
724        } else {
725            Err(ServerError::ListenerAccept {
726                message: format!("connection process {} is not live", self.pid),
727            })
728        }
729    }
730}
731
732/// Awaits the correlated reply to a single server-initiated push.
733///
734/// Returned by [`ConnectionSupervisor::push_to_connection`]. The reply slot is
735/// resolved when the originating connection process receives a `PushReply` frame
736/// carrying the same correlation id, so [`PushReplyAwaiter::receive`] blocks
737/// (bounded) for that one correlated answer.
738#[derive(Debug)]
739pub struct PushReplyAwaiter {
740    correlation_id: u64,
741    receiver: Receiver<Vec<u8>>,
742    /// This push's absolute reply deadline, mirrored from its slot. `None` (the
743    /// default push) selects the no-deadline receive path, which NEVER touches
744    /// the runtime — byte-compatible with 0.2.3, no shared-lock exposure.
745    /// `Some` lets `receive` wait `min(caller quantum, time until deadline)` and
746    /// resolve expiry promptly, so the caller's quantum can never select a
747    /// deadlined push's terminal outcome.
748    deadline: Option<Instant>,
749    /// Weak handle to the owning runtime, used ONLY by the explicit-deadline
750    /// path to resolve expiry host-side at [`receive`](Self::receive). A
751    /// no-deadline push never upgrades it. `Weak` so the awaiter never keeps the
752    /// runtime alive; if it is already gone, the slot (and its sender) is gone
753    /// with it — the connection side is torn down.
754    runtime: Weak<ConnectionRuntime>,
755}
756
757impl PushReplyAwaiter {
758    /// Returns the correlation id this awaiter is matched on.
759    #[must_use]
760    pub const fn correlation_id(&self) -> u64 {
761        self.correlation_id
762    }
763
764    /// Blocks up to `timeout` for the client's correlated reply payload.
765    ///
766    /// `timeout` is a WAIT QUANTUM ONLY — a MAXIMUM wait, not a promise to
767    /// block: an elapsed poll is a benign re-arm, never a failure; the reply's
768    /// lifetime belongs to the push. A caller may re-invoke `receive`
769    /// indefinitely after a [`ServerError::PushReplyTimeout`]: the reserved slot
770    /// is untouched and a later reply is still delivered byte-exact. The poll
771    /// quantum never changes the protocol outcome — for a deadlined push the
772    /// call waits no longer than the EARLIER of the caller's quantum and the
773    /// push's deadline, so the terminal expiry is returned promptly once due,
774    /// never held until the quantum ends and never deferred past it.
775    ///
776    /// A push with no explicit deadline never touches shared supervisor state
777    /// here: the elapsed quantum returns straight from the channel wait
778    /// (behaviour-compatible with 0.2.3 — no registry lock, no contention, no
779    /// poison exposure on the unchanged API).
780    ///
781    /// # Errors
782    /// Returns [`ServerError::PushReplyTimeout`] when no reply arrived within this
783    /// `timeout` quantum and the push's deadline (if any) is not yet due (a
784    /// benign re-arm — call again to keep waiting);
785    /// [`ServerError::PushReplyExpired`] when the push carried an explicit reply
786    /// deadline (via
787    /// [`push_to_connection_with_deadline`](ConnectionSupervisor::push_to_connection_with_deadline))
788    /// and that deadline is due (terminal: the slot is removed and its §5 cap
789    /// admission released; returned as soon as the deadline passes, even
790    /// mid-quantum — but evaluated at observation points, not against the wall
791    /// clock: a reply already delivered when this call observes the slot wins
792    /// over expiry, even if it arrived after the deadline instant); or
793    /// [`ServerError::PushReplyDisconnected`] when the connection process
794    /// dropped the reply slot (the connection closed — the prompt worker-death
795    /// signal). The variants are distinct so callers classify by type, not
796    /// message.
797    pub fn receive(&self, timeout: Duration) -> Result<Vec<u8>, ServerError> {
798        self.deadline.map_or_else(
799            || self.receive_no_deadline(timeout),
800            |deadline| self.receive_deadlined(timeout, deadline),
801        )
802    }
803
804    /// The default-push receive: exactly the 0.2.3 shape. One bounded channel
805    /// wait; an elapsed quantum is a benign timeout straight from the channel —
806    /// no runtime upgrade, no registry lock, EVER (unrelated registry work can
807    /// never stretch this call past its quantum, and registry poison cannot
808    /// reach it).
809    fn receive_no_deadline(&self, timeout: Duration) -> Result<Vec<u8>, ServerError> {
810        match self.receiver.recv_timeout(timeout) {
811            Ok(payload) => Ok(payload),
812            Err(RecvTimeoutError::Timeout) => Err(ServerError::PushReplyTimeout {
813                correlation_id: self.correlation_id,
814            }),
815            Err(RecvTimeoutError::Disconnected) => Err(ServerError::PushReplyDisconnected {
816                correlation_id: self.correlation_id,
817            }),
818        }
819    }
820
821    /// The deadlined receive: waits `min(caller quantum, time until deadline)`
822    /// and re-evaluates reply-first-then-expiry on every wake, so the caller's
823    /// quantum can never select the terminal outcome (S1). Order per iteration:
824    ///
825    /// 1. Deliver a reply already in hand — an answer that is here must never be
826    ///    reported as a timeout OR an expiry (the observation-point rule).
827    /// 2. If the deadline is due, resolve expiry atomically against the registry
828    ///    (`expire_slot`) and return the terminal outcome promptly — even when
829    ///    the caller's quantum has time left (the quantum is a max wait).
830    /// 3. Otherwise wait for the earlier of quantum-remaining and deadline; a
831    ///    wake re-runs 1-2, and an exhausted quantum before the deadline is the
832    ///    benign `PushReplyTimeout` re-arm with the slot untouched.
833    fn receive_deadlined(
834        &self,
835        timeout: Duration,
836        deadline: Instant,
837    ) -> Result<Vec<u8>, ServerError> {
838        let started = Instant::now();
839        loop {
840            if let Some(result) = self.try_take_reply() {
841                return result;
842            }
843            let now = Instant::now();
844            if now >= deadline {
845                return self.expire_slot();
846            }
847            let quantum_left = timeout.saturating_sub(now.duration_since(started));
848            if quantum_left.is_zero() {
849                return Err(ServerError::PushReplyTimeout {
850                    correlation_id: self.correlation_id,
851                });
852            }
853            match self
854                .receiver
855                .recv_timeout(quantum_left.min(deadline.duration_since(now)))
856            {
857                Ok(payload) => return Ok(payload),
858                Err(RecvTimeoutError::Disconnected) => {
859                    return Err(ServerError::PushReplyDisconnected {
860                        correlation_id: self.correlation_id,
861                    });
862                }
863                // Re-loop: deliver a reply that raced the wake, expire a
864                // now-due deadline, or report the exhausted quantum benignly.
865                Err(RecvTimeoutError::Timeout) => {}
866            }
867        }
868    }
869
870    /// Resolves a due deadline against the registry's atomic removal transition.
871    fn expire_slot(&self) -> Result<Vec<u8>, ServerError> {
872        let timeout_error = || ServerError::PushReplyTimeout {
873            correlation_id: self.correlation_id,
874        };
875        let Some(runtime) = self.runtime.upgrade() else {
876            // The runtime is gone, and the slot map (with every sender) with it:
877            // the connection side is torn down. Re-check the channel so the
878            // dropped sender reads as the established DISCONNECTED outcome — a
879            // dead runtime must not be misreported as a benign healthy-but-slow
880            // timeout (S4).
881            return self
882                .try_take_reply()
883                .unwrap_or(Err(ServerError::PushReplyDisconnected {
884                    correlation_id: self.correlation_id,
885                }));
886        };
887        match runtime.expire_push_if_due(self.correlation_id) {
888            PushSlotDisposition::Expired => Err(ServerError::PushReplyExpired {
889                correlation_id: self.correlation_id,
890            }),
891            // Unreachable by construction (this is only called with the deadline
892            // due, and the registry re-reads a monotonic clock); honest benign
893            // fallback rather than a panic.
894            PushSlotDisposition::Live => Err(timeout_error()),
895            // Another path (a concurrent `resolve_push`, or connection close)
896            // removed the slot under the registry lock while we waited on it. Its
897            // send, if any, happens under that same lock, so re-check the channel:
898            // a delivered reply is present now; a dropped sender is disconnected.
899            PushSlotDisposition::Absent => self
900                .try_take_reply()
901                .unwrap_or_else(|| Err(timeout_error())),
902        }
903    }
904
905    /// Non-blocking check for a reply already sitting in the channel. `Some` with
906    /// the payload or a disconnected error; `None` when the channel is still empty
907    /// (no reply yet — the caller re-arms).
908    fn try_take_reply(&self) -> Option<Result<Vec<u8>, ServerError>> {
909        match self.receiver.try_recv() {
910            Ok(payload) => Some(Ok(payload)),
911            Err(TryRecvError::Disconnected) => Some(Err(ServerError::PushReplyDisconnected {
912                correlation_id: self.correlation_id,
913            })),
914            Err(TryRecvError::Empty) => None,
915        }
916    }
917}
918
919/// The kernel-parked exit-event reactor (W4 leg 1 reclamation carve-out, §4.1).
920/// It is the single TOLD source that reclaims connection host records for
921/// processes that exit WITHOUT a final handler slice, replacing the retired
922/// per-accept `reap_crashed` scan for that class.
923///
924/// It blocks on beamr's sole exit-event subscription — never polling, never
925/// timed — and on each delivered [`ExitEvent::Exited`] it (1) drains the
926/// retained additive outcome so beamr's exactly-once outcome store stays bounded
927/// (we are the sole subscriber and therefore the sole drainer) and (2) reclaims
928/// the pid through [`ConnectionRuntime::reclaim_terminated`], which funnels into
929/// `remove()`. On the bounded queue's [`ExitEvent::Lagged`] overflow marker it
930/// runs exactly one reconciliation pass over the tracked records (beamr's
931/// documented recovery), driven by that one TELL — not a timer.
932///
933/// It holds WEAK handles to both the scheduler and the runtime and upgrades them
934/// per event, so it never keeps either alive past supervisor drop. It returns
935/// when the subscription disconnects (scheduler and publisher dropped) OR when a
936/// per-event upgrade fails — both observed at an event delivery, never sampled,
937/// so there is no stop flag (LAW-1). The runtime and its durable store therefore
938/// release synchronously at supervisor drop rather than after the reactor exits.
939fn run_reclaim_reactor(
940    subscription: &ExitEventSubscription,
941    scheduler: &Weak<Scheduler>,
942    runtime: &Weak<ConnectionRuntime>,
943) {
944    loop {
945        match subscription.recv() {
946            Ok(ExitEvent::Exited { pid, reason }) => {
947                let Some(runtime) = runtime.upgrade() else {
948                    return;
949                };
950                runtime.deliver_reclamation(scheduler, pid, reason);
951            }
952            Ok(ExitEvent::Lagged) => {
953                let (Some(runtime), Some(scheduler)) = (runtime.upgrade(), scheduler.upgrade())
954                else {
955                    return;
956                };
957                runtime.reap_crashed(&scheduler);
958            }
959            Err(_) => return,
960        }
961    }
962}
963
964pub(super) struct SupervisorInner {
965    scheduler: Arc<Scheduler>,
966    runtime: Arc<ConnectionRuntime>,
967    incarnations: Option<Arc<ConnectionIncarnationAuthority>>,
968}
969
970impl std::fmt::Debug for SupervisorInner {
971    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
972        formatter
973            .debug_struct("SupervisorInner")
974            .field("runtime", &self.runtime)
975            .finish_non_exhaustive()
976    }
977}
978
979impl SupervisorInner {
980    fn new(
981        services: Arc<dyn ConnectionServices>,
982        notifier: Option<Arc<dyn ConnectionNotifier>>,
983        auth_token: Option<Vec<u8>>,
984        limits: LimitsConfig,
985        fatal_shutdown: Option<ShutdownHandle>,
986    ) -> Result<Self, ServerError> {
987        let installed_services = ConnectionServiceInstallation::capture(services);
988        let incarnations = installed_services
989            .participant_service
990            .as_ref()
991            .map(
992                |service| -> Result<Arc<ConnectionIncarnationAuthority>, ServerError> {
993                    ConnectionIncarnationAuthority::startup(
994                        service.durable_store(),
995                        limits.max_connections,
996                        service.publication_conversation_limit(),
997                        service,
998                    )
999                    .map(Arc::new)
1000                },
1001            )
1002            .transpose()?;
1003        let atoms = AtomTable::with_common_atoms();
1004        let control_atom = atoms.intern(CONNECTION_SHUTDOWN_CONTROL_ATOM);
1005        let registry = Arc::new(ModuleRegistry::new());
1006
1007        let scheduler = Scheduler::with_services(
1008            SchedulerConfig {
1009                thread_count: Some(CONNECTION_SCHEDULER_THREADS),
1010                ..SchedulerConfig::default()
1011            },
1012            SchedulerServices::from_config().owned_readiness(),
1013            registry,
1014        )
1015        .map_err(|message| ServerError::ListenerAccept {
1016            message: format!("failed to start connection scheduler: {message}"),
1017        })?;
1018        let ready_atom = atoms.intern(CONNECTION_READY_ATOM);
1019        let scheduler = Arc::new(scheduler);
1020        // The runtime captures a WEAK handle to the connection scheduler so
1021        // notifier wakes (R3/R1(vi)) can be fired from another actor's slice
1022        // without a strong scheduler↔process↔runtime cycle that would leak the
1023        // whole connection scheduler.
1024        let runtime = Arc::new(ConnectionRuntime::new(
1025            ConnectionRuntimeInstallation {
1026                services: installed_services,
1027                incarnations: incarnations.clone(),
1028                fatal_shutdown,
1029            },
1030            control_atom,
1031            ready_atom,
1032            Arc::downgrade(&scheduler),
1033            notifier,
1034            auth_token,
1035            limits,
1036        ));
1037        // W4 leg 1 reclamation carve-out (§4.1): the kernel-parked exit-event
1038        // reactor is the TOLD source that reclaims a connection host record whose
1039        // process exited WITHOUT a final handler slice (external/panic
1040        // termination). It blocks on beamr's single exit-event subscription —
1041        // never a poll — and routes every reclamation through the same `remove()`
1042        // funnel as an ordinary exit. Detached on purpose: it exits when the
1043        // scheduler (and so its event publisher) drops, so there is no stop flag
1044        // to sample (LAW-1).
1045        match scheduler.subscribe_exit_events() {
1046            Some(subscription) => {
1047                let reactor_scheduler = Arc::downgrade(&scheduler);
1048                // WEAK, symmetric with the scheduler handle: the reactor must not
1049                // keep the runtime (and its durable store's writer lock) alive past
1050                // supervisor drop. It upgrades per event and exits on a failed
1051                // upgrade, so the runtime is released synchronously at drop.
1052                let reactor_runtime = Arc::downgrade(&runtime);
1053                thread::Builder::new()
1054                    .name("liminal-connection-reclaim".to_owned())
1055                    .spawn(move || {
1056                        run_reclaim_reactor(&subscription, &reactor_scheduler, &reactor_runtime);
1057                    })
1058                    .map_err(|error| ServerError::ListenerAccept {
1059                        message: format!("failed to start connection reclamation reactor: {error}"),
1060                    })?;
1061            }
1062            None => {
1063                tracing::error!(
1064                    "connection scheduler exit-event subscription unavailable; \
1065                     external-termination reclamation has no TOLD exit source (the \
1066                     shutdown-drain scan that once backstopped it was retired by W4 leg 3)"
1067                );
1068            }
1069        }
1070        Ok(Self {
1071            scheduler,
1072            runtime,
1073            incarnations,
1074        })
1075    }
1076
1077    fn spawn_connection(
1078        self: &Arc<Self>,
1079        stream: TcpStream,
1080    ) -> Result<ConnectionHandle, ServerError> {
1081        // §5 `max_connections`: ATOMIC admission reservation acquired BEFORE any
1082        // process construction (review round 1 item 7 — a signed bound must not
1083        // be exceedable by concurrent callers; check-then-spawn across an
1084        // unlocked window was). The CAS reservation is released on every failure
1085        // path below and converts into the connection record at `register`;
1086        // thereafter the single record-removal path (`remove`) releases it. An
1087        // over-cap accept therefore costs nothing and the bound holds under any
1088        // concurrency.
1089        self.runtime.try_reserve_admission()?;
1090        let reservation = AdmissionReservation {
1091            runtime: &self.runtime,
1092            armed: true,
1093        };
1094        stream
1095            .set_nonblocking(true)
1096            .map_err(|error| ServerError::ListenerAccept {
1097                message: format!("failed to configure connection stream: {error}"),
1098            })?;
1099        let peer_addr = stream.peer_addr().ok();
1100        // The host-held duplicate keeps the fd alive until the single record-removal
1101        // path has synchronously deregistered readiness. External process death can
1102        // therefore never let fd reuse overtake host-side deregistration.
1103        let fd_guard = stream
1104            .try_clone()
1105            .map_err(|error| ServerError::ListenerAccept {
1106                message: format!("failed to retain connection fd for teardown: {error}"),
1107            })?;
1108        let connection_incarnation = self.allocate_connection_incarnation()?;
1109        let holder = Arc::new(Mutex::new(Some(stream)));
1110        let runtime = Arc::clone(&self.runtime);
1111        let process_holder = Arc::clone(&holder);
1112        let factory: NativeHandlerFactory = Box::new(move || {
1113            Box::new(ConnectionProcess::from_holder(
1114                Arc::clone(&runtime),
1115                peer_addr,
1116                &process_holder,
1117                connection_incarnation,
1118            ))
1119        });
1120        let pid =
1121            self.scheduler
1122                .spawn_native(factory)
1123                .map_err(|error| ServerError::ListenerAccept {
1124                    message: format!("failed to spawn connection process: {error}"),
1125                })?;
1126        if let Err(error) =
1127            self.runtime
1128                .register_with_fd(pid, peer_addr, connection_incarnation, fd_guard)
1129        {
1130            // Registration failure leaves no host record to reap. Terminate the
1131            // just-spawned process explicitly so neither its stream nor admission
1132            // reservation can escape this failed spawn.
1133            self.scheduler.terminate_process(pid, ExitReason::Error);
1134            return Err(error);
1135        }
1136        // The reservation is now owned by the registered record: `remove` (the
1137        // single record-removal path — finish/mark_crashed/reap all funnel
1138        // through it) releases the admission when the record goes away.
1139        reservation.convert();
1140        Ok(ConnectionHandle {
1141            pid,
1142            peer_addr,
1143            connection_incarnation,
1144            supervisor: Arc::clone(self),
1145        })
1146    }
1147
1148    /// LP-WS-TRANSPORT R1.3: the sibling-transport spawn body. Mirrors
1149    /// [`Self::spawn_connection`]'s admission → incarnation → spawn → register →
1150    /// convert sequence exactly (same reservation guard, same failure rollback,
1151    /// same single record-removal ownership), differing only in that the caller
1152    /// supplies the native handler factory and the host-held fd guard instead of
1153    /// a raw `TcpStream`. Purely additive; the TCP path never calls this.
1154    fn spawn_transport_connection(
1155        self: &Arc<Self>,
1156        peer_addr: Option<SocketAddr>,
1157        fd_guard: TcpStream,
1158        build_factory: &dyn Fn(
1159            Arc<ConnectionRuntime>,
1160            Option<ConnectionIncarnation>,
1161        ) -> NativeHandlerFactory,
1162    ) -> Result<ConnectionHandle, ServerError> {
1163        self.runtime.try_reserve_admission()?;
1164        let reservation = AdmissionReservation {
1165            runtime: &self.runtime,
1166            armed: true,
1167        };
1168        let connection_incarnation = self.allocate_connection_incarnation()?;
1169        let factory = build_factory(Arc::clone(&self.runtime), connection_incarnation);
1170        let pid =
1171            self.scheduler
1172                .spawn_native(factory)
1173                .map_err(|error| ServerError::ListenerAccept {
1174                    message: format!("failed to spawn connection process: {error}"),
1175                })?;
1176        if let Err(error) =
1177            self.runtime
1178                .register_with_fd(pid, peer_addr, connection_incarnation, fd_guard)
1179        {
1180            self.scheduler.terminate_process(pid, ExitReason::Error);
1181            return Err(error);
1182        }
1183        reservation.convert();
1184        Ok(ConnectionHandle {
1185            pid,
1186            peer_addr,
1187            connection_incarnation,
1188            supervisor: Arc::clone(self),
1189        })
1190    }
1191
1192    fn allocate_connection_incarnation(
1193        &self,
1194    ) -> Result<Option<ConnectionIncarnation>, ServerError> {
1195        let Some(authority) = self.incarnations.as_ref() else {
1196            return Ok(None);
1197        };
1198        // Production-era uniqueness invariant: every published incarnation is
1199        // unique against ALL durable references — binding epochs committed
1200        // into conversation logs included — by allocator-log monotonicity
1201        // alone, not by the completeness of the reference set below.
1202        //
1203        //   1. Startup replays the durable allocator stream and STRICTLY
1204        //      increments the server incarnation, fsyncing the Startup event
1205        //      before any listener becomes ready
1206        //      (`IncarnationStream::startup`); a server value is never wrapped
1207        //      or reused, so no two process lifetimes share one.
1208        //   2. Within a lifetime, allocations are serialized under this
1209        //      authority's mutex, candidates start strictly above the durable
1210        //      `last_examined_connection_ordinal`
1211        //      (`allocate_connection_incarnation`), and every allocation's
1212        //      event is appended and flushed BEFORE its pair is published
1213        //      (`StartedIncarnationStream::allocate`), so ordinals never
1214        //      repeat within a lifetime and replay restores a head at or
1215        //      above every published ordinal.
1216        //   3. A durable reference can only name a pair this allocator
1217        //      previously PUBLISHED (binding epochs are committed only after
1218        //      their connection was admitted), and the same store's flush
1219        //      barrier orders the allocator event before any conversation-log
1220        //      entry that references it.
1221        //
1222        // The live-connection reference set below is therefore defense in
1223        // depth — a bounded collision skip against a rolled-back or divergent
1224        // allocator stream — never the uniqueness foundation, and never a raw
1225        // caller-supplied matrix.
1226        let references = self.runtime.complete_active_incarnation_references()?;
1227        authority.allocate(&references).map(Some)
1228    }
1229
1230    fn broadcast_control(&self, control: &ConnectionControl) {
1231        for connection in self.runtime.active_connections() {
1232            if !self.enqueue_control(connection.pid, control.clone()) {
1233                tracing::debug!(
1234                    connection_pid = connection.pid,
1235                    peer_addr = ?connection.peer_addr,
1236                    ?control,
1237                    "connection control message skipped because process is not live"
1238                );
1239            }
1240        }
1241    }
1242
1243    /// Queues `control` for `pid` and wakes the process. Returns whether the
1244    /// control was PUBLISHED (left in the queue with a successful wake, or
1245    /// already consumed by a drain) — `false` guarantees no consumer ever saw
1246    /// it.
1247    ///
1248    /// S8: a failed wake does NOT prove the queued control was never consumed.
1249    /// The insert releases the queue lock before the wake attempt, and a
1250    /// process already executing a control drain (each control atom drains ALL
1251    /// queued controls for the pid) can pop the just-inserted entry in that
1252    /// window, then exit before the wake check. Publication is therefore
1253    /// disambiguated BY OBSERVATION on the failed-wake path: `remove_control`
1254    /// finding and removing the entry proves no consumer saw it (truly
1255    /// unpublished — `false`); finding nothing proves a drain consumed it
1256    /// (`pop_control` is the only other remover of queue entries, and the
1257    /// removal key embeds the push's runtime-unique correlation id, so it can
1258    /// never match a different entry) — the control was published and the
1259    /// caller's slot lifecycle carries the delivery truth (`true`).
1260    fn enqueue_control(&self, pid: u64, control: ConnectionControl) -> bool {
1261        // Keep a key for the failure-path removal before the control is moved into
1262        // the queue, so a non-`Copy` (push) control can still be located and pulled
1263        // back out if the scheduler wakeup fails.
1264        let removal_key = control.clone();
1265        if self.runtime.push_control(pid, control).is_err() {
1266            return false;
1267        }
1268        // Deterministic test seam in the insert->wake window (S8 staging).
1269        #[cfg(test)]
1270        self.runtime.run_pre_wake_barrier();
1271        if self
1272            .scheduler
1273            .enqueue_atom_message(pid, self.runtime.control_atom())
1274        {
1275            true
1276        } else {
1277            // Failed wake: the entry's fate is the publication verdict. Removed
1278            // here => nobody consumed it => unpublished. Already gone => a
1279            // drain consumed it before the wake check => published. (A poisoned
1280            // queue lock reads as not-removed => published — the safe
1281            // direction: the slot lifecycle then reports the truthful outcome,
1282            // whereas claiming "unpublished" could be a lie.)
1283            !self.runtime.remove_control(pid, &removal_key)
1284        }
1285    }
1286}
1287
1288/// RAII guard for one §5 `max_connections` admission reservation.
1289///
1290/// Acquired (via [`ConnectionRuntime::try_reserve_admission`]) before any process
1291/// construction in `spawn_connection`; every early-return failure path releases
1292/// it through `Drop`, and a successful `register` converts it into the
1293/// connection record (whose removal releases the admission instead). RAII means
1294/// no failure path — present or future — can leak a reservation.
1295struct AdmissionReservation<'a> {
1296    runtime: &'a ConnectionRuntime,
1297    armed: bool,
1298}
1299
1300impl AdmissionReservation<'_> {
1301    /// Converts the reservation into record ownership: `Drop` no longer releases
1302    /// it, because the registered record's removal will.
1303    fn convert(mut self) {
1304        self.armed = false;
1305    }
1306}
1307
1308impl Drop for AdmissionReservation<'_> {
1309    fn drop(&mut self) {
1310        if self.armed {
1311            self.runtime.release_admission();
1312        }
1313    }
1314}
1315
1316#[derive(Debug, Clone, PartialEq, Eq)]
1317pub(super) enum ConnectionControl {
1318    NotifyShutdown,
1319    ForceClose,
1320    /// Server-initiated push of an opaque payload, correlated by `correlation_id`,
1321    /// to be written out as a [`Frame::Push`] by the receiving connection process.
1322    Push {
1323        correlation_id: u64,
1324        payload: Vec<u8>,
1325    },
1326}
1327
1328#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1329pub struct ActiveConnection {
1330    pid: u64,
1331    peer_addr: Option<SocketAddr>,
1332}
1333
1334#[cfg(test)]
1335#[derive(Debug, Clone)]
1336struct PreWaitBarrier {
1337    armed: Arc<Barrier>,
1338    release: Arc<Barrier>,
1339}
1340
1341/// Pid-specific, one-use deterministic gate on the reclamation delivery path
1342/// (oracle 26). The exit-event reactor stages it only for the targeted pid, so
1343/// unrelated exits still reclaim immediately; for the target it rendezvouses
1344/// `reached` (proving the pid is dead but its record still tracked — the S8
1345/// reclamation window), then `release` (the harness lets the reclaim proceed),
1346/// then `done` (the `remove()` funnel completed). It changes no production
1347/// semantics — the whole type and its call sites are `#[cfg(test)]`.
1348#[cfg(test)]
1349#[derive(Debug, Clone)]
1350struct ReclaimBarrier {
1351    pid: u64,
1352    reached: Arc<Barrier>,
1353    release: Arc<Barrier>,
1354    done: Arc<Barrier>,
1355}
1356
1357#[derive(Debug)]
1358struct ConnectionServiceInstallation {
1359    services: Arc<dyn ConnectionServices>,
1360    participant_service: Option<InstalledParticipantService>,
1361}
1362
1363impl ConnectionServiceInstallation {
1364    /// Captures the service adapter's capability posture exactly once, before
1365    /// participant incarnation startup or connection process construction.
1366    fn capture(services: Arc<dyn ConnectionServices>) -> Self {
1367        let participant_service = services.participant_service();
1368        Self {
1369            services,
1370            participant_service,
1371        }
1372    }
1373}
1374
1375#[derive(Debug)]
1376struct ConnectionRuntimeInstallation {
1377    services: ConnectionServiceInstallation,
1378    incarnations: Option<Arc<ConnectionIncarnationAuthority>>,
1379    fatal_shutdown: Option<ShutdownHandle>,
1380}
1381
1382#[derive(Debug)]
1383pub(super) struct ConnectionRuntime {
1384    services: Arc<dyn ConnectionServices>,
1385    /// Complete participant handler/store bundle captured at supervisor startup.
1386    /// `Some` is paired with an incarnation authority on `SupervisorInner`.
1387    participant_service: Option<InstalledParticipantService>,
1388    /// Same started authority used for allocation, shared for terminal Open/Complete.
1389    incarnations: Option<Arc<ConnectionIncarnationAuthority>>,
1390    /// Existing runtime shutdown activation notified by the first post-Open fatal.
1391    /// Test-only/runtime-less constructors intentionally carry `None`.
1392    fatal_shutdown: Option<ShutdownHandle>,
1393    records: Mutex<HashMap<u64, ConnectionRecord>>,
1394    controls: Mutex<Vec<QueuedConnectionControl>>,
1395    control_atom: Atom,
1396    /// R6 single `READY` wake atom for this connection scheduler. Fired by every
1397    /// wake source's notifier (R3/R1(vi)); coalescing and duplicates are harmless.
1398    ready_atom: Atom,
1399    /// Weak handle to the connection scheduler, used to build [`ReadyWaker`]s a
1400    /// notifier fires from another actor's slice. Weak so it never keeps the
1401    /// scheduler alive (the scheduler owns the processes that own this runtime).
1402    scheduler: Weak<Scheduler>,
1403    /// W4 leg 3 (§4.3) TOLD drain-completion primitive. Reuses the
1404    /// [`ShutdownHandle`] `Condvar` shape (`shutdown.rs` reuse candidate (c)): a
1405    /// monotonic connection-removal generation guarded by [`Self::drain_removed`]'s
1406    /// mutex, bumped once whenever [`Self::remove`] actually drops a record — the
1407    /// single removal funnel every exit route (in-slice `mark_crashed`/`finish`,
1408    /// the reclaim reactor, and the reconciliation scan) reaches. The
1409    /// shutdown-sequence drain/settle waiter parks on the `Condvar` and wakes only
1410    /// on a delivered exit (a generation bump + `notify_all`) or the one admitted
1411    /// deadline it passes to `wait_timeout`. No periodic reap or count scan.
1412    drain_generation: Mutex<u64>,
1413    /// Woken on every connection-record removal; the drain/settle waiter parks
1414    /// here. Paired with [`Self::drain_generation`] under the same mutex so an
1415    /// exit delivered between the waiter's arm-before-observe snapshot and its
1416    /// park cannot be lost (oracle 18).
1417    drain_removed: Condvar,
1418    /// Test-only count of drain waiter wakes that observed a real removal
1419    /// (generation advanced across the park). A quiet drain records zero — it
1420    /// wakes only for the single deadline (oracle 12).
1421    #[cfg(test)]
1422    drain_exit_wakes: AtomicU64,
1423    /// Test-only count of drain waiter deadline expirations. A quiet drain that
1424    /// times out records exactly one — one arming, one delivery, no helper tick
1425    /// (oracles 12, 16).
1426    #[cfg(test)]
1427    drain_deadline_hits: AtomicU64,
1428    /// Test-only one-use gate in the drain waiter's observe->park window, so a
1429    /// harness can deliver an exit strictly after the completion observation and
1430    /// before the park to pin the arm-before-observe barrier (oracles 18, 19).
1431    #[cfg(test)]
1432    drain_park_barrier: Mutex<Option<PreWaitBarrier>>,
1433    /// R7 (§1.2(6)) test-only per-connection slice counter, keyed by pid. Bumped
1434    /// once at the head of every serviced slice. The park-flip's permanent rule-1
1435    /// assertion (a parked connection's counter must not advance without an event)
1436    /// reads this; the instrument lands now with a test proving it counts slices.
1437    #[cfg(test)]
1438    slice_counts: Mutex<HashMap<u64, u64>>,
1439    /// One-use readiness markers for the next serviced slice of a process.
1440    #[cfg(test)]
1441    slice_observers: Mutex<HashMap<u64, Sender<u64>>>,
1442    /// One-use readiness markers emitted only after the real final probe selects
1443    /// `Wait`, immediately before the native process returns to the scheduler.
1444    #[cfg(test)]
1445    park_observers: Mutex<HashMap<u64, Sender<u64>>>,
1446    /// Most recent slice count whose real final probe selected `Wait`.
1447    #[cfg(test)]
1448    park_counts: Mutex<HashMap<u64, u64>>,
1449    /// Explicit capacities consumed in TCP process construction order.
1450    #[cfg(test)]
1451    next_outbound_capacities: Mutex<VecDeque<usize>>,
1452    #[cfg(test)]
1453    participant_holdback_pauses: Mutex<HashMap<u64, Sender<()>>>,
1454    /// Deterministic test gate placed after arm and before the final probe.
1455    #[cfg(test)]
1456    pre_wait_barrier: Mutex<Option<PreWaitBarrier>>,
1457    /// Deterministic test gate in `enqueue_control`'s insert->wake window (S8).
1458    #[cfg(test)]
1459    pre_wake_barrier: Mutex<Option<PreWaitBarrier>>,
1460    /// Pid-specific one-use gate held on the reclamation delivery path so a test
1461    /// can pin the dead-but-tracked S8 window deterministically (oracle 26).
1462    #[cfg(test)]
1463    reclaim_barrier: Mutex<Option<ReclaimBarrier>>,
1464    /// Barrier-staged slices where the final probe found newly arrived work.
1465    #[cfg(test)]
1466    pre_wait_probe_hits: AtomicU64,
1467    /// One-use observers for process-owned streams reaching their actual drop
1468    /// boundary after external scheduler termination.
1469    #[cfg(test)]
1470    process_stream_drop_observers: Mutex<HashMap<RawFd, Sender<()>>>,
1471    /// One-shot reply slots for in-flight server pushes, keyed by correlation id.
1472    /// The supervisor registers a slot in `push_to_connection`; the connection
1473    /// process resolves it when the matching `PushReply` frame arrives. Each slot
1474    /// records the owning connection pid so the close path can drop a connection's
1475    /// outstanding slots and wake their awaiters with a prompt disconnected error.
1476    push_replies: Mutex<HashMap<u64, PendingPush>>,
1477    /// Monotonic source of push correlation ids. Server-allocated, so it never
1478    /// collides with a client-chosen id on this connection.
1479    next_push_id: AtomicU64,
1480    /// §5 `max_connections` admission counter. Incremented atomically (CAS
1481    /// against the limit) BEFORE a connection process is constructed and
1482    /// decremented on every spawn-failure path and on final record removal, so
1483    /// the signed bound holds under concurrent spawns — admission is never
1484    /// derived from the records-map length across an unlocked window.
1485    admissions: AtomicU64,
1486    /// Optional application hook invoked on worker registration and on the close
1487    /// of a connection that had registered. `None` keeps liminal standalone: a
1488    /// `WorkerRegister` is accepted with no callback.
1489    notifier: Option<Arc<dyn ConnectionNotifier>>,
1490    /// Configured connection auth token (the `[auth]` section's token as opaque
1491    /// bytes). `Some` gates the `Connect` handshake — the frame's `auth_token` must
1492    /// match under a constant-time comparison; `None` leaves the server open-access,
1493    /// byte-identical to the pre-auth behaviour.
1494    auth_token: Option<Vec<u8>>,
1495    /// Operational caps (§5). Enforced with typed refusals at admission:
1496    /// per-connection subscription, conversation, push, and pending-reply counts,
1497    /// plus the shared inbox byte budget. Non-config constructors carry the signed
1498    /// defaults ([`LimitsConfig::default`]).
1499    limits: LimitsConfig,
1500}
1501
1502impl ConnectionRuntime {
1503    fn new(
1504        installation: ConnectionRuntimeInstallation,
1505        control_atom: Atom,
1506        ready_atom: Atom,
1507        scheduler: Weak<Scheduler>,
1508        notifier: Option<Arc<dyn ConnectionNotifier>>,
1509        auth_token: Option<Vec<u8>>,
1510        limits: LimitsConfig,
1511    ) -> Self {
1512        let ConnectionRuntimeInstallation {
1513            services:
1514                ConnectionServiceInstallation {
1515                    services,
1516                    participant_service,
1517                },
1518            incarnations,
1519            fatal_shutdown,
1520        } = installation;
1521        Self {
1522            services,
1523            participant_service,
1524            incarnations,
1525            fatal_shutdown,
1526            records: Mutex::new(HashMap::new()),
1527            controls: Mutex::new(Vec::new()),
1528            control_atom,
1529            ready_atom,
1530            scheduler,
1531            drain_generation: Mutex::new(0),
1532            drain_removed: Condvar::new(),
1533            #[cfg(test)]
1534            drain_exit_wakes: AtomicU64::new(0),
1535            #[cfg(test)]
1536            drain_deadline_hits: AtomicU64::new(0),
1537            #[cfg(test)]
1538            drain_park_barrier: Mutex::new(None),
1539            #[cfg(test)]
1540            slice_counts: Mutex::new(HashMap::new()),
1541            #[cfg(test)]
1542            slice_observers: Mutex::new(HashMap::new()),
1543            #[cfg(test)]
1544            park_observers: Mutex::new(HashMap::new()),
1545            #[cfg(test)]
1546            park_counts: Mutex::new(HashMap::new()),
1547            #[cfg(test)]
1548            next_outbound_capacities: Mutex::new(VecDeque::new()),
1549            #[cfg(test)]
1550            participant_holdback_pauses: Mutex::new(HashMap::new()),
1551            #[cfg(test)]
1552            pre_wait_barrier: Mutex::new(None),
1553            #[cfg(test)]
1554            pre_wake_barrier: Mutex::new(None),
1555            #[cfg(test)]
1556            reclaim_barrier: Mutex::new(None),
1557            #[cfg(test)]
1558            pre_wait_probe_hits: AtomicU64::new(0),
1559            #[cfg(test)]
1560            process_stream_drop_observers: Mutex::new(HashMap::new()),
1561            push_replies: Mutex::new(HashMap::new()),
1562            next_push_id: AtomicU64::new(1),
1563            admissions: AtomicU64::new(0),
1564            notifier,
1565            auth_token,
1566            limits,
1567        }
1568    }
1569
1570    /// Atomically reserves one §5 `max_connections` admission slot: a CAS loop
1571    /// against the configured limit, so N concurrent callers racing for the last
1572    /// slot admit EXACTLY one — the bound cannot be transiently exceeded.
1573    ///
1574    /// # Errors
1575    /// Returns [`ServerError::ConnectionLimitReached`] when every slot is taken.
1576    fn try_reserve_admission(&self) -> Result<(), ServerError> {
1577        self.ensure_participant_service_live()?;
1578        let limit = self.limits.max_connections as u64;
1579        let mut current = self.admissions.load(Ordering::Acquire);
1580        loop {
1581            if current >= limit {
1582                return Err(ServerError::ConnectionLimitReached {
1583                    limit: self.limits.max_connections,
1584                });
1585            }
1586            match self.admissions.compare_exchange_weak(
1587                current,
1588                current + 1,
1589                Ordering::AcqRel,
1590                Ordering::Acquire,
1591            ) {
1592                Ok(_) => return Ok(()),
1593                Err(observed) => current = observed,
1594            }
1595        }
1596    }
1597
1598    /// Releases one admission slot. Called by the spawn failure paths (via the
1599    /// [`AdmissionReservation`] guard) and by [`Self::remove`] when a registered
1600    /// record is removed — exactly one release per reservation. Saturating so a
1601    /// spurious release can never wrap the counter.
1602    fn release_admission(&self) {
1603        let mut current = self.admissions.load(Ordering::Acquire);
1604        loop {
1605            let next = current.saturating_sub(1);
1606            match self.admissions.compare_exchange_weak(
1607                current,
1608                next,
1609                Ordering::AcqRel,
1610                Ordering::Acquire,
1611            ) {
1612                Ok(_) => return,
1613                Err(observed) => current = observed,
1614            }
1615        }
1616    }
1617
1618    /// The operational caps (§5) this runtime enforces.
1619    pub(super) const fn limits(&self) -> &LimitsConfig {
1620        &self.limits
1621    }
1622
1623    /// The connection's single R6 `READY` wake atom.
1624    pub(super) const fn ready_atom(&self) -> Atom {
1625        self.ready_atom
1626    }
1627
1628    /// Builds a [`ReadyWaker`] targeting `pid` on the connection scheduler, if the
1629    /// scheduler is still live. `None` when the scheduler is gone (teardown) or in
1630    /// scheduler-free unit tests — a notifier with no waker simply never wakes,
1631    /// which under the busy loop is redundant anyway (the every-slice pump still
1632    /// services the source). This is the seam every wake source installs its
1633    /// notifier through (R3/R1(vi)).
1634    pub(super) fn ready_waker(&self, pid: u64) -> Option<super::wake::ReadyWaker> {
1635        let scheduler = self.scheduler.upgrade()?;
1636        let ready_pending = self
1637            .records
1638            .lock()
1639            .ok()?
1640            .get(&pid)
1641            .map(|record| Arc::clone(&record.ready_pending))?;
1642        Some(super::wake::ReadyWaker::new(
1643            &scheduler,
1644            pid,
1645            self.ready_atom,
1646            ready_pending,
1647        ))
1648    }
1649
1650    /// Acknowledges READY edges whose mailbox atoms were drained before this slice.
1651    pub(super) fn acknowledge_ready(&self, pid: u64) {
1652        if let Ok(records) = self.records.lock()
1653            && let Some(record) = records.get(&pid)
1654        {
1655            record.ready_pending.store(false, Ordering::Release);
1656        }
1657    }
1658
1659    /// Reports a READY edge queued while the current process snapshot is executing.
1660    pub(super) fn ready_pending(&self, pid: u64) -> bool {
1661        self.records
1662            .lock()
1663            .ok()
1664            .and_then(|records| {
1665                records
1666                    .get(&pid)
1667                    .map(|record| record.ready_pending.load(Ordering::Acquire))
1668            })
1669            .unwrap_or(false)
1670    }
1671
1672    /// R7: records one serviced slice for `pid`. Bumped at the head of every
1673    /// slice; the park-flip's quiescence assertion reads [`Self::slice_count`].
1674    #[cfg(test)]
1675    pub(super) fn record_slice(&self, pid: u64) {
1676        let count = if let Ok(mut counts) = self.slice_counts.lock() {
1677            let count = counts.entry(pid).or_insert(0);
1678            *count += 1;
1679            *count
1680        } else {
1681            return;
1682        };
1683        if let Ok(mut observers) = self.slice_observers.lock()
1684            && let Some(observer) = observers.remove(&pid)
1685        {
1686            let _ = observer.send(count);
1687        }
1688    }
1689
1690    #[cfg(test)]
1691    fn observe_next_slice(&self, pid: u64) -> Receiver<u64> {
1692        let (sender, receiver) = channel();
1693        if let Ok(mut observers) = self.slice_observers.lock() {
1694            observers.insert(pid, sender);
1695        }
1696        receiver
1697    }
1698
1699    #[cfg(test)]
1700    fn observe_next_park(&self, pid: u64) -> Receiver<u64> {
1701        let (sender, receiver) = channel();
1702        if let Ok(mut observers) = self.park_observers.lock() {
1703            observers.insert(pid, sender);
1704        }
1705        receiver
1706    }
1707
1708    #[cfg(test)]
1709    fn observe_settled_park(&self, pid: u64) -> Receiver<u64> {
1710        let (sender, receiver) = channel();
1711        let Ok(counts) = self.slice_counts.lock() else {
1712            return receiver;
1713        };
1714        let current = counts.get(&pid).copied().unwrap_or(0);
1715        let Ok(parks) = self.park_counts.lock() else {
1716            return receiver;
1717        };
1718        if current > 0 && parks.get(&pid).copied() == Some(current) {
1719            let _ = sender.send(current);
1720        } else if let Ok(mut observers) = self.park_observers.lock() {
1721            observers.insert(pid, sender);
1722        }
1723        drop(parks);
1724        drop(counts);
1725        receiver
1726    }
1727
1728    #[cfg(test)]
1729    pub(super) fn record_park(&self, pid: u64) {
1730        let count = self.slice_count(pid);
1731        if let Ok(mut parks) = self.park_counts.lock() {
1732            parks.insert(pid, count);
1733        }
1734        if let Ok(mut observers) = self.park_observers.lock()
1735            && let Some(observer) = observers.remove(&pid)
1736        {
1737            let _ = observer.send(count);
1738        }
1739    }
1740
1741    #[cfg(test)]
1742    fn queue_next_outbound_capacity(&self, capacity: usize) {
1743        if let Ok(mut capacities) = self.next_outbound_capacities.lock() {
1744            capacities.push_back(capacity);
1745        }
1746    }
1747
1748    #[cfg(test)]
1749    pub(super) fn take_next_outbound_capacity(&self) -> Option<usize> {
1750        self.next_outbound_capacities
1751            .lock()
1752            .ok()
1753            .and_then(|mut capacities| capacities.pop_front())
1754    }
1755
1756    #[cfg(test)]
1757    fn install_participant_holdback_pause(&self, pid: u64) -> Receiver<()> {
1758        let (sender, receiver) = channel();
1759        if let Ok(mut pauses) = self.participant_holdback_pauses.lock() {
1760            pauses.insert(pid, sender);
1761        }
1762        receiver
1763    }
1764
1765    #[cfg(test)]
1766    pub(super) fn pause_participant_holdback(&self, pid: u64) -> bool {
1767        self.participant_holdback_pauses
1768            .lock()
1769            .ok()
1770            .and_then(|mut pauses| pauses.remove(&pid))
1771            .is_some_and(|sender| {
1772                let _ = sender.send(());
1773                true
1774            })
1775    }
1776
1777    /// R7: slices serviced by connection `pid` since spawn (test instrument).
1778    #[cfg(test)]
1779    pub(super) fn slice_count(&self, pid: u64) -> u64 {
1780        self.slice_counts
1781            .lock()
1782            .map_or(0, |counts| counts.get(&pid).copied().unwrap_or(0))
1783    }
1784
1785    #[cfg(test)]
1786    fn install_pre_wait_barrier(&self) -> (Arc<Barrier>, Arc<Barrier>) {
1787        let armed = Arc::new(Barrier::new(2));
1788        let release = Arc::new(Barrier::new(2));
1789        if let Ok(mut slot) = self.pre_wait_barrier.lock() {
1790            *slot = Some(PreWaitBarrier {
1791                armed: Arc::clone(&armed),
1792                release: Arc::clone(&release),
1793            });
1794        }
1795        (armed, release)
1796    }
1797
1798    /// Installs the pid-specific reclamation gate (oracle 26) and returns its
1799    /// `(reached, release, done)` endpoints. The harness rendezvouses `reached`
1800    /// to pin the dead-but-tracked window, `release` to let the reclaim proceed,
1801    /// and `done` to observe the `remove()` funnel completing.
1802    #[cfg(test)]
1803    pub(super) fn install_reclaim_barrier(
1804        &self,
1805        pid: u64,
1806    ) -> (Arc<Barrier>, Arc<Barrier>, Arc<Barrier>) {
1807        let reached = Arc::new(Barrier::new(2));
1808        let release = Arc::new(Barrier::new(2));
1809        let done = Arc::new(Barrier::new(2));
1810        if let Ok(mut slot) = self.reclaim_barrier.lock() {
1811            *slot = Some(ReclaimBarrier {
1812                pid,
1813                reached: Arc::clone(&reached),
1814                release: Arc::clone(&release),
1815                done: Arc::clone(&done),
1816            });
1817        }
1818        (reached, release, done)
1819    }
1820
1821    /// Takes the installed reclamation gate iff it targets `pid` (one-use). Any
1822    /// other pid's delivery is ungated, so unrelated exits reclaim immediately.
1823    #[cfg(test)]
1824    fn stage_reclaim_barrier(&self, pid: u64) -> Option<ReclaimBarrier> {
1825        let mut slot = self.reclaim_barrier.lock().ok()?;
1826        if slot.as_ref().is_some_and(|barrier| barrier.pid == pid) {
1827            slot.take()
1828        } else {
1829            None
1830        }
1831    }
1832
1833    /// Installs the one-use drain-park gate (oracles 18, 19) and returns its
1834    /// `(armed, release)` endpoints. Staged in the drain waiter's observe->park
1835    /// window so a harness can deliver an exit strictly between the completion
1836    /// observation and the park. Entirely `#[cfg(test)]`; changes no production
1837    /// wait semantics.
1838    #[cfg(test)]
1839    pub(super) fn install_drain_park_barrier(&self) -> (Arc<Barrier>, Arc<Barrier>) {
1840        let armed = Arc::new(Barrier::new(2));
1841        let release = Arc::new(Barrier::new(2));
1842        if let Ok(mut slot) = self.drain_park_barrier.lock() {
1843            *slot = Some(PreWaitBarrier {
1844                armed: Arc::clone(&armed),
1845                release: Arc::clone(&release),
1846            });
1847        }
1848        (armed, release)
1849    }
1850
1851    /// Runs the one-use drain-park gate, if installed. One-use so only the staged
1852    /// park rendezvouses; every later park in the same waiter runs ungated.
1853    #[cfg(test)]
1854    fn run_drain_park_barrier(&self) {
1855        let barrier = self
1856            .drain_park_barrier
1857            .lock()
1858            .ok()
1859            .and_then(|mut slot| slot.take());
1860        let Some(barrier) = barrier else {
1861            return;
1862        };
1863        barrier.armed.wait();
1864        barrier.release.wait();
1865    }
1866
1867    /// Test-only count of drain waiter wakes that observed a real removal.
1868    #[cfg(test)]
1869    pub(super) fn drain_exit_wakes(&self) -> u64 {
1870        self.drain_exit_wakes.load(Ordering::SeqCst)
1871    }
1872
1873    /// Test-only count of drain waiter deadline expirations.
1874    #[cfg(test)]
1875    pub(super) fn drain_deadline_hits(&self) -> u64 {
1876        self.drain_deadline_hits.load(Ordering::SeqCst)
1877    }
1878
1879    /// Runs a one-use deterministic test gate after arm. Returns whether the gate
1880    /// was installed so only that staged probe contributes to observability.
1881    #[cfg(test)]
1882    pub(super) fn run_pre_wait_barrier(&self) -> bool {
1883        let barrier = self
1884            .pre_wait_barrier
1885            .lock()
1886            .ok()
1887            .and_then(|mut slot| slot.take());
1888        let Some(barrier) = barrier else {
1889            return false;
1890        };
1891        barrier.armed.wait();
1892        barrier.release.wait();
1893        true
1894    }
1895
1896    /// Installs a one-use barrier in `enqueue_control`'s insert->wake window
1897    /// (S8 staging: lets a test act as the control-drain consumer between the
1898    /// queue insertion and the wake attempt) and returns its test endpoints.
1899    #[cfg(test)]
1900    pub(super) fn install_pre_wake_barrier(&self) -> (Arc<Barrier>, Arc<Barrier>) {
1901        let armed = Arc::new(Barrier::new(2));
1902        let release = Arc::new(Barrier::new(2));
1903        if let Ok(mut slot) = self.pre_wake_barrier.lock() {
1904            *slot = Some(PreWaitBarrier {
1905                armed: Arc::clone(&armed),
1906                release: Arc::clone(&release),
1907            });
1908        }
1909        (armed, release)
1910    }
1911
1912    /// Runs the one-use insert->wake test gate, if installed.
1913    #[cfg(test)]
1914    pub(super) fn run_pre_wake_barrier(&self) {
1915        let barrier = self
1916            .pre_wake_barrier
1917            .lock()
1918            .ok()
1919            .and_then(|mut slot| slot.take());
1920        if let Some(barrier) = barrier {
1921            barrier.armed.wait();
1922            barrier.release.wait();
1923        }
1924    }
1925
1926    #[cfg(test)]
1927    pub(super) fn record_pre_wait_probe_hit(&self) {
1928        self.pre_wait_probe_hits.fetch_add(1, Ordering::AcqRel);
1929    }
1930
1931    #[cfg(test)]
1932    fn pre_wait_probe_hits(&self) -> u64 {
1933        self.pre_wait_probe_hits.load(Ordering::Acquire)
1934    }
1935
1936    #[cfg(test)]
1937    fn observe_process_stream_drop(&self, fd: RawFd) -> Receiver<()> {
1938        let (sender, receiver) = channel();
1939        if let Ok(mut observers) = self.process_stream_drop_observers.lock() {
1940            observers.insert(fd, sender);
1941        }
1942        receiver
1943    }
1944
1945    /// Publishes the process-owned stream's real drop boundary to a waiting test.
1946    #[cfg(test)]
1947    pub(super) fn record_process_stream_drop(&self, fd: RawFd) {
1948        let observer = self
1949            .process_stream_drop_observers
1950            .lock()
1951            .ok()
1952            .and_then(|mut observers| observers.remove(&fd));
1953        if let Some(observer) = observer {
1954            let _ = observer.send(());
1955        }
1956    }
1957
1958    /// Builds a runtime wrapping `services` for unit tests that exercise
1959    /// `apply_frame` without a live scheduler. Uses a fresh interned control atom
1960    /// and no notifier.
1961    #[cfg(test)]
1962    pub(super) fn for_tests(services: Arc<dyn ConnectionServices>) -> Self {
1963        let atoms = AtomTable::with_common_atoms();
1964        let control_atom = atoms.intern(CONNECTION_SHUTDOWN_CONTROL_ATOM);
1965        let ready_atom = atoms.intern(CONNECTION_READY_ATOM);
1966        Self::new(
1967            ConnectionRuntimeInstallation {
1968                services: ConnectionServiceInstallation::capture(services),
1969                incarnations: None,
1970                fatal_shutdown: None,
1971            },
1972            control_atom,
1973            ready_atom,
1974            Weak::new(),
1975            None,
1976            None,
1977            LimitsConfig::default(),
1978        )
1979    }
1980
1981    /// Builds a runtime wrapping `services` with explicit `limits` for unit tests
1982    /// that exercise the §5 admission caps without a live scheduler.
1983    #[cfg(test)]
1984    pub(super) fn for_tests_with_limits(
1985        services: Arc<dyn ConnectionServices>,
1986        limits: LimitsConfig,
1987    ) -> Self {
1988        let atoms = AtomTable::with_common_atoms();
1989        let control_atom = atoms.intern(CONNECTION_SHUTDOWN_CONTROL_ATOM);
1990        let ready_atom = atoms.intern(CONNECTION_READY_ATOM);
1991        Self::new(
1992            ConnectionRuntimeInstallation {
1993                services: ConnectionServiceInstallation::capture(services),
1994                incarnations: None,
1995                fatal_shutdown: None,
1996            },
1997            control_atom,
1998            ready_atom,
1999            Weak::new(),
2000            None,
2001            None,
2002            limits,
2003        )
2004    }
2005
2006    /// Builds a runtime wrapping `services` with a configured auth `token` for unit
2007    /// tests that exercise the `Connect` handshake enforcement without a live
2008    /// scheduler. Uses a fresh interned control atom and no notifier.
2009    #[cfg(test)]
2010    pub(super) fn for_tests_with_auth_token(
2011        services: Arc<dyn ConnectionServices>,
2012        token: Vec<u8>,
2013    ) -> Self {
2014        let atoms = AtomTable::with_common_atoms();
2015        let control_atom = atoms.intern(CONNECTION_SHUTDOWN_CONTROL_ATOM);
2016        let ready_atom = atoms.intern(CONNECTION_READY_ATOM);
2017        Self::new(
2018            ConnectionRuntimeInstallation {
2019                services: ConnectionServiceInstallation::capture(services),
2020                incarnations: None,
2021                fatal_shutdown: None,
2022            },
2023            control_atom,
2024            ready_atom,
2025            Weak::new(),
2026            None,
2027            Some(token),
2028            LimitsConfig::default(),
2029        )
2030    }
2031
2032    /// Builds a runtime wrapping `services` with a `notifier` for unit tests that
2033    /// exercise `apply_frame` and the close path without a live scheduler.
2034    #[cfg(test)]
2035    pub(super) fn for_tests_with_notifier(
2036        services: Arc<dyn ConnectionServices>,
2037        notifier: Arc<dyn ConnectionNotifier>,
2038    ) -> Self {
2039        let atoms = AtomTable::with_common_atoms();
2040        let control_atom = atoms.intern(CONNECTION_SHUTDOWN_CONTROL_ATOM);
2041        let ready_atom = atoms.intern(CONNECTION_READY_ATOM);
2042        Self::new(
2043            ConnectionRuntimeInstallation {
2044                services: ConnectionServiceInstallation::capture(services),
2045                incarnations: None,
2046                fatal_shutdown: None,
2047            },
2048            control_atom,
2049            ready_atom,
2050            Weak::new(),
2051            Some(notifier),
2052            None,
2053            LimitsConfig::default(),
2054        )
2055    }
2056
2057    pub(super) fn services(&self) -> &dyn ConnectionServices {
2058        self.services.as_ref()
2059    }
2060
2061    /// Returns the complete participant service captured at supervisor startup.
2062    pub(super) const fn participant_service(&self) -> Option<&InstalledParticipantService> {
2063        self.participant_service.as_ref()
2064    }
2065
2066    fn participant_service_fatal(&self) -> Result<Option<ParticipantServiceFatal>, ServerError> {
2067        let Some(service) = self.participant_service() else {
2068            return Ok(None);
2069        };
2070        service
2071            .service_fatal()
2072            .map_err(|error| ServerError::ParticipantIncarnation {
2073                phase: "participant fatal latch inspection",
2074                message: error.to_string(),
2075            })
2076    }
2077
2078    fn activate_fatal_shutdown(&self) {
2079        if let Some(shutdown) = self.fatal_shutdown.as_ref() {
2080            shutdown.initiate();
2081        }
2082    }
2083
2084    fn ensure_participant_service_live(&self) -> Result<(), ServerError> {
2085        let Some(fatal) = self.participant_service_fatal()? else {
2086            return Ok(());
2087        };
2088        self.activate_fatal_shutdown();
2089        Err(ServerError::ParticipantServiceFatal { fatal })
2090    }
2091
2092    fn latch_connection_fate_intent_incomplete(
2093        &self,
2094        open_sequence: u64,
2095        conversation_id: u64,
2096    ) -> Result<ParticipantServiceFatal, ServerError> {
2097        let Some(service) = self.participant_service() else {
2098            return Err(ServerError::ParticipantIncarnation {
2099                phase: "connection-fate fatal latch",
2100                message: "a durable Open lacks its installed participant service".to_owned(),
2101            });
2102        };
2103        let fatal = service
2104            .latch_connection_fate_intent_incomplete(open_sequence, conversation_id)
2105            .map_err(|error| ServerError::ParticipantIncarnation {
2106                phase: "connection-fate fatal latch",
2107                message: error.to_string(),
2108            })?;
2109        self.activate_fatal_shutdown();
2110        Ok(fatal)
2111    }
2112
2113    fn complete_connection_fate_fatal(
2114        &self,
2115        open_sequence: u64,
2116        conversations: &[u64],
2117        phase: &'static str,
2118        error: &impl std::fmt::Display,
2119    ) -> ServerError {
2120        tracing::error!(open_sequence, phase, %error, "durable connection-fate intent is incomplete");
2121        let Some(&conversation_id) = conversations.first() else {
2122            return ServerError::ParticipantIncarnation {
2123                phase: "connection-fate fatal target",
2124                message: "a durable Open has no tracked conversation target".to_owned(),
2125            };
2126        };
2127        match self.latch_connection_fate_intent_incomplete(open_sequence, conversation_id) {
2128            Ok(fatal) => ServerError::ParticipantServiceFatal { fatal },
2129            Err(latch_error) => latch_error,
2130        }
2131    }
2132
2133    /// Runs one typed terminal fold after classification and before teardown.
2134    pub(super) fn complete_connection_fate(
2135        &self,
2136        connection_incarnation: Option<ConnectionIncarnation>,
2137        class: ConnectionFateClass,
2138        conversations: &[u64],
2139    ) -> Result<(), ServerError> {
2140        if conversations.is_empty() {
2141            return Ok(());
2142        }
2143        self.ensure_participant_service_live()?;
2144        let (Some(connection_incarnation), Some(service), Some(authority)) = (
2145            connection_incarnation,
2146            self.participant_service(),
2147            self.incarnations.as_ref(),
2148        ) else {
2149            return Err(ServerError::ParticipantIncarnation {
2150                phase: "connection-fate authority composition",
2151                message: "tracked participant conversations lack a complete service/incarnation authority"
2152                    .to_owned(),
2153            });
2154        };
2155        let intent =
2156            authority.open_connection_fate(connection_incarnation, class, conversations)?;
2157        if let Err(error) = service.handle_connection_fate(intent.work_item()) {
2158            return Err(self.complete_connection_fate_fatal(
2159                intent.open_sequence,
2160                conversations,
2161                "handler",
2162                &error,
2163            ));
2164        }
2165        if let Err(error) = authority.complete_connection_fate(intent.open_sequence) {
2166            return Err(self.complete_connection_fate_fatal(
2167                intent.open_sequence,
2168                conversations,
2169                "Complete",
2170                &error,
2171            ));
2172        }
2173        Ok(())
2174    }
2175
2176    /// Resolves the bound-only protocol-error gate from participant authority.
2177    pub(super) fn connection_has_bound_participant(
2178        &self,
2179        connection_incarnation: Option<ConnectionIncarnation>,
2180        conversations: &[u64],
2181    ) -> Result<bool, ServerError> {
2182        if conversations.is_empty() {
2183            return Ok(false);
2184        }
2185        self.ensure_participant_service_live()?;
2186        let (Some(connection_incarnation), Some(service)) =
2187            (connection_incarnation, self.participant_service())
2188        else {
2189            return Err(ServerError::ParticipantIncarnation {
2190                phase: "bound participant classification",
2191                message:
2192                    "tracked participant conversations lack a complete service/incarnation pair"
2193                        .to_owned(),
2194            });
2195        };
2196        service
2197            .connection_has_bound_participant(connection_incarnation, conversations)
2198            .map_err(|error| ServerError::ParticipantIncarnation {
2199                phase: "bound participant classification",
2200                message: error.to_string(),
2201            })
2202    }
2203
2204    /// Returns the configured connection auth token as opaque bytes, or `None` when
2205    /// no `[auth]` section was configured (open access).
2206    pub(super) fn auth_token(&self) -> Option<&[u8]> {
2207        self.auth_token.as_deref()
2208    }
2209
2210    /// Returns the configured connection-keyed notifier, if any.
2211    pub(super) fn notifier(&self) -> Option<&Arc<dyn ConnectionNotifier>> {
2212        self.notifier.as_ref()
2213    }
2214
2215    /// Offers a channel publish to the notifier's observability-drain tap, returning
2216    /// `true` when the application consumed it (so the connection process skips the
2217    /// normal fan-out). `false` when no notifier is installed (liminal standalone) or
2218    /// the notifier did not recognise the channel, so the caller can invoke it
2219    /// unconditionally and fall through to the normal publish path.
2220    pub(super) fn notifier_channel_publish(&self, pid: u64, channel: &str, payload: &[u8]) -> bool {
2221        self.notifier
2222            .as_ref()
2223            .is_some_and(|notifier| notifier.on_channel_publish(pid, channel, payload))
2224    }
2225
2226    /// Stores `registration` on the connection record for `pid`, so the close
2227    /// path can later fire `on_worker_unregistered` for exactly the connections
2228    /// that registered. A missing record (the connection already closed) is a
2229    /// no-op.
2230    ///
2231    /// # Errors
2232    /// Returns [`ServerError`] when the connection registry mutex is poisoned.
2233    pub(super) fn set_registration(
2234        &self,
2235        pid: u64,
2236        registration: WorkerRegistration,
2237    ) -> Result<(), ServerError> {
2238        if let Some(record) = lock(&self.records, "connection registry")?.get_mut(&pid) {
2239            record.registration = Some(registration);
2240        }
2241        Ok(())
2242    }
2243
2244    /// Allocates the next monotonic push correlation id.
2245    fn next_push_correlation_id(&self) -> u64 {
2246        self.next_push_id.fetch_add(1, Ordering::Relaxed)
2247    }
2248
2249    /// Registers a one-shot reply slot for `correlation_id`, owned by connection
2250    /// `pid`, and returns its receiver. `deadline` is the slot's optional absolute
2251    /// reply expiry (`None` = the default no-deadline shape). The connection
2252    /// process resolves the slot via [`resolve_push`]; the close path drops the
2253    /// connection's outstanding slots via [`cancel_pushes_for_connection`]; an
2254    /// explicit deadline resolves it via [`expire_push_if_due`].
2255    ///
2256    /// # Errors
2257    /// Returns [`ServerError`] when the correlation registry mutex is poisoned.
2258    fn register_push(
2259        &self,
2260        pid: u64,
2261        correlation_id: u64,
2262        deadline: Option<Instant>,
2263    ) -> Result<Receiver<Vec<u8>>, ServerError> {
2264        let (sender, receiver) = channel();
2265        let limit = self.limits.max_pending_pushes_per_connection;
2266        {
2267            let mut slots = lock(&self.push_replies, "push correlation registry")?;
2268            // §5 `max_pending_pushes_per_connection`: refuse a new in-flight push
2269            // once this connection already holds the cap. Counted per owning pid so
2270            // one connection cannot exhaust the shared registry; slots free on
2271            // reply, deadline expiry, or connection close. The count-and-insert
2272            // stays under the one lock so the cap is enforced atomically.
2273            let outstanding = slots.values().filter(|pending| pending.pid == pid).count();
2274            if outstanding >= limit {
2275                return Err(ServerError::ConnectionCapReached {
2276                    operation: "server push".to_owned(),
2277                    cap: "max_pending_pushes_per_connection",
2278                    limit,
2279                });
2280            }
2281            slots.insert(
2282                correlation_id,
2283                PendingPush {
2284                    pid,
2285                    sender,
2286                    deadline,
2287                },
2288            );
2289        }
2290        Ok(receiver)
2291    }
2292
2293    /// Host-side, lazy evaluation of a push's reply deadline, called from an
2294    /// elapsed [`PushReplyAwaiter::receive`] quantum. This NEVER wakes the
2295    /// connection process and runs no timer — it inspects supervisor-owned state
2296    /// under the registry lock only.
2297    ///
2298    /// A slot with an explicit deadline that has passed is removed here (dropping
2299    /// its `Sender` and releasing its §5 `max_pending_pushes_per_connection` cap
2300    /// admission, since the cap is the per-pid slot count) and reported
2301    /// [`PushSlotDisposition::Expired`]. A slot with no deadline, or a deadline
2302    /// still in the future, is left UNTOUCHED and reported
2303    /// [`PushSlotDisposition::Live`] — the elapsed quantum is a benign re-arm. A
2304    /// missing slot is [`PushSlotDisposition::Absent`].
2305    fn expire_push_if_due(&self, correlation_id: u64) -> PushSlotDisposition {
2306        // S4: a poisoned registry must NOT read as slot absence — the slot (and
2307        // its cap admission) may still be in the map. Reclamation recovers the
2308        // guard: removal-only operations are sound on a recovered map (a panic
2309        // in another critical section cannot leave the HashMap itself in a
2310        // partial state; only our bookkeeping invariants could be stale, and
2311        // removal restores them). Admission (`register_push`) stays fail-closed.
2312        let mut slots = recover_lock(&self.push_replies);
2313        let Some(pending) = slots.get(&correlation_id) else {
2314            return PushSlotDisposition::Absent;
2315        };
2316        // Copy the deadline out so the immutable borrow of `slots` ends before the
2317        // conditional `remove` below takes a mutable one.
2318        let deadline = pending.deadline;
2319        match deadline {
2320            Some(at) if Instant::now() >= at => {
2321                slots.remove(&correlation_id);
2322                PushSlotDisposition::Expired
2323            }
2324            _ => PushSlotDisposition::Live,
2325        }
2326    }
2327
2328    /// Drops a registered reply slot without resolving it, used on the
2329    /// push-enqueue failure path (the control could not be delivered to a
2330    /// now-gone process, so the just-reserved slot is unreachable). Dropping the
2331    /// slot's `Sender` wakes a still-waiting awaiter with a disconnected error.
2332    ///
2333    /// Returns whether THIS call removed the slot. Removal under the registry
2334    /// mutex is the atomic resolved-vs-cancelled transition: `false` means
2335    /// another path won — [`resolve_push`](Self::resolve_push) already sent the
2336    /// reply (its send happens under the same lock, so the payload is already in
2337    /// the channel when this returns), or the connection's close path dropped
2338    /// the slot (sender gone, channel disconnected).
2339    pub(super) fn cancel_push(&self, correlation_id: u64) -> bool {
2340        // S4: reclamation recovers a poisoned guard — a rollback that silently
2341        // skipped its removal would strand the slot and its cap admission.
2342        recover_lock(&self.push_replies)
2343            .remove(&correlation_id)
2344            .is_some()
2345    }
2346
2347    /// Drops every reply slot owned by connection `pid`, waking each awaiter with a
2348    /// disconnected error (the dropped `Sender` disconnects the awaiter's
2349    /// `Receiver`). Called from the close path so a connection that exits with
2350    /// in-flight pushes signals worker death immediately instead of leaving each
2351    /// awaiter to block the full push-reply timeout. A slot that [`resolve_push`]
2352    /// already removed is gone, so it is untouched here; an unknown pid is a no-op.
2353    fn cancel_pushes_for_connection(&self, pid: u64) {
2354        // S4: the close sweep is the reclamation of last resort ("connection
2355        // close at the latest") — it must complete on a poisoned map too.
2356        recover_lock(&self.push_replies).retain(|_correlation_id, pending| pending.pid != pid);
2357    }
2358
2359    /// S3 second half (shape (b), check-after-insert): pre-publication
2360    /// confirmation that the connection record for `pid` still exists, run in
2361    /// the INSERT -> CONFIRM -> PUBLISH order (S7 — confirming after the
2362    /// enqueue let a close-swept-then-answered push report `Err` for a Push the
2363    /// client had received). `true` leaves the slot in place and the caller may
2364    /// publish; `false` means a concurrent close already removed the record —
2365    /// this call then removes the caller's own just-inserted slot (rolling back
2366    /// its cap admission) so nothing is stranded, and the caller returns
2367    /// WITHOUT publishing: an `Err` from the push methods guarantees no `Push`
2368    /// control was published.
2369    ///
2370    /// Why exactly one side always observes the slot: `remove` (the single
2371    /// record-removal path) removes the host record BEFORE sweeping the pid's
2372    /// push slots, and this check reads the record AFTER inserting the slot and
2373    /// BEFORE the control is published. Both records accesses are serialized by
2374    /// the `records` mutex, so either (i) this read precedes the record removal
2375    /// — then the slot insert precedes the sweep (insert < read < removal <
2376    /// sweep in the happens-before order) and the SWEEP observes and removes
2377    /// the slot: if the control was published in the meantime the awaiter reads
2378    /// the truthful disconnected outcome and a late client reply is a harmless
2379    /// no-op; or (ii) this read follows the record removal — then THIS call
2380    /// observes the absence, rolls the slot back itself, and nothing was
2381    /// published. When both observe (a sweep and a rollback can both run in
2382    /// case (ii) if the insert also preceded the sweep), removal is idempotent
2383    /// and the cap is derived from map membership, so nothing double-releases.
2384    ///
2385    /// Lock discipline: `records` and `push_replies` are NEVER held together —
2386    /// here (`records` read, released, then `push_replies` on rollback), in
2387    /// `remove` (`records` removal, released, then the sweep), and everywhere
2388    /// else in this file the two mutexes are taken strictly sequentially, so no
2389    /// lock-order inversion is possible. This adds ZERO work to the connection
2390    /// slice path: the re-check runs on the push caller's thread only.
2391    pub(super) fn confirm_push_registration(&self, pid: u64, correlation_id: u64) -> bool {
2392        if self.is_registered(pid) {
2393            return true;
2394        }
2395        self.cancel_push(correlation_id);
2396        false
2397    }
2398
2399    /// Number of reserved push reply slots outstanding. A benign wait-quantum
2400    /// timeout must NOT change this (the slot survives); an explicit-deadline
2401    /// expiry, a consumed reply, and connection close each release exactly one.
2402    #[cfg(test)]
2403    pub(super) fn pending_push_count(&self) -> usize {
2404        recover_lock(&self.push_replies).len()
2405    }
2406
2407    /// Reserved push reply slots owned by connection `pid` — the exact quantity
2408    /// the §5 `max_pending_pushes_per_connection` cap counts (test instrument).
2409    #[cfg(test)]
2410    pub(super) fn pending_push_count_for(&self, pid: u64) -> usize {
2411        recover_lock(&self.push_replies)
2412            .values()
2413            .filter(|pending| pending.pid == pid)
2414            .count()
2415    }
2416
2417    /// Resolves the reply slot for `correlation_id` with the client's reply
2418    /// payload, waking the [`PushReplyAwaiter`]. Called by the connection process
2419    /// when a correlated `PushReply` frame arrives. A missing slot — already
2420    /// resolved, expired at its explicit deadline, dropped by connection close, or
2421    /// an unknown id — is a harmless no-op: a late `PushReply` for a slot that is
2422    /// gone is discarded here, never delivered and never a panic or desync.
2423    pub(super) fn resolve_push(&self, correlation_id: u64, payload: Vec<u8>) {
2424        // S4: delivery-plus-removal recovers a poisoned guard — dropping a real
2425        // reply (and stranding its slot) because an unrelated critical section
2426        // panicked would kill reclamation and exact cap accounting.
2427        let mut slots = recover_lock(&self.push_replies);
2428        if let Some(pending) = slots.remove(&correlation_id) {
2429            // The send stays under the registry lock so removal and delivery are
2430            // one atomic step: a timed-out awaiter that observes the slot gone
2431            // (its `cancel_push` returned false) is then GUARANTEED to find the
2432            // payload already in the channel — without this ordering the awaiter
2433            // could see the removal, find the channel still empty, and report a
2434            // timeout for a reply that was about to land. The send itself never
2435            // blocks (unbounded channel), and a receiver dropped after an
2436            // abandoned wait makes it a benign discard.
2437            pending.sender.send(payload).ok();
2438        }
2439    }
2440
2441    pub(super) const fn control_atom(&self) -> Atom {
2442        self.control_atom
2443    }
2444
2445    /// Sole registration path for a connection: the spawn thread inserts the
2446    /// record synchronously, before `spawn_connection` returns the handle, so
2447    /// `is_tracked`/`active_connection_count` reflect the connection
2448    /// immediately. The connection handler never writes the registry (it only
2449    /// reads via `mark_crashed`/`finish`), so there is a single writer here and
2450    /// no register/ensure-register race.
2451    ///
2452    /// Ordering note: `spawn_native` only enqueues the process, so its first
2453    /// slice may run on another worker thread before this insert lands. If that
2454    /// first slice exits immediately (e.g. a missing-stream crash) its
2455    /// `mark_crashed`/`finish` removes nothing and this insert then leaves a
2456    /// record for an already-dead pid. W4 leg 1 retires the per-accept
2457    /// `reap_crashed` scan that used to self-heal that orphan continuously;
2458    /// instead [`Self::reconcile_register_orphan`] closes the race with a SINGLE
2459    /// point check on the registration event itself — never a loop.
2460    fn register_with_fd(
2461        &self,
2462        pid: u64,
2463        peer_addr: Option<SocketAddr>,
2464        connection_incarnation: Option<ConnectionIncarnation>,
2465        fd_guard: TcpStream,
2466    ) -> Result<(), ServerError> {
2467        self.register_record(pid, peer_addr, connection_incarnation, Some(fd_guard))?;
2468        self.reconcile_register_orphan(pid);
2469        Ok(())
2470    }
2471
2472    /// Closes the register-orphan race (see [`Self::register_with_fd`]) with one
2473    /// point check driven by the registration event — not a periodic scan. If
2474    /// the just-registered pid is already absent from the scheduler process
2475    /// table, its first slice has run and exited, so the record this
2476    /// registration inserted is an orphan the retiring reap scan used to sweep;
2477    /// reclaim it immediately through the ordinary `remove()` funnel. A pid still
2478    /// present is live and needs nothing here: a later external termination rides
2479    /// the exit-event reactor and an ordinary exit its own final slice.
2480    fn reconcile_register_orphan(&self, pid: u64) {
2481        let Some(scheduler) = self.scheduler.upgrade() else {
2482            return;
2483        };
2484        // The process-table lookup returns a sharded guard; bind only the
2485        // presence bool so the guard is released before `reclaim_terminated`
2486        // takes the connection registry lock (no cross-lock hold).
2487        let already_exited = scheduler.process_table().get(pid).is_none();
2488        if !already_exited {
2489            return;
2490        }
2491        let reason = scheduler
2492            .peek_exit_reason(pid)
2493            .unwrap_or(ExitReason::Normal);
2494        self.reclaim_terminated(pid, reason);
2495    }
2496
2497    /// TOLD reclamation of a connection whose process exited WITHOUT running a
2498    /// final handler slice — external/panic termination, where
2499    /// [`ConnectionProcess::Drop`] runs but no `mark_crashed`/`finish` does, and
2500    /// the register-orphan race above. Delivered the instant beamr publishes the
2501    /// process's [`ExitEvent`] (via [`run_reclaim_reactor`]) or at the
2502    /// registration point check, and routed through the SAME [`Self::remove`]
2503    /// funnel as every other teardown — no third funnel, no periodic scan.
2504    /// Idempotent: a record already removed in-slice, by the orphan reconcile, or
2505    /// by a duplicate delivery is a no-op here (remove returns `None`), so the §5
2506    /// admission gauge is released exactly once.
2507    fn reclaim_terminated(&self, pid: u64, reason: ExitReason) {
2508        let Some(record) = self.remove(pid) else {
2509            return;
2510        };
2511        self.fire_unregistered(pid, &record);
2512        tracing::warn!(
2513            connection_pid = pid,
2514            peer_addr = ?record.peer_addr,
2515            reason = ?reason,
2516            "connection process exited without a final slice; host record reclaimed by delivery"
2517        );
2518    }
2519
2520    /// One exit-event delivery: drain beamr's retained outcome (sole drainer,
2521    /// bounding its store) then reclaim through [`Self::reclaim_terminated`]. The
2522    /// only non-production element is the `#[cfg(test)]` reclamation gate, which
2523    /// is staged for at most one targeted pid and compiled out entirely in
2524    /// production — the delivery semantics are identical with or without it.
2525    fn deliver_reclamation(&self, scheduler: &Weak<Scheduler>, pid: u64, reason: ExitReason) {
2526        if let Some(scheduler) = scheduler.upgrade() {
2527            // The reason is already in-hand from the event; the drained outcome
2528            // is discarded, its purpose being only to bound beamr's store.
2529            drop(scheduler.take_exit_outcome(pid));
2530        }
2531        #[cfg(test)]
2532        let staged = self.stage_reclaim_barrier(pid);
2533        #[cfg(test)]
2534        if let Some(barrier) = staged.as_ref() {
2535            // Rendezvous: the pid is now dead but its record is still tracked —
2536            // the S8 reclamation window (oracle 26). Then wait for the harness to
2537            // release the reclaim.
2538            barrier.reached.wait();
2539            barrier.release.wait();
2540        }
2541        self.reclaim_terminated(pid, reason);
2542        #[cfg(test)]
2543        if let Some(barrier) = staged.as_ref() {
2544            // Signal the funnel completed so the harness can observe the record
2545            // gone without sampling.
2546            barrier.done.wait();
2547        }
2548    }
2549
2550    #[cfg(test)]
2551    fn register(&self, pid: u64, peer_addr: Option<SocketAddr>) -> Result<(), ServerError> {
2552        self.register_record(pid, peer_addr, None, None)
2553    }
2554
2555    fn register_record(
2556        &self,
2557        pid: u64,
2558        peer_addr: Option<SocketAddr>,
2559        connection_incarnation: Option<ConnectionIncarnation>,
2560        fd_guard: Option<TcpStream>,
2561    ) -> Result<(), ServerError> {
2562        lock(&self.records, "connection registry")?.insert(
2563            pid,
2564            ConnectionRecord {
2565                peer_addr,
2566                connection_incarnation,
2567                registration: None,
2568                readiness: None,
2569                ready_pending: Arc::new(AtomicBool::new(false)),
2570                fd_guard,
2571            },
2572        );
2573        // Single-writer insert (see doc above) pairs one gauge increment with the
2574        // decrement in `remove`, keeping `liminal_connections_active` equal to the
2575        // live record count on every teardown route.
2576        crate::metrics::connection_spawned();
2577        Ok(())
2578    }
2579
2580    pub(super) fn mark_crashed(&self, pid: u64, reason: ExitReason, peer_addr: Option<SocketAddr>) {
2581        let removed = self.remove(pid);
2582        if let Some(record) = removed.as_ref() {
2583            self.fire_unregistered(pid, record);
2584        }
2585        let removed_peer_addr = removed
2586            .as_ref()
2587            .and_then(|record| record.peer_addr)
2588            .or(peer_addr);
2589        tracing::warn!(
2590            connection_pid = pid,
2591            peer_addr = ?removed_peer_addr,
2592            reason = ?reason,
2593            "connection process crashed"
2594        );
2595    }
2596
2597    /// Whether the spawn thread has installed the host record. A first native
2598    /// slice can win the enqueue-vs-record race and must remain runnable until it
2599    /// has somewhere host-reachable to publish its readiness token.
2600    pub(super) fn is_registered(&self, pid: u64) -> bool {
2601        self.contains(pid)
2602    }
2603
2604    /// Removes a token minted in-slice when publishing it to the host record fails.
2605    pub(super) fn deregister_unpublished_readiness(&self, token: ReadinessToken) {
2606        if let Some(scheduler) = self.scheduler.upgrade() {
2607            scheduler.readiness_deregister(token);
2608        }
2609    }
2610
2611    /// Cancels deadline timers detached by reply completion or connection close.
2612    pub(super) fn cancel_deadline_timers(&self, timers: Vec<TimerRef>) {
2613        let Some(scheduler) = self.scheduler.upgrade() else {
2614            return;
2615        };
2616        if let Ok(mut wheel) = scheduler.timers().lock() {
2617            for timer in timers {
2618                wheel.cancel(timer);
2619            }
2620        }
2621    }
2622
2623    pub(super) fn finish(&self, pid: u64) {
2624        if let Some(removed) = self.remove(pid) {
2625            self.fire_unregistered(pid, &removed);
2626        }
2627    }
2628
2629    /// Records the one readiness token minted for this connection. A live
2630    /// connection never re-registers: later parked slices rearm this identity.
2631    pub(super) fn set_readiness_token_once(
2632        &self,
2633        pid: u64,
2634        token: ReadinessToken,
2635        fd: RawFd,
2636    ) -> Result<(), ServerError> {
2637        let mut records = lock(&self.records, "connection registry")?;
2638        let record = records
2639            .get_mut(&pid)
2640            .ok_or_else(|| ServerError::ListenerAccept {
2641                message: format!("connection {pid} has no host record for readiness registration"),
2642            })?;
2643        if record.readiness.is_some() {
2644            return Err(ServerError::ListenerAccept {
2645                message: format!("connection {pid} attempted to replace its readiness token"),
2646            });
2647        }
2648        record.readiness = Some(ReadinessRegistration { token, fd });
2649        drop(records);
2650        Ok(())
2651    }
2652
2653    /// Invokes `on_worker_unregistered` for a removed connection record that
2654    /// carried a worker registration. A record with no registration (a plain
2655    /// connection, or a worker connection that never registered) is a no-op, so
2656    /// only connections that actually registered deregister.
2657    fn fire_unregistered(&self, pid: u64, record: &ConnectionRecord) {
2658        if record.registration.is_some() {
2659            if let Some(notifier) = self.notifier.as_ref() {
2660                notifier.on_worker_unregistered(pid);
2661            }
2662        }
2663    }
2664
2665    fn reap_crashed(&self, scheduler: &Scheduler) -> usize {
2666        let pids = match self.records.lock() {
2667            Ok(records) => records.keys().copied().collect::<Vec<_>>(),
2668            Err(error) => {
2669                tracing::warn!(%error, "connection registry unavailable during crash reap");
2670                return 0;
2671            }
2672        };
2673        let mut reaped = 0;
2674        for pid in pids {
2675            if scheduler.process_table().get(pid).is_none() {
2676                let removed = self.remove(pid);
2677                if let Some(record) = removed.as_ref() {
2678                    self.fire_unregistered(pid, record);
2679                }
2680                let peer_addr = removed.and_then(|record| record.peer_addr);
2681                // This process exited without ever reaching `mark_crashed`/`finish`
2682                // (e.g. the beamr scheduler terminated it externally). W4 leg 1
2683                // retired this scan from the per-accept listener loop, and W4 leg 3
2684                // retired the shutdown-drain reconciliation that also drove it: the
2685                // reclaimer of these exits is now the TOLD exit-event reactor
2686                // ([`run_reclaim_reactor`]), which also composes drain completion
2687                // through the one `remove()` funnel. This scan now survives only as
2688                // that reactor's exit-event overflow (`Lagged`) recovery, driven a
2689                // bounded number of times, never periodically. beamr 0.15.4 exposes
2690                // a public, non-blocking
2691                // `peek_exit_reason` (and `take_exit_outcome`), so the real reason
2692                // IS recoverable here rather than logged as an opaque literal.
2693                let reason = scheduler.peek_exit_reason(pid);
2694                tracing::warn!(
2695                    connection_pid = pid,
2696                    ?peer_addr,
2697                    ?reason,
2698                    "connection process exited without a final slice; reclaimed by reconciliation"
2699                );
2700                reaped += 1;
2701            }
2702        }
2703        reaped
2704    }
2705
2706    fn contains(&self, pid: u64) -> bool {
2707        self.records
2708            .lock()
2709            .is_ok_and(|records| records.contains_key(&pid))
2710    }
2711
2712    #[cfg(test)]
2713    fn readiness_registration_count(&self) -> usize {
2714        self.records.lock().map_or(0, |records| {
2715            records
2716                .values()
2717                .filter(|record| record.readiness.is_some())
2718                .count()
2719        })
2720    }
2721
2722    #[cfg(test)]
2723    fn readiness_fd(&self, pid: u64) -> Option<RawFd> {
2724        self.records
2725            .lock()
2726            .ok()?
2727            .get(&pid)
2728            .and_then(|record| record.readiness.map(|registration| registration.fd))
2729    }
2730
2731    #[cfg(test)]
2732    fn readiness_token(&self, pid: u64) -> Option<ReadinessToken> {
2733        self.records
2734            .lock()
2735            .ok()?
2736            .get(&pid)
2737            .and_then(|record| record.readiness.map(|registration| registration.token))
2738    }
2739
2740    fn active_connections(&self) -> Vec<ActiveConnection> {
2741        self.records.lock().map_or_else(
2742            |_| Vec::new(),
2743            |records| {
2744                records
2745                    .iter()
2746                    .map(|(&pid, record)| ActiveConnection {
2747                        pid,
2748                        peer_addr: record.peer_addr,
2749                    })
2750                    .collect()
2751            },
2752        )
2753    }
2754
2755    /// Reads the complete active-connection incarnation set under the
2756    /// registry lock — the bounded defense-in-depth collision-skip input to
2757    /// incarnation allocation (uniqueness itself comes from allocator-log
2758    /// monotonicity; see `allocate_connection_incarnation`). Poisoning fails
2759    /// admission closed: treating an unreadable registry as empty would
2760    /// silently drop the defense layer.
2761    fn complete_active_incarnation_references(
2762        &self,
2763    ) -> Result<Vec<ConnectionIncarnation>, ServerError> {
2764        Ok(
2765            lock(&self.records, "connection incarnation reference registry")?
2766                .values()
2767                .filter_map(|record| record.connection_incarnation)
2768                .collect(),
2769        )
2770    }
2771
2772    fn push_control(&self, pid: u64, control: ConnectionControl) -> Result<(), ServerError> {
2773        lock(&self.controls, "connection control queue")?
2774            .push(QueuedConnectionControl { pid, control });
2775        Ok(())
2776    }
2777
2778    pub(super) fn pop_control(&self, pid: u64) -> Option<ConnectionControl> {
2779        let mut controls = self.controls.lock().ok()?;
2780        let index = controls.iter().position(|queued| queued.pid == pid)?;
2781        Some(controls.remove(index).control)
2782    }
2783
2784    /// Non-consuming final-probe query for controls enqueued after mailbox drain.
2785    pub(super) fn has_control(&self, pid: u64) -> bool {
2786        self.controls
2787            .lock()
2788            .is_ok_and(|controls| controls.iter().any(|queued| queued.pid == pid))
2789    }
2790
2791    /// Pulls a queued-but-unconsumed control back out of the queue. Returns
2792    /// whether THIS call removed it — `false` means the entry already left the
2793    /// queue, and since [`Self::pop_control`] is the only other remover, a
2794    /// consumer drain took it (S8's publication disambiguator). Matching is
2795    /// `pid` + full control equality; a `Push` control embeds its
2796    /// runtime-unique correlation id, so this can never remove a different
2797    /// push's entry and misreport.
2798    fn remove_control(&self, pid: u64, control: &ConnectionControl) -> bool {
2799        let Ok(mut controls) = self.controls.lock() else {
2800            return false;
2801        };
2802        let Some(index) = controls
2803            .iter()
2804            .position(|queued| queued.pid == pid && &queued.control == control)
2805        else {
2806            return false;
2807        };
2808        controls.remove(index);
2809        true
2810    }
2811
2812    fn active_count(&self) -> usize {
2813        self.records.lock().map_or(0, |records| records.len())
2814    }
2815
2816    /// Removes the connection record for `pid` and, in the same close step, drops
2817    /// every push reply slot that connection still owns so each waiting
2818    /// [`PushReplyAwaiter`] wakes immediately with a disconnected error. This runs
2819    /// on every close route — `finish`, `mark_crashed`, and `reap_crashed` all
2820    /// remove through here — and fires regardless of whether the connection ever
2821    /// registered a worker, so a plain push target is covered too.
2822    ///
2823    /// ORDER MATTERS (S3/S7): the record is removed BEFORE the push sweep. A
2824    /// push registering concurrently runs INSERT -> CONFIRM -> PUBLISH
2825    /// (`confirm_push_registration` reads the record after inserting its slot
2826    /// and before publishing its control), so with this ordering exactly one
2827    /// side always observes a racing slot: a confirm that ran before this
2828    /// removal implies the slot was inserted before the sweep below (which then
2829    /// reaps it — a control published after that confirm is answered into a
2830    /// swept slot, read as the truthful disconnected outcome); a confirm after
2831    /// this removal sees the absence, rolls the slot back itself, and never
2832    /// publishes. Sweeping first (the original order) left a window — sweep,
2833    /// then insert+confirm, then record removal — where NEITHER side observed
2834    /// the slot and it leaked past connection close. The two locks are taken
2835    /// strictly sequentially (never nested), so no lock-order inversion.
2836    fn remove(&self, pid: u64) -> Option<ConnectionRecord> {
2837        let mut removed = self
2838            .records
2839            .lock()
2840            .ok()
2841            .and_then(|mut records| records.remove(&pid));
2842        self.cancel_pushes_for_connection(pid);
2843        if let Some(registration) = removed.as_mut().and_then(|record| record.readiness.take()) {
2844            if let Some(scheduler) = self.scheduler.upgrade() {
2845                // This call is ACK'd: it returns only after the poll owner has
2846                // removed the registration. `fd_guard` is still live here.
2847                scheduler.readiness_deregister(registration.token);
2848                tracing::debug!(
2849                    registered_fd = registration.fd,
2850                    "connection readiness deregistration acknowledged"
2851                );
2852            }
2853        }
2854        // Decrement only when a record was actually present so a double-remove
2855        // (e.g. `finish` after `reap_crashed`) cannot drive the gauge negative.
2856        // The §5 admission slot is released on the same guard: the reservation
2857        // acquired in `spawn_connection` converted into this record at
2858        // `register`, so its removal is exactly one release per reservation.
2859        if removed.is_some() {
2860            crate::metrics::connection_closed();
2861            self.release_admission();
2862        }
2863        if let Some(record) = removed.as_mut() {
2864            // Explicit after-deregister drop documents and enforces the fd wall.
2865            drop(record.fd_guard.take());
2866        }
2867        // TOLD drain-completion tell (W4 leg 3, §4.3): the record map above already
2868        // reflects this removal, so bump the removal generation and wake the
2869        // drain/settle waiter AFTER the observed state is updated. Ordering the
2870        // state update before the generation bump — paired with the waiter arming
2871        // its snapshot before observing `active_count` — is the arm-before-observe
2872        // barrier that makes a concurrently delivered exit un-losable (oracle 18).
2873        // Only a real removal tells, so a double-remove drives no spurious wake.
2874        if removed.is_some() {
2875            self.signal_connection_removed();
2876        }
2877        removed
2878    }
2879
2880    /// Bumps the drain-completion generation and wakes the drain/settle waiter.
2881    /// Called from [`Self::remove`] on every route that actually drops a record.
2882    fn signal_connection_removed(&self) {
2883        // Bump the generation under the lock, release it, THEN notify. A waiter
2884        // holds this lock continuously from its generation re-check through the
2885        // atomic release inside `wait_timeout`, so it can never miss a bump
2886        // published before the notify — the Condvar lost-wakeup contract holds
2887        // without notifying under the guard.
2888        {
2889            let mut generation = recover_lock(&self.drain_generation);
2890            *generation = generation.wrapping_add(1);
2891        }
2892        self.drain_removed.notify_all();
2893    }
2894
2895    /// Parks the calling thread until every tracked connection has been removed
2896    /// or `deadline` elapses, returning `true` when the drain completed and
2897    /// `false` when the single admitted deadline won. This is the TOLD
2898    /// replacement (W4 leg 3, §4.3) for the retired reap/count/sleep drain loop:
2899    /// it never samples completion on a timer. Completion is observed only on a
2900    /// delivered connection-removal wake (composed from the one `remove()` funnel,
2901    /// so a Died/Detached/crash exit and an orderly close decrement through the
2902    /// same path — oracle 15) or the one deadline. Force-close settle reuses this
2903    /// same waiter with its own deadline rather than a second poll loop (oracle
2904    /// 14).
2905    pub(super) fn wait_for_active_connections_drained(&self, deadline: Instant) -> bool {
2906        loop {
2907            // ARM before OBSERVE: snapshot the removal generation first, so an exit
2908            // delivered after the completion observation below and before the park
2909            // bumps a generation the park detects — it is never lost (oracle 18).
2910            let snapshot = self.drain_generation_snapshot();
2911            // OBSERVE completion first: a last exit that reaches zero wins a tie
2912            // with a simultaneously elapsed deadline (oracle 19).
2913            if self.active_count() == 0 {
2914                return true;
2915            }
2916            let Some(remaining) = deadline.checked_duration_since(Instant::now()) else {
2917                #[cfg(test)]
2918                self.drain_deadline_hits.fetch_add(1, Ordering::SeqCst);
2919                return false;
2920            };
2921            #[cfg(test)]
2922            self.run_drain_park_barrier();
2923            self.park_until_removed_or(snapshot, remaining);
2924        }
2925    }
2926
2927    /// Reads the current removal generation under its mutex.
2928    fn drain_generation_snapshot(&self) -> u64 {
2929        *recover_lock(&self.drain_generation)
2930    }
2931
2932    /// Parks on the removal `Condvar` for at most `timeout`, but only while no
2933    /// removal has bumped the generation since `snapshot` — the arm-before-observe
2934    /// barrier. `wait_timeout_while` evaluates the predicate under the lock BEFORE
2935    /// waiting, so a generation already advanced (an exit landed between the
2936    /// observation and here) returns immediately without sleeping; spurious wakes
2937    /// re-wait inside the call and never return early.
2938    fn park_until_removed_or(&self, snapshot: u64, timeout: Duration) {
2939        let outcome = self
2940            .drain_removed
2941            .wait_timeout_while(recover_lock(&self.drain_generation), timeout, |current| {
2942                *current == snapshot
2943            })
2944            .unwrap_or_else(PoisonError::into_inner);
2945        // A non-timed-out return means the predicate went false — a real removal
2946        // bumped the generation and woke this park (as opposed to the deadline).
2947        #[cfg(test)]
2948        if !outcome.1.timed_out() {
2949            self.drain_exit_wakes.fetch_add(1, Ordering::SeqCst);
2950        }
2951        // Release the guard promptly; the caller re-loops unlocked.
2952        drop(outcome);
2953    }
2954}
2955
2956/// One in-flight server-push reply slot, associating the awaiter's reply `sender`
2957/// with the `pid` of the connection that owns the push. The pid lets the close
2958/// path drop exactly that connection's slots; the correlation id (the map key)
2959/// still drives [`ConnectionRuntime::resolve_push`] and
2960/// [`ConnectionRuntime::cancel_push`].
2961#[derive(Debug)]
2962struct PendingPush {
2963    pid: u64,
2964    sender: Sender<Vec<u8>>,
2965    /// Absolute reply deadline for this push, when one was requested via
2966    /// [`ConnectionSupervisor::push_to_connection_with_deadline`]. `None` is the
2967    /// default 0.2.3 shape: the slot has no per-slot deadline and is reclaimed
2968    /// only by reply-consumed or connection-close. `Some` is evaluated host-side
2969    /// and lazily in [`ConnectionRuntime::expire_push_if_due`].
2970    deadline: Option<Instant>,
2971}
2972
2973/// Host-side disposition of a reply slot at an elapsed `receive` quantum.
2974enum PushSlotDisposition {
2975    /// The slot carried an explicit deadline that has passed; this call removed
2976    /// it (releasing its §5 cap admission).
2977    Expired,
2978    /// The slot is present with no deadline, or a deadline still in the future:
2979    /// the elapsed quantum is a benign re-arm and the slot is untouched.
2980    Live,
2981    /// No slot for this correlation id — a concurrent resolve or connection close
2982    /// already removed it.
2983    Absent,
2984}
2985
2986#[derive(Debug)]
2987struct ConnectionRecord {
2988    peer_addr: Option<SocketAddr>,
2989    /// Durable pair allocated and flushed before the process was spawned.
2990    connection_incarnation: Option<ConnectionIncarnation>,
2991    /// Worker registration declared on this connection, set by `set_registration`
2992    /// when a `WorkerRegister` frame is accepted. `Some` marks a connection whose
2993    /// close must fire `on_worker_unregistered`.
2994    registration: Option<WorkerRegistration>,
2995    /// Host-reachable identity for ACK'd deregistration after external death.
2996    readiness: Option<ReadinessRegistration>,
2997    /// Shared edge set before READY enters beamr's process-table pending queue;
2998    /// the executing process reads it at its final probe.
2999    ready_pending: Arc<AtomicBool>,
3000    /// Keeps the fd alive until deregistration has been acknowledged, preventing
3001    /// stale registration delivery to a subsequently reused descriptor number.
3002    fd_guard: Option<TcpStream>,
3003}
3004
3005#[derive(Debug, Clone, Copy)]
3006struct ReadinessRegistration {
3007    token: ReadinessToken,
3008    fd: RawFd,
3009}
3010
3011#[derive(Debug, Clone, PartialEq, Eq)]
3012struct QueuedConnectionControl {
3013    pid: u64,
3014    control: ConnectionControl,
3015}
3016
3017fn lock<'a, T>(mutex: &'a Mutex<T>, context: &str) -> Result<MutexGuard<'a, T>, ServerError> {
3018    mutex.lock().map_err(|error| ServerError::ListenerAccept {
3019        message: format!("{context} unavailable: {error}"),
3020    })
3021}
3022
3023/// Locks `mutex`, RECOVERING a poisoned guard instead of failing (S4). For
3024/// lifecycle-cleanup paths only (reply delivery, expiry, cancellation, the
3025/// close sweep): removal-style operations are sound on a recovered map, and a
3026/// cleanup that silently skipped its removal would strand slots and their §5
3027/// cap admissions forever. Admission paths keep the fail-closed [`lock`].
3028fn recover_lock<T>(mutex: &Mutex<T>) -> MutexGuard<'_, T> {
3029    mutex
3030        .lock()
3031        .unwrap_or_else(std::sync::PoisonError::into_inner)
3032}