Repository navigation
Conversation
a370487 to
989b6c5
Compare
33b1193 to
4a62a77
Compare
989b6c5 to
d509711
Compare
Coherence📄 0 spec file errors · ⛔ 0 broken rules · 🚪 2 unchecked inputs · 🐛 0 bugs that came back What is Coherence?Coherence compares the code with its spec files ( This check read 44 parts of the code and 7 rules. Note These findings do not make this check fail. None of these findings are in files that this pull request changes. You do not need to fix them in this pull request. 🚪 Unchecked inputs (2)
What this means and how to fix itInput from outside this code comes in at these places. The spec does not say what checks that input. 10 more places were already like this when Coherence was added. This list does not show them. To close one of these, find the place by its name in the
To get the line to add, run |
Node SDK acceptance v2Commit: 230480c Capture v0✅ 83 passed / ❌ 4 non-passing / Drill-down: run artifacts → ❌ server_snapshot_payload_false — failed_assertionExpected native data result Code: Failed step: acceptance/public/evaluate-flags.feature:868 the public snapshot outcomes should have these semantics: ❌ server_snapshot_payload_zero — failed_assertionExpected native data result Code: Failed step: acceptance/public/evaluate-flags.feature:868 the public snapshot outcomes should have these semantics: ❌ server_snapshot_payload_null — failed_assertionExpected native data result Code: Failed step: acceptance/public/evaluate-flags.feature:868 the public snapshot outcomes should have these semantics: ❌ migration/yaml-parity-v1/remote-flags-v1.feature::Omitted GeoIP settings default to enabled in flag requests — failed_assertionFlags field differs Code: Failed step: migration/yaml-parity-v1/remote-flags-v1.feature:134 the first flags request field "geoip_disable" should equal JSON false Operation: Field: Expected: false Actual value: true Harness exit: 1; report validation exit: 1. Capture v1✅ 148 passed / ❌ 4 non-passing / Drill-down: run artifacts → ❌ server_snapshot_payload_false — failed_assertionExpected native data result Code: Failed step: acceptance/public/evaluate-flags.feature:868 the public snapshot outcomes should have these semantics: ❌ server_snapshot_payload_zero — failed_assertionExpected native data result Code: Failed step: acceptance/public/evaluate-flags.feature:868 the public snapshot outcomes should have these semantics: ❌ server_snapshot_payload_null — failed_assertionExpected native data result Code: Failed step: acceptance/public/evaluate-flags.feature:868 the public snapshot outcomes should have these semantics: ❌ migration/yaml-parity-v1/remote-flags-v1.feature::Omitted GeoIP settings default to enabled in flag requests — failed_assertionFlags field differs Code: Failed step: migration/yaml-parity-v1/remote-flags-v1.feature:134 the first flags request field "geoip_disable" should equal JSON false Operation: Field: Expected: false Actual value: true Harness exit: 1; report validation exit: 1. |
f98f32c to
fb9640e
Compare
da59e27 to
4e4bcb2
Compare
fb9640e to
e919543
Compare
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
e919543 to
0b6f101
Compare
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An attachment with a key outside filename, content, contentType and contentId, such as the wire name content_id, lost that key without an error, so an inline image could go out with a broken cid. The send now returns invalid_attachment on attachments__<n>__<key> before any request. One converter checks and maps each attachment, which drops the separate check pass and the EmailAttachment cast. The headers doc now says PostHog refuses the headers it sets itself, as the server does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A Buffer or a Base64 string passed as the attachment itself was spread key by key: a large file took seconds, then failed on a byte index, or threw a RangeError. Refuse any value that isn't an attachment object on attachments__<n> first, and look up unknown keys against the keys the SDK takes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Moved to PostHog#5514. |
Problem
A team moving from Resend sends receipts with a PDF, copies to a shared inbox, and tags for their own analytics. This PR adds
cc,bcc,headers,tagsandattachmentsto the code form, for rendered content and local templates alike.Stacks on #7. Needs the server's fields and attachments arms of
send/email/. Part of map Silthus/posthog#461.Impact
Same as the stack: Grow Workflows, billed
workflows_emailsfrom API sends. These fields remove the most common reason a Resend caller can't switch.Merge Danger
Caution
🔴 Merge risk: high · one-way door (merge-risk rubric)
Changes
invalid_formon that field instead of sending without it. The types refuse them there too.ccandbcc(a string becomes a one-item list),headersandtagsas given,attachmentsas{ filename, content, content_type?, content_id? }with aBufferorUint8Arrayas Base64.invalid_attachmentnamedvalidation_errorwith the field:attachmentsthat isn't a list (attachments), or an item that isn't an attachment object, such as a file's bytes or a Base64 string passed as the item itself (attachments__<n>).path(attachments__<n>__path), or a key the SDK doesn't send, such ascontent_id(attachments__<n>__<key>).Buffer,Uint8Arrayor string, or no content (attachments__<n>__content).cc, a missingfilenameor a header PostHog sets itself, such asFromorContent-Type, comes back from the server asvalidation_erroron that field.EmailAttachmentandEmailTagare exported.Evidence
posthog.emails.send()on a real client with an injectedfetch; the accepted and refused shapes as type tests.BufferandUint8Arrayand a 40 KB file; the same fields on both sends of a local template and none on its upload; eachinvalid_attachmentrefusal with itsfield, including aBufferand a Base64 string passed as the item; each field refused on the template form.230480c52: nodevitestand edge (1526 tests), corevitest,check-types,oxlint,oxfmt, build, references committed,pnpm check:public-apiclean.3cc39e036against475d6cbe6: the same 22 invented inputs throughposthog.emails.send()with scripted replies, recording every request and result. 18 are identical. The 4 that differ are the cases this PR adds: the new fields on both sends of a local template and never on its upload, and the attachment refusals.230480c52only adds the refusal of a non-object item.call-flags-project / add-to-project-boardfails on every fork PR (recorded as acigap).400 invalid_requeston the field, which maps tovalidation_error.Decisions
cc,bcc,headers,tags,attachmentswithfilename,content,contentType,contentIdpathcontentccor a missingfilename; the SDK checks only the shape it needs to encodeNo open questions.
Follow-ups:
emailsspec has no requirement for these fields yet; it needs one before a third SDK adds them.ccbefore any request; Node leaves them to the server. Both answervalidation_erroron the same field.Involvement: carries the PostHog#5373 review rounds. This rebuild: one full-scope GPT-6.1 Sol read at
e9195432e(1 finding, fixed by #7'sbf8cfa2b3); a QA swarm at0b6f101dewith a full two-family panel (GPT-6.1 Sol on five lenses, Claude Opus 5.5 fresh eyes: 5 fixed, 1 half rejected) and a narrow round on the fixes (1 fix); shadow diff captured; live run owed to lane dj3.Release info Sub-libraries affected
Libraries affected
Checklist
If releasing new changes
pnpm changesetto generate a changeset file🤖 Agent context
Autonomy: Human-driven (agent-assisted)
claude-opus-5-5) in Claude Code, as lane sdk3 of map Map: send code-managed email templates with one PostHog call posthog#461, directed by Michael. Rebuilt on feat(node): send email content from code with emails.send #5 after feat(node): send transactional email from a template PostHog/posthog-js#5418 merged; the behavior comes from the reviewed feat(node): send cc, bcc, headers, tags and attachments with a code send PostHog/posthog-js#5373.fleet proof.🤖 Generated with Claude Code