ver 1.5.1 — duplicate-gate precision (common tokens, cross-kind)
Live 1.5.0 use caught the gate blocking a decision note over the single vault-common token "echo" (min-normalized overlap gives any one-token entity a 1.0 score). New echo_index.gate_candidates() + token_df(): - gate blocks same-kind candidates only; cross-kind name collisions (a decision titled after its project) warn instead of blocking - a lone shared token blocks only when unique to that entity (df == 1); multi-token overlaps still block fuzzy_candidates (advisory warnings) and exit-76/--merge-into/--force semantics unchanged. +3 offline unit tests, gate e2e cases restructured +2 new; verified live both directions. All suites green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -148,6 +148,51 @@ def test_fuzzy_candidates_ignores_common_and_short_tokens() -> None:
|
||||
assert echo_index.fuzzy_candidates(index, "data pipeline") == []
|
||||
|
||||
|
||||
def test_gate_candidates_blocks_same_kind_rare_token() -> None:
|
||||
# The blocking case the gate exists for: same kind, and the shared token is unique
|
||||
# to that one entity — "Robert Smith" vs the person bob-smith must gate.
|
||||
index = {"entities": {"bob-smith": {"path": "resources/people/bob-smith.md",
|
||||
"kind": "person", "title": "Bob Smith",
|
||||
"aliases": []}}}
|
||||
gated = echo_index.gate_candidates(index, "Robert Smith", kind="person")
|
||||
assert gated and gated[0][0] == "bob-smith"
|
||||
|
||||
|
||||
def test_gate_candidates_skips_cross_kind() -> None:
|
||||
# A company/decision named after a person or project is intentional naming, not a
|
||||
# duplicate — cross-kind lookalikes warn but never block.
|
||||
index = {"entities": {"bob-smith": {"path": "resources/people/bob-smith.md",
|
||||
"kind": "person", "title": "Bob Smith",
|
||||
"aliases": []}}}
|
||||
assert echo_index.gate_candidates(index, "Smith Consulting", kind="company") == []
|
||||
# ...but the advisory candidate list still surfaces it:
|
||||
assert echo_index.fuzzy_candidates(index, "Smith Consulting")
|
||||
|
||||
|
||||
def test_gate_candidates_skips_single_vault_common_token() -> None:
|
||||
# The live 1.5.0 false positive: "echo" appears in many entity names, so any title
|
||||
# containing it scored 1.0 against every single-token "echo" entity. A lone shared
|
||||
# token only blocks when it is unique to that entity (df == 1).
|
||||
ents = {
|
||||
"echo": {"path": "projects/active/echo.md", "kind": "project",
|
||||
"title": "echo", "aliases": []},
|
||||
"echo-v-05": {"path": "projects/archived/echo-v.05.md", "kind": "project",
|
||||
"title": "echo-v.05", "aliases": []},
|
||||
}
|
||||
assert echo_index.gate_candidates({"entities": ents}, "echo handbook",
|
||||
kind="project") == []
|
||||
# multi-token overlap still blocks, even when the individual tokens are common:
|
||||
ents["echo-memory-system"] = {"path": "projects/active/echo-memory-system.md",
|
||||
"kind": "project", "title": "echo memory system",
|
||||
"aliases": []}
|
||||
ents["echo-memory-notes"] = {"path": "resources/concepts/echo-memory-notes.md",
|
||||
"kind": "concept", "title": "echo memory notes",
|
||||
"aliases": []}
|
||||
gated = echo_index.gate_candidates({"entities": ents}, "echo memory platform",
|
||||
kind="project")
|
||||
assert [s for s, _, _ in gated] == ["echo-memory-system"]
|
||||
|
||||
|
||||
def test_aliases_in_frontmatter_flow_and_block() -> None:
|
||||
flow = '---\ntype: project\naliases: ["echo memory", "echo plugin"]\n---\n# x\n'
|
||||
assert echo_index.aliases_in_frontmatter(flow) == ["echo memory", "echo plugin"]
|
||||
|
||||
Reference in New Issue
Block a user