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