You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A macOS laptop currently exhibits one resilience gap across three layers:
after a long sleep, Fabric may require a manual fabric restart before peer traffic works again;
fabric shell <peer> drops on a transient network/path loss;
if the shell client is terminated on an exceptional/signal path, the caller terminal can remain in raw mode (ordinary keys then emit control behavior).
Treat these as one end-to-end session-lifecycle direction: the endpoint must recover, an interactive session must survive the recovery window, and the local terminal must always be restored when the client finally exits.
Current code mapping
macOS startup issue macOS daemon startup can hang indefinitely in CoreWLAN before control socket bind #20 bounded the optional CoreWLAN probe before endpoint bind, but post-start wake recovery still awaits Endpoint::network_change() without a deadline. The network-change health path also accepts local Endpoint::online() as recovery before proving a trusted peer is reachable.
Generic Fabric dials already implement offset/ACK replay, bounded reconnect backoff, a detached server-session TTL, and endpoint-generation retry. Built-in shell explicitly bypasses that layer and uses a raw one-shot fabric/shell/0 stream, so one iroh stream loss tears down the PTY.
RawModeGuard relies on ordinary Rust Drop plus crossterm::disable_raw_mode(). A process-directed signal can bypass Drop, and generic cooked-mode restoration does not preserve the exact pre-shell termios state.
Required behavior
Sleep/wake and daemon path
A wake/network transition never leaves the recovery loop stuck indefinitely.
Recovery proves usable peer reachability, not only local endpoint relay-online state.
Repeated failures escalate through bounded network-change/reconnect attempts to the existing rate-limited endpoint recycle path, without a manual daemon restart.
Existing service identity, peer trust, sync state, and endpoint identity remain intact.
Shell continuity
A shell PTY is bound to a logical resumable session, not to one transient iroh attach.
Transient path loss keeps the local shell command alive, visibly reports reconnecting/resumed state on stderr, buffers/replays unacknowledged bytes exactly once, and preserves the same remote PTY/process.
Reconnect uses bounded exponential backoff and a finite server detached-session lifetime. If the session expired or cannot resume, the client exits clearly rather than silently creating a second shell.
Trust and default-deny allow_shell behavior remain unchanged.
Caller terminal safety
Capture the exact pre-shell terminal state before enabling raw mode.
Restore it on normal remote exit, protocol/transport error, panic unwind, and handled termination/hangup/quit signals; suspend/continue semantics must not strand raw mode.
Signal handling restores the terminal and then preserves expected process exit/signal behavior.
Acceptance evidence
Deterministic two-node real-iroh shell test: run a uniquely identified remote PTY, force a transport detach/endpoint recycle, send input during the outage, resume, and prove the same PTY/process plus exactly-once ordered output.
Expired-session test: detach beyond the configured TTL and prove a visible terminal-safe failure with no replacement PTY.
Unix pseudoterminal subprocess tests: compare termios before/after normal exit, connection error, SIGTERM/SIGHUP/SIGQUIT, and suspend/continue where supported.
Bounded recovery tests with injected hung/failed network-change and peer probes, plus a documented macOS sleep/wake acceptance recipe (pmset sleepnow or lid sleep, wake on a changed/renewed path, no manual restart).
README architecture/runbook and CHANGELOG describe the unified semantics and limits.
Non-goals
Do not persist a shell across a Fabric daemon process restart.
Do not add tmux-like durable history or silently launch a replacement shell after resume expiry.
Do not weaken the peer allow-list or daemon-global shell opt-in.
Production report
A macOS laptop currently exhibits one resilience gap across three layers:
fabric restartbefore peer traffic works again;fabric shell <peer>drops on a transient network/path loss;Treat these as one end-to-end session-lifecycle direction: the endpoint must recover, an interactive session must survive the recovery window, and the local terminal must always be restored when the client finally exits.
Current code mapping
Endpoint::network_change()without a deadline. The network-change health path also accepts localEndpoint::online()as recovery before proving a trusted peer is reachable.fabric/shell/0stream, so one iroh stream loss tears down the PTY.RawModeGuardrelies on ordinary RustDroppluscrossterm::disable_raw_mode(). A process-directed signal can bypassDrop, and generic cooked-mode restoration does not preserve the exact pre-shell termios state.Required behavior
Sleep/wake and daemon path
Shell continuity
allow_shellbehavior remain unchanged.Caller terminal safety
Acceptance evidence
pmset sleepnowor lid sleep, wake on a changed/renewed path, no manual restart).Non-goals