fix(review): four findings from adversarial Codex review round 1
- twitter: align backend selection with the two-phase findings pattern — an unauthenticated twitter-cli (warn) no longer blocks a fully-working OpenCLI (ok) further down the candidate list - watch: use _is_newer_version like check-update (the != comparison kept the downgrade prompt this branch fixed elsewhere) - uninstall: third copy of the skill-dir removal also gets the symlink guard (full `agent-reach uninstall` path) - doctor: a stale active_backend from a previous check on the singleton channel no longer leaks into an errored result +4 regression tests (162 total). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -199,3 +199,26 @@ class TestVersionCompare:
|
||||
def test_unparseable_falls_back_to_inequality(self):
|
||||
assert cli._is_newer_version("2026.06-beta", "1.5.0") is True
|
||||
assert cli._is_newer_version("1.5.0", "1.5.0-dev") is True
|
||||
|
||||
|
||||
class TestWatchVersionCompare:
|
||||
def test_watch_does_not_prompt_downgrade(self, monkeypatch, capsys):
|
||||
"""watch 与 check-update 同语义:本地领先远端 release 时不提示更新。"""
|
||||
class R:
|
||||
status_code = 200
|
||||
headers = {}
|
||||
|
||||
@staticmethod
|
||||
def json():
|
||||
return {"tag_name": "v1.4.2", "body": ""}
|
||||
|
||||
monkeypatch.setattr(cli, "_github_get_with_retry", lambda *a, **k: (R(), None, 1))
|
||||
monkeypatch.setattr(
|
||||
"agent_reach.doctor.check_all",
|
||||
lambda config: {"web": {"status": "ok", "name": "任意网页", "message": "ok",
|
||||
"tier": 0, "backends": ["Jina Reader"], "active_backend": "Jina Reader"}},
|
||||
)
|
||||
cli._cmd_watch()
|
||||
out = capsys.readouterr().out
|
||||
assert "新版本可用" not in out
|
||||
assert "全部正常" in out
|
||||
|
||||
@@ -104,3 +104,23 @@ class TestDoctor:
|
||||
assert "1/3 个渠道可用" in plain
|
||||
# Inactive optional channels should be summarized in one line
|
||||
assert "可选渠道可以解锁" in plain
|
||||
|
||||
|
||||
def test_stale_active_backend_does_not_leak_into_errored_result(monkeypatch):
|
||||
"""渠道单例上一轮的 active_backend 不得泄漏进本轮异常结果(Codex review 发现)。"""
|
||||
from agent_reach import doctor
|
||||
|
||||
class _ExplodingChannel:
|
||||
name = "boom"
|
||||
description = "爆炸渠道"
|
||||
tier = 0
|
||||
backends = ["a", "b"]
|
||||
active_backend = "a" # 上一轮成功的残留
|
||||
|
||||
def check(self, config=None):
|
||||
raise RuntimeError("boom")
|
||||
|
||||
monkeypatch.setattr(doctor, "get_all_channels", lambda: [_ExplodingChannel()])
|
||||
results = doctor.check_all(config=None)
|
||||
assert results["boom"]["status"] == "error"
|
||||
assert results["boom"]["active_backend"] is None
|
||||
|
||||
@@ -152,3 +152,33 @@ def test_check_twitter_cli_broken_falls_back_to_bird():
|
||||
assert status == "ok"
|
||||
assert "bird" in message
|
||||
assert channel.active_backend == "bird CLI (legacy)"
|
||||
|
||||
|
||||
def test_unauthenticated_twitter_cli_does_not_block_working_opencli():
|
||||
"""warn 候选不得屏蔽排在后面的 ok 候选(Codex review 发现)。"""
|
||||
channel = TwitterChannel()
|
||||
with patch.object(
|
||||
TwitterChannel, "_check_twitter_cli",
|
||||
return_value=("warn", "twitter-cli 已安装但未认证"),
|
||||
), patch.object(
|
||||
TwitterChannel, "_check_opencli",
|
||||
return_value=("ok", "OpenCLI 可用(复用浏览器登录态)"),
|
||||
), patch.object(TwitterChannel, "_check_bird", return_value=None):
|
||||
status, msg = channel.check()
|
||||
assert status == "ok"
|
||||
assert channel.active_backend == "OpenCLI"
|
||||
|
||||
|
||||
def test_all_warn_falls_back_to_first_warn():
|
||||
channel = TwitterChannel()
|
||||
with patch.object(
|
||||
TwitterChannel, "_check_twitter_cli",
|
||||
return_value=("warn", "twitter-cli 未认证"),
|
||||
), patch.object(
|
||||
TwitterChannel, "_check_opencli",
|
||||
return_value=("warn", "扩展未连接"),
|
||||
), patch.object(TwitterChannel, "_check_bird", return_value=None):
|
||||
status, msg = channel.check()
|
||||
assert status == "warn"
|
||||
assert channel.active_backend == "twitter-cli"
|
||||
assert "未认证" in msg
|
||||
|
||||
Reference in New Issue
Block a user