feat(hybrid-gateway): integrate muse-cli with Cloudflare netns isolation, symmetric sidechat routing, and 646-pip sync unblock

This commit is contained in:
operator
2026-10-04 22:54:01 +00:00
parent 3d5fbe5aeb
commit 1a271b1bbd
60 changed files with 5068 additions and 55 deletions
+182
View File
@@ -0,0 +1,182 @@
# Thread Bookkeeping with Pin & Archive
**Status:** runbook (2026-10-04)
**Applies to:** muse.ai side-chat threads used by the fleet DM system
## Why bookkeeping matters
Side-chat threads are addressed by UUID. UUIDs go stale (deletion,
account-side cleanup, platform reissue — observed 2026-10-04 when
`heartbeat-opm` changed UUIDs in a single day and when the hardcoded
`1e75a740` "646 tasks" UUID died ~90 minutes after being committed).
Stale UUIDs cause silent misdelivery: the SPA redirects to an arbitrary
valid thread instead of 404ing, and the old placement-blind verify
claimed success.
Duplicates compound the problem. On 2026-10-04 the user observed two
`BRAIN-INIT` messages, indicating two brain threads where one was
expected. Fuzzy sidebar name search then matches the wrong thread.
Pin and archive are the native muse.ai mechanisms for managing this.
They are gateway API methods (`/api/session/pin`,
`/api/session/unpin`, `/api/session/archive`,
`/api/session/unarchive`, `/api/session/delete`,
`/api/session/rename`), **not** CDP browser actions. Our
`muse-chat-api.py` (CDP-based) does not implement them.
## Tooling: muse-cli
The supported path is the third-party `muse-cli` tool
(`nikships/muse-cli`), which speaks the gateway protocol (Noise XX +
protobuf) directly. It is **not** installed on bl, the VM, or the
operator container as of 2026-10-04.
### Install (on bl)
```bash
# Node.js required
npm install -g muse-cli # or per-repo install per muse-cli README
```
### Auth
muse-cli needs a `hatch_sess` cookie from a logged-in browser session.
Obtain it from the operator's own browser profile — never from another
agent's session. Treat the cookie as a credential: transient use, never
logged, never in chat.
### Commands (per muse-cli PROTOCOL.md)
```bash
muse-cli pin <session_id> # pin a thread
muse-cli unpin <session_id> # unpin a thread
muse-cli session-archive <session_id> # archive a thread
muse-cli session-unarchive <session_id> # restore an archived thread
muse-cli session-rename <session_id> <title> # rename a thread
muse-cli session-delete <session_id> # delete a thread (destructive)
```
`<session_id>` is the thread UUID (the hex string in
`https://muse.ai/thread/<uuid>`).
## When to pin a thread
Pin threads that are **critical infrastructure** or **frequently
accessed during triage**:
| Thread | Alias / reuse_key | Why pinned |
|---|---|---|
| main-loop brain | `main-loop brain` | Fleet coordination point |
| 646 tasks | `646 tasks` | 646's primary work thread |
| heartbeat | `heartbeat-opm` | Pipeline health signal |
| 646-pip-coord | `646-pip-coord` | Cross-operator coordination |
| muse tasks | `muse tasks` | muse's primary work thread |
Pinning keeps these at the top of the sidebar, which:
- Prevents fuzzy-name-search confusion (searching "646" is less likely
to match the wrong thread when the right one is pinned and visible).
- Makes important threads easy to find during incident triage.
- Does **not** change the UUID — pin is purely a display/ordering
operation. `job-sidechats.json` mappings are unaffected.
## When to archive a thread
Archive threads that are **stale, duplicate, test, or dead**:
- **Duplicates:** the double `BRAIN-INIT` incident — archive the
surplus thread, keep the registered one.
- **Stale UUIDs:** threads whose UUID no longer resolves (e.g. the dead
`1e75a740` if it still exists on 646's account).
- **Test threads:** `test-auto-prov` (`b96dd020`), `pipe-7d2896`,
`pipe-1b4579`, and other autoprovision experiments.
- **Superseded threads:** old threads replaced by a renamed or
re-provisioned canonical thread.
Prefer **archive** over **delete**: archiving is reversible
(`session-unarchive`), deleting is not. Delete only when certain the
thread holds nothing worth recovering.
## Listing pinned vs archived threads
muse-cli's session listing distinguishes state. Our CDP-based
`sidechat list` scrapes visible sidebar text only and **cannot**
distinguish pinned/archived/deleted threads — another reason to use
muse-cli for bookkeeping operations.
After any pin/archive operation, verify with the list command and
confirm the expected state before updating mappings.
## Integration with job-sidechats.json
`job-sidechats.json` (on bl) is the dynamic UUID registry:
`{ "<alias>": { "thread_uuid": ..., "agent": ..., ... } }`.
Rules:
1. **Pin changes nothing** in `job-sidechats.json`. The UUID is the
same; only sidebar ordering changes.
2. **Archive the registered thread → update the mapping.** Either
remove the entry (so the next send autoprovision a fresh thread) or
point it at the surviving canonical thread's UUID.
3. **Archive a non-registered duplicate → no mapping change needed**,
but note it in the commit message for traceability.
4. **Never hardcode UUIDs** in `SIDCHAT_ALIASES` or elsewhere (lesson
from 2026-10-04). Use name-based autoprovision with the dynamic
registry. A hardcoded UUID is a ticking time bomb: it *will* go
stale, and there is no alert when it does.
## Case study: duplicate brain INIT (2026-10-04)
**What happened.** The user observed two `BRAIN-INIT` messages in the
UI, indicating two brain threads where the design calls for one. The
brain thread (`5f18476d-8994-49e7-a9e0-4838732363fe`, created 19:40 UTC
on opm's account with placement confirmed) was never registered in
`job-sidechats.json`, so 646 reported it as "still pending" and
"unwired" while a second INIT appeared.
**Contributing factors.**
- The brain thread was created but the registration step was skipped.
- Without registration, later code paths could not find the canonical
thread and created (or appeared to create) another.
- No pin/archive pass had ever been run, so there was no canonical
"this is the one true brain" signal in the sidebar.
**How archive fixes it.**
1. Identify both thread UUIDs (from dm-log `alias_resolved` /
`nav_ok` records or muse-cli session list).
2. Confirm which UUID is registered in `job-sidechats.json` under
`"main-loop brain"` — that one is canonical.
3. `muse-cli session-archive <duplicate_uuid>` on the surplus thread.
4. Pin the canonical brain thread so it stays visible.
5. Commit the `job-sidechats.json` state with a note referencing the
archived duplicate.
**Prevention.** After creating any canonical thread: register it in
`job-sidechats.json` immediately, pin it, and note the UUID in the
commit message. Run a periodic (monthly) archive pass over test and
stale threads.
## Quick reference
```bash
# one-time: install + auth (hatch_sess cookie, transient)
# pin the critical set (opm account, adjust per agent)
muse-cli pin 5f18476d-8994-49e7-a9e0-4838732363fe # main-loop brain
# archive a duplicate / stale thread
muse-cli session-archive <duplicate_uuid>
# verify, then update job-sidechats.json on bl if the archived
# thread was the registered one (re-point or remove the entry)
```
## Open items (2026-10-04)
- muse-cli is not yet installed anywhere in the fleet.
- `hatch_sess` cookie handling needs a defined transient-use procedure.
- No scheduled archive pass exists yet; propose monthly.
- CDP-based `sidechat list` cannot see archived state — bookkeeping
must go through muse-cli, not dm.py.