#!/usr/bin/env python3 """echo_quality.py — M2: keep the graph (which recall depends on) clean. [v1.0 SCAFFOLD — helpers implemented; integration into echo_links/echo_index is the merge step] Two graph-polluting bugs today: 1. Auto-link fires on any indexed entity whose name/alias is >=3 chars and word-matches the body (echo_ops.py:236). A concept titled "API" or a 2-3 char alias links to every note that happens to mention the word -> noisy, wrong edges. 2. slugify truncates to 40 chars (echo_index.py:58) with NO collision check, so two distinct long titles can resolve to the same slug -> same path -> silent merge. This module supplies the two guards. Integration: * echo_ops auto-link loop -> gate each candidate on is_confident_link(name, body) * echo_index.derive_path -> route the slug through safe_slug(existing_slugs, slug) """ from __future__ import annotations import re # Tokens too short or too common to be a confident entity reference on their own. MIN_NAME_LEN = 4 _COMMON = frozenset( "api app data note task user team work code test main repo file plan goal item " "the and for with from".split() ) def is_confident_link(name: str, body: str) -> bool: """True only if `name` is a strong enough signal to auto-link on its appearance in `body`. Rejects short names, common words, and non-matches. Multi-word names are trusted at lower length (a two-word phrase is rarely incidental).""" n = (name or "").strip() if not n: return False multiword = len(n.split()) > 1 if not multiword: if len(n) < MIN_NAME_LEN or n.lower() in _COMMON: return False return re.search(rf"\b{re.escape(n)}\b", body or "", re.IGNORECASE) is not None def safe_slug(existing_slugs, slug: str, max_len: int = 40) -> str: """Return `slug` if free, else a disambiguated `slug-2`, `slug-3`, ... that still fits `max_len` and does not collide with anything in `existing_slugs`.""" existing = set(existing_slugs or ()) if slug not in existing: return slug n = 2 while True: suffix = f"-{n}" base = slug[: max_len - len(suffix)] if len(slug) + len(suffix) > max_len else slug cand = f"{base}{suffix}" if cand not in existing: return cand n += 1