Skip to content

feat(audience): surface server-side validation rejection reasons#822

Merged
nattb8 merged 2 commits into
mainfrom
feat/sdk-684-surface-server-validation-rejections
Jul 22, 2026
Merged

feat(audience): surface server-side validation rejection reasons#822
nattb8 merged 2 commits into
mainfrom
feat/sdk-684-surface-server-validation-rejections

Conversation

@nattb8

@nattb8 nattb8 commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Summary

Ticket: SDK-684

Client-side validation (SDK-679) mirrors the server's rules, but the two will drift over time; today a rejection the server catches and the client doesn't is discarded silently once a flush completes. This adds a default, non-opt-in log per rejected message, and enriches the existing onError AudienceError with a typed Rejections list so integrators already using onError get structured data instead of hand-parsing the response. Covers both the 2xx-with-rejections and the 4xx-rejected response shapes, since the backend uses the same body for both.

This is lost data, not an advisory, so it logs at Log.Error (real Debug.LogError, not just a Warn-level text prefix) rather than Log.Warn. It's also aggregated into one call per flush instead of one per rejected message, since a batch can carry many rejections and separate Debug.LogError calls would flood the console.

Before After
Default visibility HttpTransport only counted rejected; per-message detail was discarded One Log.Error per flush listing every rejected messageId + field + reason, independent of onError
onError AudienceError had no way to carry per-message detail at all Adds Rejections: IReadOnlyList<MessageRejection>?, parsed from the same response
2xx rejection detection Only surfaced when the body's numeric rejected count was > 0 Falls back to rejections.Count too, so a body where the two have drifted apart doesn't silently drop detail (4xx already didn't have this gap)

Test plan

  • dotnet build and dotnet test pass: 389 passed, 1 skipped (pre-existing), 0 failed
  • dotnet format --verify-no-changes clean
  • New tests cover: Rejections populated on 2xx and 4xx, one aggregated Log.Error call fires with no onError wired, Log.Error uses ErrorWriter (not Writer) and fires regardless of Log.Enabled, malformed rejections in the body leaves it null instead of throwing, a 2xx body with rejected: 0 but a non-empty rejections array still fires onError
  • Verified against a real rejected-message response from a running ingest API (local unit tests only here)

🤖 Generated with Claude Code

@nattb8
nattb8 marked this pull request as ready for review July 22, 2026 03:26
@nattb8
nattb8 requested review from a team as code owners July 22, 2026 03:26
@nattb8
nattb8 force-pushed the feat/sdk-684-surface-server-validation-rejections branch from a4b1a30 to 60356a3 Compare July 22, 2026 03:46
@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown

Audience SDK — Build Size

Platform SDK Size Change
Android 0.39 / 20.00 MB +0.03 MB
Windows 0.17 / 20.00 MB +0.01 MB
iOS 8.61 / 20.00 MB +0.09 MB
macOS 1.00 / 20.00 MB +0.10 MB

SDK Size = build minus empty app. Change = vs baseline. Fails if any platform exceeds its absolute size limit.

…er message

Matches the TS SDK's console.error decision: a rejection the studio didn't
catch client-side is lost data, not an advisory, so it should log louder
than Warn. Debug/Warn share one delegate wired to plain Debug.Log with
severity conveyed only by a text prefix, so a new ErrorWriter delegate wires
Log.Error to a real Debug.LogError instead, giving it genuine Editor/crash-
reporting severity while keeping the existing capture-based test pattern.
Also aggregates the per-flush log to one call instead of one per rejected
message, since a batch can carry many rejections and that many separate
Debug.LogError calls would flood the console.

Additionally: the 2xx path only surfaced rejection detail when the body's
numeric rejected count was greater than 0, while the 4xx path always did
regardless of any count. rejected and rejections are parsed independently
from the same body, so a body where they've drifted apart would silently
drop detail on the success path; both paths now fall back to
rejections.Count when rejected is 0. Also fixed a stale helper name/message
(ParseRejectedCountThrew) left over from an earlier rename of
ParseRejectedCount to ParseRejectedResult.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@nattb8
nattb8 force-pushed the feat/sdk-684-surface-server-validation-rejections branch from 60356a3 to ff8d093 Compare July 22, 2026 05:22
@nattb8
nattb8 merged commit c045e3b into main Jul 22, 2026
52 of 56 checks passed
@nattb8
nattb8 deleted the feat/sdk-684-surface-server-validation-rejections branch July 22, 2026 06:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

2 participants