NEXO 7.11.4 — Packaged runtime contracts, cron sync, and recovery close the last install gaps

Published 2026-04-28. Patch release over v7.11.3 — no API change, but an important installed-runtime contract repair.

Why this patch exists

Source checkouts and packaged installs had drifted into two different operational contracts. The repo could contain the right files, cron manifest, and recovery logic while a real installed runtime under ~/.nexo/core still missed key pieces. That meant the code review looked green, but the machine that actually runs NEXO could still be weaker in four ways: root JSON runtime contracts were not copied, cron install/update still depended on a stale JS list, runner-health wrote a report with no reader, and some cron failures were only healed after a stale-age window even though the failure had already happened.

Root runtime contracts now ship into packaged installs

The packaged-runtime copy logic in both bin/nexo-brain.js and src/auto_update.py used to special-case a narrow set of root files. That was enough for most Python modules, but not for the JSON contracts that now define local model behavior and other runtime surfaces. In practice, local_model_manifest.json could exist in the repo and still be absent from ~/.nexo/core, so the local embeddings/reranker layer was configured in source but not in the installed runtime. v7.11.4 broadens the root-file contract: packaged installs now sync root *_manifest.json, *_defaults.json, and *_tiers.json files along with the existing Python/runtime artifacts. The installed runtime now sees the same local-model manifest-backed contract as the source tree.

Cron install/update is manifest-driven again

The long-term source of truth for core crons is src/crons/manifest.json, but some packaged install/update paths still relied on a manually maintained ALL_PROCESSES list in bin/nexo-brain.js. Once that list drifted, fresh installs and some updates stopped reflecting the real manifest: new cron entries existed in source but were not guaranteed to be installed in the runtime. v7.11.4 adds a shared syncCoreProcessesFromManifest(...) helper and routes fresh install, same-version refresh, and versioned migration/update through that manifest-driven sync first. The legacy JS allowlist remains only as a fallback path if manifest sync cannot run.

Runner health is no longer write-only

runner-health-check.py existed, wrote runner-health-report.json, and even contained a dead query path around followup activity, but it was not registered in the cron manifest and the report had no real product reader. v7.11.4 promotes the check into the runtime contract: the cron is now declared in src/crons/manifest.json, the followup activity check reports meaningful 7-day evidence, doctor/runtime health reads the report, and dashboard exposes both /api/runner-health and /api/morning-briefing. The artifacts still live on disk, but they are now attached to actual operator-facing surfaces instead of being abandoned files.

Watchdog heals failures earlier

The watchdog already knew how to heal stale cron windows, but a non-zero exit could still wait until the next stale threshold before recovery logic kicked in. v7.11.4 closes that gap. If the last ended run failed, the watchdog now requests catchup or immediate re-execute right away; it only falls back to stale-age healing if that immediate repair did not happen. The release also treats run_once_on_wake as a catchup-style recovery policy so wake-only jobs use the same catchup rail instead of a generic stale fallback. Finally, the stuck-wrapper PID match is scoped to the current runtime's nexo-cron-wrapper.sh path, so one install cannot accidentally identify another install's wrapper that happens to share the same cron_id.

Validation

The patch is covered by a targeted release sweep focused on the touched surfaces: cron recovery, watchdog/reaper behavior, cron wrapper contract, local models, resonance map, packaged runtime/update paths, cron sync, dashboard, and runtime update contract. Final result:

pytest -q \
  tests/test_cron_recovery.py \
  tests/test_watchdog_stuck_reaper.py \
  tests/test_cron_wrapper_contract.py \
  tests/test_local_models.py \
  tests/test_resonance_map.py \
  tests/test_packaged_update_runtime.py \
  tests/test_cron_sync.py \
  tests/test_dashboard_app.py \
  tests/test_runtime_update_contract.py \
  tests/test_v6_fresh_install_skip.py

117 passed

Recovery on existing hosts

Hosts already affected by the drift should recover through the normal packaged update path. After updating to v7.11.4, the runtime will re-sync the missing root JSON contracts, re-run manifest-driven cron sync, and expose runner-health through doctor/dashboard. Long-lived processes started before the update should still be restarted so they pick up the repaired runtime tree and fresh cron wiring.

Full changelog entry → · bin/nexo-brain.js · src/auto_update.py · src/scripts/nexo-watchdog.sh