Commit Graph

247 Commits

Author SHA1 Message Date
operator-main f5d92467c4 bin/muse-threads.py: JSON-contract thread bookkeeping over muse-cli-node
Wraps session-pin/unpin/archive/unarchive/rename + threads in the per-agent hybrid gateway transport (netns-isolated, auto-refreshing cookies). Emits the {ok,code,error} contract server.py needs; validates agent/thread/title; never prints secrets, never uses a shell.

Session: sidechat/muse-cli-threads-helper
2026-10-04 22:35:30 +00:00
operator 178ddc5dbf feat(cred): harden client onboarding with Instagram linking portal, age verification bypass, and fleet runbook 2026-10-04 21:43:32 +00:00
operator-main 7902622852 dm.py: autoprovision creation check — refuse to adopt parked/already-mapped thread UUIDs (fixes 2026-10-04 heartbeat misroute) 2026-10-04 21:16:50 +00:00
operator-main 5ab157b3b0 fleet alerting: fix netns naming in agent-health.sh + add fleet-alert-check.sh
agent-health.sh used bare node names for 'ip netns exec' but netns are

named warp-<node> since the NetVM layout; the 6189793 CDP-liveness check

always failed ('No such file or directory'), logging false CRITICALs and

kill -9'ing healthy browsers every 5 min. Use warp-$node.

fleet-alert-check.sh: new 5-min critical-condition detector (per-node CDP

liveness via warp-<node> netns). Consecutive-failure state machine:

page after 2 consecutive failures, re-page every 30 min while critical,

quiet-hours-aware (first alert always pages). Emits ALERT/RECOVERY

records to ~/.local/share/fleet-alert/outbox.jsonl for the container

fleet-alert-relay hook; best-effort box-ctl notify to healthy agents.

Session: sidechat/critical-alerting-pipeline
2026-10-04 20:09:36 +00:00
operator-main 8bb64c4826 Restore executable bit on sweeper/harvester (dropped by atomic mv) 2026-10-04 20:07:06 +00:00
operator-main ad9dbca7eb Restore followup/DM reliability fixes wiped by 19:43Z tree-clean
Re-applies three workstreams lost when 793d3d7 committed over uncommitted
edits, reconciled against the parallel track's committed dm.py changes:
- followup-sweeper.py: backfill thread_uuid after successful nudge sends;
  record final_nudge_target=main on final-nudge routing (C1/C2)
- response-harvester.py: resolve followups on main-chat replies when
  final_nudge_target=main (C3); harvest ALL [RESULT] markers per message
- dm.py: pre-send placement gate (fail closed when post-nav URL lacks the
  target thread UUID; skips main) — purely additive over 793d3d7+f268d3d
- sidechat_manager.py: wait_for_chat_list() settle-poll for list population
  race (sidebar button renders before titles load)
- new: bin/tests/test_followup_fixes.py (25 tests), bin/placement-audit.py,
  bin/dm-log-taxonomy.py, bin/session-probe.py,
  docs/SIDECHAT-RELIABILITY.md, docs/UUID-ROTATION.md

Verified: 25/25 tests pass, py_compile clean, sweeper/harvester dry-runs clean.
Known limitation: gate catches wrong-placement, not wrong-mapping (false
autoprovision adopting the parked thread needs a creation check).
2026-10-04 20:06:58 +00:00
operator-main f268d3d64b Harden dm.py sidechat navigation (CDP event drain + Page.navigate)
- ev(): drain CDP events until response id==1 (was blind recv,
  same bug class as box-chat-cdp.py 8d4bfa7 NO_SWITCHER fix)
- cmd_sidechat_use UUID path: use CDP Page.navigate instead of
  window.location.href via evaluate; 5 attempts, 15s SPA settle
  per attempt (was 3x4s, flaked 1/3 on url_mismatch)
- cmd_sidechat_use name path: retry 3x if not landing on /thread/

