Repository navigation
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Merging to
After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here |
🤖 CI report✅ Trunk lane — non-backend laneThis PR is assigned to the non-backend lane. It does not run backend Python tests and may merge in parallel with PRs in other lanes. ✅ Duplication (Python) — cleanNew Python code duplication introduced by this branch. Fails at 70+ tokens in app code, or 150+ tokens when both copies live in test files. Advisory while the gate proves itself: extract a shared helper instead of copying. ✅ Duplication (TypeScript) — cleanNew TypeScript code duplication introduced by this branch. Fails at 70+ tokens in app code, or 150+ tokens when both copies live in test files. Advisory while the gate proves itself: extract a shared helper instead of copying. ✅ Hogbox preview — ready, open the preview▶ Open the preview
commit |
There was a problem hiding this comment.
PostHog Review · Standard · reviewed 6ade8db: 2 Should fix.
This is the only automatic review while this pull request is a draft. Comment @posthog review to review new changes sooner. Otherwise, a review of the new changes runs when you mark it ready for review.
See this review and its findings in PostHog Review. Comment @posthog review --deep for a Deep review. A Deep review takes longer and looks deeper than a Standard review.
HostHog preview —
|
The final member check reused the cached snapshot, so a member removed while the send was prepared still passed it for up to a minute. The final check now reloads membership. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
markForRefresh only drops the cached snapshot. A fresh check still joined a lookup another send started before the member was removed, and took its stale answer. The final check now runs its own query. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ookup Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ture A stalled membership query or event store held the skipped invocation open, and with it the worker's whole batch. The lookup now runs under a statement timeout and fails closed; the blocked-event capture gives up after a second. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A capture past its deadline still holds its Redis connection or pending acquisition, so a long stall grew the backlog with every blocked send. At most ten wait at once; the rest are dropped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ill the cap The cap counted every capture in flight, so a burst of blocked sends against a healthy store lost events. Only captures that outlived their deadline count now, and each releases its slot when it settles, so captures resume once the store answers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Client Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Counting only stalled captures let every capture in the first second start a store call, so a burst during an outage could open any number of them. At most ten store calls run at once now; a capture waiting for a slot holds no connection and gives up at its deadline, and a finished call hands its slot to the next waiter, so a burst against a healthy store keeps every event. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Problem
Warning
🟡 Merge risk: medium · two-way door (merge-risk rubric)
sandboxintegration take the new branches, and no such integration exists on master yet.git revertthe merge commit. Nothing delivers through this PR and it stores no state.Changes
A send through an email integration with
provider: sandboxnow always skips with a reason in the run log, and never recordsemail_sent:workflows sandbox email blockedreasonswitch_offrecipient_not_memberrecipient_unverifiedcheck_failedWORKFLOWS_SANDBOX_SENDER_ENABLEDplus threeSES_SANDBOX_*route settings. All default to off or empty.OrganizationMembersServiceloads a team's member emails in one query and never trusts a snapshot older than a minute.Stack
master. The three Node layers land first; the sender row and the Channels row build on them.How did you test this code?
dd8e42a9780) behind the public API on a box dev stack:outside@example.comis skipped with the member message; a verified member passes the gate and skips as unavailable, since delivery arrives in feat(workflows): route sandbox email through its fixed ses identity #127150; with the worker switch off the send skips as unavailable. SES got no call. Stubs: a local SES endpoint that records each request, a DNS preload that answers an MX record forexample.com,workflows-sandbox-senderanswered true, PersonHog off (nothing on the send path reads persons).sandboxprovider, so nothing in production reaches the gate until the flagged sender ships. The member read is one indexed query per team, cached for a minute.fails closed after three seconds when the lookup cannot get a connection,keeps at most five lookups open while the pool has no connection, and runs no query for them once it recoversandfails closed instead of waiting when the member lookup stalls(an exclusive lock on the membership table from another transaction) cover the lookup.keeps at most ten blocked-event store calls open while the store stalls, and resumes once they settleandcaptures every event of a burst of blocked sends while the store answerscover the capture bound.deadline-slots.test.tscovers the slot helper both bounds share.posthog[bot]threads are answered.Test rationale: the new
sandbox senderblock inemail.service.test.tsdrivesexecuteSendEmailagainst the test Postgres and Redis with SES stubbed. No existing test sent through a sandbox integration. Its membership cases cover CC, BCC, lists, ambiguous mailboxes, unverified, inactive and other-organization members; each catches a recipient reaching delivery without being a verified member.organization-members.service.test.tsuses an injected clock to catch a stale snapshot deciding a send.Release status
Docs update
docs/internal/workflows-email-sending-tiers.mdgains a "Sandbox delivery" section: the switch, the member rule and the blocked event.🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Agent: Claude Code, Claude Opus 5.5 (
claude-opus-5-5). Review by GPT-6.1 Sol.Skills:
/recreating-fork-prs,/stacking-prs,/writing-pr-descriptions,tdd,merge-risk,qa-swarmMore context for AI agents
9ffcb7a96econto masterbf976a762be. The tree equals that fork head merged into the same master.email.service.tsandorganization-members.service.ts.🤖 Generated with Claude Code