Skip to content

Bot Social: the Auto-send hold guard is pass-through, silent on lag, and partly untested #766

Closed

Description

@Birfy

Follow-up to #737 / PR #758. Those three findings were recorded as non-blocking at review time; this issue tracks them.

1. The hold guard is written as pass-through, not allow-list

holdReasons(held) in plugins/social/src/ only recognises reasons starting with dlp. plus risk_flags. Any new reason name (for example policy.*) therefore counts as "no finding" and the send goes out without approval. PR #758 also widened the scope of this check from room messages to direct messages, so more traffic now depends on it.

Fix direction: flip it to an allow-list — only treat an approval request that is purely mvp.all_outbound_requires_approval as auto-clearable, and anything else as a hold. The face-room path shares this predicate; it had the same shape before but the exposure is larger now.

2. A lagging hold list fails silently

When the server has not listed the hold yet, the function returns false with no log and no reason, the message stays stuck, and nothing is written anywhere — which is exactly the symptom #737 was reported for. At minimum log a warn with the item id so the next report is diagnosable.

3. Two cache lines are not covered by any test

Deleting setPending(...) / pendingCache.at = 0 in the clear path still leaves the suite at 330/330. Either pin the behaviour with a test or delete the lines; dead untested state in an approval path is a trap for the next change.

Acceptance

  • A hold reason outside the documented allow-list refuses the send, with a test that goes red when the allow-list is widened.
  • A missing/lagging hold entry leaves a warn log line naming the item.
  • The two cache lines are either covered by a test or removed.

Activity

  1. added
    area:socialFriends, invites, grants, Bot Social
    bugSomething isn't working
    on Oct 22, 2026
  2. Birfy commented on Oct 22, 2026

    @Birfy
    CollaboratorAuthor

    Triaged bug + area:social (Triage). Not agent-ready yet, for a sequencing reason rather than a spec one: all three findings live in the same predicate and the same cache path that #758 (open, #737) is editing right now. A second branch against plugins/social/src/social.js today means both changes fight over one function and the review compares two half-states. When #758 merges I flip this to agent-ready, and the acceptance below is what the PR is judged against.

    Three notes that make it testable:

    Scope note: the face-room path shares the predicate, as the body says — if the fix touches it, the three acceptance items apply there too, or the PR names why not.

  3. Birfy commented on Oct 22, 2026

    @Birfy
    CollaboratorAuthor

    Written-by: Triage

    #758 is merged (59c5f13c), so the sequencing blocker is gone: this is now agent-ready. The three findings still exist on main d83d762d, re-checked at the line level rather than carried over:

    1. holdReasons() (plugins/social/src/social.js:105-116) collects a name only when it reads dlp.<x> (minus blocked) or a risk_flags category. Every other spelling is "no finding", and autoSendRemoteLine() (:1506-1525) approves at :1516 whenever holdReasons(held).length === 0. So policy.*, a renamed mvp.* reason, or any future server category clears the hold automatically.
    2. At the same :1516, !held (the server has not listed the hold yet) returns false with nothing logged; only a throw reaches the warn at :1522. That is the silent stuck message Auto-send on for a friend: the line never arrives — Bot Social outbound approval stays pending and no card exists #737 was reported for.
    3. The clear path still writes setPending(...) and pendingCache.at = 0 at :1518-1519 with no test that fails when they go.

    Acceptance — what the PR is judged against

    • Allow-list, not deny-list. An approval may be auto-cleared only when it is purely the blanket reason: every entry in reasons is mvp.all_outbound_requires_approval (that exact string, the one the tests already fixture at social.test.js:1382, :1446, :1678) and risk_flags is empty. Anything else holds, including a mixed list (['mvp.all_outbound_requires_approval', 'dlp.commitment']), an unknown policy.new_thing, an empty-but-unrecognised reason, and — decide it and say which — dlp.blocked, which :109 currently drops on the floor, so reasons: ['dlp.blocked'] today yields no finding and would be auto-approved.
    • The red is the widened allow-list. A test must go red when the guard is widened back to "any unknown reason passes"; enumerate the reasons in the test rather than deriving them from the code, or the red test is circular. Keep the intended behaviour green: the blanket-only hold is still auto-approved, or Auto-send stops working.
    • Lag is loud. When the just-sent approval is not in the listing yet, log a warn naming the approval id and do not approve; a test asserts the line, and that the item still lands on its card so the owner can decide it.
    • Cache lines: either a test that fails when setPending(...) / pendingCache.at = 0 in the clear path are deleted, or delete the two lines. Not both left untested.
    • plugins/social suite green at the tip, ## Reproduce naming the fixture shape (reasons + risk_flags), and the PR keeps the face-room path on the same predicate — it shares holdReasons.

    Not in scope: changing what Bot Social itself holds. This is the client's guard, the log line, and the two cache writes.

  4. added
    agent-readyMaintainer-approved spec: an agent may take it. Only maintainers set this; never in a template
    on Oct 22, 2026
  5. self-assigned this
    on Oct 22, 2026
  6. added
    agent-workingAn agent has claimed this issue (the claim comment names the branch)
    on Oct 22, 2026
  7. Birfy commented on Oct 22, 2026

    @Birfy
    CollaboratorAuthor

    Written-by: Dev

    Claiming this one. Branch: fix/766-auto-send-allow-list, from main d83d762d.

    Plan, one line per acceptance item:

    • The guard becomes an allow-list: a new holdIsBlanket(item) (exported next to holdReasons) returns true only when reasons is non-empty, every entry is exactly mvp.all_outbound_requires_approval, and risk_flags is empty. autoSendRemoteLine clears a hold only on that; any other name — dlp.* including dlp.blocked, policy.*, or a reason this build does not know — keeps the card. Test goes red when the predicate is widened back to "no known finding".
    • A hold the server has not listed yet gets a warn naming the approval id before the line waits on its card, with a test that captures the log.
    • The two cache lines in the clear path get a test each: setPending(...) is pinned through flybot.chatApprovals.changed() (the wait badge must drop without waiting for the next poll), pendingCache.at = 0 through the next status reading the server again instead of the cache it was just emptied into.
    • docs/subsystems/social.md gets the allow-list rule and the log line.

    No behaviour outside the hold guard moves; holdReasons (what the card says) stays as it is, so the card text does not change shape.

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

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions