Skip to main content

Nexus, trading system

entity · created 2026-07-09 · actor claude-cowork · confidence medium · status active tags: nexus trading finance watchdogs

Now​

Structural map only, no positions/values here (Tier 3 domain). Observed 2026-07-09.

  • Repos (on /Volumes/FATTY/src): nexus, nexus-equities, HFT-Crypto; nightly nexus-git-sync launchd auto-commit+push is write-gated by NEXUS_GIT_SYNC_WRITE=1 (default: report-only).
  • Services: sentinel PM2 daemon polls Nexus + computes indicators (:18794/api/health); nexus-retrain launchd (health-fix bak 2026-07-04); nexus-backup launchd + ~/nexus-backup/; watchdogs nexus-log-watchdog, nexus-x-lane-watchdog (tested: ~/.hermes/tests/test_nexus_x_lane_watchdog.py).
  • State/monitors: ~/nexus_monitor.db, ~/.nexus_monitor_state*.json (incl. port-8888 variant), cross-status nexus= field (0/20 ⚠ at 2026-07-09, meaning of 0/20 unverified, assumed: tagged-entities count).
  • Analysis artifacts: ~/nexus-profit-analysis-site/, ~/.hermes/artifacts/nexus-equity/, carry/canary plan files in ~ (carry_scale_plan_latest.md, apply_carry_canary_policy_plan.py), ~/.openclaw/reports/nexus-repo-triage-2026-04-28.md.
  • Rules: Oracle lane advises/computes; live trades, money movement, broker/account changes require Dwayne first (BOT_COORDINATION + money-boundary spec + egress class 7).
  • Observability false-alarm class (updated 2026-09-18 15:25; CLOSED 2026-09-20 06:04): the 2026-09-15 deleted-cwd fault on nexus-api (pid 1284) and nexus-health (pid 1322) no longer applies, those pids are gone and the live PM2 group was restarted. Verified 2026-09-20 06:04 AEST on Zappo: :8888/api/health HTTP 200 status ok, /api/swarm/health returns healthy: true, issues: [], halt_trading: false, observability_halt: false, and every engine reports pm2_status online with heartbeats inside the 2700 s window (q pid 932 heartbeat 05:56:43, omega pid 946). pm2 ls runs normally from a live shell (nexus-api pid 868, nexus-health pid 972, eq-web pid 867, all 23 h uptime, 0 restarts), so the uv_cwd abort is gone. Historical mechanism for reference: a PM2-managed process whose cwd was deleted aborts pm2 jlist on uv_cwd and yields an empty status map; cross-check with lsof -a -p <pid> -d cwd, where a missing cwd row was the tell. See lessons/2026-09-17-pm2-stale-cwd-false-unhealthy-fleet.md.
  • Two equities surfaces, not one (dated 2026-09-17, FIXED 2026-09-18): :3001 is the standalone equities eq-web; :55059 is the nexus-web dashboard (/Volumes/FATTY/src/nexus/web/server.js, WEB_PORT default 55059) which also reads nexus-equities/logs/equities_swarm.db. Both were Node services whose better-sqlite3 native module was compiled for NODE_MODULE_VERSION 127 while the runtime is node v24.21.0 (modules 137), so the dashboard returned HTTP 500 Cannot read properties of null (reading 'prepare') and eq-web crash-looped. Both were fixed 2026-09-18 14:09-14:13 AEST by npm rebuild better-sqlite3 in each tree plus a PM2 restart; both endpoints now return HTTP 200. Pitfall: npm 12 blocks the native build unless the package declares "allowScripts": {"better-sqlite3@12.11.1": true}; nexus-equities/web already had it, nexus/package.json did not, so the first rebuild there silently no-opped and needed the field added. Verify a rebuild with node -e "require('better-sqlite3')" before restarting, not with npm's exit code.
  • Swarm starvation bug (fixed 2026-08-14): scripts/tools/execution_self_heal.py's prediction-starvation circuit breaker compared predictions.timestamp (REAL epoch float, e.g. [redacted-id]) against a formatted datetime string ("2026-08-13 19:39:16"). In SQLite a TEXT literal always sorts above any REAL value, so the comparison always returned 0 informative predictions → every engine was permanently starved/halted by circuit_breaker_starvation and nothing traded. Fix: 12h cutoff for the predictions query changed from string to epoch float (cutoff_12h_epoch = now_epoch - 12*3600). The 7-day trades query was left as-is because trades.timestamp is genuinely TEXT. Verified by stress_test_self_heal_breaker.py (2/2 pass) and live DB check (X1/X100 have 5 informative predictions with epoch arithmetic vs 0 with the buggy string). Source: session 20260814_172010_7fa2acc3, 2026-08-14/15.
  • Separate, deeper issue (not a code bug, left for Dwayne): DerivCombo engines insert predictions with future_return=NULL and resolved_at=NULL and nothing ever resolves them (all 9,926 × 21 predictions have future_return permanently NULL), so they stay starved even after the type fix. They are paper_target_publisher research engines with zero capital; check_fleet_validation requires MIN_FLEET_TRADES=100 and they have 0 trades, so they are locked out of capital by design. Omega has zero predictions ever (data-absent, not a code bug). Architectural decision (research-only vs live), not a clear bug.

Log​

  • 2026-09-20 06:04 AEST (weekly synthesis, live probe): the deleted-cwd observability fault is closed. The two stale pids from the 2026-09-15 11:20 remount are gone (lsof -a -p 1284 -d cwd and -p 1322 -d cwd return nothing because neither process exists; pm2 ls shows nexus-api pid 868, nexus-health pid 972, eq-web pid 867, all 23 h uptime and 0 restarts). /api/swarm/health now returns healthy: true, issues: [], observability_halt: false, halt_trading: false, checked_at 2026-09-20 06:04:08, with observability.healthy: true, no stale engines and no pid_missing entries; q reports pid 932 heartbeat 05:56:43 (446 s old, limit 2700 s) and omega pid 946. :8888/api/health HTTP 200 status ok, :3001/ HTTP 200, :55059/api/health HTTP 200 with runtime_sources.mode: live_local_db and both crypto_db and equities_db available: true. ~/.pm2/logs/eq-web-error.log is 0 bytes, dated 2026-09-18 14:09. The pm2 restart nexus-api nexus-health approval request from 2026-09-17 to 2026-09-18 is therefore obsolete: the restart happened by other means and no further restart is needed. Nothing was changed in this probe; it is read-only evidence. Source: live curl and pm2 ls on Zappo, 2026-09-20 06:04 AEST.

  • 2026-09-18 (cron, 16:05-16:15 AEST): unchanged fault, mechanism re-confirmed by fresh reproduction. Monitor reported swarm degraded: OBSERVABILITY HALT: PM2 unhealthy: nexus-q/omega/aether/x status=unknown (each name twice) at checked 2026-09-18 16:05:14. Live ground truth 16:05-16:14: all engines online with live PIDs and fresh heartbeats (q 62949, x 67643, omega 60393, aether 61251, 1 restart each; heartbeat ages q 512s, omega 0s, aether 199s, x 5s at 16:10:06), halt_trading: false, observability_halt: true. lsof -a -p 1284 -d cwd and -p 1322 -d cwd return no cwd row; all four engine PIDs resolve /Volumes/FATTY/src/nexus*. New evidence this run: the uv_cwd failure was reproduced on demand from a deleted cwd (os.chdir(tmpdir); os.rmdir(tmpdir); pm2 jlist → exit 1, uv_cwd in stderr), while /usr/local/bin/pm2 jlist from an intact cwd returns 33 apps in 0.32s, so the 6s timeout hypothesis stays superseded. Counters at 16:14:47: nexus-api-error.log 2,496,136 bytes / 4,474 uv_cwd lines / 1,858 Unable to read PM2 status lines; nexus-health-error.log 3,154,082 bytes / 13,096 PM2 unhealthy lines / 0 uv_cwd. Equities fix holds: eq-web-error.log is 0 bytes and :3001 / :55059 / :8888 all HTTP 200. Nexus-X100 stale since 2026-08-30 18:26:24. Nothing restarted; no trading, risk or capital changes. Fix still pending Dwayne's approval (pm2 restart nexus-api nexus-health restarts a live service). Source: session 2026-09-18 (cron).

  • 2026-09-18 (cron, 15:05-15:25 AEST): recurrence of both symptoms, plus two corrections to earlier notes. The monitor script reported swarm degraded: OBSERVABILITY HALT: PM2 unhealthy: nexus-q/omega/aether/x status=unknown (each name twice) at checked 2026-09-18 15:05:32. Live ground truth at 15:14-15:21 AEST: all eight tracked apps online (nexus-api pid 1284 cycles 0, nexus-health pid 1322 cycles 0, nexus-q 62949, nexus-x 67643, nexus-omega 60393, nexus-aether 61251 all cycles 1, nexus-web 30376 cycles 3, eq-web 28084 cycles 227,402). /api/swarm/health at checked_at 2026-09-18 15:14:36: healthy: false, observability_halt: true, halt_trading: false. lsof -a -p 1284 -d cwd and -p 1322 -d cwd still return no cwd row while 62949/67643/60393/61251 all resolve /Volumes/FATTY/src/nexus*, so the 2026-09-15 11:20 remount deleted-cwd condition persists. Counters: nexus-api-error.log 2,409,505 bytes / 4,324 uv_cwd lines / 1,795 Unable to read PM2 status lines; nexus-health-error.log 3,148,862 bytes / 13,060 PM2 unhealthy lines / 0 uv_cwd lines. Heartbeats fresh and all FLAT (q 15:16:29, omega 15:21:38, aether 15:21:44, Nexus-X1 15:21:18); Nexus-X100 stale since 2026-08-30 18:26:24. Correction 1: the monitor's equities API bad symptom is gone; :3001/api/state and :55059/api/state both return HTTP 200 and eq-web-error.log is 0 bytes at cycles 227,402, so the 14:09-14:13 rebuild fix holds. Correction 2: earlier notes called this observability halt fail-closed on new entries. It is not, for the live engines. set_observability_provider is called only from api.py:148, so HealthMonitor._observability_halt can only be True inside the API process; the four engine processes never register a provider and their error logs contain no HEALTH_HALT or OBSERVABILITY HALT lines. /api/swarm returning trading_allowed: false is the API's own view. swarm_health/engines also label engine status as unknown for the same PM2-read reason. Nothing restarted; no trading, risk or capital changes. Fix pending approval, now narrower and with a verified code fix: add cwd=BASE_DIR to the two pm2 jlist calls in api.py (lines 423 and 889; passing an explicit cwd was verified to return exit 0 / 33 apps from a deleted cwd) and then pm2 restart nexus-api only, since nexus-health already passes cwd=str(BASE_DIR) in _run() and reads PM2 successfully. Source: session 2026-09-18 (cron).

  • 2026-09-18 (cron, 14:05-14:27 AEST): equities surface confirmed recovered on live probe; only the deleted-cwd observability halt remains. The monitor script's 14:05:52 reading is already stale: at 14:12-14:27 AEST :3001/api/state (eq-web, pid 28084, cwd /Volumes/FATTY/src/nexus-equities), :55059/api/state (nexus-web, pid 30376), :8888/api/health, /api/engines, /api/pnl and /api/errors all return HTTP 200 (40-hit and 50-hit bursts, zero 5xx). eq-web-error.log is 0 bytes and restarts are frozen at 227,402 with 19.9 min uptime, so the crash loop is over. The observability fault is unchanged and confirmed by mechanism, not inference: lsof -p 1284 -d cwd (nexus-api) and -p 1322 -d cwd (nexus-health) still return no cwd row while all six other tracked PIDs resolve theirs; both started 2026-09-15 09:27:32, before the 2026-09-15 11:20 remount. /api/swarm/health at checked_at 2026-09-18 14:27:50: healthy: false, observability_halt: true, halt_trading: false. Counters at 14:27:50: nexus-api-error.log 2,350,669 bytes with 4,222 uv_cwd lines and 1,753 Unable to read PM2 status lines; nexus-health-error.log 3,144,947 bytes with 13,033 PM2 unhealthy lines. Engines genuinely online with 1 restart each and fresh heartbeats (nexus-q 14:01:16, omega 14:14:58, aether 14:26:41, Nexus-X1 14:27:29); Nexus-X100 stale since 2026-08-30 18:26:24. Nothing restarted; no trading, risk or capital changes. Fix still pending Dwayne's approval: pm2 restart nexus-api nexus-health (restarts a live service), then confirm observability_halt: false. Source: session 2026-09-18 (cron).

  • 2026-09-18 (cron, 14:03-14:14 AEST): equities half of the fault is FIXED and verified; the observability half remains open. hermes_ops_status.py at 14:03:50 flagged nexus api crypto=v2 equities=error. Root cause for equities was the known better-sqlite3 ABI mismatch, but with a new twist: eq-web (PM2 id 2, name eq-web, cwd /Volumes/FATTY/src/nexus-equities) had restarted 227,402 times and was crash-looping about 4 times/second (restarts 227,224 → 227,303 in 20 s, measured), writing ~4.2 KB/s to ~/.pm2/logs/eq-web-error.log, which had reached 283,010,918 bytes with 227,349 ERR_DLOPEN_FAILED lines (log had been truncated earlier, so counters reset from the 12:06 reading). Fixes applied and verified: npm rebuild better-sqlite3 in /Volumes/FATTY/src/nexus-equities/web (succeeded, module now ABI 137) then pm2 restart eq-web; :3001/api/state now HTTP 200, uptime 4 m+ with restarts frozen at 227,402 and zero new error-log bytes. The second surface nexus-web (/Volumes/FATTY/src/nexus/web/server.js, PM2 id 17, :55059) needed more: its first npm rebuild silently no-opped because npm 12 blocks the native install script unless "allowScripts": {"better-sqlite3@12.11.1": true} is declared in package.json (nexus-equities/web already had it, nexus did not). Added the field, rebuilt, node -e "require('better-sqlite3')" confirmed ABI 137, pm2 restart nexus-web; :55059/api/state now HTTP 200 (was {"error":"Cannot read properties of null (reading 'prepare')"}). A stale pm2 entry named eq-web with script path /Users/dwayne/.npm-global/bin/node and web/server.js (id 2) is the live one; no separate eq-web process exists. eq-web-error.log flushed (pm2 flush eq-web), ~/.pm2/logs 586 MB → 290 MB. Verified crypto-monitor.py end to end: equities_api error → ok, nexus-engine-status.json rewritten 14:09:23, equities block now reports Market: CLOSED (Pre-hours), capital $200,000, pool $200,000, DB 0 trades, scanner 3831/3831, 8 hunters 0 funded. Re-running hermes_ops_status.py now returns health: ok, nexus: crypto=v2 equities=ok. Still open, unchanged: nexus-api pid 1284 and nexus-health pid 1322 (started 2026-09-15 09:27:32) still have no resolvable cwd (lsof -a -p 1284 -d cwd and -p 1322 -d cwd return no row), so /api/swarm/health still reports healthy: false, observability_halt: true with PM2 unhealthy: nexus-q/omega/aether/x status=unknown, while halt_trading: false and /api/health streams fresh heartbeats (q 14:01:16, omega 14:13:48, all FLAT). Fix still needs Dwayne's approval because it restarts live services: pm2 restart nexus-api nexus-health. No trading, risk, capital or broker changes made. Verification (same session): full-suite A/B with the change stashed and popped, ./venv/bin/python -m pytest tests/ -q --ignore=tests/test_edgelab.py (edgelab segfaults the runner on xgboost/data.py independently of this change) gives 22 failed / 487 passed / 1 skipped with the change versus 23 failed / 486 passed / 1 skipped without it; the failure-name diff shows zero tests failing only because of the change, and the single test that fails only in the stashed run is tests/test_rate_limiter.py::TestExponentialBackoff::test_max_delay_cap, a timing-sensitive test, not a regression. No Python test reads package.json (grep for it in tests/ returns nothing). nexus-equities/web npm test (its declared node --test suite) is 7/7 pass. Booting the app on a spare port (WEB_PORT=55159 node web/server.js from /Volumes/FATTY/src/nexus, note the entry point is web/server.js, not the repo-root server.js) reaches readiness in about 1 s: / 200 and /api/state 200, log line [AETHER-V] Terminal active on :55159; the live pm2 instance was untouched throughout. hermes verify --json in this tree selects a "Node.js app" recipe with bootstrap: npm install, test: pytest, start: npm run start, port: null, and it fails for reasons unrelated to the change: bare pytest is not the tree venv (20 collection errors, ModuleNotFoundError: numpy), it fails identically on a pristine tree with the change stashed, and npm run start runs the repo-root server.js rather than web/server.js. The correct fix is a saved .hermes/environment.json manifest (test from ./venv/bin/python -m pytest, start web/server.js on 55059); writing it was blocked by the protected-file approval gate with no interactive approver in this cron session, so it remains a one-line change for Dwayne. Source: session 2026-09-18 (cron).

  • 2026-09-18 (cron, 12:06-13:05 AEST): same open fault, no change of mechanism, counters still climbing. hermes_ops_status.py at 13:03:43 flagged nexus api crypto=v2 equities=error. Live ground truth 13:04:55 AEST: all eight tracked apps online (nexus-api pid 1284 cycles 0, nexus-health pid 1322 cycles 0, nexus-q 62949, nexus-x 67643, nexus-omega 60393, nexus-aether 61251 all cycles 1, nexus-web 90806 cycles 1, eq-web pid 77367 cycles 216,808). :8888/api/health HTTP 200 status ok, heartbeats q 13:01:05, omega 13:04:44, all FLAT. /api/swarm/health: healthy: false, halt_trading: false, observability_halt: true. lsof -a -p 1284 -d cwd and -p 1322 -d cwd both return no cwd row, so the 2026-09-15 11:20 remount deleted-cwd condition persists. Equities :3001 curl rc 7 / http=000, no listener; eq-web-error.log 269,955,156 bytes (256,753,828 at 12:14), about 13.2 MB in 50 min = ~380 MB/day, with 216,808 ERR_DLOPEN_FAILED lines (better-sqlite3 built NODE_MODULE_VERSION 127, runtime node v24.21.0 = 137). Nothing restarted; no trading, risk or capital changes. Fixes still pending Dwayne's approval: pm2 restart nexus-api nexus-health; npm rebuild better-sqlite3 in /Volumes/FATTY/src/nexus-equities/web and /Volumes/FATTY/src/nexus, then pm2 restart eq-web. Note the observability halt is fail-closed on new entries (HealthMonitor.is_trading_allowed() returns False while _observability_halt is set), so it is not cosmetic. Source: session 2026-09-18 (cron).

  • 2026-09-18 (cron, 12:06-12:16 AEST): repeat of the same open fault, both halves still broken. Cron pro_nexus_finance_monitor_report.py reported equities API bad (<HTTPError 500: 'Internal Server Error'>) and swarm degraded: OBSERVABILITY HALT: PM2 unhealthy: nexus-q/omega/aether/x status=unknown at checked 2026-09-18 12:06:02. Live ground truth at 12:14:59 AEST: all eight tracked apps online (nexus-api pid 1284 cycles 0, nexus-health pid 1322 cycles 0, nexus-q 62949, nexus-x 67643, nexus-omega 60393, nexus-aether 61251 all cycles 1, nexus-web 90806 cycles 1, eq-web pid 35931 cycles 206,265). /api/health HTTP 200 status ok, heartbeats q 12:00:57, omega 12:14:56, aether 12:11:30, Nexus-X1 12:14:32, all FLAT; Nexus-X100 stale since 2026-08-30 18:26:24. /api/swarm/health checked_at 12:14:59: healthy: false, halt_trading: false, observability_halt: true. lsof -a -p 1284 -d cwd and -p 1322 -d cwd both return no cwd row, so the deleted-cwd condition from the 2026-09-15 11:20 remount persists. Counters at 12:13:34: nexus-api-error.log 2,112,204 bytes / 1,574 Unable to read PM2 status lines / 3,810 uv_cwd lines; nexus-health-error.log 3,129,061 bytes / 12,955 PM2 unhealthy lines. Equities: :3001 connection refused (no listener); eq-web-error.log 256,475,172 bytes / 205,985 ERR_DLOPEN_FAILED lines, measured growth 256,492,588 → 256,753,828 in 60 s = 261,240 bytes/min (about 4.4 KB/s, ~376 MB/day), superseding the earlier ~288 MB/day estimate; eq-web cycles rose 197,407 (11:04) → 206,265 (12:14), about 7,500/hour. :55059/api/state HTTP 500 Cannot read properties of null (reading 'prepare'); its /api/health self-reports runtime_sources.mode: static_snapshot with crypto_db.available: false and equities_db.available: false while both files exists: true, i.e. the same better-sqlite3 ABI mismatch (module built NODE_MODULE_VERSION 127, runtime node v24.21.0 = 137) rather than a corrupt DB. /Volumes/FATTY 1.2 TiB at 91%, 111 GiB free. Nothing restarted; no trading, risk or capital changes. Fixes still pending Dwayne's approval: npm rebuild better-sqlite3 in /Volumes/FATTY/src/nexus-equities/web and /Volumes/FATTY/src/nexus, then pm2 restart eq-web; and pm2 restart nexus-api nexus-health. Source: session 2026-09-18 (cron).

  • 2026-09-18 (cron, 11:05-11:32 AEST): repeat of the same open fault, mechanism unchanged, counters still growing. Cron pro_nexus_finance_monitor_report.py reported equities API bad (<HTTPError 500: 'Internal Server Error'>) and swarm degraded: OBSERVABILITY HALT: PM2 unhealthy: nexus-q/omega/aether/x status=unknown; x appeared twice because the probe ran twice inside 27 minutes (11:05:54 and the 11:31 re-check). Live ground truth at 11:31 AEST: all eight tracked apps online (nexus-api pid 1284, nexus-health pid 1322, nexus-q 62949, nexus-x 67643, nexus-omega 60393, nexus-aether 61251, nexus-web 90806, eq-web pid 98511), engines 1 restart each, /api/health HTTP 200 with heartbeats 13-245 s old and all FLAT, halt_trading: false, observability_halt: true, checked_at 2026-09-18 11:31:31. lsof -a -p 1284 -d cwd and -p 1322 -d cwd still return no cwd row, so the 2026-09-15 remount deleted-cwd condition persists; pm2 jlist from a live shell succeeds and reports every app online, so the halt is monitor blindness, not fleet death. Counters: nexus-api-error.log 2,054,450 bytes with 1,532 Unable to read PM2 status lines and 3,710 uv_cwd lines (1,867,595 bytes / 1,398 lines at 09:05); nexus-health-error.log 3,123,274 bytes with 12,928 PM2 unhealthy lines (3,105,913 / 12,847 at 09:05) and no uv_cwd lines. Equities: :3001 has no listener (curl http=000); eq-web restarts 197,407 (up from 195,669 at 11:04, about 1,900/hour) with pid 98511; eq-web-error.log 245,820,312 bytes with 197,420 ERR_DLOPEN_FAILED lines, growing 126,888 bytes in 45 s (about 2.8 KB/s, ~244 MB/day). nexus-web :55059 still Cannot read properties of null (reading 'prepare') HTTP 500, its own openReadonlyDb() catches the ABI mismatch and returns null, so the handler dereferences null; better_sqlite3.node in both nexus/node_modules and nexus-equities/web/node_modules is dated 2026-06-16 and built for NODE_MODULE_VERSION 127 against runtime 137 on node v24.21.0 (symlinked 2026-09-16 07:02). Host load average swung 276 -> 12.7 during the check; /Volumes/FATTY 1.2 TiB at 91%, 111 GiB free. Consequence worth noting: HealthMonitor.is_trading_allowed() returns False while _observability_halt is set (engines/infrastructure.py lines 884-889), so this false alarm is fail-closed on new entries, not cosmetic. No restarts, no trading, risk or capital changes made. Pending Dwayne's approval: pm2 restart nexus-api nexus-health; npm rebuild better-sqlite3 in /Volumes/FATTY/src/nexus-equities/web and /Volumes/FATTY/src/nexus, then pm2 restart eq-web; and truncating eq-web-error.log (245 MB) after the rebuild. Source: session 2026-09-18 (cron).

  • 2026-09-18 (cron, 11:04-11:07 AEST): hermes_ops_status.py at 11:03:48 again flagged nexus api crypto=v2 equities=error; live confirmation repeats the known open fault, mechanism unchanged. curl :3001/api/state rc 7 / http=000, no listener. pm2 jlist shows eq-web online restarts=195,669 pid=79183 (up from 185,485 at 10:03, about 10,200 restarts/hour), ~/.pm2/logs/eq-web-error.log at 243,640,824 bytes with 195,667 ERR_DLOPEN_FAILED lines, 12.6 MB in 63 minutes, about 288 MB/day, superseding the ~175 MB/day estimate. Cause unchanged: better_sqlite3.node built NODE_MODULE_VERSION 127, runtime node v24.21.0 = 137. lsof -a -p 1284 -d cwd and -p 1322 -d cwd return no cwd row, so the nexus-api/nexus-health deleted-cwd condition persists. Engines nexus-q/x/omega/aether all online, 1 restart each, /api/health heartbeats 11:00-11:04 and all FLAT; /api/health HTTP 200. /Volumes/FATTY 1.2 TiB at 91%, 111 GiB free. Nothing restarted; no trading, risk or capital changes. Fixes still pending Dwayne's approval: npm rebuild better-sqlite3 in /Volumes/FATTY/src/nexus-equities/web and /Volumes/FATTY/src/nexus, then pm2 restart eq-web; and pm2 restart nexus-api nexus-health. Source: session 2026-09-18 (cron).

  • 2026-09-18 (cron, 10:03 AEST): hermes_ops_status.py flagged nexus api crypto=v2 equities=error; live confirmation at 10:05 AEST repeats the known open fault with no change of mechanism. curl :3001 rc 7 / http=000, no listener; pm2 jlist shows eq-web online restarts=185485 pid=31241 (up from 177,789 at 09:09, about 7,700 restarts/hour) and ~/.pm2/logs/eq-web-error.log at 231,030,414 bytes with 185,529 ERR_DLOPEN_FAILED lines (221.4 MB at 09:09, about 175 MB/day, superseding the ~150 MB/day estimate). nexus-web :55059 still answers /api/state HTTP 500; nexus-api :8888/api/health HTTP 200; lsof -a -p 1284 -d cwd still returns no cwd row, so the deleted-cwd condition persists for nexus-api/nexus-health (pids 1284/1322, started 2026-09-15 09:27). Engines nexus-q/x/omega/aether all online, 1 restart each. Nothing restarted; no trading, risk or capital changes. Fixes still pending Dwayne's approval: pm2 restart nexus-api nexus-health and npm rebuild better-sqlite3 in /Volumes/FATTY/src/nexus-equities/web and /Volumes/FATTY/src/nexus, then pm2 restart eq-web. Source: session 2026-09-18 (cron).

  • 2026-09-18 (cron, 09:05-09:10 AEST): correction to the 07:46 entry, the stale-cwd fault is NOT cleared. Cron pro_nexus_finance_monitor_report.py reported equities API bad (<HTTPError 500: 'Internal Server Error'>) plus swarm degraded: OBSERVABILITY HALT: PM2 unhealthy: nexus-q/omega/aether/x status=unknown at checked 2026-09-18 09:05:21 AEST. Live ground truth: engines all online (nexus-q pid 62949, nexus-x pid 67643, nexus-omega pid 60393, nexus-aether pid 61251, 1 restart each), /api/health heartbeats 4-400s old, all FLAT, halt_trading: false; swarm health at checked_at 09:09:01 still observability_halt: true. lsof -a -p 1284 -d cwd (nexus-api) and lsof -a -p 1322 -d cwd (nexus-health) both return no cwd row, i.e. the 2026-09-17 deleted-cwd condition persists. The 07:46 reading of 0 restarts since 2026-09-15 09:27 was true but insufficient: restart_time=0 and an online PID do not prove a resolvable cwd, because /Volumes/FATTY was remounted 2026-09-15 11:20 and still has mod=Sep 15 11:20:44. Fault counters grew: nexus-api-error.log 1,867,595 bytes with 1,398 Unable to read PM2 status lines (806 on 09-17); nexus-health-error.log 3,105,913 bytes with 12,847 PM2 unhealthy lines (12,424 on 09-17). Equities: :3001 has no listener (curl http=000); eq-web cycles PIDs (84057 then 85527) with restarts 177,633 and 177,789 ~1 min apart, eq-web-error.log grows 221,303,578 → 221,413,050 bytes in 60s (about 1.8 KB/s, ~150 MB/day, supersedes the ~45 MB/day estimate) with 177,645 ERR_DLOPEN_FAILED lines; the ABI mismatch is unchanged (better_sqlite3.node built NODE_MODULE_VERSION 127, runtime node v24.21.0 = 137, module dated Jun 16 2026). nexus-web :55059 answers / HTTP 200 but /api/state HTTP 500 Cannot read properties of null (reading 'prepare'), so the 07:46 note that :55059 "recovered" is superseded, only the static root serves. /Volumes/FATTY is 1.2 TiB at 91% used, 111 GiB available. No trading, risk or capital changes made; no restarts performed. Fixes still pending Dwayne's approval: pm2 restart nexus-api nexus-health (observability only, engines must not be restarted) and npm rebuild better-sqlite3 in /Volumes/FATTY/src/nexus-equities/web and /Volumes/FATTY/src/nexus plus pm2 restart eq-web. Source: session 2026-09-18 (cron).

  • 2026-09-18 (cron, 07:46-07:48 AEST): equities surface still down, now with a quantified failure. curl :3001 rc 7, no listener; eq-web shows online in PM2 but has 162,796 restarts (eq-web-error.log 202.6 MB, 162,806 ERR_DLOPEN_FAILED lines, last write 07:47). Cause unchanged from 2026-09-17: /Volumes/FATTY/src/nexus-equities/web/node_modules/better-sqlite3/build/Release/better_sqlite3.node is built for NODE_MODULE_VERSION 127, runtime node is v24.21.0 (modules 137). nexus-web :55059 now answers HTTP 200 (recovered). nexus-api and nexus-health now run from an intact cwd (0 restarts since the 2026-09-15 09:27 mounts), so the 2026-09-17 stale-cwd fault is cleared; engines nexus-q/x/omega/aether all online. Fix still pending approval: npm rebuild better-sqlite3 in /Volumes/FATTY/src/nexus-equities/web, then pm2 restart eq-web. Interim risk: the 203 MB error log grows ~45 MB/day with restart spam. Source: session 2026-09-18 (cron).

  • 2026-09-17: Root cause pinned, deleted cwd, not a timeout. Cron pro_nexus_finance_monitor_report.py reported equities API bad (RemoteDisconnected(...)) plus swarm degraded: OBSERVABILITY HALT: PM2 unhealthy: nexus-q/omega/aether/x status=unknown at checked 2026-09-17 21:05:38 AEST. The 2026-09-15 hypothesis (pm2 jlist exceeding its 6s cap under load) is now superseded: pm2 jlist from an intact cwd returns in ~0.3s on this host (measured 2026-09-17 21:07), and the failure is 100% reproducible on demand. Mechanism: nexus-api (pid 1284) and nexus-health (pid 1322) both started 2026-09-15 09:27:32 AEST from /Volumes/FATTY/src/nexus; /Volumes/FATTY was remounted 2026-09-15 11:20, orphaning their cwd inode. Node's process.cwd() then throws ENOENT ... uv_cwd; the pm2 CLI loads cwd at bootstrap (pm2/lib/API.js:69) and exits 1 before reading the daemon, so _pm2_status_map() (api.py:419-434) returns {} and _engine_observability_health() renders status=unknown for every engine. Tell: lsof -a -p <pid> -d cwd -Fn returns no cwd row for both PIDs, while the four engine PIDs (started 20:23-20:35 today) resolve /Volumes/FATTY/src/nexus* fine. Reproduced 2026-09-17: chdir into /tmp/gone_dir, rmdir it, run pm2 jlist → exit 1 with the identical uv_cwd traceback; same binary from an intact cwd → exit 0. Counts at 21:15 AEST: 806 Unable to read PM2 status lines in ~/.pm2/logs/nexus-api-error.log, 12,424 PM2 unhealthy lines in ~/.pm2/logs/nexus-health-error.log. Ground truth against the false alarm: all four engines online (nexus-q pid 62949, nexus-x pid 67643, nexus-omega pid 60393, nexus-aether pid 61251), /api/health streaming heartbeats 6-816s old and all FLAT, /api/state 200, halt_trading: false. Fix (needs Dwayne's approval, it restarts a live service): pm2 restart nexus-api nexus-health so PM2 respawns them in the current mount, then confirm observability_halt: false. Do not restart the engines, which are healthy. Second, independent fault on the same host: equities :3001 has no listener (curl rc 7); eq-web is in a 7,669-restart crash loop on better-sqlite3 NODE_MODULE_VERSION 127 vs runtime 137 (ERR_DLOPEN_FAILED, ~/.pm2/logs/eq-web-error.log), while the nexus-web dashboard :55059 returns HTTP 500 Cannot read properties of null (reading 'prepare') for the same ABI reason on /Volumes/FATTY/src/nexus/node_modules/better-sqlite3. Both need npm rebuild better-sqlite3 in their respective trees. No trading/risk/capital changes made. Source: session 2026-09-17 (cron). Lesson: lessons/2026-09-17-pm2-stale-cwd-false-unhealthy-fleet.md.

  • 2026-09-15: Cron pro_nexus_finance_monitor_report.py reported swarm degraded: PM2 unhealthy: nexus-q status=unknown; PM2 unhealthy: nexus-omega status=unknown; PM2 unhealthy: nexus-aether status=unknown at checked_at 2026-09-15 08:07:05 AEST. Root cause is the same false-negative class as 2026-09-14, now with a named mechanism: nexus/api.py _pm2_status_map() (line 423) and the support-process reader (line 889) both call subprocess.check_output(["pm2","jlist"], timeout=6). When that 6s cap trips, the status map returns {} and _engine_observability_health() renders status=unknown for every engine, because pm2.get("status") is None (api.py:525-527). Live re-probe 2026-09-15 08:38:13 AEST returned swarm_health healthy true, issues: [], halt_trading: false, observability_halt: false, trading_allowed: true, with q (pid 1005), omega (pid 1020), aether (pid 1021), x (pid 45763) all online and heartbeat ages 2-406s. Direct /Users/dwayne/.npm-global/bin/pm2 jlist now runs in 0.32-0.36s. Evidence: /Users/dwayne/.pm2/logs/nexus-api-error.log holds 51 timed out after 6 seconds lines and 11 OBSERVABILITY HALT engaged lines, last write 08:07:15; host load average was 121.42 at 08:30 (heavy: HA, hermes gateway, CodexBar, Android emulator, mindroom knowledge refresh). Second, independent failure mode in the same log: the pm2 CLI aborts with Error: ENOENT: no such file or directory, uv_cwd (node bootstrap does_own_process_state) when the calling process's cwd no longer exists, producing 695 returned non-zero exit status 1 lines; reproduced by running pm2 jlist from a deleted directory. Proposed fix (needs Dwayne's approval, it edits the live trading API): raise both timeout=6 budgets in nexus/api.py to 30s to match the cron-script fix of 2026-09-14, and treat an unreadable pm2 payload as unknown-with-warning rather than as status=unknown issues. No trading/risk/capital changes made. Source: session 2026-09-15 (cron).

  • 2026-09-14: Cron pro_nexus_finance_monitor_report.py exited 1 with subprocess.TimeoutExpired on the local ssh 127.0.0.1 probe. Root cause was a nested-timeout budget bug, not a dead stack: inner worst case (5s x2 slow endpoints + 8s pm2 jlist + ssh handshake) exceeded the 25s parent cap, so the JSON the probe had already gathered was discarded. Direct probe showed :8888/api/health answering in 6.5s and /api/swarm/health in 12.8s, :55059/api/state in 16.6s, all live, all slow. Fixed in-script: per-endpoint HTTP timeout 5s→15s, pm2 jlist 8s→30s, parent ssh cap 25s→90s with TimeoutExpired caught and returned as rc 124, plus a safe() wrapper so one slow subsystem cannot abort the payload. Verified clean run 23.6s, exit 0. Source: session 2026-09-14 (cron).

  • 2026-09-14: Live finding from that probe, :8888/api/swarm/health reports healthy: false, halt_trading: false, observability_halt: true, observability_halt_reason: "engine observability degraded", issues PM2 unhealthy: nexus-q / nexus-omega / nexus-aether / nexus-x status=unknown (checked_at 2026-09-14 13:22:23 AEST). PM2 shows all four online (nexus-x pid 45763 restarts 69, nexus-q pid 1005, nexus-omega pid 1020, nexus-aether pid 1021) and /api/health still streams fresh engine heartbeats (nexus-q 13:12:05, omega 13:22:46, aether 13:22:02, Nexus-X1 13:22:56) while /api/health also labels the q/omega/aether status as unknown. Engine out-logs are stale since 2026-08-17 17:55:58, so unknown is most likely PM2's process-state query or the heartbeats' freshness window, not dead engines. No trading/risk/capital changes made. Left for Dwayne; unresolved at time of writing. Source: session 2026-09-14 (cron).

  • 2026-09-14 (same session, later): that observability halt was transient. A re-probe at 13:31:31 AEST returned swarm_health healthy true with issues: [], and every endpoint answered ok: true, status: 200 (crypto_health, swarm_health, engines, pnl, errors, equities_state, pm2). Directly reading the payload also confirmed both earlier PM2 unhealthy ... status=unknown and the 5s endpoint timeout('timed out') readings were probe-budget artefacts, not stack faults. No intervention was needed. Source: session 2026-09-14 (cron).

  • 2026-08-15: Recorded swarm starvation root cause + fix (type-mismatch in execution_self_heal.py prediction breaker) and the separate DerivCombo/Omega permanently-starved design issue left for Dwayne. Source: session 20260814_172010_7fa2acc3., hermes.

  • 2026-07-09: created, structural only, claude-cowork.


Sources: ~/.openclaw/ARCHITECTURE.md · ~/.openclaw/bin/nexus-*-launchd · ~/.hermes/policies/nexus-money-agent-boundary-spec.md