Skip to content

HOT-set management

Purpose: how to manage the snippet’s redirect / HOT set — the per-id pins that make the edge snippet 307 deterministically to a pre-rendered variant object, instead of falling through to the worker.

Applies to: the watermark-router edge snippet (apps/snippet/watermark-router.snippet.js), its HOT set, and the generate / verify / deploy / purge tooling under scripts/cloudflare/. For any concrete host/customer/id, decode the code names (H01–H14, C01/C02, S01–S04, K01, …) in the internal decoder (not published).

The snippet is a referrer-blind, binding-less edge function that runs before the worker. For a request it can do one of three things:

  1. Pass through to the worker (fetch(request)) — the default, and the source of truth for clean-vs-watermarked.
  2. 307 to the public variant object (cache.vumbnail.com/thumbnails/{id}/wm.jpg), skipping the worker entirely.
  3. Short-circuit malformed paths to a shared error asset.

The 307 redirect path fires only when both conditions hold:

const watermark = shouldWatermarkRequest(request); // referrer host in WM_DOMAINS, not paying
if (!watermark) return fetch(request);
if (!HOT.has(videoId)) return fetch(request); // <-- the HOT-set gate
return Response.redirect(buildWatermarkRedirectLocation(videoId), 307);

So HOT is the per-id allowlist that decides which ids get the cheap deterministic edge redirect vs. which fall through to the worker. It is a pure cost / determinism lever — it is not a correctness boundary (the worker still decides clean-vs-wm for anything that passes through).

Every HOT hit is a worker request (and ~1.13 KV reads) avoided. At illustrative blended rates of ~$0.50/1M worker requests and ~$0.50/1M KV reads, the avoided-worker path is worth roughly $1.07/1M skipped requests. The HOT set concentrates that savings on the highest-volume reviewed referrer ids. See cost-safe-cache-purging for the billing-shift caveat (worker+KV → R2 Class B).

Decay semantics (read this before pinning anything)

Section titled “Decay semantics (read this before pinning anything)”

A HOT id is just a string pin. When a catalog rotates and an id stops being requested, it is eventually pruned out of HOT. Decay does not fall back to clean.

BeliefReality
”Rotated-out id leaves HOT → snippet passes through → served clean”FALSE for any host still in the worker referrer cohort.
What actually happensThe id silently leaves the redirect set and falls back to the worker path. If the worker still watermarks that referrer cohort, the id is still watermarked — by the worker, not the edge.
What decay actually erodesDelivery determinism, not coverage. The mark stays; the cheap deterministic edge 307 is what is lost.

Consequences:

  • Determinism (and the cost savings) holds only for HOT ids of hosts that have been removed from the worker cohort. While a host stays in the cohort, a non-HOT id re-pins wm via the worker. See referrer-cohort-and-delivery-policy.
  • “Cost looks fine” is not a success signal for a rotating host. A decayed HOT set bills cleanly while determinism rots. Track coverage (currentHotCoveragePct), not dollars, as the health metric.
  • Disabling the snippet does not restore clean — it routes traffic back to the still-cohorted worker. HOT-set work never substitutes for cohort changes.

Cadence is driven by how fast the host’s catalog rotates, not by its volume:

Catalog typeCadenceRationale
Rotating / fast-decay (e.g. auction lots, seasonal)DailyTop ids churn day-to-day; stale pins decay out fast.
Stable catalogWeekly (or on coverage drop)Top ids are durable; refresh only when coverage dips.
Single-hero / single-video hostPin onceOne id carries ~all traffic; no recurring refresh.

Reference instances (decode in the internal decoder (not published)): a rotating-catalog host like H03 → daily; stable hosts → weekly; a single-hero host like H02 (and a pin-once host like H07) → pin once.

Coverage floors that gate a refresh / hold:

  • Rotating host: hold and refresh if currentHotCoveragePct < 0.85 or it drops >5 absolute points batch-over-batch.
  • Stable host: floor 0.80.

scripts/cloudflare/analyze-whale-hotset.ts computes currentHotCoveragePct per host but is report-only today — it does not exit non-zero below the floor. Until a coverage-floor exit code exists, a rotating host kept in HOT requires either a wired alarm or a written manual daily re-verify.

The 32KB package budget — PRUNE, do not append

Section titled “The 32KB package budget — PRUNE, do not append”

The snippet package has a hard 32 KB (32,768 B) Cloudflare limit. The HOT set is the dominant variable-size payload, so it must be actively pruned, never blindly grown.

Rules:

  • Prune, don’t append. A daily refresh splices in the new top ids for a host and removes the decayed ones. Appending forever blows the budget.
  • Per-host id caps. Cap each rotating host at roughly 20–30 ids. Past the cap you are pinning long-tail ids that decay before they pay off.
  • Keep ≥4 KB margin. Fail any generated/--write output that projects > 28,672 B (4 KB margin under the 32 KB cap). Several KB of headroom must stay free for comments, tests, and small safety checks.
  • Per-id referrer comments are load-bearing. The verify/analyze parsers string-scan const HOT = new Set([…]); and the trailing // host comments. Any writeback must preserve them.
  • Never reformat the file during a refresh/flip. bunx biome format on the snippet reflows the HOT set and blinds the string-scan parsers → false-green gates. Forbidden during any HOT-set change.

Approximate per-id cost: id.length + 6 bytes (quotes, comma, indent). Use that to project a candidate before writing.

Illustrative scenario sizing from a prior expansion (your numbers will differ):

ScenarioEst. source sizeHeadroom under 32 KB
Baseline snippet~12,000 B~20,700 B
top50-per-host~15,200 B~17,500 B
top100-per-host~18,300 B~14,500 B
top200-per-host~22,500 B~10,300 B
coverage50-per-host~25,200 B~7,600 B
”everything at once”~32,100 B~600 B — do not ship

HOT-set changes are externalized and gated. Never hand-edit ids straight into a deploy.

Pull fresh path-referrer and cohort artifacts, then rank ids per host:

Terminal window
bun scripts/cloudflare/analyze-whale-hotset.ts \
--path-referrer-json <fresh-path-referrer.json> \
--cohort-report-json <fresh-cohort-report.json> \
--previous-path-referrer-json <yesterday.json> \
--out-json artifacts/cloudflare/whale-hotset-opportunity.<date>.json

This reports per-host concentration, coverage targets, top-id overlap vs. the previous snapshot (stability), how many ids each scenario adds, and whether the resulting snippet still fits the 32 KB limit. Use top-set overlap to judge churn: low overlap = rotating = shorter cap + daily cadence.

Apply the delta for rotating hosts — add the new top ids, drop the decayed ones, honor the per-host cap, preserve referrer comments. A --write / CONFIRM_HOTSET_WRITE=YES mode must fail before writing if the projected source exceeds the 28,672 B budget.

3. Backfill the variant object BEFORE it can be redirected to

Section titled “3. Backfill the variant object BEFORE it can be redirected to”

A HOT id that has no wm.jpg in R2 would 307 users straight into a 404. So ensure the object exists before the pin can go live:

Terminal window
# verify only (gate — exits non-zero on any missing wm.jpg)
bun scripts/cloudflare/verify-watermark-snippet-hotset.ts verify
# backfill missing objects (renders wm.jpg from the clean source)
CONFIRM_ENSURE=YES CLOUDFLARE_API_TOKEN=... CLOUDFLARE_ACCOUNT_ID=... \
bun scripts/cloudflare/verify-watermark-snippet-hotset.ts ensure

verify parses every quoted id out of the HOT set and HEADs each …/wm.jpg; any non-200 fails. ensure pulls the clean source (R2 clean.jpg, or the worker with a clean-forcing referer), applies the watermark, and writes wm.jpg. For a rotating host, source the clean image from R2 clean.jpg, not a worker fetch — a worker fetch for a cohorted host can return an already-watermarked image and bake a double mark that the 200-check won’t catch.

Backfill spends money / writes R2 objects — keep estimates under the repo cost-estimate threshold or commit a written estimate (see cost-safe-cache-purging).

Catch a reflow-blinded parser: the parsed HOT count must equal the rg -c quoted-id count must equal pre-edit + added. A mismatch means the file was reformatted and the gates are lying.

5. Deploy, then purge public-cache-lag 404s

Section titled “5. Deploy, then purge public-cache-lag 404s”

After deploy goes live (content sha matches, rule enabled), purge the bare cached keys whose prior 404/clean cache entries would otherwise mask the new pins:

  • Just-in-time re-HEAD each wm.jpg and require 200 before purging its key; skip + flag any 404 (do not purge into a 404 storm).
  • A newly-backfilled object can return a cached 404 at the edge from a prior miss — purge those specific public URLs so the first real viewer gets the object, not the stale miss.
  • Respect purge rate limits and use the correct zone (a wrong-zone purge silently no-ops). Full purge mechanics live in cost-safe-cache-purging.
  • verify-watermark-snippet-hotset.ts verify0 missing wm.jpg.
  • Parse-count cross-check passes (parsed == rg -c == pre-edit + added).
  • Projected source size < 28,672 B (4 KB margin under 32 KB).
  • Per-id referrer comments intact; file not biome-reformatted.
  • Every new id maps to a public wm.jpg (200) from multiple colos.
  • Coverage above floor for every rotating host being kept (or written manual re-verify).
  • Rollback snapshot regenerated for this batch (see safe-deploys).
SymptomLikely causeFix
HOT id 307s to a 404wm.jpg never backfilled, or purged while still HOTRe-ensure; never delete a still-HOT id’s warm wm.jpg.
Gates green but flip didn’t takeFile was biome-reformatted → parsers string-scanning HOT blindedRestore formatting; re-run parse-count cross-check.
Cost looks fine but determinism erodingDecayed HOT set on a rotating host (silent worker fallback)Track currentHotCoveragePct, not dollars; refresh HOT.
Snippet over 32 KB after refreshAppended instead of pruned; per-host cap exceededPrune decayed ids; enforce ~20–30/host cap.
Non-HOT id still watermarked after purgeHost still in worker cohort → worker re-pins wmRemove host from cohort in the same release (referrer-cohort-and-delivery-policy).
  • referrer-cohort-and-delivery-policy — the worker cohort that the HOT set’s determinism depends on.
  • cost-safe-cache-purging — purge mechanics, rate limits, zone selection, cost estimates.
  • staged-rollouts — flipping hosts in batches; HOT/cohort ordering.
  • safe-deploys — snippet rollback snapshots and the git-is-the-only-content-rollback rule.
  • The internal decoder (not published) — decoder for every host / customer / id code name used above.