Test: 2/2 DM sends succeeded when browser healthy (tests 3-5
hit 646 browser death mid-test, infra issue not nav issue).

Session: sidechat/chromebox-ops
2026-10-04 19:47:33 +00:00
operator-main c59d492d49 Restore executable bit on bin/dm.py
Session: sidechat/chromebox-ops
2026-10-04 19:43:30 +00:00
operator-main 793d3d78d7 Remove hardcoded sidechat UUIDs from dm.py (heartbeat, 646-opm-work)
Thread UUIDs rotate -- heartbeat-opm died twice in one day
(5bd5b350 -> 0077e918 -> dead), dropping self_main_loop digests.
SIDCHAT_ALIASES is now intentionally empty; targets fall through to
job-sidechats.json dynamic mappings then name-based sidechat use with
autoprovision, which self-heals. Also removed stale heartbeat-opm and
pipe-9735f2 entries (dead UUID 0077e918) from job-sidechats.json.

Test: dm.py send to heartbeat resolved via name and SENT+VERIFIED
(thread 5f18476d-8994-49e7-a9e0-4838732363fe).

Session: sidechat/chromebox-ops
2026-10-04 19:43:04 +00:00
operator-main 18db8ff80b Fix self_main_loop exit code, [!] false positive, state race
- Exit 0 on success (was 1 when prompts sent, confusing systemd)
- [!] flag now uses word-boundary regex excluding hyphenated
  identities (operator-646 no longer triggers; 'operator needed' does)
- State writes now hold fcntl exclusive lock with fresh reload,
  preventing timer check from clobbering enable/disable changes

Session: sidechat/chromebox-ops
2026-10-04 19:39:50 +00:00
operator-main 5121dde90e fix: drop stale hardcoded sidechat UUID, use job-sidechats.json mapping
- bin/dm.py: remove 646 tasks -> 1e75a740 from SIDCHAT_ALIASES. That UUID is stale (not a valid thread on 646 account; SPA redirects elsewhere, causing misdelivery). Alias now falls through to job-sidechats.json/autoprovision. Do NOT re-add hardcoded UUIDs.

- job-sidechats.json: live autoprovisioned mappings for 646-pip and 646 tasks (2026-10-04).

- bin/box-chat-cdp.py: CDP robustness -- drain events until command response, retry switcher lookup while SPA settles, fresh reconnect per retry (transient NO_SWITCHER on pip/opm 2026-10-04).

Session: sidechat/uuid-stale-fix
2026-10-04 19:02:35 +00:00
operator-main 8d4bfa7053 Fix transient NO_SWITCHER / CDP race in box-chat-cdp.py
Three fixes for flaky main-chat reads (pip/opm):
1. ENSURE: retry chat-switcher lookup 4x with 2s waits instead of
   immediate NO_SWITCHER (React may still be rendering).
2. ev(): drain CDP events until matching command id arrives;
   previously the first recv() could grab a browser event instead
   of our evaluate response, returning None.
3. main(): reconnect fresh websocket on each retry (3 attempts);
   reusing a stale ws after page navigation gave dead JS contexts.

Verified: 7/8 reads succeed across all 4 agents; the 1 failure
was THREAD_NOT_FOUND while opm was actively in a side chat,
self-healed on next attempt.

Session: sidechat/chromebox-ops
2026-10-04 19:02:17 +00:00
operator-main 0822960810 Add main-loop enable/disable per-agent toggle
- self_main_loop.py: 'enabled' map in config (default all True);
  do_check skips disabled agents (marks disabled:true in results);
  new enable/disable actions with optional --agent.
- box-ctl.py: main-loop enable|disable [--agent <name>] actions,
  USAGE updated.

Check skips disabled agents so the loop can be toggled per
Chromebox without stopping the systemd timer.

Session: sidechat/chromebox-ops
2026-10-04 18:52:54 +00:00
operator-main e93e9b6122 Add self_main_loop.py main-chat self-monitor + box main-loop action
Reads each fleet agent's muse.ai Main chat on a 5-min systemd timer
(self-main-loop.timer). On new messages since the per-agent watermark,
posts a concise digest to that agent's prompting sidechat (dm.py, opm
as neutral sender - mirrors box notify), prompting the operator to
check main chat via DM/box. Escapes the main-chat-goes-unread failure
mode. No backfill on first run; silent when nothing new; read/send
failures logged without killing the timer; flock overlap guard.

box-ctl.py: main-loop check | status (fleet section).

Session: sidechat/chromebox-ops
2026-10-04 18:39:46 +00:00
operator-main f679ced960 Add identity-audit-check.sh and box identity-audit action
identity-audit-check.sh: proper script replacing the identity-audit-watch
cron inline SSH one-liner. Reads a bl-local cache of the VM audit JSON
(bl cannot SSH to VM; VM hourly audit should push to var/identity-audit.json).
Exits 0 clean, 1 on drift, 2 if cache missing.

box-ctl.py: new identity-audit action returning drift as JSON.
2026-10-04 18:35:57 +00:00
operator-main a76a776a87 Add cdp-latency-check.sh and box cdp-latency action
Proper script replacing the inline-SSH latency monitor. Probes each relay /json/version via pinned ports from netvm-names.sh, outputs name:latency_ms:code per node. box-ctl.py cdp-latency runs it and returns JSON.
2026-10-04 18:34:52 +00:00
operator-main 882dfd8254 Add watchdog-alert-check.sh (box watchdog-alerts helper script)
Self-contained FAILED-relaunch scanner for chromebox-watchdog.log
with watermark at NETVM_ROOT/watchdog-alert-watermark.txt.
Exits 0 quiet when clean, 1 with new lines printed when alerting.
The box-ctl.py watchdog-alerts action (in 2db0d92) drives this script.

Session: sidechat/chromebox-ops
2026-10-04 18:34:33 +00:00
operator-main 2db0d92d5a Add chrome-error-scan.sh and box chrome-errors action
Self-contained per-profile chrome log scanner with watermark-based
new-match detection. Box CLI action returns JSON per-profile counts.

Session: sidechat/chromebox-ops
2026-10-04 18:34:09 +00:00
operator-main 31ed4e2f99 Add relay-health-check.sh and box relay-health action
Converts the cdp-relay-health-monitor from inline SSH (nested quoting
bugs) to a proper self-contained script on bl. Uses pinned ports from
netvm-names.sh as single source of truth.

New files/actions:
- bin/relay-health-check.sh: checks all four CDP relays, exits 0/1
- box-ctl.py relay-health: JSON wrapper for the Box CLI

Session: sidechat/chromebox-ops
2026-10-04 18:32:44 +00:00
operator-main 550e30901b fix: placement verification and sidechat policy enforcement
- dm.py: placement-aware verify (verify_placement), checked_uuid logging, placement_mismatch events
- main-chat-watchdog.py: P0 alerts on placement_mismatch
- box-ctl.py: notify routes to sidechat, box policy command
- jobs: ops-audit and pipe-demo use sidechats
- response-harvester.py: chain deduplication

Session: sidechat/ops-restore
2026-10-04 18:29:13 +00:00
operator-main ae1bf17de5 Fix relay watchdog false-positive: sudo the pkill
restart_relay() ran pkill without sudo, but relay processes are
root-owned and the timer runs as User=super. The kill failed EPERM
(silently swallowed by || true), the old relay kept running, and
SO_REUSEADDR let the replacement double-bind the same port. The
post-restart health check then passed and logged "restarted OK"
when nothing was actually restarted.

Adding sudo -n to the pkill, matching the sudo -n ip netns exec
already used to start the relay.

