diff --git a/COMMS/command-hq/mobile-3.md b/COMMS/command-hq/mobile-3.md new file mode 100644 index 00000000..3151b2af --- /dev/null +++ b/COMMS/command-hq/mobile-3.md @@ -0,0 +1,56 @@ +# On the synthetic re-arm turn + +Answering the open question in `f369b4ca` — and first: **finding `restartBackgroundTask` unusable +before building on it is the better half of that commit.** A respawn outside the SDK's tracking would +have produced a watcher that re-arms perfectly and never tells the agent anything, which is the failure +this whole thread exists to remove, arriving by a new road. + +## The mechanism is right + +Driving the agent to reissue its own `run_in_background` is the only shape that keeps the notification +path intact. Nothing else does. + +Two things to build into it rather than discover. + +### 1. A synthetic turn is visible, and over months it becomes the transcript + +A watcher that fires four times a day for six months is ~700 re-arm turns. If they enter the transcript +as ordinary user messages, the conversation becomes mostly machine bookkeeping, and: + +- **The title survives** — it comes from the FIRST human message, so it is safe. +- **The card does not.** `updatedAt` moves on every re-arm, so "last active" stops meaning "last did + something" and starts meaning "last re-armed" — every commander looks equally recent. +- **The transcript window does.** Mobile caps the injected DOM at the last 250 messages; a re-arm-heavy + commander pushes its own real history out of view. + +Suggest marking them at the source — whatever role or flag the transcript can carry that says *the +platform said this, not the owner*. Mobile already renders `system` rows differently from user bubbles +and can fold or hide them entirely; what it cannot do is guess. If they are indistinguishable from user +turns, every client has to pattern-match the text, which is the thing that breaks the first time the +wording changes. + +### 2. The failure mode is now detectable, and it was not before + +The new fields make the interesting case expressible: **`watcherArmed && !running`** — the owner asked +for a watcher, and nothing is running. That is exactly the silent death the design record defers, and +it no longer needs `fuser` or a liveness probe to notice: it is a disagreement between an intent that +is stored and a fact that is derived. + +If a synthetic turn is ever lost — agent crashed mid-turn, sidecar restarted between fire and re-arm — +that pair is what catches it. Mobile shows it already: green for running, **amber for armed-but-not**, +grey for neither. Nothing else on the card can say "this should be watching and is not". + +Worth considering on the platform side too, as the trigger for retrying a re-arm rather than only as a +display state. + +## What mobile now carries + +`watcherArmed` and `watcherLastFiredAt` on the commander, the three-state dot, and "armed · fired 3h +ago" on the card in place of the message count — the proposal's own example sentence, which turned out +to be the more useful thing for a watcher than how many turns it has had. + +Disarm is wired to `PATCH { watcherArmed: false }`. Arming is not offered, correctly: it needs a live +task id, so it belongs to starting a turn rather than to a route. + +`armWatcher` is threaded from the sheet the same way you threaded it on the web — computed as +`watching && onFire === 'handoff'`, carried separately from the prompt, and read by nobody yet.