forked from jason/echo
ver 1.0
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
#!/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 mpm".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
|
||||
Reference in New Issue
Block a user