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