Skip to content

fix(#1166): a cold create-lead no longer costs the attribution - #1167

Merged
TortoiseWolfe merged 1 commit into
mainfrom
fix/1166-cold-start-loses-the-lead-id
Sep 10, 2026
Merged

TortoiseWolfe merged 1 commit into
mainfrom
fix/1166-cold-start-loses-the-lead-id

Conversation

@TortoiseWolfe

Copy link
Copy Markdown
Owner

#1165 shipped booking attribution and it worked — when the function was warm. Driving the real
browser path on production, minutes apart:

click 1 (cold)  →  lead recorded, landed on /schedule/           ← no ?lead=, attribution lost
click 2 (warm)  →  lead recorded, landed on /schedule/?lead=93a0305b-…
                   embed: app.cal.com/turtle-wolfe/15min/embed?…&lead_ref=93a0305b-…

Both clicks wrote a lead. Only the second could ever be matched to a booking. On a low-traffic site
the cold one is the common case — so the feature would have looked built and mostly not worked, and
failed silently: the row looks perfect and simply never leaves link_opened.

The API run that shipped #1165 could not have caught this — it warmed the function itself on its
first call. Only clicking the real page after a lull showed it.

The wait comes out rather than getting longer

Raising the cap punishes the visitor. Pinging the function on a schedule buys warmth with a
recurring cost and still loses the genuinely-first click.

leads.id is a UUID primary key and an INSERT may supply it — so BookingCta mints one with
crypto.randomUUID(), puts it on the URL immediately, and records in the background with
keepalive. No await, no cap, no cold-start sensitivity, and no schema change.

Generated at click time, not render time. This page is statically exported, so an id minted
during render would be baked into the HTML and every visitor would share one.

What it concedes, stated plainly

The id is caller-supplied. A collision is a unique violation, now answered 409 rather than
500. A chosen id lets somebody mark a lead they invented as scheduled — a row they created
about themselves. Neither is worth a mechanism.

Shape is not conceded. Anything that is not a v4 UUID is refused before Postgres sees it.

Driven live after redeploying

caller-supplied id         →  201 with that id
the same id again          →  409 "That lead id already exists"
"'; drop table leads; --"  →  400 "id is not a uuid"

One test needed care rather than a number bump

The FR-024a case smuggled an id that happens to be a valid v4 UUID, so that key is now
legitimately accepted. It keeps the exact key list — which is what catches a new field leaking
in later — and now names utm_*, name, email and status explicitly, so the rule survives the
list changing again.

5,834 unit tests, 961 script tests, deno check clean across 18 functions.

Closes #1166.

🤖 Generated with Claude Code

#1165 shipped booking attribution and it worked — when the function was warm.
Driving the real browser path on production, minutes apart:

  click 1 (cold)  ->  lead recorded, landed on /schedule/            no ?lead=
  click 2 (warm)  ->  lead recorded, landed on /schedule/?lead=93a0305b-...
                      embed: app.cal.com/turtle-wolfe/15min/embed?...&lead_ref=93a0305b-...

Both clicks wrote a lead. Only the second could ever be matched to a booking. On
a low-traffic site the cold one is the common case, so the feature would have
looked built and mostly not worked — and failed silently, because the row looks
perfect and simply never leaves `link_opened`.

The API run that shipped #1165 could not have caught this: it warmed the function
itself on the first call.

THE WAIT COMES OUT RATHER THAN GETTING LONGER. Raising the cap punishes the
visitor; pinging the function on a schedule buys warmth with a recurring cost and
still loses the genuinely-first click. `leads.id` is a UUID primary key and an
INSERT may supply it, so BookingCta now mints one with crypto.randomUUID(), puts
it on the URL immediately, and records in the background with keepalive. No
await, no cap, no cold-start sensitivity, and no schema change.

Generated at CLICK time, not render time: this page is statically exported, so an
id minted during render would be baked into the HTML and every visitor would
share one.

What it concedes, stated plainly: the id is caller-supplied. A collision is a
unique violation, now answered 409 rather than 500. A CHOSEN id lets somebody
mark a lead they invented as `scheduled` — a row they created about themselves.
Neither is worth a mechanism. Shape is not conceded: anything that is not a v4
UUID is refused before Postgres sees it.

Driven live after redeploying:

  caller-supplied id       -> 201 with that id
  the same id again        -> 409 "That lead id already exists"
  "'; drop table leads; --" -> 400 "id is not a uuid"

The FR-024a case needed care rather than a number bump: it smuggled an `id` that
happens to be a valid v4 UUID, so that key is now legitimately accepted. It keeps
the exact key list, which is what catches a NEW field leaking in, and names
utm_*/name/email/status explicitly so the rule survives the list changing again.

Closes #1166.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@TortoiseWolfe
TortoiseWolfe merged commit 1d31a1e into main Sep 10, 2026
26 checks passed
@TortoiseWolfe
TortoiseWolfe deleted the fix/1166-cold-start-loses-the-lead-id branch September 10, 2026 21:12
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.

Booking attribution silently fails on a cold create-lead — the first click after a lull loses the lead id

2 participants