Repository navigation
fix(#1166): a cold create-lead no longer costs the attribution - #1167
Merged
Merged
Conversation
#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>
8 tasks
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.
#1165 shipped booking attribution and it worked — when the function was warm. Driving the real
browser path on production, minutes apart:
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.idis a UUID primary key and an INSERT may supply it — soBookingCtamints one withcrypto.randomUUID(), puts it on the URL immediately, and records in the background withkeepalive. 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
409rather than500. A chosen id lets somebody mark a lead they invented asscheduled— a row they createdabout 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
One test needed care rather than a number bump
The FR-024a case smuggled an
idthat happens to be a valid v4 UUID, so that key is nowlegitimately accepted. It keeps the exact key list — which is what catches a new field leaking
in later — and now names
utm_*,name,emailandstatusexplicitly, so the rule survives thelist changing again.
5,834 unit tests, 961 script tests,
deno checkclean across 18 functions.Closes #1166.
🤖 Generated with Claude Code