Skip to main content

liminal_server/server/connection/
supervisor.rs

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