Surface common tracker pattern link across APIs

Expose the existing tracker_patterns.common_tracker_pattern_id foreign
key on the TrackerPattern type so it is possible to tell whether a
pattern is linked to the global common-tracker catalog (its description
likely came from the seed or the mapping/enrichment agents) or has no
link (added manually or inherited). This is a read-only debugging aid
for agent-generated descriptions; no migration or write path changes.

The field is added in sync across all four API surfaces (GraphQL, MCP,
CLI, n8n) plus the console UI, and covered by e2e assertions for both
the linked and unlinked cases.

Signed-off-by: Émile Ré <emile@probo.com>
This commit is contained in:
Émile Ré
2026-06-02 17:31:54 +02:00
parent 9ac71f948f
commit aebb2a1ed0
12 changed files with 208 additions and 53 deletions

View File

@@ -313,6 +313,16 @@ type TrackerPattern implements Node
"""
commonThirdParty: CommonThirdParty @goField(forceResolver: true)
"""
The common tracker-pattern catalog entry this pattern is linked to,
if any. Non-null means the pattern was matched to the global catalog
(so its description may originate from the Open Cookie Database seed
or the mapping/enrichment agents); null means no catalog link
(description was added manually or inherited). Exposed primarily for
debugging agent-generated descriptions.
"""
commonTrackerPatternId: ID
detectedTrackers(
first: Int
after: CursorKey

View File

@@ -31,10 +31,14 @@ type (
// (cookieCategory, detectedTrackers, thirdParty, commonThirdParty,
// detectedCount, permission) are populated by the resolver.
//
// ThirdPartyID and CommonTrackerPatternID are not exposed in
// GraphQL — they are foreign-key handles the resolver uses to load
// the linked third party (org-scoped or via the common catalog)
// without re-querying coredata.
// ThirdPartyID is not exposed in GraphQL — it is a foreign-key
// handle the resolver uses to load the linked org-scoped third
// party without re-querying coredata.
//
// CommonTrackerPatternID is exposed directly as the
// commonTrackerPatternId field: a non-null value indicates the
// pattern is linked to the common tracker-pattern catalog, which is
// used to debug the provenance of agent-generated descriptions.
TrackerPattern struct {
ID gid.GID `json:"id"`
TrackerType coredata.TrackerType `json:"trackerType"`
@@ -55,7 +59,7 @@ type (
Permission bool `json:"permission"`
ThirdPartyID *gid.GID `json:"-"`
CommonTrackerPatternID *gid.GID `json:"-"`
CommonTrackerPatternID *gid.GID `json:"commonTrackerPatternId,omitempty"`
}
TrackerPatternConnection struct {

View File

@@ -9560,6 +9560,11 @@ components:
- "null"
format: date-time
description: Timestamp when a cookie last matched this pattern
common_tracker_pattern_id:
anyOf:
- $ref: "#/components/schemas/GID"
- type: "null"
description: Linked common tracker-pattern catalog ID, if any. Non-null indicates the pattern was matched to the global catalog (description may originate from the seed or agents); null means no catalog link.
created_at:
type: string
format: date-time

View File

@@ -26,21 +26,22 @@ func NewTrackerPattern(p *coredata.TrackerPattern) *TrackerPattern {
}
return &TrackerPattern{
ID: p.ID,
OrganizationID: p.OrganizationID,
CookieBannerID: p.CookieBannerID,
CookieCategoryID: p.CookieCategoryID,
TrackerType: TrackerPatternTrackerType(p.TrackerType),
Pattern: p.Pattern,
MatchType: TrackerPatternMatchType(p.MatchType),
DisplayName: p.DisplayName,
MaxAgeSeconds: p.MaxAgeSeconds,
Description: p.Description,
Source: source,
Excluded: p.Excluded,
LastMatchedAt: p.LastMatchedAt,
CreatedAt: p.CreatedAt,
UpdatedAt: p.UpdatedAt,
ID: p.ID,
OrganizationID: p.OrganizationID,
CookieBannerID: p.CookieBannerID,
CookieCategoryID: p.CookieCategoryID,
TrackerType: TrackerPatternTrackerType(p.TrackerType),
Pattern: p.Pattern,
MatchType: TrackerPatternMatchType(p.MatchType),
DisplayName: p.DisplayName,
MaxAgeSeconds: p.MaxAgeSeconds,
Description: p.Description,
Source: source,
Excluded: p.Excluded,
LastMatchedAt: p.LastMatchedAt,
CommonTrackerPatternID: p.CommonTrackerPatternID,
CreatedAt: p.CreatedAt,
UpdatedAt: p.UpdatedAt,
}
}