# rmux — Known Issues

## Fixed

- ~~**C1. Mutex deadlock**~~ — PTY reader/writer/screen теперь в per-session `Arc<Mutex<>>`, глобальный менеджер лочится только для lookup
- ~~**C2. decode_frame без лимита → OOM**~~ — `MAX_FRAME_SIZE` (16 MiB) в `protocol/codec.rs`, фреймы больше лимита отклоняются с ProtocolError
- ~~**C3. Screen render under global lock**~~ — рендер теперь под per-session lock (микросекунды)
- ~~**C4. encode truncation >4GB**~~ — `u32::try_from()` вместо `as u32` кастинга, возвращает ProtocolError::EncodeTooLarge
- ~~**I2. Stdin task hangs**~~ — `tokio::select!` между stdin и socket задачами
- ~~**I3. resize(0,0) underflow**~~ — `sanitize_dimensions()` в `screen/grid.rs` кламает к минимум 1×1
- ~~**I4. Kill responds with Connected**~~ — добавлен `ServerMsg::SessionKilled`
- ~~**I5. Hardcoded 80x24**~~ — `ClientMsg::Connect` теперь включает `cols`/`rows`
- ~~**I6. SGR accumulation**~~ — структурированный `Style` (bold, dim, italic, fg, bg, RGB/256) с корректным накоплением атрибутов
- ~~**I7. render_line SGR leak**~~ — трекинг текущего стиля + reset при смене
- ~~**S5. No protocol message size limit**~~ — `MAX_FRAME_SIZE` + `u32::try_from` в codec.rs
- ~~**S6. Attach hardcodes history=10000**~~ — `--history` флаг добавлен в команду Attach
- ~~**S7. Alt screen не восстанавливает main buffer**~~ — сохранение/восстановление grid и cursor при входе/выходе из alt screen

### Рефакторинг (2026-03-01)

- ~~**R1. eprintln! вместо логирования**~~ — заменены на `tracing::{info,warn,debug}`. Клиентские user-facing сообщения оставлены как `eprintln!`
- ~~**R2. .lock().unwrap() на мьютексах**~~ — заменены на `.lock().map_err(...)` с логированием
- ~~**R3. Смешение ответственностей**~~ — `screen.rs` разделён на 6 модулей; `server.rs` на 4; `client.rs` на 3; `protocol.rs` на 3
- ~~**R4. Socket dir permissions**~~ — `socket_dir()` устанавливает `0o700` атомарно через `DirBuilder`
- ~~**R5. Dead sessions не чистятся**~~ — периодическая задача каждые 30 секунд, `SessionManager::cleanup_dead_sessions()`
- ~~**R6. Detach key дропает байты**~~ — байты до `0x1c` отправляются серверу перед Detach
- ~~**R7. render_line пробел для пустых строк**~~ — `render_line()` возвращает `" "` для полностью пустых строк
- ~~**R8. Дублированный read-loop**~~ — `read_one_message<T>()` helper устраняет дублирование
- ~~**R9. Неиспользуемый error.rs**~~ — `RmuxError`/`SessionError` удалены, `ProtocolError` перенесён в `protocol/codec.rs`
- ~~**R10. Неиспользуемые методы**~~ — убраны `Screen::{cols,rows,title}`, `Grid::{clear_region,set_cell}`, `SessionManager::get_mut`

### Баг-фиксы (2026-03-01, review)

- ~~**B1. No resize on reattach**~~ (critical) — pty и screen ресайзятся при реаттаче если размер терминала изменился
- ~~**B2. Orphaned tasks in select!**~~ — `client_to_pty.abort()` / `drop(pty_to_client)` вместо одностороннего select
- ~~**B3. Drain channel before SessionEnded**~~ — оставшиеся данные из PTY обрабатываются перед отправкой SessionEnded
- ~~**B4. Session creation error not sent to client**~~ — ошибка отправляется клиенту до `into_split()`
- ~~**B5. Session PID shows server PID**~~ — `child_pid()` через `portable_pty::Child::process_id()`
- ~~**B6. DECSCUSR reset**~~ — `\x1b[ q` → `\x1b[0 q`
- ~~**B7. Raw mode before Connected**~~ — ручной read-loop с сохранением leftover байт
- ~~**B8. No timeout on initial message**~~ — 30s таймаут на первый ClientMsg
- ~~**B9. TOCTOU в socket_dir**~~ — атомарный `DirBuilder::new().mode(0o700).create()` + проверка владельца
- ~~**B10. PTY reader contention on reattach**~~ — `try_clone_reader()` per connection вместо shared reader

