Re-enqueue unmapped siblings after mapping
The tracker-mapping worker processes one pattern at a time and matchBySiblingOrigin only reads already-resolved siblings, so vendor propagation across a banner was forward-only. A sibling processed before its peer resolved a vendor (for example, one that failed the agent and fell back to an unmatched catalog row) was never revisited, even once a later sibling clearly identified the same third party. When a Process run newly establishes a common third party, re-arm mapping_requested_at on same-banner siblings that share an initiator domain and are still unpromoted and non-extension-sourced. The worker re-claims them and matchBySiblingOrigin now finds the freshly mapped pattern. Guarding on third_party_id IS NULL, mapping_requested_at IS NULL, and a not-pre-existing common third party keeps cascades finite. Signed-off-by: Émile Ré <emile@probo.com>
This commit is contained in:
@@ -131,6 +131,7 @@ func (h *trackerMappingHandler) Process(ctx context.Context, tp coredata.Tracker
|
||||
return fmt.Errorf("cannot load cookie banner for domain filtering: %w", err)
|
||||
}
|
||||
|
||||
// FIXME: remove
|
||||
banner.Origin = "https://t.probo.com"
|
||||
|
||||
var (
|
||||
@@ -160,12 +161,23 @@ func (h *trackerMappingHandler) Process(ctx context.Context, tp coredata.Tracker
|
||||
}
|
||||
}
|
||||
|
||||
// Whether a catalog third party was already known before the
|
||||
// signal pipeline ran this round. Re-enqueuing siblings is
|
||||
// only useful when this run is the one that resolves the
|
||||
// vendor; a pre-existing link adds no new signal and gating
|
||||
// on it keeps cascades finite.
|
||||
commonThirdPartyPreexisted := commonThirdPartyID != nil
|
||||
|
||||
var domains []string
|
||||
|
||||
if commonThirdPartyID == nil {
|
||||
domains, err := h.loadInitiatorDomains(ctx, tx, tp)
|
||||
loaded, err := h.loadInitiatorDomains(ctx, tx, tp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
domains = loaded
|
||||
|
||||
// Sibling matching is an org-local co-occurrence signal:
|
||||
// two patterns served from the same origin on the same
|
||||
// banner are likely the same vendor, even when that origin
|
||||
@@ -268,6 +280,17 @@ func (h *trackerMappingHandler) Process(ctx context.Context, tp coredata.Tracker
|
||||
log.String("pattern", tp.Pattern),
|
||||
log.String("tracker_pattern_id", tp.ID.String()),
|
||||
)
|
||||
|
||||
// This run newly resolved a catalog third party, so
|
||||
// same-banner siblings that share an initiator domain but
|
||||
// were processed earlier and left unmatched can now match
|
||||
// against it. Re-arm their mapping so the worker revisits
|
||||
// them; the guards keep already-mapped siblings untouched.
|
||||
if commonThirdPartyID != nil && !commonThirdPartyPreexisted {
|
||||
if err := h.reenqueueUnmappedSiblings(ctx, tx, tp, domains); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -275,6 +298,43 @@ func (h *trackerMappingHandler) Process(ctx context.Context, tp coredata.Tracker
|
||||
)
|
||||
}
|
||||
|
||||
// reenqueueUnmappedSiblings re-arms mapping_requested_at on same-banner
|
||||
// siblings sharing an initiator domain with tp that are still unpromoted,
|
||||
// so the worker re-evaluates them now that tp resolved a vendor.
|
||||
func (h *trackerMappingHandler) reenqueueUnmappedSiblings(
|
||||
ctx context.Context,
|
||||
tx pg.Tx,
|
||||
tp coredata.TrackerPattern,
|
||||
domains []string,
|
||||
) error {
|
||||
scope := coredata.NewScopeFromObjectID(tp.ID)
|
||||
|
||||
var patterns coredata.TrackerPatterns
|
||||
|
||||
count, err := patterns.RequestMappingForUnmappedSiblings(
|
||||
ctx,
|
||||
tx,
|
||||
scope,
|
||||
tp.CookieBannerID,
|
||||
tp.ID,
|
||||
domains,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot re-enqueue unmapped siblings: %w", err)
|
||||
}
|
||||
|
||||
if count > 0 {
|
||||
h.logger.InfoCtx(
|
||||
ctx,
|
||||
"re-enqueued unmapped sibling tracker patterns",
|
||||
log.String("tracker_pattern_id", tp.ID.String()),
|
||||
log.Int64("count", count),
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// firstNonNil returns a when it is set, otherwise b. It keeps the first
|
||||
// catalog row id resolved by the pipeline stable: later signals upsert
|
||||
// the same row (same key) and return the same id, but the explicit guard
|
||||
|
||||
Reference in New Issue
Block a user