detached fa28b1c

docs: remove the quic-resilience plan document

commit
fa28b1cd525d48c296034f62f47e30c1c695718c
author
brice · · 2026-10-07 10:56 UTC
parent
12ef17b
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
refs
feat/quic-resilience
1 file · +0 -74
D docs/plans/quic-resilience.md +0 -74
@@ -1,74 +0,0 @@
1-# Plan: mosh-like remote resilience
2-
3-Goal: on a lossy or intermittent link (4G, roaming, sleep), the UI never
4-freezes, typed input is kept and delivered when the link returns, and SSH is
5-used only to authenticate the first QUIC handshake.
6-
7-Reference: [mosh](https://github.com/mobile-shell/mosh)
8-(`src/network/transportsender-impl.h`, `src/frontend/terminaloverlay.cc`).
9-
10-## Diagnosis (before Phases 1 and 2)
11-
12-1. Input path blocks on the network: `sessionAttachmentWorker.send` waits for
13- `SendClient`, which waits for the carriage write. While QUIC stalls, the
14- worker loop stops reading keys, servicing overlays, and painting.
15-2. Every reconnect re-runs SSH: `_broker-mux-quic-proxy` serves one
16- connection with one-time credentials and exits with it.
17-3. No connection migration: one UDP socket per connection, no `AddPath`.
18-4. Slow detection, early give-up: keepalive 15 s / idle 60 s; 5 resume
19- attempts over a few seconds, then back to the picker.
20-5. `LinkState` is only ever `Offline` at teardown; `degraded`/`probing` are
21- documented but never produced.
22-6. Daemon ignores `Input.InputSeq`, so input in flight at a drop is lost or
23- would be duplicated by a replay.
24-
25-## Phase 1 — non-blocking client send (done)
26-
27-- Per-attachment ordered outbox drained by one sender goroutine; the worker
28- loop enqueues and keeps running. Write failure settles the run as before.
29-- Bounded by count and bytes. An input delivery stays undecided until the
30- outbox wrote it, so the pump reads no newer keys meanwhile (backpressure)
31- and a link failure preserves exactly the unwritten keys for the resume.
32-- Lifecycle exits drain the outbox for at most 2 s.
33-
34-## Phase 2 — patient resume (done, except status text)
35-
36-- QUIC keepalive 2 s; idle timeout stays 60 s.
37-- A route that stays down keeps resuming for the 15-minute park window; a
38- session that drops right after attaching still gives up after 5 flaps.
39-- During the resume backoff, Ctrl-C or a lone Esc returns to the picker;
40- other keys are kept (bounded) and replayed into the resumed session.
41-- TODO: status bar "last contact Ns ago" while resuming.
42-
43-## Phase 3 — exactly-once input across resume (protocol bump)
44-
45-- Daemon tracks last applied `InputSeq` per attachment; drops `<=` seqs.
46-- `Welcome` on resume carries the last applied seq; client replays unacked
47- input after it. Bump `protocol.Version`.
48-
49-## Phase 4 — SSH only for first handshake (remote helpers, trust)
50-
51-- Remote QUIC proxy outlives one connection for the park window and issues a
52- resume ticket (bearer secret, bound to cert fingerprint + session, expiry,
53- single active use, memory only).
54-- Reconnect dials QUIC directly with the ticket; SSH only on rejection/expiry.
55-- Picker host health uses the live link + a ticket-based QUIC probe, never
56- SSH.
57-- Needs a security review (ticket theft, replay, expiry) before merge.
58-
59-## Phase 5 — real link states and path migration
60-
61-- Derive `degraded`/`probing` from RTT and last-packet age in the adapter.
62-- On stall or local address change, `AddPath` + probe + switch.
63-
64-## Phase 6 — client-rendered palette on remote sessions
65-
66-- The command palette is rendered by the serving daemon, so each keystroke
67- costs a full round trip on a remote session. Render it client-side like
68- the session picker, fed by the daemon's command catalogue, and send only
69- the chosen command.
70-
71-## Phase 7 — optional predictive local echo
72-
73-- mosh-style overlay with underline-until-confirmed. Breaks the "thin client
74- interprets nothing" rule; needs an explicit design decision.
@@ -1,74 +0,0 @@
1-# Plan: mosh-like remote resilience
2-
3-Goal: on a lossy or intermittent link (4G, roaming, sleep), the UI never
4-freezes, typed input is kept and delivered when the link returns, and SSH is
5-used only to authenticate the first QUIC handshake.
6-
7-Reference: [mosh](https://github.com/mobile-shell/mosh)
8-(`src/network/transportsender-impl.h`, `src/frontend/terminaloverlay.cc`).
9-
10-## Diagnosis (before Phases 1 and 2)
11-
12-1. Input path blocks on the network: `sessionAttachmentWorker.send` waits for
13- `SendClient`, which waits for the carriage write. While QUIC stalls, the
14- worker loop stops reading keys, servicing overlays, and painting.
15-2. Every reconnect re-runs SSH: `_broker-mux-quic-proxy` serves one
16- connection with one-time credentials and exits with it.
17-3. No connection migration: one UDP socket per connection, no `AddPath`.
18-4. Slow detection, early give-up: keepalive 15 s / idle 60 s; 5 resume
19- attempts over a few seconds, then back to the picker.
20-5. `LinkState` is only ever `Offline` at teardown; `degraded`/`probing` are
21- documented but never produced.
22-6. Daemon ignores `Input.InputSeq`, so input in flight at a drop is lost or
23- would be duplicated by a replay.
24-
25-## Phase 1 — non-blocking client send (done)
26-
27-- Per-attachment ordered outbox drained by one sender goroutine; the worker
28- loop enqueues and keeps running. Write failure settles the run as before.
29-- Bounded by count and bytes. An input delivery stays undecided until the
30- outbox wrote it, so the pump reads no newer keys meanwhile (backpressure)
31- and a link failure preserves exactly the unwritten keys for the resume.
32-- Lifecycle exits drain the outbox for at most 2 s.
33-
34-## Phase 2 — patient resume (done, except status text)
35-
36-- QUIC keepalive 2 s; idle timeout stays 60 s.
37-- A route that stays down keeps resuming for the 15-minute park window; a
38- session that drops right after attaching still gives up after 5 flaps.
39-- During the resume backoff, Ctrl-C or a lone Esc returns to the picker;
40- other keys are kept (bounded) and replayed into the resumed session.
41-- TODO: status bar "last contact Ns ago" while resuming.
42-
43-## Phase 3 — exactly-once input across resume (protocol bump)
44-
45-- Daemon tracks last applied `InputSeq` per attachment; drops `<=` seqs.
46-- `Welcome` on resume carries the last applied seq; client replays unacked
47- input after it. Bump `protocol.Version`.
48-
49-## Phase 4 — SSH only for first handshake (remote helpers, trust)
50-
51-- Remote QUIC proxy outlives one connection for the park window and issues a
52- resume ticket (bearer secret, bound to cert fingerprint + session, expiry,
53- single active use, memory only).
54-- Reconnect dials QUIC directly with the ticket; SSH only on rejection/expiry.
55-- Picker host health uses the live link + a ticket-based QUIC probe, never
56- SSH.
57-- Needs a security review (ticket theft, replay, expiry) before merge.
58-
59-## Phase 5 — real link states and path migration
60-
61-- Derive `degraded`/`probing` from RTT and last-packet age in the adapter.
62-- On stall or local address change, `AddPath` + probe + switch.
63-
64-## Phase 6 — client-rendered palette on remote sessions
65-
66-- The command palette is rendered by the serving daemon, so each keystroke
67- costs a full round trip on a remote session. Render it client-side like
68- the session picker, fed by the daemon's command catalogue, and send only
69- the chosen command.
70-
71-## Phase 7 — optional predictive local echo
72-
73-- mosh-style overlay with underline-until-confirmed. Breaks the "thin client
74- interprets nothing" rule; needs an explicit design decision.

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 12

Tags 11

↑↓ moveenter openesc close