### Rendering fixes (2026-03-02)

- ~~**F1. DL/IL outside scroll region**~~ — `'M'`/`'L'` теперь проверяют `y >= scroll_top` перед операцией
- ~~**F2. Colon RGB color space ID**~~ — `parse_extended_color` корректно парсит `38:2:CS:R:G:B` (6 элементов) и `38:2:R:G:B` (5 элементов)
- ~~**F3. Underline variants (SGR 4:N, 21)**~~ — `underline: u8` вместо `bool` (0=none, 1=single, 2=double, 3=curly, 4=dotted, 5=dashed). SGR 21 = double underline
- ~~**F4. CSI 3J clear scrollback**~~ — `scrollback.clear()` + `pending_scrollback.clear()` при `J 3`
- ~~**F5. DECSC/DECRC full state**~~ — `SavedCursor` struct сохраняет position + style + charsets + autowrap. ESC 7/8, CSI s/u, mode 1048 все используют полное сохранение
- ~~**F6. Alt screen modes save/restore**~~ — `TerminalModes` сохраняются при входе в alt screen (1049/1047/47) и восстанавливаются при выходе
- ~~**F7. RIS clears saved cursor state**~~ — ESC c очищает `saved_cursor_state` (полный `SavedCursor`)

### Critical bugfixes (2026-03-02)

- ~~**Critical #1. Terminal not restored on panic/signal**~~ — panic hook + SIGINT/SIGTERM handlers вызывают `emergency_restore()`. Глобальный `ORIGINAL_TERMIOS` через `OnceLock<StdMutex<>>`.
- ~~**Critical #2. Unbounded pending_scrollback**~~ — `pending_scrollback` ограничен `scrollback_limit`. При переполнении старые строки удаляются (полная история доступна через `get_history()` при реаттаче).
- ~~**Critical #3. Bincode OOM vulnerability**~~ — `bincode_config()` с `Options::with_limit(MAX_FRAME_SIZE)` заменяет все `bincode::serialize/deserialize`. Fixint encoding для consistency.
- ~~**Critical #4. No graceful server shutdown**~~ — SIGTERM/SIGINT handlers + `SocketGuard` RAII для cleanup сокет-файла. `accept()` loop продолжает при transient errors. SIGHUP игнорируется. Dead sessions дропаются вне lock.
- ~~**Critical #5. Blocking stdin thread leak**~~ — watch channel для cancellation stdin task + `shutdown_timeout(100ms)` на runtime.

### Important bugfixes (2026-03-02)

- ~~**Important #1. Quadratic buffer drain**~~ — cursor-based frame processing, single `drain()` per read cycle.
- ~~**Important #2. History exceeds MAX_FRAME_SIZE**~~ — History сообщения чанкуются при отправке.
- ~~**Important #7. Alt screen cursor per mode**~~ — только mode 1049 save/restore cursor, modes 47/1047 — нет (per xterm spec).
- ~~**Important #8. DL/IL/SU/SD unclamped loops**~~ — count ограничен размером scroll region.
- ~~**Important #9. render_line efficiency**~~ — `to_sgr_with_reset()` вместо separate reset + set.
- ~~**Important #18. socket_dir test XDG_RUNTIME_DIR**~~ — тест корректно обрабатывает оба пути.
- ~~**Important #19. CLI semantics enforcement**~~ — `ConnectMode` enum: New → CreateOnly, Attach → AttachOnly, Open → CreateOrAttach.
- ~~**Important #20. PID-based name collisions**~~ — timestamp-based `generate_name()` вместо PID.

---

## Open

*Нет открытых issues.*

---

## Minor / Future

- **S4.** Hot-path allocations — `current_style.clone()` on every `print()`
