# Upgrade Guide — vNEXT

<!-- assembled-by: assemble-next-md -->
<!-- bump: patch -->

## What Changed

Scopes the emergency "fix command" gate to the **Agent Attention topic** so it can no longer swallow ordinary messages in other topics. The gate in `wireTelegramRouting` (`src/commands/server.ts`) used to intercept any message starting with `restart`, `fix `, or `clean ` in **every** topic, hand it to `handleFixCommand`, and `return` — but `handleFixCommand` only does anything in the Agent Attention topic and returns `false` everywhere else. So in a normal topic the message was bounced back with *"I didn't recognize that command. Available fix commands: …"* (a list that even advertised "restart sessions" as valid) **and never routed to the session**. A user typing "restart sessions" to revive a stuck session in that session's own topic was hit by exactly this: the gate ate the message. The decision is now a pure, unit-tested helper `shouldInterceptFixCommand(text, topicId, attentionTopicId)` that returns true only inside the attention topic; `wireTelegramRouting` resolves the attention topic via a late-bound `getAttentionTopicId` and both call sites pass it. Outside the attention topic the message falls through to normal session routing — including plain phrases like "restart the build" or "fix the login page" that were silently eaten before.

## What to Tell Your User

If you ever messaged a session something starting with "restart", "fix", or "clean" — including trying to revive a stuck session by typing "restart sessions" — and got a confusing *"I didn't recognize that command"* reply (with a list that literally showed the command you typed), that message was being intercepted and never reached the session. That's fixed: those messages now go through to the session like any other. The "fix command" shortcuts (restart, fix auth, clean processes, …) still work — they just only apply in the Agent Attention topic, which is where I post the notifications you tap to resolve.

## Summary of New Capabilities

| Capability | How to Use |
|-----------|-----------|
| Fix-command shortcuts scoped to the Agent Attention topic | unchanged — tap/reply in the Attention topic; everywhere else your message reaches the session |
| Ordinary "restart/fix/clean …" messages reach the session | just send them normally in any session topic |

## Evidence

Reproduction (live, 2026-06-09, topic 21624 "initiatives and maturation check-ins"): the user typed `restart sessions` to unstick a session and got *"I didn't recognize that command. Available fix commands: … • restart sessions — Restart stuck sessions"* — the gate swallowed the message (no `restart sessions` ever appeared in the session's tmux pane) while listing the exact command as valid. Root cause traced in code: the gate's `isFixCommand` verb test ran in all topics and `return`ed after `handleFixCommand` (which guards on `topicId === agent-attention-topic` and returns `false` otherwise).

After the fix: new unit suite `tests/unit/fix-command-routing.test.ts` (17 tests) pins both sides of the boundary — in the attention topic every fix verb intercepts (and verb-lookalikes "fixture"/"cleanup" do not), while in a non-attention topic "restart sessions", "restart the build", "fix the login page", "clean up this function" all return `false` (fall through to the session); a null/undefined attention topic never intercepts. `tsc --noEmit` clean; the full set of unit tests importing `commands/server` (38 files, 364 tests) green.

## The problem

You sent a session a message to wake it up — "restart sessions" — and instead
of doing anything, I replied *"I didn't recognize that command"* and showed you
a list of commands that literally included "restart sessions." That's
maddening: I rejected the exact thing I told you to type. Worse, your message
never actually reached the session at all.

Here's what was really happening under the hood.

I have a set of emergency "fix command" shortcuts — short things you can type
like "restart", "fix auth", "clean processes" — that I handle directly without
spinning up a whole AI session. They exist for one specific place: the **Agent
Attention topic**, where I post little "something needs fixing, tap to resolve"
notifications. In that topic, typing "restart" should just work.

The bug: the code that *catches* those shortcut words was running in **every
topic**, not just the Attention topic. So any message you sent that happened to
start with "restart", "fix ", or "clean " got grabbed by the shortcut-catcher
first. The catcher then asked the real handler to run it — but the real handler
checks "am I in the Attention topic?" and, if not, quietly says "not mine" and
does nothing. At that point the catcher gave up with the confusing "I didn't
recognize that command" message **and threw your message away** — it never got
passed along to the session you were actually talking to.

So two everyday things were broken:
1. Trying to revive a stuck session by typing "restart sessions" in that
   session's own topic — eaten, with a misleading reply.
2. Just talking normally — "restart the build", "fix the login page", "clean up
   this function" — anything that started with one of those words got silently
   swallowed instead of reaching the session.

## What already exists

- The fix-command shortcuts ("restart", "fix auth", etc.) and the handler that
  runs them. These were already correctly limited to the Attention topic *on
  the execution side* — the handler refuses to act anywhere else.
- The normal path that routes a message to its session. That path was always
  there; the shortcut-catcher was just jumping in front of it and stopping it.

## What's new

One small, surgical change: the shortcut-catcher now checks **which topic it's
in before grabbing the message.** It only intercepts inside the Agent Attention
topic. Everywhere else, the message flows straight through to the session like
any other message.

The check is a tiny pure function, `shouldInterceptFixCommand(text, topicId,
attentionTopicId)`, that returns "yes, intercept" only when the message is in
the Attention topic AND looks like a fix command. It's covered by 17 unit tests
that nail down both sides: in the Attention topic the shortcuts still fire (and
lookalike words like "fixture" or "cleanup" correctly don't); in any other
topic, "restart sessions" and friends fall through to the session.

## The safeguards in plain terms

- **Nothing is removed.** The fix-command shortcuts still work exactly as
  before — they were always Attention-topic-only on the execution side; now the
  catching side agrees. So no real capability is lost.
- **Fail-safe default.** If I don't yet know which topic is the Attention topic
  (e.g. very early at startup), the catcher simply doesn't intercept — messages
  go to the session. That's the safe direction: route, don't swallow.
- **It only makes the gate *less* aggressive.** This change can only let more
  messages through to sessions; it can never block a message that wasn't already
  being blocked. That's why the risk is low.

## What you need to decide

Nothing complicated. This is a bug fix that makes your messages reliably reach
your sessions. The only judgment call is whether to ship it as a normal patch
(yes) — there's no new setting to configure and no behavior you have to opt
into. After it deploys, "restart sessions" (and ordinary chat starting with
restart/fix/clean) will reach the session instead of being eaten.
