Buildkite webhooks can land before Spawn's goroutine has persisted the build UUID to (knot, pipeline_rkey, workflow) mapping. The window is small but real: CreateBuild returns, Buildkite fires build.scheduled, the webhook handler runs LookupBuildkiteBuildByUUID and gets nothing, and the event is dropped on the floor forever.
HandleWebhook now reconstructs the ref from the build's meta_data when the lookup misses. We already attach tack:knot, tack:pipeline_rkey, and tack:workflow at CreateBuild time, so a Buildkite-originated webhook for one of our builds always carries enough information to recover the tuple. Org and pipeline slug come from the payload's top-level organization and embedded build.pipeline objects.
The reconstructed ref is opportunistically inserted via the existing ON CONFLICT DO UPDATE, so subsequent webhooks and any /logs request hit the cache instead of redoing the meta_data dance. If the authoritative Spawn-side insert lands afterwards it just refreshes the row.
Builds without our tack:* meta_data still no-op, preserving the 'foreign build sharing this webhook URL' behavior. WebhookPayload gains an Organization field so the org slug is available without poking at Build.Pipeline.