Skip to content

feat(emails): send cc, bcc and attachments with a code send - #326

Open
Silthus wants to merge 15 commits into
mainfrom
posthog/emails-cc-bcc-attachments
Open

Silthus wants to merge 15 commits into
mainfrom
posthog/emails-cc-bcc-attachments

Conversation

@Silthus

@Silthus Silthus commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

💡 Motivation and Context

A Rust backend that sends an invoice, a receipt or a report through PostHog can't attach the file or copy anyone in today: CodeEmail takes one to and the content, nothing more. posthog-node and posthog-python are gaining cc, bcc and attachments on the code form (PostHog/posthog-js#5514, PostHog/posthog-python#1172), backed by the server contract in PostHog/posthog#127988. This PR brings posthog-rs to the same shape.

Stacked on #324, which adds client.emails(). Review that one first.

use posthog_rs::{CodeEmail, EmailAttachment};

posthog
    .emails()
    .send(
        CodeEmail::new("jane@example.com", "invoice", "Your invoice")
            .html(r#"<img src="cid:logo"><p>Your invoice is attached.</p>"#)
            .cc("finance@example.com")
            .bcc("archive@example.com")
            .attachment(EmailAttachment::new("invoice.pdf", invoice_pdf).content_type("application/pdf"))
            .attachment(EmailAttachment::new("logo.png", logo_png).content_id("logo")),
    )
    .await?;

Note

Merge risk: low, one-way door once released. Every change is additive: three builder methods on CodeEmail and a new EmailAttachment type. A send that uses none of them sends the same body as before.

Changes:

  • cc and bcc. CodeEmail::cc(address) and CodeEmail::bcc(address) each add one bare address; call them again to add more. The body carries a list, and omits the field when there are none, as posthog-python does.
  • Attachments. CodeEmail::attachment(EmailAttachment) adds a file. EmailAttachment::new(filename, bytes) encodes the bytes as standard Base64 once; EmailAttachment::from_base64(filename, content) sends content the caller already encoded as is. content_type and content_id are optional; a content_id shows the file inline as cid:<id>. The body carries {filename, content, content_type?, content_id?} per file, the server contract's shape.
  • No content in logs. EmailAttachment's Debug prints the file name, type and ID, and the content only as <N Base64 characters>, so a printed CodeEmail never dumps a file.
  • Template form unchanged. TemplateEmail takes none of these, because a template sets its own recipients and content and the server refuses them on that form.
  • Limits stay on the server. PostHog takes at most 10 addresses in each of cc and bcc, and at most 10 files with 512 KB of file content in total (counted before Base64), and refuses blocked file types such as .exe. The docs say so, and the SDK passes the server's 400 invalid_request through as a validation_error whose field() names the address or file (cc__0, attachments__0__filename), with why and fix. Checking the limits in the SDK too would make two sources of truth.
  • What the type system rules out. posthog-python and posthog-node refuse a path key, unknown keys and wrong types with invalid_attachment. Here EmailAttachment has no such fields, so those mistakes don't compile.
  • base64 becomes a regular dependency (it was optional, for the mcp feature). Cargo.lock is unchanged.
  • Docs: a "Copies and attachments" section in the Emails guide, the README example, and a doc example on EmailAttachment. Changeset: minor.

💚 How did you test it?

Test seams: Client::emails() on a real async and a real blocking client against the recording httpmock server from #324.

  • code_send_carries_copies_and_attachments (async and blocking) pins the body: two cc, one bcc, a binary PDF that isn't valid UTF-8 encoded once (JVBERgCf/w==) with its content_type, and a pre-encoded PNG with a content_id, sent unchanged.
  • a_printed_send_never_shows_the_file pins the Debug output.
  • a_server_without_a_field_refuses_the_send_and_names_it pins what an older server's refusal looks like to the caller: a validation_error with field() == Some("attachments"), after one request and no retry.

Proof at the head, beyond the tests:

  • Live run against a local PostHog stack: Django at feat(messaging): send cc, bcc and attachments on a code send posthog#127988 with cdp-api and the workers at #127986 (top of #127985 → #127995 → #127986), sending through maildev. The SDK's real async client ran five sends:
    • Two cc, one bcc, a binary PDF and an inline PNG (content_id("logo")): all four recipients got the email. The cc header lists both copies; the bcc address is only in the envelope, with no Bcc header. Both files arrived byte-identical (sha256 of each against the file sent), the PNG inline as cid:logo.
    • A file passed with from_base64 arrived byte-identical.
    • A .exe file: 400, validation_error with field() attachments__0__filename, plus why and fix. No email went out.
    • A named cc ("Jane <jane@example.com>"): 400, field() cc__0. No email went out.
    • A plain send without copies or files was delivered as before.
  • Older server (Django at feat(messaging): send an email with inline html from code posthog#127123, before the fields existed): the send with cc, bcc and files got 400 validation_error with field() attachments, and no email went out, not even without the files. A send with only a cc got the same refusal naming cc, and one with only a bcc named bcc; neither reached any address. A plain send to the same server was delivered. The test a_server_without_a_field_refuses_the_send_and_names_it scripts that recorded reply.
  • Shadow diff against posthog-python (feat: send cc, bcc and attachments with emails.send posthog-python#1172): both SDKs sent four inputs to one local recorder: everything at once, one cc, empty lists, and one file with every field. Method, path, JSON body (including each file's Base64 and the omitted empty fields) and the meaningful headers match in all four; only User-Agent differs, by SDK name.
  • Existing sends unchanged: one binary with feat: send transactional email with client.emails() #324's six shadow inputs plus a code send with two reply_to addresses, built against this PR's base and against its head, sent identical requests (method, path, body, every compared header) in all seven.
  • Lane gate: fmt, clippy (default and mcp), public API snapshot, the MSRV 1.78 checks, and the lib, doc, async email, blocking email and mcp tests.

📝 Checklist

  • All commits are signed (see Commit signing)
  • I reviewed the submitted code.
  • I added tests to verify the changes.
  • I updated the docs if needed.
  • No breaking change or entry added to the changelog.

If releasing new changes

  • Ran sampo add to generate a changeset file

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

  • Written by Claude Code, Claude Opus 5.5 (claude-opus-5-5), as the posthog-rs slice of the transactional email SDK ports, directed by Michael.
  • Decisions: cc and bcc add one address per call, like the crate's other builders, instead of taking a list; EmailAttachment has two constructors (bytes, or Base64 already encoded) instead of the reference SDKs' "bytes or string" union, so the caller says which one they hold; limits are left to the server.

🤖 Generated with Claude Code

Silthus and others added 12 commits November 2, 2026 15:52
Add `client.emails()` with two send forms, `TemplateEmail` for a template
made transactional in PostHog and `CodeEmail` for content the app rendered,
and `get` for an email's delivery status. Both clients share the argument
checks, flat request body, error mapping and retry policy; shutdown refuses
new email requests and waits for those in flight within its timeout.

New client options: app_host, email_request_timeout_seconds,
email_request_max_retries and migrated_from.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Each Emails handle retries inside request(); send and get only parse the
  2xx reply, so a malformed success is never retried.
- The email test server is httpmock's stateful responder instead of a raw
  TCP server.
- New tests pin email_request_timeout_seconds against a slow server, and
  that it replaces a custom HTTP client's longer timeout.
- wait_idle drops an explicit Notified::enable that notify_waiters does not
  need.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The wait now fails when the send ends without reaching the server, or
after 10 seconds, instead of hanging.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Error::Email holds an EmailError, whose source was a boxed dyn Error. That
made posthog_rs::Error lose UnwindSafe and RefUnwindSafe, which it has on
main, so code that moves an SDK error across catch_unwind would stop
compiling. The source now sits in a newtype that keeps both, and a unit test
pins Send, Sync, UnwindSafe and RefUnwindSafe on Error and EmailError.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both clients read an email reply in full, so a hostile or misconfigured app
host could make the application buffer an oversized or gzip-expanded body.
They now read at most 1 MiB after decompression. A larger body is unreadable,
as a failed read was already: an acceptance becomes a retryable network
error, and a refusal still counts by its status and Retry-After.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A raw-socket server claims a 10 MB body, sends 1.1 MiB and holds the
connection open. Both clients must report the oversized reply within
5 seconds, well before their 10 second request timeout. A client that read
the whole body first fails this test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`futures::executor::block_on(client.shutdown())`, as the global
`posthog_rs::shutdown()` runs it, returned before a send in its retry
backoff finished. Off a Tokio runtime, shutdown now blocks the calling
thread until the requests end or `shutdown_timeout_ms` passes. From a
transport callback it still waits for nothing.

Also from the qa-swarm round 2 panel:
- `SendEmail` is `#[non_exhaustive]`, so a later send form isn't a
  breaking change.
- `Error::Email` returns the email error's cause from `source()`, so a
  chain report no longer prints the message twice.
- The network-error test proves its retry by the backoff it waits.
- One shared rule turns a read body into a reply for both clients, and
  inline comments became names and docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A `CodeEmail` takes `cc` and `bcc`, one address per call, and
`attachment(EmailAttachment)`. `EmailAttachment::new` encodes the file's
bytes as Base64 once; `from_base64` sends encoded content as is, with an
optional `content_type` and `content_id`. Empty lists stay off the wire,
so an older PostHog still sends a plain email, and a send that does carry
one of these fields to a PostHog without it is refused with an error
naming the field. `TemplateEmail` has none of these: the template sets
its own recipients and content. An attachment's `Debug` output never
shows its content.

Matches posthog-python (PostHog/posthog-python#1172) and posthog-node
(PostHog/posthog-js#5514), against the server contract in
PostHog/posthog#127988.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…l request

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Silthus and others added 2 commits November 4, 2026 07:25
The cross-version live run against PostHog/posthog#127123 answered a send
with attachments with 400 validation_error, code invalid_input and attr
attachments. The test now scripts that reply instead of a guessed one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PostHog caps attachments at 512 KB of decoded file content. The method doc
and the guide now say so, since Base64 makes the encoded content about a
third larger.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Silthus
Silthus marked this pull request as ready for review November 4, 2026 08:14
@Silthus
Silthus requested a review from a team as a code owner November 4, 2026 08:14

@stamphog stamphog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not approved — this change needs a human reviewer.

Re-adding the stamphog label gives the same result unless the changed files change.

Gates denied automated approval for a manifest/toolchain classification and mandatory manual routing, although the manifest contains no changed executable hooks. The risky areas have no independent assurance; request review from a teammate, Codex, or Claude and have a maintainer assess the gate denial before re-requesting.

  • Trusted gate results deny automated approval because the manifest was classified as a toolchain change and the change requires manual routing. The actual Cargo.toml hunks change dependency availability and feature membership, not scripts or lifecycle hooks; request human review and maintainer assessment of the gate classification.
Gate mechanics and policy version
Gate Result
prerequisites ✓ all clear
deny-list ✗ matches: deps_toolchain (scripts/hooks changed in Cargo.toml)
size ✓ 156L, 5F substantive, 315L/11F incl. docs/generated/snapshots — within ceiling
tier ✗ classified as T2-never: T2-never (315L, 11F, cross-cutting, feat)
stamphog 2.7.0 .stamphog/policy.yml @ b910bcd · reviewed head b910bcd

@marandaneto marandaneto left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code looks good; no qualifying findings. Verdict: correct.

cargo/posthog-rs: minor
---

A `CodeEmail` takes copies and files: `cc` and `bcc` each add one address, and `attachment` adds an `EmailAttachment`. `EmailAttachment::new` takes the file's bytes and encodes them as Base64 once; `EmailAttachment::from_base64` sends content you already encoded as is. Add `content_type` and `content_id`, and reference a `content_id` as `cid:<id>` in the HTML to show the file inline. PostHog can't fetch a file from a path or URL, and an attachment's `Debug` output never shows its content. A `TemplateEmail` takes none of these, because the template sets its own recipients and content. A PostHog version that doesn't take one of these fields yet refuses the send with an error that names the field, and never sends the email without it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we can merge both changesets into just done? its the same feat, or maybe you should merge main into this branch to fix conflicts?

…-attachments

# Conflicts:
#	README.md
#	api/public-api.txt
#	examples/README.md
#	src/client/async_client.rs
#	src/client/blocking.rs
#	src/client/mod.rs
#	src/emails/async_emails.rs
#	src/emails/blocking_emails.rs
#	src/emails/guide.md
#	src/emails/mod.rs
#	src/emails/shared.rs
#	src/emails/types.rs
#	src/lib.rs
#	tests/test_emails.rs
#	tests/test_emails_blocking.rs
@github-actions

github-actions Bot commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

posthog-rs-v0 Compliance Report

Date: 2026-11-06 08:09:53 UTC
Duration: 15413ms

✅ All Tests Passed!

46/46 tests passed


Capture Tests

✅ 29/29 tests passed

View Details
Test Status Duration
Format Validation.Event Has Required Fields ✅ 115ms
Format Validation.Event Has Uuid ✅ 128ms
Format Validation.Event Has Lib Properties ✅ 127ms
Format Validation.Distinct Id Is String ✅ 124ms
Format Validation.Token Is Present ✅ 127ms
Format Validation.Custom Properties Preserved ✅ 126ms
Format Validation.Event Has Timestamp ✅ 127ms
Retry Behavior.Retries On 503 ✅ 5131ms
Retry Behavior.Does Not Retry On 400 ✅ 2131ms
Retry Behavior.Does Not Retry On 401 ✅ 2130ms
Retry Behavior.Respects Retry After Header ✅ 5087ms
Retry Behavior.Implements Backoff ✅ 15081ms
Retry Behavior.Retries On 500 ✅ 5076ms
Retry Behavior.Retries On 502 ✅ 5079ms
Retry Behavior.Retries On 504 ✅ 5078ms
Retry Behavior.Max Retries Respected ✅ 15078ms
Deduplication.Generates Unique Uuids ✅ 83ms
Deduplication.Preserves Uuid On Retry ✅ 5020ms
Deduplication.Preserves Uuid And Timestamp On Retry ✅ 10034ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ✅ 5029ms
Deduplication.No Duplicate Events In Batch ✅ 21ms
Deduplication.Different Events Have Different Uuids ✅ 19ms
Compression.Sends Gzip When Enabled ✅ 19ms
Batch Format.Uses Proper Batch Structure ✅ 21ms
Batch Format.Flush With No Events Sends Nothing ✅ 30ms
Batch Format.Multiple Events Batched Together ✅ 77ms
Error Handling.Does Not Retry On 403 ✅ 2060ms
Error Handling.Does Not Retry On 413 ✅ 2071ms
Error Handling.Retries On 408 ✅ 5065ms

Feature_Flags Tests

✅ 17/17 tests passed

View Details
Test Status Duration
Request Payload.Request With Person Properties Device Id ✅ 46ms
Request Payload.Flags Request Uses V2 Query Param ✅ 44ms
Request Payload.Flags Request Hits Flags Path Not Decide ✅ 22ms
Request Payload.Flags Request Omits Authorization Header ✅ 34ms
Request Payload.Token In Flags Body Matches Init ✅ 30ms
Request Payload.Groups Round Trip ✅ 31ms
Request Payload.Groups Default To Empty Object ✅ 29ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False ✅ 31ms
Request Payload.Disable Geoip Omitted Defaults To False ✅ 29ms
Request Payload.Flag Keys To Evaluate Contains Only Requested Key ✅ 30ms
Request Lifecycle.No Flags Request On Init Alone ✅ 26ms
Request Lifecycle.No Flags Request On Normal Capture ✅ 35ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests ✅ 38ms
Request Lifecycle.Mock Response Value Is Returned To Caller ✅ 47ms
Retry Behavior.Retries Flags On 502 ✅ 229ms
Retry Behavior.Retries Flags On 504 ✅ 233ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event ✅ 28ms

@github-actions

github-actions Bot commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

posthog-rs-v1 Compliance Report

Date: 2026-11-06 08:10:17 UTC
Duration: 23123ms

✅ All Tests Passed!

111/111 tests passed


Capture_V1 Tests

✅ 94/94 tests passed

View Details
Test Status Duration
Endpoint And Method.Targets V1 Endpoint ✅ 169ms
Endpoint And Method.Does Not Use Legacy Endpoints ✅ 165ms
Required Headers.Has Authorization Bearer Header ✅ 167ms
Required Headers.Has Content Type Json ✅ 167ms
Required Headers.Has Posthog Sdk Info Format ✅ 165ms
Required Headers.Has Posthog Attempt Header ✅ 167ms
Required Headers.Has Posthog Request Id ✅ 167ms
Required Headers.Has Posthog Request Timestamp ✅ 166ms
Required Headers.Has User Agent ✅ 164ms
Body Format.Body Has Created At And Batch ✅ 164ms
Body Format.No Api Key In Body ✅ 154ms
Body Format.No Sent At In Body ✅ 154ms
Event Format.Event Has Required Root Fields ✅ 152ms
Event Format.Event Uuid Is Valid ✅ 151ms
Event Format.Event Timestamp Is Rfc3339 ✅ 152ms
Event Format.Distinct Id Is String ✅ 152ms
Event Format.Distinct Id At Root Not Properties ✅ 156ms
Event Format.Custom Properties Preserved ✅ 152ms
Event Format.Set Properties Preserved ✅ 151ms
Event Format.Set Once Properties Preserved ✅ 152ms
Event Format.Groups Properties Preserved ✅ 144ms
Event Format.Sdk Generates Uuid If Not Provided ✅ 146ms
Event Format.Event Has Required Root Fields Batch ✅ 180ms
Event Format.Event Uuid Is Valid Batch ✅ 180ms
Event Format.Event Timestamp Is Rfc3339 Batch ✅ 179ms
Event Format.Distinct Id Is String Batch ✅ 179ms
Event Format.Distinct Id At Root Not Properties Batch ✅ 179ms
Event Format.Custom Properties Preserved Batch ✅ 193ms
Event Format.Set Properties Preserved Batch ✅ 178ms
Event Format.Set Once Properties Preserved Batch ✅ 176ms
Event Format.Groups Properties Preserved Batch ✅ 165ms
Event Format.Sdk Generates Uuid If Not Provided Batch ✅ 167ms
Batch Behavior.Multiple Events In Single Batch ✅ 212ms
Batch Behavior.Batch Envelope Smoke ✅ 190ms
Batch Behavior.Flush With No Events Sends Nothing ✅ 118ms
Batch Behavior.Flush At Triggers Batch ✅ 1142ms
Batch Behavior.Created At Reflects Batch Creation Time ✅ 126ms
Deduplication.Generates Unique Uuids ✅ 210ms
Deduplication.Different Events Same Content Different Uuids ✅ 140ms
Deduplication.Preserves Uuid On Retry ✅ 5130ms
Deduplication.Preserves Timestamp On Retry ✅ 5097ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ✅ 5126ms
Deduplication.No Duplicate Events In Batch ✅ 155ms
Header Behavior On Retry.Attempt Header Starts At One ✅ 85ms
Header Behavior On Retry.Attempt Header Increments On Retry ✅ 10095ms
Header Behavior On Retry.Request Id Preserved On Retry ✅ 5086ms
Header Behavior On Retry.Different Requests Have Different Request Ids ✅ 2070ms
Header Behavior On Retry.Request Timestamp Changes On Retry ✅ 5071ms
Response Format Validation.Success Response Has Uuid Keyed Results ✅ 68ms
Response Format Validation.Success Response Has Ok For Each Event ✅ 39ms
Response Format Validation.Success No Retry After When All Ok ✅ 42ms
Response Format Validation.Success Retry After Present When Retry Events ✅ 34ms
Response Format Validation.Success No Retry After When Drop Only ✅ 36ms
Response Format Validation.Response Echoes Request Id ✅ 33ms
Retry Behavior.Retries On 408 ✅ 5038ms
Retry Behavior.Retries On 500 ✅ 5031ms
Retry Behavior.Retries On 503 ✅ 5026ms
Retry Behavior.Retries On 504 ✅ 5027ms
Retry Behavior.Retryable Errors Have Retry After ✅ 2028ms
Retry Behavior.Respects Retry After On Retryable Error ✅ 8027ms
Retry Behavior.Does Not Retry On 400 ✅ 2027ms
Retry Behavior.Does Not Retry On 401 ✅ 2032ms
Retry Behavior.Does Not Retry On 402 ✅ 2034ms
Retry Behavior.Does Not Retry On 413 ✅ 2030ms
Retry Behavior.Does Not Retry On 415 ✅ 2031ms
Retry Behavior.Non Retryable Errors Have No Retry After ✅ 2030ms
Retry Behavior.Implements Backoff ✅ 15035ms
Retry Behavior.Max Retries Respected ✅ 15026ms
Partial Batch Handling.Handles 200 Full Success ✅ 2032ms
Partial Batch Handling.Handles 200 With All Ok ✅ 3054ms
Partial Batch Handling.Does Not Retry Dropped Events ✅ 3050ms
Partial Batch Handling.Does Not Retry Limited Events ✅ 3029ms
Partial Batch Handling.Prunes Ok Events On Partial Retry ✅ 5029ms
Partial Batch Handling.Prunes Dropped Events On Partial Retry ✅ 5030ms
Partial Batch Handling.Retries Only Retry Events From Partial ✅ 5030ms
Partial Batch Handling.Partial Retry Preserves Uuids ✅ 5028ms
Partial Batch Handling.Partial Retry Attempt Header Increments ✅ 5035ms
Partial Batch Handling.Partial Retry Request Id Preserved ✅ 5035ms
Partial Batch Handling.Respects Retry After On Partial ✅ 5028ms
Partial Batch Handling.Unknown Result Treated As Terminal ✅ 3028ms
Partial Batch Handling.Mixed Ok Drop Limited No Retry ✅ 3037ms
Compression.Sends Gzip Content Encoding ✅ 27ms
Compression.No Content Encoding When Disabled ✅ 24ms
Compression.Compressed Body Is Decompressible ✅ 27ms
Error Handling.Does Not Retry On Unknown 4Xx ✅ 2026ms
Event Options.Cookieless Mode Override ✅ 25ms
Event Options.Disable Skew Correction Override ✅ 26ms
Event Options.Process Person Profile Override ✅ 26ms
Event Options.Product Tour Id Override ✅ 25ms
Event Options.Unset Options Omitted ✅ 25ms
Event Options.Options Override In Batch ✅ 26ms
Geoip And Historical Migration.Geoip Disable Injected Into Properties ✅ 25ms
Geoip And Historical Migration.Historical Migration Set In Body ✅ 26ms
Geoip And Historical Migration.Historical Migration Absent By Default ✅ 26ms

Feature_Flags Tests

✅ 17/17 tests passed

View Details
Test Status Duration
Request Payload.Request With Person Properties Device Id ✅ 17ms
Request Payload.Flags Request Uses V2 Query Param ✅ 17ms
Request Payload.Flags Request Hits Flags Path Not Decide ✅ 17ms
Request Payload.Flags Request Omits Authorization Header ✅ 17ms
Request Payload.Token In Flags Body Matches Init ✅ 19ms
Request Payload.Groups Round Trip ✅ 18ms
Request Payload.Groups Default To Empty Object ✅ 19ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False ✅ 17ms
Request Payload.Disable Geoip Omitted Defaults To False ✅ 17ms
Request Payload.Flag Keys To Evaluate Contains Only Requested Key ✅ 18ms
Request Lifecycle.No Flags Request On Init Alone ✅ 13ms
Request Lifecycle.No Flags Request On Normal Capture ✅ 26ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests ✅ 20ms
Request Lifecycle.Mock Response Value Is Returned To Caller ✅ 16ms
Retry Behavior.Retries Flags On 502 ✅ 222ms
Retry Behavior.Retries Flags On 504 ✅ 219ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event ✅ 27ms

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants