mailbox notify: record that the terminal path is unverified through tmux
Measured on tor-ms22: the layering here is kitty -> tmux (on the host) -> docker exec -> pi (in the container), with two clients attached to one tmux session. Test OSC sequences written straight to pi's tty produced no notification on the remote client; the local client is still unobserved. Most likely tmux is dropping OSC types it does not implement — reaching the outer terminal needs tmux's DCS passthrough (ESC P tmux; ... ESC \, inner ESC doubled) plus allow-passthrough on, which is not the default and is not implemented here. The point worth keeping is structural, not incidental: the container can see NEITHER layer. KITTY_WINDOW_ID is absent because docker exec does not forward it, and TMUX is absent because tmux runs one level further out on the host. So a containerised client cannot detect the terminal it is speaking to or the multiplexer it must speak through, and autodetection is not merely unreliable here — it is blind. Explicit configuration is the only route, which is why the previous commit added forced kitty/osc777 modes. No behaviour or defaults changed: in-TUI notify remains the default and the terminal path stays opt-in. Also flagged the unsettled routing question — a pane's output reaches every attached client, so a work laptop and a home machine would both ping from one arriving ask.
This commit is contained in:
@@ -326,6 +326,12 @@ The consequence is a **UX gap, not a defect**: from the outside, an inbound ask
|
|||||||
1. **A delivery note in the message itself** — it says this is a queued message, that nothing woke the agent, and that any message starts the turn that will handle it. Costs nothing, changes no behaviour, and converts "why is it ignoring me?" into "right, I nudge it."
|
1. **A delivery note in the message itself** — it says this is a queued message, that nothing woke the agent, and that any message starts the turn that will handle it. Costs nothing, changes no behaviour, and converts "why is it ignoring me?" into "right, I nudge it."
|
||||||
2. **A notification at poll time**, because the note only reaches someone already looking, and the case that actually loses an ask is nobody looking. `MEMPALACE_MAILBOX_NOTIFY` unset → in-TUI `ctx.ui.notify` (the surface `session_start` already uses); `=desktop` → additionally a terminal-native notification (Kitty `OSC 99`, else `OSC 777`), which is how a ping escapes a container with no `notify-send`, DBus or host access — the escape sequence is interpreted by the terminal emulator on the human's machine; `=0` → silent. Title and body are stripped of `;` and control bytes so a payload cannot forge an OSC field or terminate the sequence early. It fires only when something is due, because a ping on an empty poll trains its reader to ignore it.
|
2. **A notification at poll time**, because the note only reaches someone already looking, and the case that actually loses an ask is nobody looking. `MEMPALACE_MAILBOX_NOTIFY` unset → in-TUI `ctx.ui.notify` (the surface `session_start` already uses); `=desktop` → additionally a terminal-native notification (Kitty `OSC 99`, else `OSC 777`), which is how a ping escapes a container with no `notify-send`, DBus or host access — the escape sequence is interpreted by the terminal emulator on the human's machine; `=0` → silent. Title and body are stripped of `;` and control bytes so a payload cannot forge an OSC field or terminate the sequence early. It fires only when something is due, because a ping on an empty poll trains its reader to ignore it.
|
||||||
|
|
||||||
|
**⚠️ Unverified through a multiplexer — measured 2026-08-26, tor-ms22.** The terminal-native path is written and syntax-checked but has **not** been observed to fire. On this client the layering is `kitty → tmux (on the host) → docker exec → pi (in the container)`, with two clients attached to the same tmux session (one local, one remote over SSH). Test sequences written directly to pi's tty produced **no notification on the remote client**; the local client is unobserved so far. The likely mechanism is that **tmux drops OSC sequences it does not itself implement** — reaching the outer terminal requires wrapping them in tmux's DCS passthrough (`ESC P tmux; … ESC \`, with inner `ESC` bytes doubled) *and* `allow-passthrough on`, which is not the default.
|
||||||
|
|
||||||
|
This compounds §7.11's detection problem rather than repeating it: **the container cannot see either layer**. `KITTY_WINDOW_ID` is absent because `docker exec` does not forward it, and `TMUX` is absent because tmux is running one level further out, on the host — so the client cannot detect the terminal it is speaking to *or* the multiplexer it must speak through. Explicit configuration is the only reliable route; autodetection is structurally blind here.
|
||||||
|
|
||||||
|
Open, and deliberately not settled by guessing: whether the local client shows it (pending); whether to add DCS-wrapping modes; and with two clients attached, **which** client should be notified — a pane's output reaches every attached client, so a work laptop and a home machine would both ping.
|
||||||
|
|
||||||
Still deliberately **not** done: `MEMPALACE_MAILBOX_TRIGGER=1` (opt-in, default off) to start a turn on arrival. Worth revisiting once notification is proven in daily use — but a machine that auto-turns on inbound events writes to a shared log with nobody watching, and §7.1 (no idempotency guard) is the reason to be slow about it.
|
Still deliberately **not** done: `MEMPALACE_MAILBOX_TRIGGER=1` (opt-in, default off) to start a turn on arrival. Worth revisiting once notification is proven in daily use — but a machine that auto-turns on inbound events writes to a shared log with nobody watching, and §7.1 (no idempotency guard) is the reason to be slow about it.
|
||||||
|
|
||||||
### 7.12 The mailbox is an obligation channel, so a report addressed to you is never delivered
|
### 7.12 The mailbox is an obligation channel, so a report addressed to you is never delivered
|
||||||
|
|||||||
@@ -343,6 +343,15 @@ which touches the no-`triggerTurn` decision:
|
|||||||
not because it is unreliable. Title and body are stripped of `;` and control
|
not because it is unreliable. Title and body are stripped of `;` and control
|
||||||
bytes, so a payload can neither forge an OSC field nor end the sequence early.
|
bytes, so a payload can neither forge an OSC field nor end the sequence early.
|
||||||
|
|
||||||
|
**⚠️ Not yet observed firing through tmux (2026-08-26).** If pi runs inside a
|
||||||
|
multiplexer — e.g. `kitty → tmux on the host → docker exec → pi` — tmux drops
|
||||||
|
OSC sequences it does not implement, so the ping can vanish silently between
|
||||||
|
the container and the human. Reaching the outer terminal needs tmux's DCS
|
||||||
|
passthrough plus `allow-passthrough on`, which is not implemented here yet.
|
||||||
|
Note the client can detect *neither* layer: `KITTY_WINDOW_ID` is not forwarded
|
||||||
|
by `docker exec`, and `TMUX` is unset because tmux runs one level further out.
|
||||||
|
Verify with a hand-written sequence in your own stack before trusting it.
|
||||||
|
|
||||||
It fires **only when something is due** — the same condition as the delivery
|
It fires **only when something is due** — the same condition as the delivery
|
||||||
itself. A ping on an empty poll would train its reader to ignore it, which is
|
itself. A ping on an empty poll would train its reader to ignore it, which is
|
||||||
the failure this whole feature exists to reverse.
|
the failure this whole feature exists to reverse.
|
||||||
|
|||||||
Reference in New Issue
Block a user