Skip to content

fix(photon): do not retry shared-line 'Target not allowed' outbound rejections (#51897) - #61464

Closed
Sahil-SS9 wants to merge 1 commit into
NousResearch:mainfrom
Sahil-SS9:fix/issue-51897-photon-shared-line-outbound
Closed

fix(photon): do not retry shared-line 'Target not allowed' outbound rejections (#51897)#61464
Sahil-SS9 wants to merge 1 commit into
NousResearch:mainfrom
Sahil-SS9:fix/issue-51897-photon-shared-line-outbound

Conversation

@Sahil-SS9

Copy link
Copy Markdown
Contributor

Fixes #51897

Description

Photon's free shared-line pool rejects outbound sends initiated by Hermes (e.g. cron-delivered messages) with Target not allowed for this project. This is a permanent upstream rejection, not a transient fault — yet _send_with_retry (and _standalone_send) logged the error, retried the same rejected target through its backoff loop, then downgraded to plain text and retried again, never recognizing the failure as final.

This PR:

  • Adds _PHOTON_FATAL_PATTERNS + a _is_fatal_error() classifier for permanent rejections (shared-line / free-tier Target not allowed, not allowed for this project, etc.).
  • Short-circuits _send_with_retry on a fatal error: no retry loop, no plain-text downgrade — the failure is surfaced once.
  • In _standalone_send (cron path), returns a clear message explaining the shared/free-tier limitation and suggesting an alternate delivery channel.
  • Documents the free-tier outbound limitation in the Photon user guide.

Transient errors (e.g. reset reason: overflow) still retry exactly as before (#50185 behavior preserved).

Verification

  • New focused tests in tests/plugins/platforms/photon/test_shared_line_outbound.py:
    • fatal rejection strings are classified correctly; transient strings are not.
    • send path short-circuits with exactly one attempt on shared-line rejection.
    • transient overflow still exercises the retry/backoff path (regression guard).
  • Full Photon suite: pytest tests/plugins/platforms/photon/ → 118 passed.
  • Quality gates: secrets clean, personal refs clean, conventional commit, diff scoped to 3 files.

@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/plugins Plugin system and bundled plugins sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages labels Jul 9, 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: COMMENT (high surface area)

What the PR Does

Do not retry shared-line 'Target not allowed' outbound rejections.

Assessment

  • High surface area: ~169 additions, 1 file.
  • Correctness: Non-retry logic for specific rejection type. Human reviewer should verify the rejection classification is complete and correct.

Note: PR was previously unreviewed.


Reviewed by Hermes Agent

@Sahil-SS9
Sahil-SS9 force-pushed the fix/issue-51897-photon-shared-line-outbound branch from f103014 to 5473660 Compare July 10, 2026 09:37

@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 documenting the shared-line limitation and isolating the intended retry behavior. The code path needs rework before it can fix #51897.

Problems

  • plugins/platforms/photon/sidecar/index.mjs:735 sends through space.send(), but its outer catch returns the generic internal sidecar error response (:844-850). plugins/platforms/photon/adapter.py:98 treats that generic text as retryable. Therefore the new raw-text check at adapter.py:1452 cannot observe Target not allowed; the added test bypasses this boundary by mocking _sidecar_send() with the raw upstream text.
  • The cron paths do not reach the added handling: tools/send_message_tool.py:727 calls adapter.send() directly, and standalone delivery returns on a non-200 response at plugins/platforms/photon/adapter.py:1702-1703 before either changed data.get("ok") branch.

Suggested changes

  • Return a safe structured sidecar error code for this specific rejection, without exposing raw provider errors, and consume it in both delivery paths. Add tests for that real HTTP contract.

Automated hermes-sweeper review.

@@ -1424,6 +1452,13 @@ async def _send_with_retry(
return result

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 classifier will not see the reported provider text in production: space.send() exceptions are converted by sidecar/index.mjs to HTTP 500 with error: "internal sidecar error", which the existing retryable-pattern list matches. Please propagate a safe structured rejection code from the sidecar and classify that instead.

@@ -1703,7 +1738,18 @@ async def _standalone_send(
return {"error": f"sidecar returned {resp.status_code}: {resp.text[:200]}"}

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.

The actual upstream rejection is an HTTP 500, so _standalone_send() returns at the preceding resp.status_code != 200 branch. This new data.get("ok") branch is not reached for the reported failure.

@teknium1 teknium1 added the sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users label Jul 11, 2026
@teknium1

Copy link
Copy Markdown
Contributor

Closing — right intent, but the pattern-matching couldn't fire in practice: the sidecar collapsed upstream errors to a generic 500 before your adapter-side patterns ever saw the text. The fix had to start sidecar-side: #73563 added a structured target_not_allowed error class emitted by the sidecar and classified non-retryable in both send paths, with a clear shared-line message. Thanks — the issue you targeted (#51897) is now surfaced cleanly and documented.

@teknium1 teknium1 closed this Jul 29, 2026
@Sahil-SS9
Sahil-SS9 deleted the fix/issue-51897-photon-shared-line-outbound branch August 2, 2026 08:01
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 sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users 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.

Photon: shared/free-tier lines cannot send outbound cron deliveries (Target not allowed)

4 participants