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