@@ -0,0 +1,34 @@
|
|||||||
|
"""drop write-path uses edges that cross projects
|
||||||
|
|
||||||
|
Revision ID: 0126
|
||||||
|
Revises: 0125
|
||||||
|
Create Date: 2026-10-26
|
||||||
|
|
||||||
|
The write path records a `uses` edge with basis `hook` when a session pulled a
|
||||||
|
snippet and then wrote code naming its symbol. That is by-name evidence, like
|
||||||
|
the proposer's `reference` edges 0125 removed, and a body never calls a
|
||||||
|
function defined in another project's repository. The write path now applies
|
||||||
|
the same by-name test, so it writes no such edge; this removes the ones it
|
||||||
|
wrote before. Judged edges keep their own basis and are left alone.
|
||||||
|
|
||||||
|
Downgrade restores nothing: the removed edges were never facts.
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
|
||||||
|
revision = "0126"
|
||||||
|
down_revision = "0125"
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
op.execute(
|
||||||
|
"DELETE FROM code_shape_uses u USING code_shapes s, notes n "
|
||||||
|
"WHERE u.shape_id = s.id AND u.snippet_id = n.id "
|
||||||
|
"AND u.basis = 'hook' "
|
||||||
|
"AND n.project_id IS NOT NULL AND n.project_id <> s.project_id"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
pass
|
||||||
@@ -1798,7 +1798,7 @@ def _semantic_priority(row) -> tuple:
|
|||||||
# were examined under, so a tightened rule re-examines everything once. A
|
# were examined under, so a tightened rule re-examines everything once. A
|
||||||
# change that does not alter what is proposed needs no bump. A stale "miss"
|
# change that does not alter what is proposed needs no bump. A stale "miss"
|
||||||
# basis on an old row is inert: a miss is not evidence (see _SEMANTIC_LIMIT).
|
# basis on an old row is inert: a miss is not evidence (see _SEMANTIC_LIMIT).
|
||||||
_PROPOSER_VERSION = 7
|
_PROPOSER_VERSION = 8
|
||||||
# Signature resemblance floor, name blanked (difflib ratio) — and a length
|
# Signature resemblance floor, name blanked (difflib ratio) — and a length
|
||||||
# floor, because `def NAME():` resembles `def NAME(x):` at 0.95 while saying
|
# floor, because `def NAME():` resembles `def NAME(x):` at 0.95 while saying
|
||||||
# nothing; a family shape has parameters to resemble.
|
# nothing; a family shape has parameters to resemble.
|
||||||
@@ -1939,7 +1939,9 @@ def names_canon(
|
|||||||
unless the canon is recorded in this very file;
|
unless the canon is recorded in this very file;
|
||||||
- never a generic verb, with or without a leading underscore;
|
- never a generic verb, with or without a leading underscore;
|
||||||
- a bare lowercase word (`file`, `seen`, `seal`) only where it is called
|
- a bare lowercase word (`file`, `seen`, `seal`) only where it is called
|
||||||
as `word(`, because as a plain word it is everyone's variable.
|
as `word(`, because as a plain word it is everyone's variable. No space
|
||||||
|
is allowed before the parenthesis: formatted code never has one, and
|
||||||
|
prose does ("a file (not a directory)").
|
||||||
Same kind and language family are checked by the callers' loops."""
|
Same kind and language family are checked by the callers' loops."""
|
||||||
sym = _norm_symbol(canon.symbol or "")
|
sym = _norm_symbol(canon.symbol or "")
|
||||||
if not sym:
|
if not sym:
|
||||||
@@ -1954,7 +1956,7 @@ def names_canon(
|
|||||||
if not any(lp and _path_touches(lp, path) for lp, _ls in canon.locations):
|
if not any(lp and _path_touches(lp, path) for lp, _ls in canon.locations):
|
||||||
return False
|
return False
|
||||||
if kind == "sym" and re.fullmatch(r"[a-z]+", sym):
|
if kind == "sym" and re.fullmatch(r"[a-z]+", sym):
|
||||||
return re.search(rf"(?<![\w$]){re.escape(sym)}\s*\(", body or "") is not None
|
return re.search(rf"(?<![\w$]){re.escape(sym)}\(", body or "") is not None
|
||||||
return references_symbol(body, sym, kind)
|
return references_symbol(body, sym, kind)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -602,6 +602,8 @@ def test_a_plain_word_counts_only_where_it_is_called():
|
|||||||
seen = Canon(8, "sym", "seen", (("src/tree.py", "seen"),), "def seen(f):", _norm_text("x"), 2, "python")
|
seen = Canon(8, "sym", "seen", (("src/tree.py", "seen"),), "def seen(f):", _norm_text("x"), 2, "python")
|
||||||
assert reference_canons("sym", "src/a.py", "walk", "if path in seen:\n return", [seen]) == []
|
assert reference_canons("sym", "src/a.py", "walk", "if path in seen:\n return", [seen]) == []
|
||||||
assert reference_canons("sym", "src/a.py", "walk", "if seen(f):\n return", [seen]) == [8]
|
assert reference_canons("sym", "src/a.py", "walk", "if seen(f):\n return", [seen]) == [8]
|
||||||
|
# Prose puts a space before the parenthesis; a call does not.
|
||||||
|
assert reference_canons("sym", "src/a.py", "walk", "// a seen (or unseen) path\nreturn p", [seen]) == []
|
||||||
# A leading underscore does not get a generic verb past the stoplist.
|
# A leading underscore does not get a generic verb past the stoplist.
|
||||||
run = Canon(9, "sym", "_run", (("src/x.py", "_run"),), "def _run(cmd):", _norm_text("x"), 2, "python")
|
run = Canon(9, "sym", "_run", (("src/x.py", "_run"),), "def _run(cmd):", _norm_text("x"), 2, "python")
|
||||||
assert reference_canons("sym", "src/a.py", "go", "_run(['ls'])", [run]) == []
|
assert reference_canons("sym", "src/a.py", "go", "_run(['ls'])", [run]) == []
|
||||||
|
|||||||
Reference in New Issue
Block a user