feat(quality): GOAT synthesis improvements - hybrid cross-source linking, YouTube synonyms, human-readable xref tags

Ran 15-way blinded comparison (5 topics x 3 versions). CROSS won all 5 topics
(4.74/5.0 avg vs HN 4.10, Base 3.73). Then improved CROSS further:

- dedupe.py: hybrid similarity (token+trigram Jaccard) at 0.40 threshold,
  cross-source links went from 3 to 13 items across 5 topics
- render.py: [xref: HN5, HN4] -> [also on: HN, Reddit] for human-readable tags
- youtube_yt.py: SYNONYMS dict so "hip hop" matches "rap" (0.33 -> 0.71 score)
- SKILL.md: instruction #7 tells Claude to lead with cross-platform signals

Validation: improved CROSS scores 4.38/5.0 vs original 3.98 (+0.40), wins 4/5
topics. Biggest gains in specificity (+0.8) and format compliance (+1.0).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Matt Van Horn
2026-02-25 16:06:53 -08:00
parent 0591f55f0e
commit bed0557b65
72 changed files with 17077 additions and 13 deletions
+50 -8
View File
@@ -5,6 +5,15 @@ from typing import List, Set, Tuple, Union
from . import schema
# Stopwords for token-based Jaccard (cross-source linking)
STOPWORDS = frozenset({
'the', 'a', 'an', 'to', 'for', 'how', 'is', 'in', 'of', 'on',
'and', 'with', 'from', 'by', 'at', 'this', 'that', 'it', 'my',
'your', 'i', 'me', 'we', 'you', 'what', 'are', 'do', 'can',
'its', 'be', 'or', 'not', 'no', 'so', 'if', 'but', 'about',
'all', 'just', 'get', 'has', 'have', 'was', 'will', 'show', 'hn',
})
def normalize_text(text: str) -> str:
"""Normalize text for comparison.
@@ -59,12 +68,44 @@ def _get_cross_source_text(item: AnyItem) -> str:
Same as get_item_text() but truncates X posts to 100 chars
to level the playing field against short Reddit/HN titles.
Strips 'Show HN:' prefix from HN titles for fairer matching.
"""
if isinstance(item, schema.XItem):
return item.text[:100]
if isinstance(item, schema.HackerNewsItem):
title = item.title
if title.startswith("Show HN:"):
title = title[8:].strip()
elif title.startswith("Ask HN:"):
title = title[7:].strip()
return title
return get_item_text(item)
def _tokenize_for_xref(text: str) -> Set[str]:
"""Tokenize text for cross-source token Jaccard comparison."""
words = re.sub(r'[^\w\s]', ' ', text.lower()).split()
return {w for w in words if w not in STOPWORDS and len(w) > 1}
def _token_jaccard(text_a: str, text_b: str) -> float:
"""Token-level Jaccard similarity (word overlap)."""
tokens_a = _tokenize_for_xref(text_a)
tokens_b = _tokenize_for_xref(text_b)
if not tokens_a or not tokens_b:
return 0.0
intersection = len(tokens_a & tokens_b)
union = len(tokens_a | tokens_b)
return intersection / union if union else 0.0
def _hybrid_similarity(text_a: str, text_b: str) -> float:
"""Hybrid similarity: max of char-trigram Jaccard and token Jaccard."""
trigram_sim = jaccard_similarity(get_ngrams(text_a), get_ngrams(text_b))
token_sim = _token_jaccard(text_a, text_b)
return max(trigram_sim, token_sim)
def find_duplicates(
items: List[Union[schema.RedditItem, schema.XItem]],
threshold: float = 0.7,
@@ -159,17 +200,18 @@ def dedupe_hackernews(
def cross_source_link(
*source_lists: List[AnyItem],
threshold: float = 0.5,
threshold: float = 0.40,
) -> None:
"""Annotate items with cross-source references.
Compares items across different source types using Jaccard similarity
on char trigrams. When similarity exceeds threshold, adds bidirectional
cross_refs with the related item's ID. Modifies items in-place.
Compares items across different source types using hybrid similarity
(max of char-trigram Jaccard and token Jaccard). When similarity exceeds
threshold, adds bidirectional cross_refs with the related item's ID.
Modifies items in-place.
Args:
*source_lists: Variable number of per-source item lists
threshold: Similarity threshold for cross-linking (default 0.5)
threshold: Similarity threshold for cross-linking (default 0.40)
"""
all_items = []
for source_list in source_lists:
@@ -178,8 +220,8 @@ def cross_source_link(
if len(all_items) <= 1:
return
# Pre-compute trigrams using cross-source text extraction
ngrams = [get_ngrams(_get_cross_source_text(item)) for item in all_items]
# Pre-compute cross-source text for each item
texts = [_get_cross_source_text(item) for item in all_items]
for i in range(len(all_items)):
for j in range(i + 1, len(all_items)):
@@ -187,7 +229,7 @@ def cross_source_link(
if type(all_items[i]) is type(all_items[j]):
continue
similarity = jaccard_similarity(ngrams[i], ngrams[j])
similarity = _hybrid_similarity(texts[i], texts[j])
if similarity >= threshold:
# Bidirectional cross-reference
if all_items[j].id not in all_items[i].cross_refs: