fix(plugin): write-path hooks say when Scribe did not answer — once per outage, shared marker, record nudge withheld on an unanswered call; check_plugin allows exactly that line when unreachable; plugin 0.1.43 (#2932)
CI & Build / Python lint (push) Successful in 3s
CI & Build / TypeScript typecheck (push) Successful in 13s
CI & Build / Plugin hooks (push) Successful in 13s
CI & Build / integration (push) Successful in 40s
CI & Build / Python tests (push) Failing after 49s
CI & Build / Build & push image (push) Skipped
CI & Build / Python lint (push) Successful in 3s
CI & Build / TypeScript typecheck (push) Successful in 13s
CI & Build / Plugin hooks (push) Successful in 13s
CI & Build / integration (push) Successful in 40s
CI & Build / Python tests (push) Failing after 49s
CI & Build / Build & push image (push) Skipped
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -909,29 +909,35 @@ def _hook_runtime_env():
|
||||
"SCRIBE_URL": "http://127.0.0.1:9", "SCRIBE_TOKEN": "t"}
|
||||
|
||||
|
||||
def test_hook_nudges_recording_when_copies_exist_but_nothing_is_recorded(tmp_path):
|
||||
"""#2664: the local arm proves duplication; when Scribe has no record of it,
|
||||
the same context block must ask for create_snippet — the one moment the
|
||||
recording nudge is earned rather than noise. An unreachable server counts
|
||||
as "nothing recorded": the local finding needed no server, and the nudge
|
||||
fails open with it (here: a refused connection stands in for the instance)."""
|
||||
env = _hook_runtime_env()
|
||||
def _dup_repo(tmp_path, env):
|
||||
repo = tmp_path / "repo"
|
||||
repo.mkdir()
|
||||
subprocess.run(["git", "init", "-q"], cwd=repo, check=True, env=env)
|
||||
(repo / "a.py").write_text("def debounce(fn):\n return fn\n")
|
||||
# git grep searches the index, so the existing copy must be staged.
|
||||
subprocess.run(["git", "add", "."], cwd=repo, check=True, env=env)
|
||||
out = subprocess.run(
|
||||
["bash", str(HOOK)],
|
||||
input=json.dumps({
|
||||
"session_id": "s-nudge", "cwd": str(repo), "tool_name": "Write",
|
||||
"tool_input": {"file_path": str(repo / "b.py"),
|
||||
"content": "def debounce(fn):\n return fn\n"},
|
||||
}),
|
||||
capture_output=True, text=True, env=env,
|
||||
)
|
||||
return repo
|
||||
|
||||
|
||||
def _write_event(repo, session="s-nudge"):
|
||||
return json.dumps({
|
||||
"session_id": session, "cwd": str(repo), "tool_name": "Write",
|
||||
"tool_input": {"file_path": str(repo / "b.py"),
|
||||
"content": "def debounce(fn):\n return fn\n"},
|
||||
})
|
||||
|
||||
|
||||
def test_hook_nudges_recording_when_copies_exist_but_nothing_is_recorded(tmp_path):
|
||||
"""#2664: the local arm proves duplication; when Scribe ANSWERS that it has
|
||||
no record of it, the same context block must ask for create_snippet — the
|
||||
one moment the recording nudge is earned rather than noise."""
|
||||
with http_sink(b'{"context":"","note_ids":[],"sync_note_ids":[]}') as (port, seen):
|
||||
env = dict(_hook_runtime_env(), SCRIBE_URL=f"http://127.0.0.1:{port}")
|
||||
repo = _dup_repo(tmp_path, env)
|
||||
out = subprocess.run(["bash", str(HOOK)], input=_write_event(repo),
|
||||
capture_output=True, text=True, env=env)
|
||||
assert out.returncode == 0
|
||||
assert seen and seen[0]["path"] == ["b.py"]
|
||||
assert out.stdout.strip(), (
|
||||
"hook produced no output — the local arm should have found the "
|
||||
"staged duplicate and nudged"
|
||||
@@ -939,6 +945,51 @@ def test_hook_nudges_recording_when_copies_exist_but_nothing_is_recorded(tmp_pat
|
||||
ctx = json.loads(out.stdout)["hookSpecificOutput"]["additionalContext"]
|
||||
assert "already defined" in ctx # the duplication finding
|
||||
assert "create_snippet" in ctx # the recording ask riding it
|
||||
assert "did not answer" not in ctx
|
||||
|
||||
|
||||
def test_hook_says_when_scribe_did_not_answer_once_per_outage(tmp_path):
|
||||
"""#2932: a configured instance that does not answer (refused connection)
|
||||
is SAID — the write went unchecked — instead of the hook failing open in
|
||||
silence; the record nudge's "nothing recorded" claim is withheld. Once per
|
||||
outage: a second miss is quiet, an answer clears the marker, and the next
|
||||
miss speaks again. The marker is shared with the after-write hook."""
|
||||
env = _hook_runtime_env() # SCRIBE_URL → a refused port
|
||||
repo = _dup_repo(tmp_path, env)
|
||||
marker = tmp_path / "scribe-priorart" / "s-out.unreached"
|
||||
env["TMPDIR"] = str(tmp_path)
|
||||
out = subprocess.run(["bash", str(HOOK)], input=_write_event(repo, "s-out"),
|
||||
capture_output=True, text=True, env=env)
|
||||
assert out.returncode == 0
|
||||
ctx = json.loads(out.stdout)["hookSpecificOutput"]["additionalContext"]
|
||||
assert "already defined" in ctx
|
||||
assert "Scribe did not answer the prior-art check for `b.py` within 5s" in ctx
|
||||
assert "UNCHECKED" in ctx and "list_shapes" in ctx
|
||||
assert "None of those existing copies is recorded" not in ctx
|
||||
assert marker.is_file()
|
||||
# Second miss inside the quiet window: local arm only.
|
||||
out = subprocess.run(["bash", str(HOOK)], input=_write_event(repo, "s-out"),
|
||||
capture_output=True, text=True, env=env)
|
||||
ctx = json.loads(out.stdout)["hookSpecificOutput"]["additionalContext"]
|
||||
assert "already defined" in ctx and "did not answer" not in ctx
|
||||
# An answer clears the marker …
|
||||
with http_sink(b'{"context":"","note_ids":[],"sync_note_ids":[]}') as (port, _seen):
|
||||
up = dict(env, SCRIBE_URL=f"http://127.0.0.1:{port}")
|
||||
subprocess.run(["bash", str(HOOK)], input=_write_event(repo, "s-out"),
|
||||
capture_output=True, text=True, env=up)
|
||||
assert not marker.exists()
|
||||
# … so the next outage is announced afresh.
|
||||
out = subprocess.run(["bash", str(HOOK)], input=_write_event(repo, "s-out"),
|
||||
capture_output=True, text=True, env=env)
|
||||
assert "did not answer" in json.loads(out.stdout)["hookSpecificOutput"]["additionalContext"]
|
||||
# A write the hook had nothing local to say about still carries the line
|
||||
# (the line is the whole message then): a fresh session, no duplicate.
|
||||
(repo / "a.py").unlink()
|
||||
subprocess.run(["git", "add", "-A"], cwd=repo, check=True, env=env)
|
||||
out = subprocess.run(["bash", str(HOOK)], input=_write_event(repo, "s-out-2"),
|
||||
capture_output=True, text=True, env=env)
|
||||
ctx = json.loads(out.stdout)["hookSpecificOutput"]["additionalContext"]
|
||||
assert ctx.startswith("> Scribe did not answer")
|
||||
|
||||
|
||||
def test_hook_stays_quiet_about_recording_when_nothing_is_duplicated(tmp_path):
|
||||
|
||||
Reference in New Issue
Block a user