fix(hooks): definition detector covers all code, not a language shortlist (#2682)
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 8s
CI & Build / integration (push) Successful in 18s
CI & Build / TypeScript typecheck (push) Successful in 32s
CI & Build / Python tests (push) Successful in 53s
CI & Build / Build & push image (push) Successful in 27s
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 8s
CI & Build / integration (push) Successful in 18s
CI & Build / TypeScript typecheck (push) Successful in 32s
CI & Build / Python tests (push) Successful in 53s
CI & Build / Build & push image (push) Successful in 27s
ARM 1 extracted definitions with patterns for CSS/JS/TS/Python only — the languages of the repo it was born in — so the local duplication proof, and the #2664 record nudge gated on it, were structurally unreachable in Go/Kotlin/Rust projects (Minstrel, FabledExchange): precisely where recording was observed never to happen. One modifier-strip plus a definition-keyword family (func/fun/fn/function/ def/sub, struct/trait/interface/enum/object/protocol/type, plus Go method receivers) now covers them all; impl is excluded because several impl blocks per type is normal Rust, and keyword-less declarations (C/Java/Dart) are documented out of scope. Grep patterns mirror the same forms so hits are definitions, never call sites. Parameterized tests pin the coverage per language family. Plugin 0.1.30. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -861,3 +861,52 @@ def test_hook_stays_quiet_about_recording_when_nothing_is_duplicated(tmp_path):
|
||||
)
|
||||
assert out.returncode == 0
|
||||
assert "create_snippet" not in out.stdout
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("fname", "definition"),
|
||||
[
|
||||
("scanner.go", "func Resolve(x int) error {\n\treturn nil\n}\n"),
|
||||
("scanner_m.go",
|
||||
"func (s *Scanner) Resolve(x int) error {\n\treturn nil\n}\n"),
|
||||
("queue.kt", "suspend fun refreshQueue(id: Long) {\n}\n"),
|
||||
("fetch.rs", "pub async fn fetch_all() -> u32 {\n 0\n}\n"),
|
||||
("adapter.go", "type ForgeAdapter struct {\n\tname string\n}\n"),
|
||||
],
|
||||
ids=["go-func", "go-method", "kotlin-fun", "rust-fn", "go-type"],
|
||||
)
|
||||
def test_local_arm_finds_duplicates_in_every_language_family(
|
||||
tmp_path, fname, definition
|
||||
):
|
||||
"""#2682: the definition detector must cover ALL code, not the languages of
|
||||
the repo it was born in. Its original CSS/JS/Python-only patterns silently
|
||||
amputated the local arm — and the #2664 recording nudge gated on it — for
|
||||
every Go/Kotlin/Rust project, which is exactly where the operator observed
|
||||
recording never happening. Each case stages an existing copy and writes the
|
||||
same definition to a second file; the hook must prove the duplication and
|
||||
ask for the record."""
|
||||
env = _hook_runtime_env()
|
||||
repo = tmp_path / "repo"
|
||||
repo.mkdir()
|
||||
subprocess.run(["git", "init", "-q"], cwd=repo, check=True, env=env)
|
||||
(repo / fname).write_text(definition)
|
||||
subprocess.run(["git", "add", "."], cwd=repo, check=True, env=env)
|
||||
ext = fname.rsplit(".", 1)[1]
|
||||
out = subprocess.run(
|
||||
["bash", str(HOOK)],
|
||||
input=json.dumps({
|
||||
"session_id": f"s-lang-{ext}", "cwd": str(repo),
|
||||
"tool_name": "Write",
|
||||
"tool_input": {"file_path": str(repo / f"copy.{ext}"),
|
||||
"content": definition},
|
||||
}),
|
||||
capture_output=True, text=True, env=env,
|
||||
)
|
||||
assert out.returncode == 0
|
||||
assert out.stdout.strip(), (
|
||||
f"hook produced no output for {fname} — the local arm should have "
|
||||
f"found the staged duplicate definition"
|
||||
)
|
||||
ctx = json.loads(out.stdout)["hookSpecificOutput"]["additionalContext"]
|
||||
assert "already defined" in ctx
|
||||
assert "create_snippet" in ctx
|
||||
|
||||
Reference in New Issue
Block a user