Session: sidechat/chromebox-ops
2026-10-04 18:22:10 +00:00
operator-main c07802dfa2 Fix watchdog relaunch-loop: guard before relaunch, main-process PID filter
The relaunch-loop guard only protected the kill step, not the relaunch.
When CDP was unreachable on a slow-starting browser, the watchdog would
invoke netvm-chrome.sh (which kills the existing browser) before checking
if it was recently launched — piling up 5 chromiums on opm.

Now the <120s check runs before the relaunch and skips the entire cycle.
Also fixed the PID check to match only the main browser process
(--remote-debugging-port, excluding --type= renderer/gpu children).

Session: sidechat/chromebox-ops
2026-10-04 18:21:55 +00:00
operator-main 8d5d5c0f3b Unify CDP relay ports: pin registry ports in netvm-names.sh
netvm-node-up.sh was starting the CDP relay with the hash-derived
CDP_PORT while cdp-relay-watchdog.sh pinned muse->9410, pip->9420,
646->9430, opm->9440. Since netvm-chrome.sh calls netvm-node-up.sh
on every browser relaunch, each restart spawned a wrong-port zombie
relay (9353, 10355, 10239...).

The pinning now lives in netvm_names() itself, making it the single
source of truth for all consumers (node-up, chrome, cdp, accounts,
watchdog). CDP_PORT_OVERRIDE still takes precedence for future nodes.

Session: sidechat/chromebox-ops
2026-10-04 18:21:47 +00:00
cred-driver 7b5271a69a muse-signin: mask secrets in progress output at the source
Identifier, OTP code, and account-name values replaced with [redacted] in all progress prints. Line structure and markers preserved (APPROVAL_NEEDED/NEEDS_HUMAN/SUCCESS prefixes intact); exit codes 0/2/3/4 unchanged, no consumer parses stdout. Defense in depth: onboard-driver already scrubs its passthrough; this covers manual operator flows too.
2026-10-04 18:07:48 +00:00
cred-driver 86da8b5539 onboard-driver: scrub secrets from signin output passthrough
- Redact identifier/code (>=4 chars) from muse-signin.py stdout/stderr before passthrough (it echoes OTP input).

- Catch TimeoutExpired: its str() includes argv with --email/--otp; print generic timeout instead.

- Log email_masked instead of raw email to job-log.jsonl (rc=4 branch).
2026-10-04 17:48:54 +00:00
op-thread-uuid ae4f2640ad dm: emit thread_uuid on the SENT and VERIFIED line
dm_send already knows the thread UUID at send time (alias resolution, nav URL capture, autoprovision capture) but dropped it: the only stdout channel the board parses carried no thread info, so every auto-logged DM row had thread_uuid null.

Now prints '... SENT and VERIFIED thread=<uuid>' when known, unchanged line otherwise (main-chat sends, UUID-capture failures stay honestly null -- never fabricated). Backward compatible: board _BOX_DM_SENT_RE has no end anchor; bl consumers (job-dispatch.py, siphon-bl.py) use substring matching.

Worktree note: unrelated uncommitted changes remain (job_id followup-correlation hunks in this file, followup-sweeper.py, response-harvester.py, untracked helpers) -- not mine, not staged.

