Skip to content

fix(slack): preserve progress edits on network failures - #64267

Closed
2001Y wants to merge 1 commit into
NousResearch:mainfrom
2001Y:fix/slack-progress-edit-network-retry
Closed

fix(slack): preserve progress edits on network failures#64267
2001Y wants to merge 1 commit into
NousResearch:mainfrom
2001Y:fix/slack-progress-edit-network-retry

Conversation

@2001Y

@2001Y 2001Y commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Slack tool-progress updates use chat.update to keep one editable progress message. A transient aiohttp DNS/connection failure was returned as a permanent edit failure, so the gateway disabled editing for the rest of the turn and posted later tool updates as new messages.

This change classifies TimeoutError and aiohttp.ClientConnectionError as retryable for the idempotent chat.update path. It deliberately keeps Slack API errors and TLS/certificate/fingerprint validation failures non-retryable. The retryable result lets the existing gateway consumer retain the same progress message ID and catch up on the next edit.

The aiohttp exception lookup uses the module rebound by Slack's lazy dependency loader, so both initial-import and post-install states behave the same way.

Related Issue

N/A — reproduced from a live Slack gateway ClientConnectorDNSError while updating a tool-progress message.

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • plugins/platforms/slack/adapter.py
    • mark timeouts and aiohttp.ClientConnectionError failures from chat.update as retryable transient failures;
    • keep aiohttp TLS/certificate/fingerprint validation errors and Slack API response errors non-retryable;
    • resolve the active aiohttp exception classes after lazy dependency rebinding.
  • tests/gateway/test_slack_block_kit_adapter.py
    • cover TimeoutError, the observed ClientConnectorDNSError, TLS/certificate/fingerprint errors, plain OSError, Slack API errors, and lazy dependency rebinding.
  • tests/gateway/test_run_progress_topics.py
    • verify end-to-end that a retryable edit failure retains the original progress message ID and does not post a replacement bubble.
  • tests/gateway/test_slack.py
    • preserve installed Slack/aiohttp packages during test collection instead of replacing them with partial mocks;
    • cover package importability so ordinary multi-file pytest runs cannot regress.

How to Test

  1. Run scripts/run_tests.sh tests/gateway/test_slack_block_kit_adapter.py tests/gateway/test_run_progress_topics.py tests/gateway/test_slack.py -- -q -o addopts=.
  2. Run scripts/run_tests.sh tests/gateway/test_slack*.py tests/gateway/test_run_progress_topics.py -- -q -o addopts=.
  3. Run scripts/run_tests.sh.
  4. Run python scripts/check-windows-footguns.py plugins/platforms/slack/adapter.py tests/gateway/test_slack.py tests/gateway/test_slack_block_kit_adapter.py tests/gateway/test_run_progress_topics.py and ruff check for the same paths.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: macOS 27.0 (Apple Silicon)

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

Screenshots / Logs

Observed failure class (sanitized):

aiohttp.client_exceptions.ClientConnectorDNSError:
Cannot connect to host slack.com:443 ssl:default

Verification:

Changed Slack adapter/progress files in one ordinary pytest process: 269 passed
All Slack + progress files: 450 passed
Windows footgun scan: passed
Ruff: passed
Canonical full suite: 33 failures across 14 unrelated files; all 14 failing files also failed on a detached origin/main baseline at b663d50a6. The Slack/progress files modified by this PR remained green.

The full-suite checkbox remains unchecked because the canonical suite was not completely green. The baseline comparison used the same scripts/run_tests.sh runner and environment; its failing-file set covered every file that failed on this branch.

@alt-glitch alt-glitch added type/bug Something isn't working comp/plugins Plugin system and bundled plugins platform/slack Slack app adapter P3 Low — cosmetic, nice to have sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages labels Jul 14, 2026

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

Verdict: Approved

This PR preserves progress edits on network failures in Slack.

Looks Good

  • Network resilience improvement.
  • Well-scoped: 4 files.

No Issues Found


Reviewed by Hermes Agent

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for tracing the transient Slack failure to the edit-result contract. The normal progress consumer already preserves an editable message when result.retryable is true (gateway/run.py:18191-18207), and the proposed Slack classification fits that contract.

Problems

  • The overflow sibling path still unconditionally disables editing after any failed edit: gateway/run.py:18095-18099. Once _split_progress_groups() produces multiple groups, a retryable Slack chat.update failure will still set can_edit = False, recreating the replacement-bubble behavior this PR addresses.

Suggested changes

  • Teach _roll_progress_overflow_if_needed() to retain can_edit for result.retryable, and add an overflow regression covering that branch.
  • Salvage the adapter hunk against current main: SlackAdapter.edit_message now routes via metadata-aware _get_client and stop_typing calls (plugins/platforms/slack/adapter.py:1545-1553).

Automated hermes-sweeper review.

return SendResult(
success=False,
error=str(e),
retryable=True,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This retryable result is honored by the normal progress loop, but not by the overflow branch: current gateway/run.py:18095-18099 sets can_edit = False for every failed _edit_progress_message. Please extend that branch to preserve the message ID when result.retryable is true and add an overflow regression.

@teknium1 teknium1 added the sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform label Jul 16, 2026
@2001Y
2001Y force-pushed the fix/slack-progress-edit-network-retry branch from 913015d to 36ab5ac Compare July 19, 2026 16:09
teknium1 added a commit that referenced this pull request Jul 23, 2026
- rt.cms012@gmail.com -> trac3r00 (#68378; commit authored as
  'Minseo-Choi' — trac3r00's display name, same account)
- 15167896+2001Y@users.noreply.github.com -> 2001Y (#64267)
- hello@jeromeiveson.com -> Trantor-develops (#57196)
- boumagent@gmail.com -> patp (#18859)
- dorukardahan@hotmail.com -> dorukardahan (#17184) was already mapped.
teknium1 added a commit that referenced this pull request Jul 23, 2026
- rt.cms012@gmail.com -> trac3r00 (#68378; commit authored as
  'Minseo-Choi' — trac3r00's display name, same account)
- 15167896+2001Y@users.noreply.github.com -> 2001Y (#64267)
- hello@jeromeiveson.com -> Trantor-develops (#57196)
- boumagent@gmail.com -> patp (#18859)
- dorukardahan@hotmail.com -> dorukardahan (#17184) was already mapped.
teknium1 added a commit that referenced this pull request Jul 23, 2026
… tests

CI shards run without the slack extras; the two #64267 tests import the
real SDK (SlackApiError, the lazy-rebind path) and errored with
ModuleNotFoundError. Skip on bare environments — classification coverage
for stdlib exception types (OSError/TimeoutError/cert errors) still runs
everywhere.
teknium1 added a commit that referenced this pull request Jul 23, 2026
- rt.cms012@gmail.com -> trac3r00 (#68378; commit authored as
  'Minseo-Choi' — trac3r00's display name, same account)
- 15167896+2001Y@users.noreply.github.com -> 2001Y (#64267)
- hello@jeromeiveson.com -> Trantor-develops (#57196)
- boumagent@gmail.com -> patp (#18859)
- dorukardahan@hotmail.com -> dorukardahan (#17184) was already mapped.
teknium1 added a commit that referenced this pull request Jul 23, 2026
… tests

CI shards run without the slack extras; the two #64267 tests import the
real SDK (SlackApiError, the lazy-rebind path) and errored with
ModuleNotFoundError. Skip on bare environments — classification coverage
for stdlib exception types (OSError/TimeoutError/cert errors) still runs
everywhere.
@teknium1

Copy link
Copy Markdown
Contributor

Merged via #70189 — your commit was cherry-picked/reapplied onto current main with your authorship preserved in git history: your transient-transport classifier was cherry-picked (we added importorskip for CI environments without the slack extras).

Thanks for the contribution!

@teknium1 teknium1 closed this Jul 23, 2026
randlee pushed a commit to randlee/hermes-agent that referenced this pull request Aug 11, 2026
- rt.cms012@gmail.com -> trac3r00 (NousResearch#68378; commit authored as
  'Minseo-Choi' — trac3r00's display name, same account)
- 15167896+2001Y@users.noreply.github.com -> 2001Y (NousResearch#64267)
- hello@jeromeiveson.com -> Trantor-develops (NousResearch#57196)
- boumagent@gmail.com -> patp (NousResearch#18859)
- dorukardahan@hotmail.com -> dorukardahan (NousResearch#17184) was already mapped.
randlee pushed a commit to randlee/hermes-agent that referenced this pull request Aug 11, 2026
… tests

CI shards run without the slack extras; the two NousResearch#64267 tests import the
real SDK (SlackApiError, the lazy-rebind path) and errored with
ModuleNotFoundError. Skip on bare environments — classification coverage
for stdlib exception types (OSError/TimeoutError/cert errors) still runs
everywhere.
prmartinow pushed a commit to prmartinow/hermes-agent that referenced this pull request Aug 26, 2026
- rt.cms012@gmail.com -> trac3r00 (NousResearch#68378; commit authored as
  'Minseo-Choi' — trac3r00's display name, same account)
- 15167896+2001Y@users.noreply.github.com -> 2001Y (NousResearch#64267)
- hello@jeromeiveson.com -> Trantor-develops (NousResearch#57196)
- boumagent@gmail.com -> patp (NousResearch#18859)
- dorukardahan@hotmail.com -> dorukardahan (NousResearch#17184) was already mapped.
prmartinow pushed a commit to prmartinow/hermes-agent that referenced this pull request Aug 26, 2026
… tests

CI shards run without the slack extras; the two NousResearch#64267 tests import the
real SDK (SlackApiError, the lazy-rebind path) and errored with
ModuleNotFoundError. Skip on bare environments — classification coverage
for stdlib exception types (OSError/TimeoutError/cert errors) still runs
everywhere.
melon-xf added a commit to melon-xf/hermes-agent that referenced this pull request Sep 3, 2026
- rt.cms012@gmail.com -> trac3r00 (NousResearch#68378; commit authored as
  'Minseo-Choi' — trac3r00's display name, same account)
- 15167896+2001Y@users.noreply.github.com -> 2001Y (NousResearch#64267)
- hello@jeromeiveson.com -> Trantor-develops (NousResearch#57196)
- boumagent@gmail.com -> patp (NousResearch#18859)
- dorukardahan@hotmail.com -> dorukardahan (NousResearch#17184) was already mapped.
melon-xf added a commit to melon-xf/hermes-agent that referenced this pull request Sep 3, 2026
… tests

CI shards run without the slack extras; the two NousResearch#64267 tests import the
real SDK (SlackApiError, the lazy-rebind path) and errored with
ModuleNotFoundError. Skip on bare environments — classification coverage
for stdlib exception types (OSError/TimeoutError/cert errors) still runs
everywhere.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have platform/slack Slack app adapter sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants