feat(hybrid-gateway): integrate muse-cli with Cloudflare netns isolation, symmetric sidechat routing, and 646-pip sync unblock
This commit is contained in:
@@ -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.
|
||||
Reference in New Issue
Block a user