feat(monitoring): match citations by canonical link and scope summary by brand/keyword/platform/date
Replace the domain+title fuzzy alias scoring with a canonical candidate-key index built from published-link aliases — only exact matches now resolve to a SaaS source, eliminating false positives across articles sharing a host (e.g. m.163.com vs www.163.com). Surface the summary scoping that already existed on loadCitationRanking / loadCitedArticles by accepting brand_id, keyword_id, ai_platform_id and business_date on CitationSummary, plumbing them through the handler and admin tracking view. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -425,23 +425,33 @@ func TestBuildMonitoringCitationFactCanDisableContentResolution(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestScoreMonitoringAliasCandidateUsesDomainWithTitleEvidence(t *testing.T) {
|
||||
lastPath := "article-42"
|
||||
func TestScoreMonitoringAliasCandidateUsesCanonicalArticleKey(t *testing.T) {
|
||||
input := monitoringAliasLookupInput{
|
||||
NormalizedURL: "https://m.example.com/article-42",
|
||||
RegistrableDomain: "example.com",
|
||||
LastPathSegment: &lastPath,
|
||||
TitleKey: normalizeMonitoringAliasTitle("北京口腔医院全面测评"),
|
||||
NormalizedURL: "https://m.163.com/dy/article/KRPRE8DJ0556MCR0.html",
|
||||
MatchKeys: monitoringCitationCandidateKeys("https://m.163.com/dy/article/KRPRE8DJ0556MCR0.html", ""),
|
||||
}
|
||||
candidate := monitoringAliasCandidate{
|
||||
NormalizedURL: "https://www.example.com/posts/article-42",
|
||||
RegistrableDomain: "example.com",
|
||||
LastPathSegment: "article-42",
|
||||
TitleKey: normalizeMonitoringAliasTitle("北京口腔医院全面测评"),
|
||||
NormalizedURL: "https://www.163.com/dy/article/KRPRE8DJ0556MCR0.html",
|
||||
MatchKeys: monitoringCitationCandidateKeys("https://www.163.com/dy/article/KRPRE8DJ0556MCR0.html", ""),
|
||||
}
|
||||
|
||||
if score := scoreMonitoringAliasCandidate(input, candidate); score < 90 {
|
||||
t.Fatalf("scoreMonitoringAliasCandidate() = %d, want strong domain/title match", score)
|
||||
if score := scoreMonitoringAliasCandidate(input, candidate); score != 100 {
|
||||
t.Fatalf("scoreMonitoringAliasCandidate() = %d, want canonical URL match", score)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScoreMonitoringAliasCandidateRejectsSameDomainDifferentArticle(t *testing.T) {
|
||||
input := monitoringAliasLookupInput{
|
||||
NormalizedURL: "https://www.163.com/dy/article/KIN5DDMK0556GQZ8.html",
|
||||
MatchKeys: monitoringCitationCandidateKeys("https://www.163.com/dy/article/KIN5DDMK0556GQZ8.html", ""),
|
||||
}
|
||||
candidate := monitoringAliasCandidate{
|
||||
NormalizedURL: "https://www.163.com/dy/article/KRPRE8DJ0556MCR0.html",
|
||||
MatchKeys: monitoringCitationCandidateKeys("https://www.163.com/dy/article/KRPRE8DJ0556MCR0.html", ""),
|
||||
}
|
||||
|
||||
if score := scoreMonitoringAliasCandidate(input, candidate); score != -1 {
|
||||
t.Fatalf("scoreMonitoringAliasCandidate() = %d, want no same-domain match", score)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user