From 72c7d3b28d1568db3e50ad26593f566b8215889f Mon Sep 17 00:00:00 2001 From: John Carlo San Pedro Date: Wed, 8 Jul 2026 17:41:54 +1200 Subject: [PATCH 1/2] fix(audience): stop mutating queued events on consent change (SDK-647) Consent changes now gate only future collection; events already recorded keep the consent level (and userId) they were captured under. Under GDPR the applicable consent is the one in force at capture time, so there is no need to retroactively rewrite or purge already-queued events. - SetConsent(None) no longer purges the queue (session teardown and anonymous-id wipe are unchanged); previously-recorded events are sent. - SetConsent(Full -> Anonymous) no longer strips userId / drops identify+alias from queued events. - Remove now-dead EventQueue.ApplyAnonymousDowngrade and the DiskStore rewrite helpers. The record-time consent gate in EnqueueChecked is retained: an in-flight event still finalises its consent at the moment it is enqueued (Unity's threading analog of stamping at capture time). It never rewrites events already in the queue. --- .../SampleApp/Scripts/AudienceSample.cs | 8 +- .../Tests/Runtime/SampleAppLiveFireTests.cs | 5 +- .../Audience/Runtime/ImmutableAudience.cs | 33 +++---- .../Audience/Runtime/Transport/DiskStore.cs | 92 +------------------ .../Audience/Runtime/Transport/EventQueue.cs | 38 ++------ .../Tests/Runtime/Core/SessionTests.cs | 23 +++-- .../Tests/Runtime/ImmutableAudienceTests.cs | 78 +++++++++------- .../Tests/Runtime/Transport/DiskStoreTests.cs | 84 ----------------- 8 files changed, 86 insertions(+), 275 deletions(-) diff --git a/examples/audience/Assets/SampleApp/Scripts/AudienceSample.cs b/examples/audience/Assets/SampleApp/Scripts/AudienceSample.cs index 8d5dfcf75..26e304251 100644 --- a/examples/audience/Assets/SampleApp/Scripts/AudienceSample.cs +++ b/examples/audience/Assets/SampleApp/Scripts/AudienceSample.cs @@ -176,9 +176,9 @@ private void OnSendCustomEvent() => RunAndLog("track()", () => // ---- SDK action handlers: consent ---- - // None purges the queue + clears the anonymous ID; dropping below Full - // clears UserId. Mirror is reset whenever the new level can no longer - // identify. + // None clears the anonymous ID and stops future collection; already-queued + // events are kept. Dropping below Full clears UserId. Mirror is reset + // whenever the new level can no longer identify. private void OnSetConsent(ConsentLevel level) => RunAndLog("setConsent()", () => { var previous = ImmutableAudience.CurrentConsent; @@ -191,7 +191,7 @@ private void OnSetConsent(ConsentLevel level) => RunAndLog("setConsent()", () => }; var effects = new List(); if (previous == ConsentLevel.None && level != ConsentLevel.None) effects.Add("queue started, session created"); - if (level == ConsentLevel.None) effects.Add("queue purged, anonymous ID cleared"); + if (level == ConsentLevel.None) effects.Add("tracking stopped, anonymous ID cleared (queued events kept)"); if (!level.CanIdentify() && previous.CanIdentify()) effects.Add("userId cleared"); if (effects.Count > 0) payload["effects"] = effects; OnSdkStateChanged(); diff --git a/examples/audience/Assets/SampleApp/Tests/Runtime/SampleAppLiveFireTests.cs b/examples/audience/Assets/SampleApp/Tests/Runtime/SampleAppLiveFireTests.cs index a009c2ba0..0210ad0ec 100644 --- a/examples/audience/Assets/SampleApp/Tests/Runtime/SampleAppLiveFireTests.cs +++ b/examples/audience/Assets/SampleApp/Tests/Runtime/SampleAppLiveFireTests.cs @@ -266,7 +266,7 @@ public IEnumerator Alias_AndFlush_FlushReportsOk() } [UnityTest] - public IEnumerator SetConsent_None_PurgesQueueAndPersists() + public IEnumerator SetConsent_None_KeepsQueueAndPersists() { // Init at default Anonymous; enqueue an event; revoke; flush. No errors. yield return LoadAndInit(); @@ -276,7 +276,8 @@ public IEnumerator SetConsent_None_PurgesQueueAndPersists() yield return SetConsentVia(SampleAppUi.Buttons.ConsentNone); - // Flushing after revocation should be a no-op (queue purged). No error. + // Events recorded before revocation are kept (consent is determined at + // capture time), so flushing sends them without error. _root.Q