buildkite: fall back to meta_data on webhook cache miss
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.
authored by