Skip to content

errors: name the cause, not the symptom (WhatsApp aiohttp preflight, lossless-compaction wording, empty-session resume) + CONTRIBUTING convention - #111630

Open
Finn763 wants to merge 1 commit into
NousResearch:mainfrom
Finn763:fix/111128-descr
Open

Finn763 wants to merge 1 commit into
NousResearch:mainfrom
Finn763:fix/111128-descr

Conversation

@Finn763

@Finn763 Finn763 commented Sep 15, 2026

Copy link
Copy Markdown

Summary

Part of #111128 (wave: "Error messages lie — one convention plus a sweep"). A bounded slice: three user-visible messages that named a proximate symptom now name the real cause and the way out, plus the convention section the issue asks to land.

Every message below was verified unclaimed (gh search prs --state open <issue#> + the issue's keyword search + timeline/triage comments) before it was touched.

1. #71308 — WhatsApp bridge blamed for a broken Python dep

adapter.connect() reported "Bridge HTTP server did not start in 15s" forever while the bridge was healthy: a half-removed aiohttp left an importable namespace shell whose missing ClientSession raised AttributeError inside three blanket except Exception handlers.

Now a preflight names the cause and the fix — "aiohttp is installed but unusable: (namespace package: no __init__.py on disk) has no ClientSession — a half-removed or partially overwritten install. The bridge was never reached. Reinstall it: pip install --force-reinstall aiohttp" (separate text for the not-installed case), fatal code whatsapp_aiohttp_unusable, retryable=False, checked before node/bridge/creds. The genuine bridge-timeout string is kept for real bridge failures. This also stops the useless 15 s poll.

2. #53000 — lossless compaction told the user its accuracy degraded

agent/conversation_compression.py printed "⚠️ Session compressed N times — accuracy may degrade." even for engines that keep compacted turns retrievable. Engines can now declare ContextEngine.lossless_compaction = True (mirroring the existing emit_automatic_compaction_status convention) and the line becomes "ℹ️ Session compacted N times — this engine keeps compacted turns retrievable, so nothing was lost. /new only if you want a clean slate." Read via type(compressor), so mock engines and the base engine keep today's wording.

3. #27168 — resuming an empty session lied about "Starting fresh"

_preload_resumed_session aborts with exit 1, so "Session found but has no messages. Starting fresh." was false on that path. Both paths now state the empty transcript and give the command: "…its transcript is empty (nothing was committed to it, or the messages were cleared)… delete the empty one with: hermes sessions delete <id>". Exit codes and return values untouched.

4. Convention

CONTRIBUTING.md gains "Error Messages: Name the Cause, Not the Symptom" (one paragraph): every user-facing error must name the actual cause plus the next step, never the proximate symptom; suppressed exceptions must carry their reason into the final message; add a regression test on the touched path. Examples cite #105150 (payment/credit vs missing key) and this commit's aiohttp-vs-bridge case.

Evidence

  • RED at HEAD (production files restored from git show HEAD:<path>, test files kept): 5 failed / 2 passed across the three test files — the three new preflight cases, the lossless-engine case, and the updated resume assertion.
  • GREEN with the change: tests/gateway/test_whatsapp_connect.py tests/agent/test_compression_count_warning.py tests/hermes_cli/test_resume_quiet_stderr.py tests/agent/test_413_compression.py tests/gateway/test_whatsapp_stale_bridge.py tests/gateway/test_telegram_noise_filter.py → 197 passed, 0 failed, 2 skipped.

Scope note

Three message fixes, not five: the wave's own list was swept first and all 10 listed children are claimed by open PRs or already fixed on main — #105150 (#64146), #96416 (#96437), #99831 (#99840), #53639 (#78045), #25087 (#24513/#52545), #85172 (#102591), #31791 (#31801/#106948), #65101 (#65128), #65099 (#65106); #70908 is fixed on main (cron/scheduler.py gates provider classification on provider_reachable). The three here come from the same cause-naming family and were each unclaimed. Behaviour changed: strings and the aiohttp guard only — no i18n, no logging overhaul.

…nvention

Wave NousResearch#111128 (error messages name the proximate symptom instead of the cause).
Three user-facing messages reported the wrong subsystem at the failure site:

- whatsapp: a half-removed aiohttp stays importable (namespace shell, no
  ClientSession), so every health probe raised AttributeError inside a blanket
  except and connect() blamed the Node bridge with "Bridge HTTP server did not
  start in 15s" forever. Preflight now names the broken dependency and the fix
  (pip install --force-reinstall aiohttp) (NousResearch#71308).
- agent: the repeated-compaction warning claimed "accuracy may degrade" even for
  engines whose compaction keeps turns retrievable (LCM-style). Engines can
  declare ContextEngine.lossless_compaction = True and the message then says what
  actually happened (NousResearch#53000).
- cli: resuming a session with an empty transcript printed "found but has no
  messages. Starting fresh." — on the preload path it actually aborted with exit
  1. Both paths now name the empty transcript and the way out
  (hermes sessions delete <id>) (NousResearch#27168).

CONTRIBUTING.md gains the convention: every user-facing error names the actual
cause plus the remediation step, never the proximate symptom; regression test on
the touched path.

Tests: assertions added/updated on all three paths.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/compression Context compression and continuation sessions comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have platform/whatsapp WhatsApp Business adapter type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants