feat: F3.4 semantic_collapse — n-gram Jaccard dedup defeats synonym padding

This commit is contained in:
Dispatch#70948f 2026-07-28 14:07:07 +00:00
parent 906eb26188
commit 593868aa8d
1 changed files with 45 additions and 0 deletions

View File

@ -522,6 +522,51 @@ if __name__ == "__main__":
f"sent={ns.total_sent}, recv={ns.total_received}{shadow}")
# ── Semantic collapse (F3.4) ─────────────────────────────
# Defense against synonym padding: adversary generates 50 unique strings
# that all mean "hello", defeating unique_concepts count in F3.3.
# Collapse semantically similar concepts before counting.
# Atomic Raven (Colony, 2026-07-28) identified the attack vector.
def _char_ngrams(s: str, n: int = 3) -> set:
return set(s[i:i+n] for i in range(max(len(s) - n + 1, 1)))
def _jaccard(a: str, b: str) -> float:
sa, sb = _char_ngrams(a), _char_ngrams(b)
if not sa or not sb:
return 0.0
return len(sa & sb) / len(sa | sb)
def semantic_collapse(concepts: list, threshold: float = 0.6) -> list:
"""Collapse similar concepts into canonical forms using n-gram Jaccard.
A cheap proxy for semantic similarity. Catches "greeting-1"/"greeting-2"
style padding but preserves genuinely diverse concepts.
threshold: Jaccard similarity above which concepts merge.
0.6 collapses trivial suffix variations, keeps distinct concepts.
Returns deduplicated concept list (canonical forms only).
"""
canonicals = [] # (canonical_form, ngrams)
mapping = {}
for c in concepts:
matched = False
for canon, canon_ngrams in canonicals:
if _jaccard(c, canon) >= threshold:
mapping[c] = canon
matched = True
break
if not matched:
canonicals.append((c, _char_ngrams(c)))
mapping[c] = c
return list(set(mapping[c] for c in concepts))
# ── Agent-alias merging ──────────────────────────────────
# Agents that change names mid-corpus create phantom signals
# in temporal analysis. merge_aliases() canonicalizes from_id/to_id