Session: sidechat/box-dms-ui
2026-10-04 17:44:33 +00:00
operator 33a0f295b6 feat(pipeline): register 3-stage ops-audit pipeline definitions and wire super-cli prune command 2026-10-04 17:23:28 +00:00
operator 2b19d2cb45 feat(pipeline): add stop and prune commands to pipeline engine and CLI
- Add stop_pipeline and prune_pipelines to bin/pipeline_engine.py
- Support prefix matching and custom cancellation reason
- Wire 'super pipeline stop <run_id>' and 'super pipeline prune [--max-age H]' into bin/super-cli.py
2026-10-04 16:58:15 +00:00
operator 6cafdfabef feat(pipeline): add multi-agent pipeline engine, sidechat auto-provisioning, and CDP event isolation
- Add bin/pipeline_engine.py for persistent multi-agent execution tracking in pipelines.json
- Add jobs/pipe-demo-step1.json and jobs/pipe-demo-step2.json demo pipeline definitions
- Use ev1 in bin/muse-chat-api.py across send/messages/compose/create to avoid dropping return values on CDP event chatter
- Support Muse unconfirmed signup error handling in bin/muse-signin.py
- Add runtime state and telemetry files to .gitignore
- Track dynamic pipe sidechat mappings in job-sidechats.json
2026-10-04 16:56:15 +00:00
operator 1d739f6b6a feat(loop): codify external intrinsic loop management, progressive remediation, and operational runbook
- Add bin/gravity.py loop diagnostics, reconstruction, and progressive remediation
- Wire hard-break alerting to job-log audit and operator direct message
- Add comprehensive architecture and operational specification in docs/LOOP-MANAGEMENT.md
- Add sidechat thread auto-provisioning fallback on 'Navigated to: None' in bin/dm.py
- Support Muse unconfirmed signup error handling in bin/muse-signin.py
- Track dynamic pipe sidechat mappings in job-sidechats.json
2026-10-04 16:52:54 +00:00
operator-main 5b3d77fb60 feat(tests): add comprehensive unit test suite for variables, strategy modulation, and loop health 2026-10-04 16:50:13 +00:00
operator 5063fcb469 fix(cdp_queue): auto-purge stale queue tickets older than 2x acquire timeout 2026-10-04 16:47:36 +00:00
operator 2fa2955fb3 feat(harvester): add opportunistic harvest_main_feed with zero navigation and per-node fault isolation 2026-10-04 16:45:34 +00:00
operator 8bfe94d0f3 test(nav): add unit test suite for main chat policy, sidechat routing, and transfer lifecycle 2026-10-04 16:43:50 +00:00
operator-main cf8f59b737 fix(watchdog): generalize CDP page health check for Muse targets 2026-10-04 16:39:30 +00:00
operator 87fd93e7a6 feat(dm): implement Reset-at-Begin and Leave-in-Sidechat pattern to preserve Main Chat DOM 2026-10-04 16:39:23 +00:00
operator aa125bb7be feat(onboarding): propagate NEEDS_SIGNUP (code 4) through onboard-driver and muse-signin 2026-10-04 16:37:26 +00:00
operator 7a35b684c4 feat: unified fleet CLI, Main Chat preservation policy, sidechat routing, and file transfers
- Added CHAT_POLICY.md and README.md banner enforcing sidechat-first and file-transfer-first rules.
- Added strict Main Chat block to super dm send and super dm wo with --allow-main-chat override.
- Implemented file transfer staging and metadata registry in super dm send-file and super dm files (with clean subcommand).
- Added full job lifecycle management (show, create, enable, disable, delete, run --follow) to super-cli.py and box-ctl.py.
- Audited all jobs in jobs/*.json and redirected automated dispatches away from Main Chat.
- Hardened chromebox-watchdog.sh with systemd user session environment exports and stale singleton cleanup.
- Added compose_check command choice to muse-chat-api.py.
2026-10-04 16:34:25 +00:00
operator 4a935bd0c7 feat(automation): sidechat auto-provisioning, response harvester, followup sweeper, and super CLI 2026-10-04 16:23:10 +00:00
box-ctl a214355f16 box-ctl: expand actions (vars, strat, loop) + harden input validation 2026-10-04 16:17:10 +00:00
operator-main a32670731f chromebox-watchdog: fix kill loop on slow cold starts
Two fixes: (1) retry health check 4x with 15s gaps after relaunch instead of single 25s check; (2) skip kill if browser launched <2min ago (probably still starting). Prevents watchdog from killing a working-but-slow browser.

Session: sidechat/chromebox-ops
2026-10-04 13:17:13 +00:00
operator-main 5f0a77d04b Integrate cdp_queue into CDP path
All CDP sessions now go through per-node queue (max 2 concurrent, priority levels). DM sends use high priority. Graceful fallback if module unavailable.

Session: sidechat/chromebox-ops
2026-10-04 13:15:59 +00:00
operator-main 0d25696860 docs: exec-server -> exec-constrained stale references (bl:8444)
- docs/TOKEN_POLICY.md: rewritten for exec-constrained.py (named ops,
  -n exec-constrained, {op,args,ts,nonce} envelope; rotate endpoint gone)
- bin/chromebox-gateway.py: exec-server naming -> shared exec token files
- docs/DM-HTTPS-DESIGN-646.md + docs/DM-OVER-HTTPS-DESIGN.md: port
  8443->8444, namespace exec-server->exec-constrained, envelope updated,
  cloudflared port fix marked done 2026-10-04
2026-10-04 13:04:45 +00:00
operator-main 6e9421644a Add cdp_queue.py: per-browser CDP operation queue
Per-node FIFO, max 2 concurrent, priority levels (high/normal/low), flock-based cross-process coordination. DM sends use high priority.

Session: sidechat/chromebox-ops
2026-10-04 13:04:24 +00:00
operator-main f9dce15a6d netvm-topology.sh: relay check by connectivity, not pidfiles
Pidfiles go stale and lie. Primary verdict now curls the veth IP:port. Also pins registry CDP ports (hash-derived CDP_PORT was wrong).

Session: sidechat/chromebox-ops
2026-10-04 12:41:40 +00:00
operator-main 343920e0c3 Watchdog upgrades: stage-specific logging + new CDP relay watchdog
chromebox-watchdog.sh: HEALTH_FAIL_REASON pinpoints which health stage failed (no process / CDP unreachable / no Chat page); chromium stdout redirected to per-profile chromebox-<profile>.log; 10MB log rotation (one generation); Chat title match relaxed to .*Chat.

bin/cdp-relay-watchdog.sh (new): keeps per-node CDP relays alive. Two-stage check: (1) host veth IP assigned (fail-loud, no auto-fix — veth recreation touches WireGuard/iptables), (2) relay connectivity via curl to veth IP:port (never trust pidfiles — observed stale 2026-10-04). Restarts dead/misrouted relays in-netns. Runs via systemd timer every 5min. Pattern mirrors chromebox-watchdog.sh.

Session: sidechat/chromebox-ops
2026-10-04 12:40:56 +00:00
operator-main 45741f1151 bin/box-chat.py + box-chat-cdp.py — read-only bl helper for Box thread oversight
Session: sidechat/box-chat
2026-10-04 04:31:39 +00:00
operator-main 844aa73bd9 UUID-based sidechat reuse for heartbeat\n\n- Add url command to muse-chat-api.py\n- Dispatcher: reuse_key -> thread UUID mapping in job-sidechats.json\n- Capture UUID after first send, reuse on subsequent runs\n- Fixes multi-spawn bug (was matching by auto-generated title) 2026-10-04 04:03:28 +00:00
operator-main a9812cd355 Add box-ctl.py: allowlisted bl helper for Box API mutations\n\n- 14 actions: timer-list/status/create/delete/start/stop/enable/disable,\n job-list/get/put/delete/trigger, notify\n- Name regex ^[a-z0-9-]{1,64}$, full job schema validation per design §6\n- Cron→OnCalendar conversion + systemd-analyze verification\n- Fixed unit templates (only validated name interpolated)\n- Git commits on job put/delete; audit log to box-ctl.jsonl\n- No shell=True, no string interpolation into commands\n- Tested: full lifecycle on bl (boxtest job) 2026-10-04 04:02:19 +00:00
operator-main 72574baa4b Replace Ctrl+J with click-based chat activation\n\n- New _ensure_chat_active(): compose -> switcher -> nav-chat priority\n- hatch-nav-chat click recovers from stripped /thread/new state\n- Ctrl+J needed keyboard focus which stripped states lack 2026-10-04 03:46:47 +00:00