Skip to content

fix(cron): fall through when live delivery is unconfirmed (#47056) - #47127

Closed
Tranquil-Flow wants to merge 1 commit into
NousResearch:mainfrom
Tranquil-Flow:fix/47056-cron-delivery-active
Closed

fix(cron): fall through when live delivery is unconfirmed (#47056)#47127
Tranquil-Flow wants to merge 1 commit into
NousResearch:mainfrom
Tranquil-Flow:fix/47056-cron-delivery-active

Conversation

@Tranquil-Flow

Copy link
Copy Markdown
Contributor

Summary

Fixes #47056.

Cron delivery via deliver: origin can silently drop output when the live gateway adapter returns None or an unexpected object without a success attribute. The previous check treated both shapes as successful delivery, logged delivered ... via live adapter, and skipped the standalone fallback even though the gateway never saw the message.

This patch:

  • adds _confirm_adapter_delivery() to require explicit adapter success confirmation
  • treats None, missing success, and success=False as unconfirmed delivery
  • falls through to the standalone HTTP delivery path when live delivery is unconfirmed
  • preserves the happy path for SendResult(success=True)
  • logs the result shape and error attribute for operator triage

Verification

RED proof on upstream/main:

tests/cron/test_scheduler.py::TestDeliverResultLiveAdapterSilentFailure::test_live_adapter_returning_none_falls_through_to_standalone FAILED
tests/cron/test_scheduler.py::TestDeliverResultLiveAdapterSilentFailure::test_live_adapter_returning_dict_without_success_falls_through FAILED
tests/cron/test_scheduler.py::TestDeliverResultLiveAdapterSilentFailure::test_live_adapter_returning_sendresult_success_is_accepted PASSED
tests/cron/test_scheduler.py::TestDeliverResultLiveAdapterSilentFailure::test_live_adapter_returning_sendresult_failure_falls_through PASSED

GREEN proof on this branch:

/Users/evinova-self/.hermes/hermes-agent/venv/bin/python3 -m pytest tests/cron/test_scheduler.py::TestDeliverResultLiveAdapterSilentFailure tests/cron/test_scheduler.py::TestDeliverResultTimeoutCancelsFuture -v -o "addopts=" --tb=short
# 6 passed in 0.13s

Nearby suite:

/Users/evinova-self/.hermes/hermes-agent/venv/bin/python3 -m pytest tests/cron/test_scheduler.py -q -o "addopts=" --tb=short
# 140 passed, 1 warning in 3.16s

Duplicate / competitor check

Before publication, I checked:

  • open Tranquil-Flow PRs referencing 47056: none
  • open Tranquil-Flow branches matching fix/47056*: none
  • open PRs mentioning issue 47056: none
  • open PRs matching distinctive keywords cron delivery active session: none

No competing PR was found.

Auto-published by Moonsong via Path B automated pipeline.

…firmed result (NousResearch#47056)

When a cron job completes while the user has an active conversation, the
live adapter's send() can return None (e.g. swallowed exception, busy
platform) or a non-SendResult object missing a 'success' attribute.  The
previous check if send_result and not getattr(send_result, 'success',
True): silently treated both shapes as success — the scheduler logged
"delivered to <chat> via live adapter" while the gateway never saw
the message, permanently losing cron output.

Replace the condition with a strict confirmation helper that requires an
explicit success attribute set to a truthy value.  When the live
adapter cannot confirm delivery, fall through to the standalone HTTP
path so the message still reaches the chat.

Regression tests cover all four shapes:
- send() returns None              → fall through to standalone
- send() returns dict w/o success   → fall through to standalone
- send() returns SendResult(True)   → accepted as delivered
- send() returns SendResult(False)  → fall through (pre-existing behavior)

Closes NousResearch#47056
@Tranquil-Flow
Tranquil-Flow force-pushed the fix/47056-cron-delivery-active branch from 01ad864 to cb51491 Compare June 16, 2026 08:23
@alt-glitch alt-glitch added type/bug Something isn't working comp/cron Cron scheduler and job management P1 High — major feature broken, no workaround labels Jun 16, 2026
kshitijk4poor pushed a commit that referenced this pull request Jun 21, 2026
…47056, #43014)

Consolidates three cron-delivery defects in cron/scheduler.py::_deliver_result
that all stem from how the live-adapter send result is interpreted.

#38922 — duplicate message on confirmation timeout.
  future.result(timeout=60) raising TimeoutError bubbled to the outer
  except handler, which left delivered=False, so `if not delivered:` re-sent
  the identical message via the standalone path. future.cancel() cannot
  un-send a request already in flight on the wire, so a slow confirmation
  deterministically produced a duplicate. The send was already dispatched onto
  the gateway loop, so a bare timeout is now treated as delivered
  (assume-delivered is safer than guaranteed-duplicate) and the standalone
  fallback is skipped. The live-adapter media attempt is also skipped on
  timeout since the contended loop would re-block each 30s media budget.

#47056 — silent drop when the gateway has an active session.
  The old check `if send_result is None or not getattr(send_result,
  "success", True)` let a result object missing a `success` attribute default
  to True = counted as a successful delivery, so the scheduler logged
  "delivered via live adapter" while the gateway never processed the message.
  Delivery is now confirmed via _confirm_adapter_delivery(): only an explicit,
  truthy `success` attribute counts; None or a `success`-less object falls
  through to the standalone path so the message actually arrives.

  A genuine send Exception (not a slow confirmation) still falls through to
  the standalone path, and is caught by run_job's outer handler — it is
  recorded as the job's last_error and never crashes the cron ticker.

#43014 — deliver=origin fails to resolve in CLI sessions.
  A CLI-created job has no {platform, chat_id} origin, so deliver=origin (and
  auto-detect / deliver=None) was unresolvable and emitted "no delivery target
  resolved" on every run. An unresolvable origin with no configured home
  channel is now treated as local (output stays in last_output), matching the
  documented auto-deliver contract; a concrete unresolvable platform target
  still reports a real error.

Salvaged from #41007 (timeout discriminator), folding in #47127's
_confirm_adapter_delivery hardening and #38937 / #43063's origin→local
fallback. Tests rewritten as behavior contracts (timeout => no duplicate;
None / success-less result => standalone fallback; confirmed success => no
fallback; CLI origin => local, explicit platform => still errors).

Co-authored-by: Evi Nova <66773372+Tranquil-Flow@users.noreply.github.com>
Co-authored-by: kyssta-exe <kyssta-exe@users.noreply.github.com>
@kshitijk4poor

Copy link
Copy Markdown
Collaborator

Thanks — your _confirm_adapter_delivery hardening (a None / success-less adapter result must not count as a confirmed delivery) is exactly right and is now on main in #50018 (02a3288), with you credited as a co-author. Closing as superseded — appreciated.

kpadilha pushed a commit to kpadilha/hermes-agent that referenced this pull request Jun 24, 2026
…arch#38922, NousResearch#47056, NousResearch#43014)

Consolidates three cron-delivery defects in cron/scheduler.py::_deliver_result
that all stem from how the live-adapter send result is interpreted.

NousResearch#38922 — duplicate message on confirmation timeout.
  future.result(timeout=60) raising TimeoutError bubbled to the outer
  except handler, which left delivered=False, so `if not delivered:` re-sent
  the identical message via the standalone path. future.cancel() cannot
  un-send a request already in flight on the wire, so a slow confirmation
  deterministically produced a duplicate. The send was already dispatched onto
  the gateway loop, so a bare timeout is now treated as delivered
  (assume-delivered is safer than guaranteed-duplicate) and the standalone
  fallback is skipped. The live-adapter media attempt is also skipped on
  timeout since the contended loop would re-block each 30s media budget.

NousResearch#47056 — silent drop when the gateway has an active session.
  The old check `if send_result is None or not getattr(send_result,
  "success", True)` let a result object missing a `success` attribute default
  to True = counted as a successful delivery, so the scheduler logged
  "delivered via live adapter" while the gateway never processed the message.
  Delivery is now confirmed via _confirm_adapter_delivery(): only an explicit,
  truthy `success` attribute counts; None or a `success`-less object falls
  through to the standalone path so the message actually arrives.

  A genuine send Exception (not a slow confirmation) still falls through to
  the standalone path, and is caught by run_job's outer handler — it is
  recorded as the job's last_error and never crashes the cron ticker.

NousResearch#43014 — deliver=origin fails to resolve in CLI sessions.
  A CLI-created job has no {platform, chat_id} origin, so deliver=origin (and
  auto-detect / deliver=None) was unresolvable and emitted "no delivery target
  resolved" on every run. An unresolvable origin with no configured home
  channel is now treated as local (output stays in last_output), matching the
  documented auto-deliver contract; a concrete unresolvable platform target
  still reports a real error.

Salvaged from NousResearch#41007 (timeout discriminator), folding in NousResearch#47127's
_confirm_adapter_delivery hardening and NousResearch#38937 / NousResearch#43063's origin→local
fallback. Tests rewritten as behavior contracts (timeout => no duplicate;
None / success-less result => standalone fallback; confirmed success => no
fallback; CLI origin => local, explicit platform => still errors).

Co-authored-by: Evi Nova <66773372+Tranquil-Flow@users.noreply.github.com>
Co-authored-by: kyssta-exe <kyssta-exe@users.noreply.github.com>
pai-scaffolde pushed a commit to pai-scaffolde/hermes-agent that referenced this pull request Jun 28, 2026
…arch#38922, NousResearch#47056, NousResearch#43014)

Consolidates three cron-delivery defects in cron/scheduler.py::_deliver_result
that all stem from how the live-adapter send result is interpreted.

NousResearch#38922 — duplicate message on confirmation timeout.
  future.result(timeout=60) raising TimeoutError bubbled to the outer
  except handler, which left delivered=False, so `if not delivered:` re-sent
  the identical message via the standalone path. future.cancel() cannot
  un-send a request already in flight on the wire, so a slow confirmation
  deterministically produced a duplicate. The send was already dispatched onto
  the gateway loop, so a bare timeout is now treated as delivered
  (assume-delivered is safer than guaranteed-duplicate) and the standalone
  fallback is skipped. The live-adapter media attempt is also skipped on
  timeout since the contended loop would re-block each 30s media budget.

NousResearch#47056 — silent drop when the gateway has an active session.
  The old check `if send_result is None or not getattr(send_result,
  "success", True)` let a result object missing a `success` attribute default
  to True = counted as a successful delivery, so the scheduler logged
  "delivered via live adapter" while the gateway never processed the message.
  Delivery is now confirmed via _confirm_adapter_delivery(): only an explicit,
  truthy `success` attribute counts; None or a `success`-less object falls
  through to the standalone path so the message actually arrives.

  A genuine send Exception (not a slow confirmation) still falls through to
  the standalone path, and is caught by run_job's outer handler — it is
  recorded as the job's last_error and never crashes the cron ticker.

NousResearch#43014 — deliver=origin fails to resolve in CLI sessions.
  A CLI-created job has no {platform, chat_id} origin, so deliver=origin (and
  auto-detect / deliver=None) was unresolvable and emitted "no delivery target
  resolved" on every run. An unresolvable origin with no configured home
  channel is now treated as local (output stays in last_output), matching the
  documented auto-deliver contract; a concrete unresolvable platform target
  still reports a real error.

Salvaged from NousResearch#41007 (timeout discriminator), folding in NousResearch#47127's
_confirm_adapter_delivery hardening and NousResearch#38937 / NousResearch#43063's origin→local
fallback. Tests rewritten as behavior contracts (timeout => no duplicate;
None / success-less result => standalone fallback; confirmed success => no
fallback; CLI origin => local, explicit platform => still errors).

Co-authored-by: Evi Nova <66773372+Tranquil-Flow@users.noreply.github.com>
Co-authored-by: kyssta-exe <kyssta-exe@users.noreply.github.com>
indigokarasu pushed a commit to indigokarasu/hermes-agent that referenced this pull request Jul 1, 2026
…arch#38922, NousResearch#47056, NousResearch#43014)

Consolidates three cron-delivery defects in cron/scheduler.py::_deliver_result
that all stem from how the live-adapter send result is interpreted.

NousResearch#38922 — duplicate message on confirmation timeout.
  future.result(timeout=60) raising TimeoutError bubbled to the outer
  except handler, which left delivered=False, so `if not delivered:` re-sent
  the identical message via the standalone path. future.cancel() cannot
  un-send a request already in flight on the wire, so a slow confirmation
  deterministically produced a duplicate. The send was already dispatched onto
  the gateway loop, so a bare timeout is now treated as delivered
  (assume-delivered is safer than guaranteed-duplicate) and the standalone
  fallback is skipped. The live-adapter media attempt is also skipped on
  timeout since the contended loop would re-block each 30s media budget.

NousResearch#47056 — silent drop when the gateway has an active session.
  The old check `if send_result is None or not getattr(send_result,
  "success", True)` let a result object missing a `success` attribute default
  to True = counted as a successful delivery, so the scheduler logged
  "delivered via live adapter" while the gateway never processed the message.
  Delivery is now confirmed via _confirm_adapter_delivery(): only an explicit,
  truthy `success` attribute counts; None or a `success`-less object falls
  through to the standalone path so the message actually arrives.

  A genuine send Exception (not a slow confirmation) still falls through to
  the standalone path, and is caught by run_job's outer handler — it is
  recorded as the job's last_error and never crashes the cron ticker.

NousResearch#43014 — deliver=origin fails to resolve in CLI sessions.
  A CLI-created job has no {platform, chat_id} origin, so deliver=origin (and
  auto-detect / deliver=None) was unresolvable and emitted "no delivery target
  resolved" on every run. An unresolvable origin with no configured home
  channel is now treated as local (output stays in last_output), matching the
  documented auto-deliver contract; a concrete unresolvable platform target
  still reports a real error.

Salvaged from NousResearch#41007 (timeout discriminator), folding in NousResearch#47127's
_confirm_adapter_delivery hardening and NousResearch#38937 / NousResearch#43063's origin→local
fallback. Tests rewritten as behavior contracts (timeout => no duplicate;
None / success-less result => standalone fallback; confirmed success => no
fallback; CLI origin => local, explicit platform => still errors).

Co-authored-by: Evi Nova <66773372+Tranquil-Flow@users.noreply.github.com>
Co-authored-by: kyssta-exe <kyssta-exe@users.noreply.github.com>
waefrebeorn pushed a commit to waefrebeorn/slermes that referenced this pull request Jul 2, 2026
…arch#38922, NousResearch#47056, NousResearch#43014)

Consolidates three cron-delivery defects in cron/scheduler.py::_deliver_result
that all stem from how the live-adapter send result is interpreted.

NousResearch#38922 — duplicate message on confirmation timeout.
  future.result(timeout=60) raising TimeoutError bubbled to the outer
  except handler, which left delivered=False, so `if not delivered:` re-sent
  the identical message via the standalone path. future.cancel() cannot
  un-send a request already in flight on the wire, so a slow confirmation
  deterministically produced a duplicate. The send was already dispatched onto
  the gateway loop, so a bare timeout is now treated as delivered
  (assume-delivered is safer than guaranteed-duplicate) and the standalone
  fallback is skipped. The live-adapter media attempt is also skipped on
  timeout since the contended loop would re-block each 30s media budget.

NousResearch#47056 — silent drop when the gateway has an active session.
  The old check `if send_result is None or not getattr(send_result,
  "success", True)` let a result object missing a `success` attribute default
  to True = counted as a successful delivery, so the scheduler logged
  "delivered via live adapter" while the gateway never processed the message.
  Delivery is now confirmed via _confirm_adapter_delivery(): only an explicit,
  truthy `success` attribute counts; None or a `success`-less object falls
  through to the standalone path so the message actually arrives.

  A genuine send Exception (not a slow confirmation) still falls through to
  the standalone path, and is caught by run_job's outer handler — it is
  recorded as the job's last_error and never crashes the cron ticker.

NousResearch#43014 — deliver=origin fails to resolve in CLI sessions.
  A CLI-created job has no {platform, chat_id} origin, so deliver=origin (and
  auto-detect / deliver=None) was unresolvable and emitted "no delivery target
  resolved" on every run. An unresolvable origin with no configured home
  channel is now treated as local (output stays in last_output), matching the
  documented auto-deliver contract; a concrete unresolvable platform target
  still reports a real error.

Salvaged from NousResearch#41007 (timeout discriminator), folding in NousResearch#47127's
_confirm_adapter_delivery hardening and NousResearch#38937 / NousResearch#43063's origin→local
fallback. Tests rewritten as behavior contracts (timeout => no duplicate;
None / success-less result => standalone fallback; confirmed success => no
fallback; CLI origin => local, explicit platform => still errors).

Co-authored-by: Evi Nova <66773372+Tranquil-Flow@users.noreply.github.com>
Co-authored-by: kyssta-exe <kyssta-exe@users.noreply.github.com>
habarmc1223-sudo pushed a commit to habarmc1223-sudo/hermes-agent-fluxmem that referenced this pull request Jul 8, 2026
…arch#38922, NousResearch#47056, NousResearch#43014)

Consolidates three cron-delivery defects in cron/scheduler.py::_deliver_result
that all stem from how the live-adapter send result is interpreted.

NousResearch#38922 — duplicate message on confirmation timeout.
  future.result(timeout=60) raising TimeoutError bubbled to the outer
  except handler, which left delivered=False, so `if not delivered:` re-sent
  the identical message via the standalone path. future.cancel() cannot
  un-send a request already in flight on the wire, so a slow confirmation
  deterministically produced a duplicate. The send was already dispatched onto
  the gateway loop, so a bare timeout is now treated as delivered
  (assume-delivered is safer than guaranteed-duplicate) and the standalone
  fallback is skipped. The live-adapter media attempt is also skipped on
  timeout since the contended loop would re-block each 30s media budget.

NousResearch#47056 — silent drop when the gateway has an active session.
  The old check `if send_result is None or not getattr(send_result,
  "success", True)` let a result object missing a `success` attribute default
  to True = counted as a successful delivery, so the scheduler logged
  "delivered via live adapter" while the gateway never processed the message.
  Delivery is now confirmed via _confirm_adapter_delivery(): only an explicit,
  truthy `success` attribute counts; None or a `success`-less object falls
  through to the standalone path so the message actually arrives.

  A genuine send Exception (not a slow confirmation) still falls through to
  the standalone path, and is caught by run_job's outer handler — it is
  recorded as the job's last_error and never crashes the cron ticker.

NousResearch#43014 — deliver=origin fails to resolve in CLI sessions.
  A CLI-created job has no {platform, chat_id} origin, so deliver=origin (and
  auto-detect / deliver=None) was unresolvable and emitted "no delivery target
  resolved" on every run. An unresolvable origin with no configured home
  channel is now treated as local (output stays in last_output), matching the
  documented auto-deliver contract; a concrete unresolvable platform target
  still reports a real error.

Salvaged from NousResearch#41007 (timeout discriminator), folding in NousResearch#47127's
_confirm_adapter_delivery hardening and NousResearch#38937 / NousResearch#43063's origin→local
fallback. Tests rewritten as behavior contracts (timeout => no duplicate;
None / success-less result => standalone fallback; confirmed success => no
fallback; CLI origin => local, explicit platform => still errors).

Co-authored-by: Evi Nova <66773372+Tranquil-Flow@users.noreply.github.com>
Co-authored-by: kyssta-exe <kyssta-exe@users.noreply.github.com>
santhreal pushed a commit to santhreal/hermes-agent that referenced this pull request Jul 13, 2026
…arch#38922, NousResearch#47056, NousResearch#43014)

Consolidates three cron-delivery defects in cron/scheduler.py::_deliver_result
that all stem from how the live-adapter send result is interpreted.

NousResearch#38922 — duplicate message on confirmation timeout.
  future.result(timeout=60) raising TimeoutError bubbled to the outer
  except handler, which left delivered=False, so `if not delivered:` re-sent
  the identical message via the standalone path. future.cancel() cannot
  un-send a request already in flight on the wire, so a slow confirmation
  deterministically produced a duplicate. The send was already dispatched onto
  the gateway loop, so a bare timeout is now treated as delivered
  (assume-delivered is safer than guaranteed-duplicate) and the standalone
  fallback is skipped. The live-adapter media attempt is also skipped on
  timeout since the contended loop would re-block each 30s media budget.

NousResearch#47056 — silent drop when the gateway has an active session.
  The old check `if send_result is None or not getattr(send_result,
  "success", True)` let a result object missing a `success` attribute default
  to True = counted as a successful delivery, so the scheduler logged
  "delivered via live adapter" while the gateway never processed the message.
  Delivery is now confirmed via _confirm_adapter_delivery(): only an explicit,
  truthy `success` attribute counts; None or a `success`-less object falls
  through to the standalone path so the message actually arrives.

  A genuine send Exception (not a slow confirmation) still falls through to
  the standalone path, and is caught by run_job's outer handler — it is
  recorded as the job's last_error and never crashes the cron ticker.

NousResearch#43014 — deliver=origin fails to resolve in CLI sessions.
  A CLI-created job has no {platform, chat_id} origin, so deliver=origin (and
  auto-detect / deliver=None) was unresolvable and emitted "no delivery target
  resolved" on every run. An unresolvable origin with no configured home
  channel is now treated as local (output stays in last_output), matching the
  documented auto-deliver contract; a concrete unresolvable platform target
  still reports a real error.

Salvaged from NousResearch#41007 (timeout discriminator), folding in NousResearch#47127's
_confirm_adapter_delivery hardening and NousResearch#38937 / NousResearch#43063's origin→local
fallback. Tests rewritten as behavior contracts (timeout => no duplicate;
None / success-less result => standalone fallback; confirmed success => no
fallback; CLI origin => local, explicit platform => still errors).

Co-authored-by: Evi Nova <66773372+Tranquil-Flow@users.noreply.github.com>
Co-authored-by: kyssta-exe <kyssta-exe@users.noreply.github.com>
Gravezzz pushed a commit to Gravezzz/hermes-agent that referenced this pull request Jul 21, 2026
…arch#38922, NousResearch#47056, NousResearch#43014)

Consolidates three cron-delivery defects in cron/scheduler.py::_deliver_result
that all stem from how the live-adapter send result is interpreted.

NousResearch#38922 — duplicate message on confirmation timeout.
  future.result(timeout=60) raising TimeoutError bubbled to the outer
  except handler, which left delivered=False, so `if not delivered:` re-sent
  the identical message via the standalone path. future.cancel() cannot
  un-send a request already in flight on the wire, so a slow confirmation
  deterministically produced a duplicate. The send was already dispatched onto
  the gateway loop, so a bare timeout is now treated as delivered
  (assume-delivered is safer than guaranteed-duplicate) and the standalone
  fallback is skipped. The live-adapter media attempt is also skipped on
  timeout since the contended loop would re-block each 30s media budget.

NousResearch#47056 — silent drop when the gateway has an active session.
  The old check `if send_result is None or not getattr(send_result,
  "success", True)` let a result object missing a `success` attribute default
  to True = counted as a successful delivery, so the scheduler logged
  "delivered via live adapter" while the gateway never processed the message.
  Delivery is now confirmed via _confirm_adapter_delivery(): only an explicit,
  truthy `success` attribute counts; None or a `success`-less object falls
  through to the standalone path so the message actually arrives.

  A genuine send Exception (not a slow confirmation) still falls through to
  the standalone path, and is caught by run_job's outer handler — it is
  recorded as the job's last_error and never crashes the cron ticker.

NousResearch#43014 — deliver=origin fails to resolve in CLI sessions.
  A CLI-created job has no {platform, chat_id} origin, so deliver=origin (and
  auto-detect / deliver=None) was unresolvable and emitted "no delivery target
  resolved" on every run. An unresolvable origin with no configured home
  channel is now treated as local (output stays in last_output), matching the
  documented auto-deliver contract; a concrete unresolvable platform target
  still reports a real error.

Salvaged from NousResearch#41007 (timeout discriminator), folding in NousResearch#47127's
_confirm_adapter_delivery hardening and NousResearch#38937 / NousResearch#43063's origin→local
fallback. Tests rewritten as behavior contracts (timeout => no duplicate;
None / success-less result => standalone fallback; confirmed success => no
fallback; CLI origin => local, explicit platform => still errors).

Co-authored-by: Evi Nova <66773372+Tranquil-Flow@users.noreply.github.com>
Co-authored-by: kyssta-exe <kyssta-exe@users.noreply.github.com>
leewenjie pushed a commit to leewenjie/hermes-agent that referenced this pull request Aug 7, 2026
…arch#38922, NousResearch#47056, NousResearch#43014)

Consolidates three cron-delivery defects in cron/scheduler.py::_deliver_result
that all stem from how the live-adapter send result is interpreted.

NousResearch#38922 — duplicate message on confirmation timeout.
  future.result(timeout=60) raising TimeoutError bubbled to the outer
  except handler, which left delivered=False, so `if not delivered:` re-sent
  the identical message via the standalone path. future.cancel() cannot
  un-send a request already in flight on the wire, so a slow confirmation
  deterministically produced a duplicate. The send was already dispatched onto
  the gateway loop, so a bare timeout is now treated as delivered
  (assume-delivered is safer than guaranteed-duplicate) and the standalone
  fallback is skipped. The live-adapter media attempt is also skipped on
  timeout since the contended loop would re-block each 30s media budget.

NousResearch#47056 — silent drop when the gateway has an active session.
  The old check `if send_result is None or not getattr(send_result,
  "success", True)` let a result object missing a `success` attribute default
  to True = counted as a successful delivery, so the scheduler logged
  "delivered via live adapter" while the gateway never processed the message.
  Delivery is now confirmed via _confirm_adapter_delivery(): only an explicit,
  truthy `success` attribute counts; None or a `success`-less object falls
  through to the standalone path so the message actually arrives.

  A genuine send Exception (not a slow confirmation) still falls through to
  the standalone path, and is caught by run_job's outer handler — it is
  recorded as the job's last_error and never crashes the cron ticker.

NousResearch#43014 — deliver=origin fails to resolve in CLI sessions.
  A CLI-created job has no {platform, chat_id} origin, so deliver=origin (and
  auto-detect / deliver=None) was unresolvable and emitted "no delivery target
  resolved" on every run. An unresolvable origin with no configured home
  channel is now treated as local (output stays in last_output), matching the
  documented auto-deliver contract; a concrete unresolvable platform target
  still reports a real error.

Salvaged from NousResearch#41007 (timeout discriminator), folding in NousResearch#47127's
_confirm_adapter_delivery hardening and NousResearch#38937 / NousResearch#43063's origin→local
fallback. Tests rewritten as behavior contracts (timeout => no duplicate;
None / success-less result => standalone fallback; confirmed success => no
fallback; CLI origin => local, explicit platform => still errors).

Co-authored-by: Evi Nova <66773372+Tranquil-Flow@users.noreply.github.com>
Co-authored-by: kyssta-exe <kyssta-exe@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cron Cron scheduler and job management P1 High — major feature broken, no workaround type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Cron delivery silently dropped when gateway has active user session (origin delivery)

3 participants