Skip to content

Commit b866793

Browse files
committed
fix(ashby): fold offer id into the idempotency key when present
When application.updatedAt is present, the key ignored sibling data fields — a candidateHire delivery carries both application and offer, so two deliveries sharing an application snapshot could collide even though they concern different offers. Append offer.id to the discriminator when present; it's the only sibling object Ashby's schema ever pairs with application.
1 parent 3306dc5 commit b866793

2 files changed

Lines changed: 21 additions & 1 deletion

File tree

apps/sim/lib/webhooks/providers/ashby.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,25 @@ describe('ashbyHandler', () => {
204204
)
205205
})
206206

207+
it('distinguishes candidateHire deliveries sharing application id + updatedAt but differing in offer', () => {
208+
const application = { id: 'app-1', status: 'Hired', updatedAt: '2026-01-01T00:00:00Z' }
209+
const first = {
210+
action: 'candidateHire',
211+
data: { application, offer: { id: 'offer-1' } },
212+
}
213+
const second = {
214+
action: 'candidateHire',
215+
data: { application, offer: { id: 'offer-2' } },
216+
}
217+
expect(ashbyHandler.extractIdempotencyId!(first)).not.toBe(
218+
ashbyHandler.extractIdempotencyId!(second)
219+
)
220+
// a genuine retry of `first` (identical offer too) still dedupes
221+
expect(ashbyHandler.extractIdempotencyId!({ ...first })).toBe(
222+
ashbyHandler.extractIdempotencyId!(first)
223+
)
224+
})
225+
207226
it('returns null when no recognizable resource is present', () => {
208227
expect(ashbyHandler.extractIdempotencyId!({ action: 'ping', data: {} })).toBeNull()
209228
expect(ashbyHandler.extractIdempotencyId!({})).toBeNull()

apps/sim/lib/webhooks/providers/ashby.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ export const ashbyHandler: WebhookProviderHandler = {
5050

5151
if (application?.id) {
5252
const discriminator = application.updatedAt ?? buildFallbackDeliveryFingerprint(data)
53-
return `ashby:${action}:${application.id}:${discriminator}`
53+
const offerSuffix = offer?.id ? `:${offer.id}` : ''
54+
return `ashby:${action}:${application.id}:${discriminator}${offerSuffix}`
5455
}
5556
if (offer?.id) {
5657
return `ashby:${action}:${offer.id}`

0 commit comments

Comments
 (0)