fix(site): keep a refusal a browser would not store - #157
Merged
Conversation
readPreference fell back to the in-memory answer only when localStorage threw. A browser can let the read succeed and refuse the write — Safari's private mode and a full quota both do — and there the stored value came back null, so an explicit "Do not allow" was read as no answer at all: the banner stayed up and, outside a prior-consent country, the tag loaded anyway. The answer given on this page now governs it whenever storage has none of its own, however storage failed to keep it. Claude-Session: https://claude.ai/code/session_013MqwrF5NA179khDtEQdib5
5 tasks
This file has claimed since it was written that every other open tab is told about the change and acts on it. Nothing did. The storage listener lived inside subscribe, whose only caller is the privacy page's control, and that subscriber redraws its own status text rather than re-applying the preference. So a reader with a documentation page open who went to /privacy and denied kept being measured in the tab they left behind, until it happened to reload. Applying the preference on the storage event is what makes the claim true. Claude-Session: https://claude.ai/code/session_013MqwrF5NA179khDtEQdib5
This reverts commit 1af0090.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
An explicit Do not allow could be discarded, and analytics could start anyway.
readPreference()fell back to the in-memory answer only whenlocalStoragethrew. A browser can let the read succeed and refuse the write: Safari's private mode and an exhausted quota both do. TherewritePreferencekept the choice in memory,setItemthrew and was swallowed, and the nextreadPreference()readnullback from storage and returned it.apply()then treated the reader as unanswered. Neither thedeniednor thegrantedbranch ran, so the banner stayed on screen, and in a country the code classifies asnot_requiredthe fallback calledmayRun("not_required", null), which is true, and loaded the tag.The stored value still wins when there is one. The change is that the answer given on this page governs it whenever storage has none of its own, however storage failed to keep it.
Why this is correct
getItemto succeed whilesetItemthrows, which is why the originalcatch-only fallback missed it: nothing throws on the read path.memoryPreferenceis assigned only inwritePreference, so falling back to it cannot manufacture a grant the reader never made, and a valid stored value still wins.memoryPreferencestartsnull, so a first visit with empty storage still reads as unanswered and the banner still asks.removeItem, nolocalStorage.clear), so a persisted answer is never revoked out from under an open page.window.oneboxAnalytics.preference, which isreadPreferenceitself, so the banner and the control cannot disagree.8146452applies the preference on thestorageevent, so a withdrawal in one tab still stops the tag in the others.just checkpasses, including the site build.Effect on the safety envelope
Makes a refusal effective where it was being dropped. Nothing new is stored, no new request is made, and what is sent when measurement is allowed is unchanged.
fanout carries an identical copy of this component and has the same bug: labstack/fanout#227. It also still needs the cross-tab fix this repository already has.
Checklist
just checkpasses locally.just checkverifies this).https://claude.ai/code/session_013MqwrF5NA179khDtEQdib5