Skip to content

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

Closed

Description

@Birfy

#954/#961 stopped the new permanent-failure card from offering Retry, but the button is still there — including for a failure that happened today on a build that has #961. The render is not right: two of the three failed-card surfaces never look at the flag at all, and #961 only fixed the third.

Evidence (reproduced on 2ab9e392)

One rule, three surfaces, two spellings:

surface file what it checks
social dock plugins/social/client.js:1979-1982 item.retry === false — correct, fixed by #961
chat-bubble card core/src/client/held-reply.js:52-54 (data-flybot="held-reply-actions") status === 'failed' only
dock card core/src/client/flybot-slots.js:287 / :297 status === 'failed' only

The flag does exist and is written correctly:

  • core/src/host/hooks.js:470 — if (error?.noRetry === true) approval.noRetry = true, stored with the record.
  • core/src/host/hooks.js:509 — ...(a.noRetry === true ? { retry: false } : {}), so heldReplies carries retry: false.

The two core cards simply never read it. What makes this easy to half-fix is that the same rule arrives under two field names: the dock gets the raw approval (noRetry: true), the bubble gets heldReplies (retry: false).

A second, smaller subset: a failure recorded by a build before #961 has no noRetry in the record, so no reader can derive it. That subset is unavoidable and is not the main defect — the main defect is that today's failures still get the button because the two core surfaces ignore the flag.

Expected

A failed card whose reason is terminal never draws Retry, on any of the three surfaces, whether the failure happened today or three builds ago. The decision "this can never succeed" is made in one place and both the writer and the view read it.

Hard requirement

One predicate, both spellings. canRetry(record) (or a normalisation at the producer so both noRetry and retry collapse into one shape before any renderer sees it) must be the single decision used by all three surfaces. Fixing held-reply.js while leaving flybot-slots.js alone — or the reverse — is a half fix and will be sent back.

For the pre-#961 records, derive the terminal answer from the stored error text at view time (the reasons are already sentences: "is no longer shared with you … Ask its owner for a new invite", bot_not_found). No state migration, and the derivation lives inside the same predicate, not a second copy of the string list.

Acceptance

  1. A new failure with a terminal reason (record has noRetry: true) renders with no Retry on all three surfaces — bubble card, dock card, social dock.
  2. The same is true for a record that reaches the view as heldReplies (retry: false): both spellings take the same branch.
  3. A persisted failed hold written before #961 (fixture: status: 'failed', error "… is no longer shared with you … Ask its owner for a new invite.", no noRetry) renders with no Retry.
  4. A failed hold with a retryable reason (429 / timeout / paused) still renders Retry on all three surfaces — the negative control.
  5. Only one copy of the terminal/retryable decision exists in the tree; no renderer re-implements it and no reason string is matched in two files.
  6. The approval view's shape does not change for other readers: heldRepliesOf keeps its fields, and no state migration is required.

Where

core/src/client/held-reply.js:52-54, core/src/client/flybot-slots.js:287/:297 (the actual fix), core/src/host/hooks.js:470/:509 (the flag and the predicate's home), plugins/social/client.js:1979-1982 (keeps working, may switch to the shared predicate). Any core/ file touched here must be mirrored byte-identically in patches/ds-bot/files/, and the mirror must be regenerated with hunk line numbers that a real git apply accepts.

Red proof

On 2ab9e392: a fixture that feeds both spellings of one terminal failure renders Retry in held-reply.js and in flybot-slots.js — two red — while a 429 record keeps Retry. Restoring only one of the two cards must leave exactly one red, which is how the half fix gets caught.

Dedupe

Not #954/#961: those changed what a new failure says and whether the social dock offers Retry; this is the other two surfaces plus the one-predicate requirement. Not #963 (looks) and not #955 (room hint text).

Activity

  1. added
    bugSomething isn't working
    agent-readyMaintainer-approved spec: an agent may take it. Only maintainers set this; never in a template
    area:uiWeb/desktop UI and copy
    area:socialFriends, invites, grants, Bot Social
    on Oct 24, 2026
  2. changed the title [-]Failed cards written before #961 keep a Retry that can never work: the render is right, the stored record has no flag[/-] [+]A failed card that can never succeed still offers Retry: two core cards never read the flag, and #961 fixed only the social dock[/+] on Oct 24, 2026
  3. Birfy commented on Oct 24, 2026

    @Birfy
    CollaboratorAuthor

    Claimed on fix/968-can-retry @ 78ec20a5 — PR #975.

    One predicate (core/src/shared/held-retry.js, canRetry) now decides the Retry button on all three surfaces: the chat bubble, the dock card, and the social plugin's own dock. Both spellings (noRetry: true on an approval, retry: false on a hold) go through it, and a record written before the flag existed is read from its stored error/code at render time — no migration. core/client.js rebuilt, patches/ds-bot/ regenerated.

  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 a commit that references this issue on Oct 24, 2026
  7. removed
    agent-readyMaintainer-approved spec: an agent may take it. Only maintainers set this; never in a template
    on Oct 24, 2026
  8. removed
    agent-workingAn agent has claimed this issue (the claim comment names the branch)
    on Oct 24, 2026
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 working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions