nexo-brain 2.6.20 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,6 +6,7 @@ import json
6
6
  import os
7
7
  import platform
8
8
  import plistlib
9
+ import re
9
10
  import subprocess
10
11
  import sys
11
12
  import time
@@ -38,6 +39,8 @@ SPECIAL_LAUNCHAGENT_IDS = {"prevent-sleep", "tcc-approve"}
38
39
  SPECIAL_ENV_NORMALIZE_IDS = SPECIAL_LAUNCHAGENT_IDS
39
40
  OPTIONALS_FILE = NEXO_HOME / "config" / "optionals.json"
40
41
  SCHEDULE_FILE = NEXO_HOME / "config" / "schedule.json"
42
+ PACKAGE_JSON = NEXO_CODE / "package.json"
43
+ CHANGELOG_FILE = NEXO_CODE / "CHANGELOG.md"
41
44
 
42
45
 
43
46
  def _codex_bootstrap_config_status() -> dict:
@@ -190,6 +193,7 @@ def _client_assumption_regressions() -> list[str]:
190
193
  return []
191
194
  allowed_claude_projects = {
192
195
  (src_root / "scripts" / "deep-sleep" / "collect.py").resolve(),
196
+ Path(__file__).resolve(),
193
197
  }
194
198
  offenders: list[str] = []
195
199
  for path in src_root.rglob("*.py"):
@@ -224,6 +228,44 @@ def _load_json(path: Path) -> dict:
224
228
  return json.loads(path.read_text())
225
229
 
226
230
 
231
+ def _latest_periodic_summary(kind: str) -> dict | None:
232
+ pattern = f"*-{kind}-summary.json"
233
+ candidates: list[tuple[str, Path]] = []
234
+ for path in (NEXO_HOME / "operations" / "deep-sleep").glob(pattern):
235
+ try:
236
+ payload = json.loads(path.read_text())
237
+ except Exception:
238
+ continue
239
+ label = str(payload.get("label", "") or "")
240
+ if label:
241
+ candidates.append((label, path))
242
+ if not candidates:
243
+ return None
244
+ _, path = sorted(candidates, key=lambda item: item[0])[-1]
245
+ try:
246
+ payload = json.loads(path.read_text())
247
+ except Exception:
248
+ return None
249
+ return payload if isinstance(payload, dict) else None
250
+
251
+
252
+ def _package_version() -> str:
253
+ try:
254
+ payload = json.loads(PACKAGE_JSON.read_text())
255
+ except Exception:
256
+ return ""
257
+ return str(payload.get("version", "") or "").strip()
258
+
259
+
260
+ def _top_changelog_version() -> str:
261
+ try:
262
+ text = CHANGELOG_FILE.read_text(encoding="utf-8")
263
+ except Exception:
264
+ return ""
265
+ match = re.search(r"^## \[([^\]]+)\]", text, flags=re.MULTILINE)
266
+ return match.group(1).strip() if match else ""
267
+
268
+
227
269
  def _count_checks(checks) -> int:
228
270
  if isinstance(checks, list):
229
271
  return len(checks)
@@ -1529,6 +1571,143 @@ def check_client_assumption_regressions() -> DoctorCheck:
1529
1571
  )
1530
1572
 
1531
1573
 
1574
+ def check_protocol_compliance() -> DoctorCheck:
1575
+ summary = _latest_periodic_summary("weekly")
1576
+ if not summary:
1577
+ return DoctorCheck(
1578
+ id="runtime.protocol_compliance",
1579
+ tier="runtime",
1580
+ status="degraded",
1581
+ severity="warn",
1582
+ summary="No weekly Deep Sleep protocol summary found",
1583
+ repair_plan=[
1584
+ "Run the Deep Sleep pipeline so weekly summaries include protocol compliance again",
1585
+ ],
1586
+ escalation_prompt=(
1587
+ "NEXO cannot verify heartbeat / guard_check / change_log compliance because the latest weekly Deep Sleep summary is missing."
1588
+ ),
1589
+ )
1590
+
1591
+ protocol = summary.get("protocol_summary") or {}
1592
+ overall = protocol.get("overall_compliance_pct")
1593
+ guard = protocol.get("guard_check") or {}
1594
+ heartbeat = protocol.get("heartbeat") or {}
1595
+ change_log = protocol.get("change_log") or {}
1596
+ evidence = [f"weekly summary: {summary.get('label', 'unknown')}"]
1597
+ if overall is not None:
1598
+ evidence.append(f"overall protocol compliance: {overall:.1f}%")
1599
+ if guard.get("compliance_pct") is not None:
1600
+ evidence.append(
1601
+ f"guard_check: {guard.get('executed', 0)}/{guard.get('required', 0)} ({guard['compliance_pct']:.1f}%)"
1602
+ )
1603
+ if heartbeat.get("compliance_pct") is not None:
1604
+ evidence.append(
1605
+ f"heartbeat with context: {heartbeat.get('with_context', 0)}/{heartbeat.get('total', 0)} ({heartbeat['compliance_pct']:.1f}%)"
1606
+ )
1607
+ if change_log.get("compliance_pct") is not None:
1608
+ evidence.append(
1609
+ f"change_log after edits: {change_log.get('logged', 0)}/{change_log.get('edits', 0)} ({change_log['compliance_pct']:.1f}%)"
1610
+ )
1611
+
1612
+ status = "healthy"
1613
+ severity = "info"
1614
+ repair_plan: list[str] = []
1615
+ if overall is None:
1616
+ status = "degraded"
1617
+ severity = "warn"
1618
+ repair_plan.append("Ensure Deep Sleep extractions keep writing protocol_summary data")
1619
+ elif overall < 45:
1620
+ status = "critical"
1621
+ severity = "error"
1622
+ elif overall < 70:
1623
+ status = "degraded"
1624
+ severity = "warn"
1625
+
1626
+ if status != "healthy":
1627
+ repair_plan.extend(
1628
+ [
1629
+ "Reinforce heartbeat discipline on every user message",
1630
+ "Call nexo_guard_check before production/shared edits",
1631
+ "Record production changes with nexo_change_log after editing",
1632
+ ]
1633
+ )
1634
+
1635
+ return DoctorCheck(
1636
+ id="runtime.protocol_compliance",
1637
+ tier="runtime",
1638
+ status=status,
1639
+ severity=severity,
1640
+ summary="Protocol compliance looks healthy" if status == "healthy" else "Protocol compliance needs hardening",
1641
+ evidence=evidence,
1642
+ repair_plan=repair_plan,
1643
+ escalation_prompt=(
1644
+ "Heartbeat / guard_check / change_log discipline is drifting. NEXO is at risk of repeating known errors and hiding change history."
1645
+ ) if status != "healthy" else "",
1646
+ )
1647
+
1648
+
1649
+ def check_release_artifact_sync() -> DoctorCheck:
1650
+ version = _package_version()
1651
+ changelog_version = _top_changelog_version()
1652
+ evidence = []
1653
+ status = "healthy"
1654
+ severity = "info"
1655
+ repair_plan: list[str] = []
1656
+
1657
+ if version:
1658
+ evidence.append(f"package version: {version}")
1659
+ if changelog_version:
1660
+ evidence.append(f"top changelog version: {changelog_version}")
1661
+
1662
+ if version and changelog_version and version != changelog_version:
1663
+ status = "critical"
1664
+ severity = "error"
1665
+ evidence.append("package/changelog release version mismatch")
1666
+ repair_plan.append("Bump or align CHANGELOG.md before publishing")
1667
+
1668
+ sync_script = NEXO_CODE / "scripts" / "sync_release_artifacts.py"
1669
+ if not sync_script.is_file():
1670
+ status = "critical"
1671
+ severity = "error"
1672
+ evidence.append(f"missing release artifact sync script at {sync_script}")
1673
+ repair_plan.append("Restore scripts/sync_release_artifacts.py")
1674
+ else:
1675
+ try:
1676
+ result = subprocess.run(
1677
+ [sys.executable, str(sync_script), "--check"],
1678
+ cwd=str(NEXO_CODE),
1679
+ capture_output=True,
1680
+ text=True,
1681
+ )
1682
+ except Exception as exc:
1683
+ status = "degraded" if status == "healthy" else status
1684
+ severity = "warn" if severity == "info" else severity
1685
+ evidence.append(f"artifact sync check failed to run: {exc}")
1686
+ repair_plan.append("Run scripts/sync_release_artifacts.py manually and inspect the local environment")
1687
+ else:
1688
+ if result.returncode != 0:
1689
+ status = "degraded" if status == "healthy" else status
1690
+ severity = "warn" if severity == "info" else severity
1691
+ detail = result.stderr.strip() or result.stdout.strip() or "artifact sync check failed"
1692
+ evidence.append(detail.splitlines()[0])
1693
+ repair_plan.append("Run scripts/sync_release_artifacts.py before publishing")
1694
+ else:
1695
+ evidence.append("release artifacts in sync")
1696
+
1697
+ return DoctorCheck(
1698
+ id="runtime.release_artifacts",
1699
+ tier="runtime",
1700
+ status=status,
1701
+ severity=severity,
1702
+ summary="Release artifact discipline OK" if status == "healthy" else "Release artifact discipline needs attention",
1703
+ evidence=evidence,
1704
+ repair_plan=repair_plan,
1705
+ escalation_prompt=(
1706
+ "Release-facing artifacts drifted away from the source version contract. Publishing now risks another hotfix release."
1707
+ ) if status != "healthy" else "",
1708
+ )
1709
+
1710
+
1532
1711
  def run_runtime_checks(fix: bool = False) -> list[DoctorCheck]:
1533
1712
  """Run all runtime-tier checks. Read-only by default."""
1534
1713
  return [
@@ -1542,6 +1721,8 @@ def run_runtime_checks(fix: bool = False) -> list[DoctorCheck]:
1542
1721
  check_claude_desktop_shared_brain(),
1543
1722
  check_transcript_source_parity(),
1544
1723
  check_client_assumption_regressions(),
1724
+ check_protocol_compliance(),
1725
+ check_release_artifact_sync(),
1545
1726
  check_launchagent_integrity(fix=fix),
1546
1727
  check_personal_script_registry(fix=fix),
1547
1728
  check_skill_health(fix=fix),