Repository navigation
Conversation
Silthus
force-pushed
the
workflows-sandbox/daily-caps
branch
from
October 12, 2026 14:34
88b9f08 to
cafa118
Compare
Silthus
force-pushed
the
workflows-sandbox/daily-caps
branch
from
October 12, 2026 21:37
cafa118 to
887f65f
Compare
Silthus
force-pushed
the
workflows-sandbox/daily-caps
branch
from
October 12, 2026 23:14
887f65f to
101fa94
Compare
Silthus
force-pushed
the
workflows-sandbox/daily-caps
branch
from
October 13, 2026 03:24
101fa94 to
45c0fbc
Compare
Silthus
force-pushed
the
workflows-sandbox/daily-caps
branch
from
October 19, 2026 10:58
45c0fbc to
2d22d29
Compare
This was referenced Oct 19, 2026
Silthus
force-pushed
the
workflows-sandbox/daily-caps
branch
from
October 19, 2026 13:11
2d22d29 to
20c7356
Compare
Silthus
force-pushed
the
workflows-sandbox/daily-caps
branch
from
October 19, 2026 13:36
20c7356 to
27d1e52
Compare
Silthus
force-pushed
the
workflows-sandbox/daily-caps
branch
from
October 23, 2026 16:26
27d1e52 to
9c0f754
Compare
This was referenced Oct 23, 2026
Silthus
force-pushed
the
workflows-sandbox/daily-caps
branch
from
October 24, 2026 13:11
9c0f754 to
6457899
Compare
Owner
Author
|
Note 🤖 Claude Opus 5.5 responding on behalf of Michael Decision lines for this PR. The Decisions table in the description links each row here.
|
19 tasks
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Silthus
force-pushed
the
workflows-sandbox/daily-caps
branch
from
October 26, 2026 04:59
6457899 to
3f2f72d
Compare
Owner
Author
|
Replaced by the re-sliced fork stack: #604. Tracked in Silthus/personal#71. |
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
After #434, sandbox email reaches only verified members of the organization, but nothing limits how much of it goes out. A workflow on a busy event can send thousands of sandbox emails to the same few teammates. That fills their inboxes and spends the shared sender's sending quota, which other new teams need to try email.
Sandbox sends need a small daily allowance per project and per organization.
Supersedes PostHog#111690 (left open as the original draft)
Supersedes PostHog#112071 (closed). Includes its cap-token refund, claim-once, and late-return fixes; the route layer includes its empty-settings fix.
Stack: layer 5 of 12, stacked on #434. Next: #450.
This fork PR moves to an upstream PostHog/posthog PR after review.
Caution
🔴 Merge risk: high · one-way door (merge-risk rubric)
Changes
Before:
flowchart LR Send[Sandbox send] --> Members[Final membership check] --> SES[SES delivery] classDef phYellow fill:#f9bd2b,stroke:#f9bd2b,color:#000; classDef phBlue fill:#1d4aff,stroke:#1d4aff,color:#fff; classDef phRed fill:#f54e00,stroke:#f54e00,color:#fff; class Send phYellow; class Members phBlue; class SES phRed;After:
flowchart LR Send[Worker or API test send] --> Members[Bounded organization snapshot] --> Claim[Atomic sandbox claim] --> Recheck[Membership check with same snapshot] --> SES[SES delivery] Claim --> Skip[Skip when denied] SES -->|Throttle| Return[Deduplicated expiring return] --> Retry[Existing delivery retry] Retry --> Members classDef phYellow fill:#f9bd2b,stroke:#f9bd2b,color:#000; classDef phBlue fill:#1d4aff,stroke:#1d4aff,color:#fff; classDef phRed fill:#f54e00,stroke:#f54e00,color:#fff; class Send,Skip phYellow; class Members,Claim,Recheck,Return,Retry phBlue; class SES phRed;Known follow-ups (found in the UI walk, not fixed here):
How did you test this code?
Current evidence, 2026-10-24, head
64578999614.Owed proofs:
8ac8853cc82, which contains this layer. The stack's cdp-api sent through the workflow test-run endpoint to a local SES fake that records each request. 9 of 9 cases pass. 12 of 13 recorded cases match the run atfa33d78fb36. Case 2c (an unverified member on To) now shows the verify-your-email guidance with reasonrecipient_unverified, and makes no SES request. For this layer: case 3 sets a project daily cap of 1. The first send goes out; the second skips with cap guidance and no SES request.fa33d78fb36, because round 4 does not touch the own-sender path or the base worker. Own-sender SES requests from fork master448d802and that tip are identical across 7 cases (stored flows, editor drafts, a custom From name, unverified and missing senders), apart from the per-run signatures of tracking tokens. One intended difference: an editor test run with an empty recipient reportsskippedinstead ofsuccess, because feat(workflows): test templates with the sandbox sender #451 reports skipped email steps in test runs. Live sends are unchanged.Changes in this layer since the 2026-10-19 heads (restacked onto fork master
448d802: the cdp-api dependencies inserver.tscombine master's idempotency Valkey pool with this layer's sandbox email pools):emailValidationValkeydoc no longer says it is null on cdp-api. Wiring and docs; the existing suites cover it.cdp-services.tsandserver.tsnow tell the email workers' pools apart from the SES-only pool on sandbox-enabled cdp-api. Docs only.recipient_unverifiedreason from feat(workflows): restrict sandbox email to verified org members #434. Type and wiring only; the cap behavior is unchanged (222 tests passed in this layer's Node suites).Local gate at the stack tip
8ac8853cc82, shared by every layertscand frontendtsgo: clean.Test seams: RateLimiterService against local Redis and EmailService through SES, membership expiry and refunds.
Test rationale: The replay and cross-project cases extend existing cap coverage. Post-claim membership checks refund a send blocked after a stalled claim; the extra pre-claim membership check is removed.
Gaps: real AWS SES delivery and the AWS-side tenant pause (every proof uses a local SES fake or an unreachable SES), clustered Valkey, the production data shape (prod-shape gap until production read access on 2026-11-02), and fork CI, which fails during setup: path selection fails without a GitHub App client ID, and the Security aggregate rejects its fork-skipped path-filter job. Application CI is a verification gap.
Earlier evidence (superseded heads)
Round 3 heads, 2026-10-23. This layer's head:
9c0f75432bd. Stack tipfa33d78fb36.fa33d78fb36, which contains this layer. The stack's cdp-api sent through the workflow test-run endpoint to a local SES fake that records each request. 9 of 9 cases pass, identical to the earlier run. For this layer: case 3 sets a project daily cap of 1. The first send goes out; the second skips with cap guidance and no SES request.fa33d78fb36: Python 3007 passed; Node CDP 42 suites, 1157 passed; email service suites at the final heads of feat(workflows): restrict sandbox email to verified org members #434, feat(workflows): cap sandbox sends and refund ses throttles #441, feat(workflows): test templates with the sandbox sender #451 and feat(workflows): honor shared sandbox tenant pauses #453 passed; frontend Jest 17 changed suites, 290 passed; mypy, Nodetscand frontendtsgoclean; ruff, oxfmt, oxlint, prettier and eslint clean on the files changed since round 2. Final read 1 found nothing.Whole-stack QA swarm, 2026-10-19. Reviewed tip
cfee7e148ae. This layer's head:27d1e529411.b9bd346ed0e(this stack's cdp-api against a local SES fake, workflow test-run endpoint): a sandbox send to a verified member went out from the fixed identity through the sandbox tenant and configuration set. The step's From name, From address and Reply-To were ignored with a log line. A non-member on CC and an unverified member were blocked with the clear message. A paused tenant state skipped sandbox sends while own-sender sends continued.1a0fe3663c2; later fixes touch no Node code): Node CDP messaging, members and rate limiter suites (includingemail-tracking.service.test.ts, which now runs), the cdp-api suite, the Python sandbox, tenant, tier, reputation and validation suites, the frontend Jest suites of this stack, ruff, and the strict pre-push preflight: pass.Rebased onto master
734468db6f9(2026-10-19), head2d22d29e4a7.withEmailValidationValkeytowithEmailActionValkeysinserver.ts. It now grants the frequency cap pool too.withEmailActionValkeys. With the sandbox switch off, cdp-api wiring matches master.email-tracking.service.test.tsdid not run then. It runs now; see the QA swarm block above. Fork CI still fails during setup, as noted below. Real AWS delivery and clustered Valkey remain unchecked.Checks at the stack tip
Stack tip
b9bd346ed0e(#456), shared by every layer:tsgo: no errors. Nodetsgo: no errors in CDP. The 23 errors it reports are all in session replay files that need the unbuilt Rust@posthog/replay-anonymizermodule.product:lint(workflows, cdp), IDOR coverage,hogli build:openapi(no diff), and the strict pre-push preflight: pass.The organization transfer and stalled-claim cases extend the existing delivery seam. Independently aged caches must share one authorization snapshot.
Observed organization snapshot verification
Observed targeted verification after QA fixes
Observed combined-stack gate
👉 Stay up-to-date with PostHog coding conventions for a smoother review.
Release status
Docs update
Provisioning uses
workflows-sandbox-sender; delivery usesWORKFLOWS_SANDBOX_SENDER_ENABLED, off by default.The existing workflow email sending tiers document now covers sandbox allowances, inline test sends, and throttle refunds.
🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Decisions
Involvement: restack onto fork master
448d802on 2026-10-23; round 1 with GPT-6.1 Sol lanes plus Claude Opus 5.5 fresh eyes for group G2; round 2 on the fix diff; final read 1 by GPT-6.1 Sol per group, with no findings; proofs captured; final read 2 by GPT-6.1 Sol on the round 4 decisions, with no findings; the round 4 live run and a UI walk of the two changed surfaces. Before that: the 2026-10-19 whole-stack QA swarm and the modernize rebase (see Earlier evidence). No review bots run on the fork.Agent: Codex with GPT-6.1 Sol (gpt-6.1-sol) built the original layers, orchestrated by Claude Code with Claude Opus 5.5 (claude-opus-5-5). Restack, review fixes and this description refresh: Claude Opus 5.5 (claude-opus-5-5). Review: GPT-6.1 Sol (gpt-6.1-sol). Fresh eyes: Claude Opus 5.5 (claude-opus-5-5).
Skills:
tdd,pr,stacking-prs,writing-pr-descriptions,merge-risk,qa-swarm,writing-tests,writing-code-comments,using-redis-token-buckets,running-ci-preflight, andwriting-voice. The description refresh usedpr-description,writing-pr-descriptions,writing-voiceandmerge-risk.The rebuild adapts the original allowance code to master's SES retry path and preserves recipient normalization and UTM handling. Sources are public repository changes; test addresses are invented.
🤖 Generated with Claude Code