Skip to content

feat(discord): proactive text send-leg through the shared DeliveryProvider (5b stage 1) - #3098

Merged
qingyun-wu merged 1 commit into
feat/discord-delivery-providerfrom
feat/discord-proactive-provider
Aug 18, 2026
Merged

qingyun-wu merged 1 commit into
feat/discord-delivery-providerfrom
feat/discord-proactive-provider

Conversation

@qingyun-wu

Copy link
Copy Markdown
Collaborator

Stacked on #3095 (feat/discord-delivery-provider). Merge order: #3091 → #3092 → #3094 → #3095 → this. Child-only layer: pr3095..HEAD, 3 files, +187/−6.

What

Stage 1 of migrating poll_proactive behind the delivery-core seam: the text send-leg only. The bridge keeps claim/retry orchestration — the proactive-*.txt .sending claim protocol is shared by the discord/telegram/slack bridges on the same files, so moving claiming requires a cross-bridge migration fence (single-protocol-per-epoch); that is deliberately out of this PR. Attachments stay on the WS client (the provider has no file surface yet).

  • src/discord_proactive_send.py — deliver_text(provider, channel_id, text, item_id, chunker): per-chunk delivery through DiscordDeliveryProvider, per-chunk idempotency keys ({item}#{i}).
  • Receipt → exception mapping, chosen to make duplicate sends structurally hard:
    • OUTCOME_UNKNOWN → send_failure_policy.UnconfirmedDelivery — the policy's capped-transient class (bounded retry visible to the bridge's attempt budget, then park). This replaces the old WS behavior where a timeout looked like a plain failure and was retried on the next poll — the 2026-08-16 12-duplicate incident's shape.
    • NOT_DELIVERED → ProviderSendFailed, permanent (a 4xx does not become a 200), carrying sent_chunks so the bridge's progressed signal survives partial sends.
  • poll_proactive wiring: DM leg and [channel:] redirect leg both deliver text via asyncio.to_thread(deliver_text, ...); the redirect's fail-loudly semantics (literal marker kept in DM + WARN on failure) are unchanged — a provider failure raises into the existing except path.

Evidence

At HEAD:

$ python3 tests/discord-proactive-send.test.py
PASS: proactive send-leg — ordered confirmed chunks, capped-transient UNKNOWN, permanent refusal with progress
$ python3 tests/discord-delivery-provider.test.py   # unchanged sibling
PASS: DiscordDeliveryProvider — contract receipts, raising config errors, real core+backend wiring
$ bash scripts/review-checks.sh --diff <(git diff pr3095..HEAD)
review-checks: PASS (hardcoded-paths + root-artifacts + prose-cap clean)
$ bash scripts/lint-workspace-resolution.sh --diff
✓ no new workspace-resolution anti-patterns in this diff.

Before (parent): poll_proactive sent text via await dm.send(chunk) / await _target_ch.send(chunk) (WS client, no receipts, timeout = retry-next-poll). After: chunks earn canonical CONFIRMED / NOT_DELIVERED / OUTCOME_UNKNOWN receipts with the mapping above.

Live-path status

This is the live proactive delivery loop, so harness proof is not sufficient for merge-readiness per repo policy. The live round trip (bridge restart on this branch → synthetic proactive-*.txt → message observed in the owner DM, including one UNKNOWN injection) is planned as part of the stack's post-merge restart chain, same protocol as #3086's done-chain; happy to run it pre-merge on request instead.

Signed: @sutando-qingyun-001:ag2.space

🤖 Generated with Claude Code

…vider (5b stage 1)

The bridge keeps claim/retry orchestration (the cross-bridge .sending
protocol needs a migration fence before claiming moves); the outbound
text chunks now earn canonical receipts. OUTCOME_UNKNOWN maps to the
policy's capped-transient UnconfirmedDelivery — bounded retry visible to
the attempt budget, then park — and NOT_DELIVERED parks as permanent.
Attachments stay on the WS client (provider has no file surface yet).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@qingyun-wu

Copy link
Copy Markdown
Collaborator Author

Folded into #3095 at the owner's direction — the provider and its first activated caller (the proactive text send-leg) now review as one unit, which is what both review threads asked to see. Branch feat/discord-proactive-provider is superseded.

@qingyun-wu
qingyun-wu merged commit 37b0969 into feat/discord-delivery-provider Aug 18, 2026
2 checks passed
@qingyun-wu
qingyun-wu deleted the feat/discord-proactive-provider branch August 18, 2026 08:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants