Repository navigation
Description
Map: Map: let teams send a first email before verifying their domain
Spec: Spec: sandbox sender
Cast: GPT-6.1 Sol (Michael, 2026-10-03)
Question
Can a send from the sandbox sender go out through the sandbox route, from the fixed address, with the PostHog-built display name and nothing the step overrides?
Delivers end to end. A workflow send, a workflow test run and a template test send on the sandbox sender reach SES (spec section "Send path"):
- Prefactor first, no behavior change:
sesRouteFor(integration, teamId, trackingEnabled)returns{ tenantName, configurationSetName }; own-sender sends stay byte-identical. provider = sandbox:TenantName = SES_SANDBOX_TENANT_NAME,ConfigurationSetName = SES_SANDBOX_CONFIGURATION_SET, FromSES_SANDBOX_FROM_ADDRESSwith the row'sname,FeedbackForwardingEmailAddressthe same address, no Reply-To. Stepfrom.email,from.nameandreplyToare ignored with one info log line.- Sandbox sends are untracked: no pixel, no link rewrite,
email_untrackedalongsideemail_sentfor live sends as for any untracked send. - Global switch
WORKFLOWS_SANDBOX_SENDER_ENABLED(default off): off skips every sandbox send with a clear log line,skipped = true, and{ success: false }on the VM stack. - The team-level tier cap does not apply to sandbox sends and is not drained by them.
- Analytics:
workflows sandbox email senton SES acceptance (is_test,recipient_count,source) andworkflows sandbox email blockedwithreason = switch_off. One small helper owns both events; later tickets add reasons. - New Node config keys in
nodejs/src/cdp/config.ts:WORKFLOWS_SANDBOX_SENDER_ENABLED,SES_SANDBOX_TENANT_NAME,SES_SANDBOX_CONFIGURATION_SET,SES_SANDBOX_FROM_ADDRESS.
Test seams. EmailService.executeSendEmail with real Postgres fixtures, the real rate limiter and sesV2Client.send mocked; assert the SendEmailCommand input, logs, skipped, metrics and captured events. Parameterize test vs live where the behavior is the same.
Write scope. nodejs/src/cdp/services/messaging/email.service.ts, a new sandbox module beside it, nodejs/src/cdp/config.ts, and their tests.
Acceptance criteria
- Own-sender sends produce the same
SendEmailCommandas before (existing tests stay green unchanged). - A sandbox send uses the sandbox tenant, set, address and display name, whatever overrides the step carries.
- Switch off: no SES call, a skip log line, and a
blockedevent withswitch_off. - A sandbox send never claims the tier cap buckets.
How to build (map #225)
/tddred-green-refactor, outside-in, at the seams named above. Real Postgres, Valkey and ClickHouse; mock only the SES client (Node and boto3) and the PostHog analytics client.- Repo skills apply where the diff touches their area:
/writing-tests,/improving-drf-endpoints,/django-migrations,/writing-ui-components,/writing-kea-logics,/writing-user-facing-copy,/writing-code-comments. - Public repo: state sandbox rules as product rules. Cap values come from the private note the map points at; never quote it. Fixture addresses use
example.com. - Shipped means a draft PR handed off by
/qa-swarm(see the map's Notes for remotes and branches). Never mark ready, enqueue or merge.
Activity
Silthus commentedon Oct 3, 2026
Scope addition (conductor, from the outside-code checklist): every sandbox send carries a short identification footer that PostHog renders after templating, so a recipient can tell it came from the PostHog test sender and which organization sent it. The team cannot edit or remove it. No
List-Unsubscribeheader: recipients are members of the sending organization. Write the copy with/writing-user-facing-copy.Silthus commentedon Oct 3, 2026
Note
🤖 GPT-6.1 Sol responding on behalf of Michael
Runtime: Codex native subagent
Worker: /root/impl_232_sol
Worktree: /home/coder/.t3/worktrees/posthog/sandbox-232-route
Branch: feat/workflows-sandbox-route
Cap: four hours, deadline 23:13 UTC on 2026-10-03; the deadline wake removes itself on completion or first wake.
CodeRabbit slot: 2 of 3
The per-project integration row shipped in draft PR PostHog#111368 at 72ded8d. This worker owns this ticket alone and builds on that head. Heavy checks share /tmp/heavy-check.lock; review panels share a separate process-held lock so they cannot overlap.
Silthus commentedon Oct 3, 2026
Note
🤖 GPT-6.1 Sol responding on behalf of Michael
Claimed for implementation at
EmailService.executeSendEmail. I will keep the sending switch off by default and add the fixed route, identity and mandatory organization footer here; recipient membership, sandbox caps and the shared pause gate remain in their own tickets. The production constructor wiring incdp-services.tsis included so the new Node settings reach the sender.Silthus commentedon Oct 3, 2026
Note
🤖 GPT-6.1 Sol responding on behalf of Michael
Draft PR #111401 adds the sandbox send route, fixed identity, organization footer and default-off sending switch. The
EmailService.executeSendEmailtests, Node typecheck and lint pass; fresh QA is running on7b73ca18ba8.Silthus commentedon Oct 3, 2026
Note
🤖 GPT-6.1 Sol responding on behalf of Michael
The four-hour deadline fired and was removed. The previous native worker is absent from the current registry, with no active check or review lock. Its commits, proof and QA ledger are preserved. The lane is orphaned pending recovery; this does not resolve the ticket or imply a ready review handoff.
Silthus commentedon Oct 3, 2026
Note
🤖 GPT-6.1 Sol responding on behalf of Michael
Runtime: Codex native subagent
Worker: /root/recover_232_sol
Cap: two hours; deadline 01:16 UTC on 2026-10-04. The deadline task removes itself on first wake or when both workers report.
CodeRabbit slot: 2 of 3
Recovering preserved code, proof and review state from the orphaned lane. Existing completed review panels are retained; fresh panels run only where new code requires them. No merge authority.
Silthus commentedon Oct 4, 2026
Note
🤖 GPT-6.1 Sol responding on behalf of Michael
The two-hour recovery deadline fired and was removed. The recovery worker is absent from the registry, and no check or review lock is active. Its clean branch at 8dc512c, 130 passing tests and completed review reports are retained. QA round 3 is incomplete, so this ticket remains open. Recovering the remaining review and final fix without repeating completed lanes.
Silthus commentedon Oct 4, 2026
Note
🤖 GPT-6.1 Sol responding on behalf of Michael
Runtime: T3 Code app-owned child, Codex GPT-6.1 Sol
Task: node:delegated-task:command%3Amcp%3Aecac12db-1ef4-434a-b75a-80da090a501e%3Adelegate-task%3Asandbox232-final-review-recovery-20261004
Child: thread:delegated-task:command%3Amcp%3Aecac12db-1ef4-434a-b75a-80da090a501e%3Adelegate-task%3Asandbox232-final-review-recovery-20261004
Cap: two hours; parent deadline wake removes itself on completion or first wake.
CodeRabbit slot: 2 of 3
Continuing the remaining QA lenses on 8dc512c and the final review round after verified fixes. Completed code, tests and review reports are retained. The T3-owned task replaces the orphaned native lane after reviewer dispatch limits. It operates only on the existing route branch and this ticket; no merge authority.
Silthus commentedon Oct 4, 2026
Note
🤖 GPT-6.1 Sol responding on behalf of Michael
Sandbox routing, fixed sender identity and mandatory organization identification remain the agreed scope; draft PR #111401 is blocked after four QA rounds on
cf108096cd162f9d17cd89e7effde552241a3090because malformed HTML can lose the footer.Pending decision: authorize a scoped follow-up that rejects sandbox sends unless finalized HTML reparses with the identification footer directly in the body in both scripting modes?
The recommendation is yes; the issue stays open and the PR stays draft while awaiting Michael, with the worker terminal and no fifth round started.
Silthus commentedon Oct 4, 2026
Note
🤖 GPT-6.1 Sol responding on behalf of Michael
Michael authorized the scoped follow-up on 2026-10-04: enforce the identification-footer contract on finalized HTML and reject unsafe sandbox output before sending. The previous four QA rounds and blocked handoff remain preserved; this authorized follow-up receives a fresh bounded QA cycle.
Runtime: T3 Code app-owned child, Codex GPT-6.1 Sol
Task: node:delegated-task:command%3Amcp%3A253588e1-b06d-459d-9078-ae7221b04ba9%3Adelegate-task%3Asandbox232-footer-invariant-followup-20261004
Child: thread:delegated-task:command%3Amcp%3A253588e1-b06d-459d-9078-ae7221b04ba9%3Adelegate-task%3Asandbox232-footer-invariant-followup-20261004
Worktree: /home/coder/.t3/worktrees/posthog/sandbox-232-route
Branch: feat/workflows-sandbox-route
Start head: cf10809
Cap: four hours, with a deadline wake that deletes itself on first wake or terminal completion.
CodeRabbit slot: 2 of 3
The worker owns this ticket and draft PR #111401, with test-first proof and fresh QA. The conductor owns map coordination; no merge authority.
Silthus commentedon Oct 4, 2026
Note
🤖 GPT-6.1 Sol responding on behalf of Michael
Resolved in draft PR #111401 at
0007a4f79c7: sandbox messages now retain organization identification or fail before delivery.The public send tests and native browser proof of captured SES HTML passed; the fresh GPT-6.1 Sol / Claude Sonnet 5.5 panel has no new in-scope fix or decision.
Fork Node.js CI awaits maintainer approval, and the ancillary reviewer workflow failed before any jobs and denied a rerun for insufficient rights; sending stays off pending the mapped safeguards.