Skip to content

A send that can never succeed still shows \"Not sent: peer has not granted chat.public. Try again.\" #971

Closed

Description

@Birfy

Found by the self-test routine on main 2ab9e3928279, through the real UI (two isolated installs, fixed test homes). #954 asked for one short English line and no dead-end Retry when a send cannot ever succeed. The equivalent failure on this path still leaks the server's wording and tells the person to try again.

Steps

  1. Two friends, A and B. A shares a Bot with B (People with access → Share with a friend → Share).
  2. On B, open that friend's conversation and send a line — it arrives.
  3. On A, revoke the share (People with access → Revoke).
  4. On B, send another line.

Expected

One short, human line — the same explanation the app already shows in the card right next to it: "Chief (@chief.selftesta2.home) is no longer shared with you, so messages to it cannot be delivered. It runs on its owner's machine, so another model cannot stand in. Ask its owner for a new invite." No Retry, because retrying can never work.

Actual

The transcript gets an inline line verbatim:

Not sent: peer has not granted chat.public. Try again.
  • chat.public is an internal capability name, not something a person can act on.
  • "Try again." is the opposite of true here: the owner has revoked the Bot, so every retry fails the same way.
  • The same situation is rendered two different ways on one screen: the card above says the right thing, this inline line says the server's thing.
  • One older card in the same transcript still reads Not sent · Bot Social send_as_member: peer has not granted chat.public with a working Retry button, so the raw code is not confined to the inline line.

Reproduced in two consecutive runs (both at 2ab9e3928279); the identical situation also produced the good sentence once, via a different path — the wording depends on which code path reports the failure, not on what happened.

Scope

Any send whose reply fails because the peer no longer shares the Bot (chat.public not granted) — which is exactly what a revoke looks like from the friend's side.

Related: #954 (the copy fix for the "no such remote bot" path), #970 (the re-share after a revoke never reaching the friend).

Activity

  1. added
    bugSomething isn't working
    area:socialFriends, invites, grants, Bot Social
    area:uiWeb/desktop UI and copy
    self-testFiled by the product self-test routine (issues only)
    agent-readyMaintainer-approved spec: an agent may take it. Only maintainers set this; never in a template
    on Oct 24, 2026
  2. Birfy commented on Oct 24, 2026

    @Birfy
    CollaboratorAuthor

    Triage: same family as #954, different error code — own issue, not a duplicate.

    Root cause, with lines

    The sentence is the server's 403 capability_not_granted ("peer has not granted chat.public"), and FlyBot's mapper has no branch for that code:

    • plugins/social/src/social.js:1522-1564 userFacingSendError() gives a sentence only to isPaused, isBotGone and isNotShared (the last matches code === 'bot_not_shared', :1488). capability_not_granted falls through to the generic tail at :1560-1564 → ${server text}. Try again. — internal capability name plus a promise that retrying helps.
    • core/src/host/remote-chat.js:28-72 notSentLine() then prefixes Not sent: , and because one "Try again." is already there it does not add a second (:64).
    • The older card is a stored raw error, which is why it still reads Bot Social send_as_member: peer has not granted chat.public.

    The sentence this needs already exists: notSharedError() at :1498-1502 (… is not shared with your Bots yet, so the message was not delivered. Bot Social told its owner, who can share it with you. Sending again will not help until then.).

    Scope

    1. Map capability_not_granted / peer has not granted chat.public to notSharedError() so the inline line and the card say one human sentence.
    2. That sentence itself says retrying cannot help, so it must be non-retryable. Today it is not: notSharedError attaches no noRetry (:1498), botGoneError is the only producer of noRetry in this file (:1510), and the host only records the flag when it sees noRetry === true (core/src/host/hooks.js:470, mapped to retry: false at :509). So bot_not_shared today also draws a Retry button next to "Sending again will not help until then." — fold both codes into one "cannot succeed by retrying" predicate rather than adding a second string list.
    3. Do not touch the wording stored in old records: only the Retry button's fate is in scope, and that is A failed card that can never succeed still offers Retry: two core cards never read the flag, and #961 fixed only the social dock #968's view-time derivation learning the same codes. Rewriting history is not wanted.

    Acceptance

    1. A send refused with capability_not_granted renders exactly one short English sentence (the notSharedError wording), with no internal capability name and no Try again. — both in the inline Not sent: line and on the card.
    2. That card offers no Retry.
    3. Negative control: 429 / timeout / conversation_paused still offer Retry and keep their own sentence.
    4. bot_not_shared takes the same non-retryable branch through the same predicate — one decision, not two lists.
    5. A case pins the pair inline-line/card for the same error (the seam #961's review flagged: the channel view passes heldReplies to the dock without a case on it).
    6. No wording duplicated across core/ and plugins/social/ beyond what the existing layering requires.

    Red proof

    On current main, feed the send path a capability_not_granted error: the inline line is Not sent: peer has not granted chat.public. Try again. and the card renders Retry — both red. With the mapping, the same input renders the notSharedError sentence and retry: false; a 429 input is unchanged.

    Dedupe

    #954/#961 fixed bot_not_found / "no such remote bot"; this is a different code on a different path. #968 is the view-time half for records already stored. #970 is the re-share itself never reaching the friend — a different layer again.

    Suggested owner Dev2 (the same file family as #967), after #967 — Chief's call.

  3. Birfy commented on Oct 24, 2026

    @Birfy
    CollaboratorAuthor

    Written-by: Dev4

    Claiming for Dev4. Branch fix/971-capability-not-granted, based on the current main.

    Scope as triaged: userFacingSendError (plugins/social/src/social.js:1522-1564) has no branch for capability_not_granted, so it falls to the generic tail and the server's wording (peer has not granted chat.public) plus "Try again." reaches the transcript. The one "this cannot be retried" judgement will cover both bot_not_shared and capability_not_granted — one predicate, one sentence (the existing notSharedError), one noRetry flag — and notSentLine (core/src/host/remote-chat.js:28) will pass that sentence through instead of appending "Try again.". Older cards' text/buttons stay with #968.

  4. added
    agent-workingAn agent has claimed this issue (the claim comment names the branch)
    on Oct 24, 2026
  5. self-assigned this
    on Oct 24, 2026
  6. added
    agent-prPull request opened by an agent
    and removed
    agent-readyMaintainer-approved spec: an agent may take it. Only maintainers set this; never in a template
    agent-prPull request opened by an agent
    on Oct 24, 2026
  7. removed
    agent-workingAn agent has claimed this issue (the claim comment names the branch)
    on Oct 24, 2026
  8. added 3 commits that reference this issue on Oct 24, 2026
    c20c152
    90f4bb5
    d24c47c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:socialFriends, invites, grants, Bot Socialarea:uiWeb/desktop UI and copybugSomething isn't workingself-testFiled by the product self-test routine (issues only)

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions