You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(audience-core): surface backend-rejected batches as VALIDATION_REJECTED instead of silent drop
Fixes a silent data-loss bug uncovered while wiring the new error
surface. When the backend returned 200 with body { accepted: N, rejected: M }
the queue would clear the entire batch on result.ok and never observe
that M messages were dropped — no callback fired, no metric, no log.
The fix has three parts working together:
1. httpSend now parses the 2xx response body. If it reports rejected > 0,
httpSend returns ok:false with status:200 and body containing the
parsed { accepted, rejected } counts. Also fires a new
`transport_partial_rejected` metric for internal observability.
2. toAudienceError adds a 2xx-with-rejection branch that maps to the new
AudienceErrorCode 'VALIDATION_REJECTED', with a human-readable
message ("Backend rejected M of N messages") and the parsed body
preserved as responseBody.
3. MessageQueue.flush now distinguishes terminal failures from
retryable ones. On VALIDATION_REJECTED the batch is dropped (the
backend deterministically rejected those messages — retrying won't
help) AND onError fires. Generic FLUSH_FAILED / NETWORK_ERROR still
retain messages for retry on the next flush cycle, as before.
TDD: started with the failing queue test that captures the user-facing
contract (partial-success drops the batch + fires onError). Saw it
fail (queue retained both messages). Implemented the fix across
errors.ts + queue.ts + transport.ts. Added supplemental tests for the
httpSend detection path and the toAudienceError mapping branch.
Tests: 109 core, 47 sdk, 64 pixel. All pass.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
0 commit comments