Repository navigation
Conversation
This was referenced Oct 27, 2026
Sandbox sends claim a daily allowance per project and per recipient address across the organization right before delivery. A reached allowance skips the send. SES throttles give the claim back. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The CDP API's SES Valkey pool no longer stops the process on repeated errors, and it bounds connection and command waits, so an outage skips sandbox sends instead. A claim now carries its own return deadline, so an old claim cannot refund into a refilled bucket. Refs Silthus/personal#199 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Silthus
force-pushed
the
workflows-sandbox-delivery/daily-caps
branch
from
October 28, 2026 10:00
d68a209 to
e189abd
Compare
This was referenced Oct 28, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The sandbox sender lets a team without a verified domain send workflow email to its own members through one shared PostHog SES identity.
Without a daily limit, one project could send unlimited mail through that identity, or one member could receive a flood of it.
This PR caps sandbox sends per project and per recipient address each day, so a send over either cap skips instead of going out.
Part of Silthus/personal#199 (sandbox delivery, slice 1 of 3 there). Stacked on #599.
Replaces #441.
Stack
workflows-sandbox-delivery/route(feat(workflows): route sandbox email through its fixed ses identity #599). Lands after feat(workflows): route sandbox email through its fixed ses identity #599 and every PR below it.e189abdf886: Node typecheck and lint clean, touched Node suites 254 passed. Review: GPT-6.1 Sol through a delegated review of the restack (each PR's diff, its conflict resolutions, the slice seams and the save gate), no findings.e189abdf886, 2026-10-28: live run below. Proof gate: fails only on the fork-onlycigap (exit 3); every other check passes.Impact
Grow Workflows, activation rate: the caps are a condition for enabling the sandbox sender in production.
No production team sees this yet:
WORKFLOWS_SANDBOX_SENDER_ENABLEDstays off.Merge Danger
Warning
🟡 Merge risk: medium · two-way door (merge-risk rubric)
sandboxintegration claim the caps. Own-domain sends do not touch the new code.SES_RATE_LIMITER_VALKEY_*) for test sends. That pool is non-fatal and bounds its waits, so a Valkey outage skips sandbox test sends instead of stopping the CDP API. With the switch off, it opens nothing new.RateLimiterService(claimAllOrNothing,returnClaim). Existing callers do not use them.Production lines: 382 changed (
git diff --numstatagainst #599, tests and docs excluded).Changes
Right before delivery, every sandbox send, test sends included, claims two daily allowances at once:
WORKFLOWS_SANDBOX_DAILY_TEAM_CAP(25)WORKFLOWS_SANDBOX_DAILY_RECIPIENT_CAP(5)workflows sandbox email blockedevent with reasoncap_reached.How did you test this code?
Live run on the slice tip
Live run of the V1 tip
1c08de0b9b4on a PostHog preview. Stubs: a local SES endpoint that records each call, andexample.comseeded as a valid MX domain.Channels created the sandbox sender. A test send to a verified member was accepted and reached SES with the sandbox tenant, its configuration set, the fixed From address and the footer.
A test send to an address outside the organization was skipped before SES.
Daily cap, on the V3 preview: five test sends to one member were accepted; the sixth and seventh were skipped with the per-address limit message, and SES got five calls.
Lane gate on HEAD:
tscpasses. eslint, oxlint and prettier pass on the changed files.semgrep --config .semgrep/rules/security/reports nothing on the lines this PR adds.Red: 22 new tests fail on feat(workflows): route sandbox email through its fixed ses identity #599's code. For the review fixes, the unreachable-pool test on the old pool stopped the jest process with SIGTERM. Green:
email.service.test.ts,rate-limiter.service.test.tsandsandbox-email-sender.test.tspass on HEAD.Test seams:
EmailService.executeSendEmailwith a sandbox integration, against the test Postgres, a real Redis limiter, and a stubbed SES client: send or skip, run log, events, and the claim left in Redis.RateLimiterService.claimAllOrNothingandreturnClaimagainst real Redis: replay, a return after the claim's window, and an unreachable Valkey through the CDP API's optional pool.Proofs owed (
fleet proof gate):sandboxintegration exists in production.Silthus/posthog.Test rationale: the
daily capsblock drives real sends throughexecuteSendEmailwith a real Redis limiter, because the regressions that matter are a send over a cap going out, a repeated address charged twice, or a claim kept after the send skipped. The limiter tests cover the replay and late-return guards, which no send-level test can reach.Release status
Docs update
docs/internal/workflows-email-sending-tiers.mddocuments the two allowances, their settings, and the fail-closed behavior.🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Agent: Claude Code, Claude Opus 5.5 (implementation). Design pass and review by Codex, GPT-6.1 Sol.
Ported from the reviewed source PR above onto the route PR as a wayfinder ticket lane. Skills:
tdd,/writing-tests,pr-description,merge-risk,qa-swarmdesign pass.No duplicate: this replaces the source fork PR named above, which stays open until the stack exists.
Public artifact: all test data is invented (
example.comaddresses).Decisions
Involvement: no grilling rounds; design pass (1 lane, no findings); review (GPT-6.1 Sol, 1 round with 2 findings fixed; final read clean); proof captured as test output.
🤖 Generated with Claude Code