hermes - 💡(How to fix) Fix [Bug]: Kanban notifications can be lost for failed sends and decomposed child tasks

Official PRs (…)
ON THIS PAGE

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Root Cause

  • gateway/run.py::_kanban_notifier_watcher calls await adapter.send(...) but does not inspect the returned SendResult. Exceptions are handled, but soft failures are not.
  • hermes_cli/kanban_db.py::decompose_triage_task() inserts child task rows directly with workspace_kind='scratch' and without copying any kanban_notify_subs rows from the root task.

Fix Action

Fix / Workaround

I have a local tested patch ready that:

RAW_BUFFERClick to expand / collapse

Bug Description

Kanban notification delivery can silently lose user-visible blocked/completed events in two related paths:

  1. The gateway Kanban notifier treats adapter.send() returning SendResult(success=False) as a successful delivery. The notifier has already claimed the unseen event cursor before sending, so a soft delivery failure advances the subscription past the event and the next tick will not retry it.

  2. A triage task created from a gateway chat can be auto-subscribed, but decompose_triage_task() creates child tasks with fresh rows that do not inherit the root task's notify subscriptions. When one of those child tasks blocks or completes, the originating chat receives no notification.

A related workflow issue also appears when the root triage task uses a persistent dir workspace: decomposed children are inserted as scratch tasks with no workspace_path, so workers run in per-task scratch directories instead of the root project directory. This can make follow-up/QA tasks unable to see artifacts from prior child work.

Steps to Reproduce

Notifier soft-failure path:

  1. Create a task and add a notify subscription.
  2. Complete or block the task so a terminal notification event exists.
  3. Run the gateway Kanban notifier with a platform adapter whose send() returns SendResult(success=False) without raising.
  4. Query unseen events for the subscription.

Decompose path:

  1. Create a triage task with a notify subscription from a gateway chat.
  2. Decompose it into child tasks.
  3. Inspect notify subscriptions on the child task ids.
  4. If the root task uses workspace_kind=dir with a project workspace_path, inspect the child task workspace fields.

Expected Behavior

  • SendResult(success=False) should be treated as a failed delivery, preserving or rewinding the notification cursor so the next notifier tick can retry.
  • Decomposed child tasks should inherit the root task's gateway notification subscriptions, so blocked/completed events reach the originating chat.
  • Decomposed child tasks should inherit a valid root dir workspace instead of defaulting to scratch when the root task is explicitly scoped to a persistent project directory.

Actual Behavior

  • SendResult(success=False) is currently logged as delivered and the event cursor is advanced, so the notification is lost.
  • Decomposed child tasks have no notify subscriptions, so child blocked/completed events are silent.
  • Decomposed child tasks are inserted as workspace_kind='scratch' with workspace_path=NULL even when the root task uses a persistent dir workspace.

Affected Component

Gateway (Telegram/Discord/Slack/WhatsApp), CLI (interactive chat)

Messaging Platform (if gateway-related)

DingTalk observed locally; the SendResult soft-failure path is platform-agnostic.

Debug Report

Not uploaded. This was reproduced with focused local regression tests against the current codebase.

Operating System

macOS

Python Version

Python 3.14.3 in the local test venv

Hermes Version

Current main as of 2026-05-25.

Root Cause Analysis

  • gateway/run.py::_kanban_notifier_watcher calls await adapter.send(...) but does not inspect the returned SendResult. Exceptions are handled, but soft failures are not.
  • hermes_cli/kanban_db.py::decompose_triage_task() inserts child task rows directly with workspace_kind='scratch' and without copying any kanban_notify_subs rows from the root task.

Proposed Fix

I have a local tested patch ready that:

  • checks SendResult.success in _kanban_notifier_watcher and routes success=False through the existing failure/rewind path;
  • copies root notify subscriptions to each decomposed child task;
  • preserves root workspace_kind='dir' + workspace_path for decomposed child tasks;
  • adds regression tests for all three cases.

Validation run locally:

  • scripts/run_tests.sh tests/gateway/test_kanban_notifier.py tests/hermes_cli/test_kanban_notify.py tests/hermes_cli/test_kanban_decompose_db.py tests/hermes_cli/test_kanban_decompose.py tests/hermes_cli/test_kanban_db.py -- -q => 210 passed
  • scripts/run_tests.sh tests/hermes_cli/test_kanban_core_functionality.py -- -q => 164 passed
  • uv run --extra dev ruff check gateway/run.py hermes_cli/kanban_db.py tests/gateway/test_kanban_notifier.py tests/hermes_cli/test_kanban_decompose_db.py => All checks passed
  • git diff --check => clean

Are you willing to submit a PR for this?

  • I'd like to fix this myself and submit a PR

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING