Add duration-aware tracker pattern merging

Trackers sharing a prefix but with materially different lifetimes
(e.g. session vs 1-year) were incorrectly merged into a single
prefix pattern. Port the snap table from cookie-utils.ts into Go
and use it to bucket durations so only trackers that display the
same human-readable lifetime can merge. Update the unique index
to include COALESCE(max_age_seconds, -1) so prefix patterns with
different durations can coexist.

Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
Émile Ré
2026-05-06 17:12:56 +04:00
parent a911fcc220
commit 93cf5a5986
4 changed files with 286 additions and 83 deletions

View File

@@ -0,0 +1,18 @@
-- Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
--
-- Permission to use, copy, modify, and/or distribute this software for any
-- purpose with or without fee is hereby granted, provided that the above
-- copyright notice and this permission notice appear in all copies.
--
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
-- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
-- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
-- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-- PERFORMANCE OF THIS SOFTWARE.
DROP INDEX idx_tracker_patterns_unique_pattern_per_banner;
CREATE UNIQUE INDEX idx_tracker_patterns_unique_pattern_per_banner
ON tracker_patterns (cookie_banner_id, tracker_type, pattern, COALESCE(max_age_seconds, -1));

View File

@@ -149,6 +149,7 @@ func (tp *TrackerPattern) LoadByBannerIDTypeAndPattern(
cookieBannerID gid.GID,
trackerType TrackerType,
pattern string,
maxAgeSeconds *int,
) error {
q := `
SELECT
@@ -174,6 +175,7 @@ WHERE
AND cookie_banner_id = @cookie_banner_id
AND tracker_type = @tracker_type
AND pattern = @pattern
AND COALESCE(max_age_seconds, -1) = COALESCE(@max_age_seconds, -1)
LIMIT 1;
`
@@ -183,6 +185,7 @@ LIMIT 1;
"cookie_banner_id": cookieBannerID,
"tracker_type": trackerType,
"pattern": pattern,
"max_age_seconds": maxAgeSeconds,
}
maps.Copy(args, scope.SQLArguments())
@@ -393,7 +396,7 @@ INSERT INTO tracker_patterns (
@created_at,
@updated_at
)
ON CONFLICT (cookie_banner_id, tracker_type, pattern) DO NOTHING
ON CONFLICT (cookie_banner_id, tracker_type, pattern, COALESCE(max_age_seconds, -1)) DO NOTHING
`
args := pgx.StrictNamedArgs{