muse-agent-example/tests/集成/test_受控修订候选.py
zizi cf0f4fb985 W20–W24:保存知识方法、迁移框架、审校修订与案例行为的集成成果
接续 88dd570,保存 W20–W24 已实现的共享接口、业务入口、迁移、工作台、测试与文档。
W20/W22/W23 保持 in_progress,W21/W24 保持 verified;此提交不宣称方法或规则正式启用、多轮返修、真实角色评测完成。

W25 新增实验、标定、逐调用交付与角色执行及其迁移/测试/索引留在实施工作树,原有私人和旧实现保留项不纳入。

验证:离线 571、前端 33 通过;PG 469 项通过、2 项浏览器未启用,2 项误带入的 W25 用例已移出本提交;最终任务与交付边界 37 项通过。make 检查、最终类型、84 项资源及 diff 检查通过。未重跑浏览器或 Pi 宿主,不以合成调用认证外部模型效果。
独立整体审查四维通过;证据保存在 R2-20260909/提交W20-W24。
2026-09-13 16:24:42 +08:00

125 lines
5.2 KiB
Python

"""真实诊断与明确作者范围生成新候选,当前正文保持;失败无副作用。"""
from dataclasses import asdict, replace
import pytest
import test_规则库与诊断 as 诊断测试
from muse.共享.错误 import Muse错误
from muse.审校修订.接口 import 修订请求, 允许选区
from muse.正式变更.接口 import 固定哈希
from muse.正文写作.接口 import 文本节点, 正文草稿, 段落, 段落哈希, 选段修改
pytestmark = pytest.mark.数据库
诊断环境 = 诊断测试.诊断环境
def 准备(env):
app, 身份, target = env
svc = app.要求审校()
svc.导入规则候选(身份)
report = svc.生成诊断(身份, target, 预览候选=True)
finding = next(f for f in report["report"]["findings"] if f["rule_id"] == "l002")
doc = app.要求正文().读取正文(身份, "diagnosis-ch")
from pydantic import TypeAdapter
draft = TypeAdapter(正文草稿).validate_python(doc["document"])
p = draft.paragraphs[0]
patch = 选段修改(p.paragraph_id, 段落哈希(p), 0, 7, "值得注意的是,", "", finding["id"])
return (
svc,
身份,
修订请求(
report["diagnosis_id"],
固定哈希(report["report"]),
(patch,),
(允许选区("p1", 0, 7),),
(finding["id"],),
"移除作者确认无功能的元话语",
),
doc,
)
def test_真实诊断批准选区仅生成候选且同命令幂等__231001(诊断环境):
svc, 身份, 请求, 原稿 = 准备(诊断环境)
app = 诊断环境[0]
receipt = svc.提出修订(身份, "patch-1", 请求)
assert receipt == svc.提出修订(身份, "patch-1", 请求)
candidate = app.要求正文().读取候选(身份, receipt["target_ref"])
assert candidate["visible_text"] == "窗外正在下雨。"
assert candidate["decision"] == "undecided"
assert app.要求正文().读取正文(身份, "diagnosis-ch") == 原稿
assert receipt["results"][0]["checks"]["semantic_status"] == "unverified"
@pytest.mark.parametrize(
"bad", ["missing_finding", "unapproved", "outside", "hash", "text", "purpose"]
)
def test_伪发现和越范围修订不产生候选__231002(诊断环境, bad):
svc, 身份, r, 原稿 = 准备(诊断环境)
app = 诊断环境[0]
with pytest.raises((Muse错误, ValueError)):
if bad == "missing_finding":
r = replace(r, patches=(replace(r.patches[0], finding_id="fake"),))
elif bad == "unapproved":
r = replace(r, approved_findings=())
elif bad == "outside":
r = replace(r, allowed_ranges=(允许选区("p1", 1, 7),))
elif bad == "hash":
r = replace(r, diagnosis_hash="0" * 64)
elif bad == "text":
r = replace(r, patches=(replace(r.patches[0], original="伪造"),))
else:
r = replace(r, purpose="")
svc.提出修订(身份, "bad-patch", r)
assert app.要求正文().列出候选(身份, "diagnosis-ch") == []
assert app.要求正文().读取正文(身份, "diagnosis-ch") == 原稿
def test_旧诊断不能覆盖作者后来保存的新稿__231003(诊断环境):
svc, 身份, r, _ = 准备(诊断环境)
app = 诊断环境[0]
app.要求正文().保存人工(
身份, "later", "diagnosis-ch", 1, 正文草稿((段落("p1", (文本节点("作者的新句子。"),)),))
)
with pytest.raises(Muse错误):
svc.提出修订(身份, "stale-patch", r)
assert app.要求正文().读取正文(身份, "diagnosis-ch")["visible_text"] == "作者的新句子。"
assert app.要求正文().列出候选(身份, "diagnosis-ch") == []
def test_cli_default_persists_revision__1d9f2c(诊断环境, tmp_path):
import json
import subprocess
import sys
_, 身份, req, original = 准备(诊断环境)
app = 诊断环境[0]
secret = tmp_path / "password"
secret.write_text("synthetic-only")
secret.chmod(0o600)
config = tmp_path / "author.toml"
config.write_text(
'["数据库"]\n"取值方式"="受控存储"\n"位置"='
+ json.dumps(app.要求数据库().引用.位置)
+ '\n["资源"]\n"发布身份"="test"\n["HTTP"]\n"作者ID"='
+ json.dumps(身份.作者)
+ '\n"口令文件"='
+ json.dumps(str(secret))
+ "\n"
)
path = tmp_path / "revision.json"
path.write_text(
json.dumps({"command_id": "cli-revision", "request": asdict(req)}, ensure_ascii=False)
)
command = [sys.executable, "-I", "-m", "muse", "审校", str(config), "作者修订", str(path)]
first = subprocess.run(command, cwd=tmp_path, capture_output=True, text=True, timeout=30)
assert first.returncode == 0, first.stderr
second = subprocess.run(command, cwd=tmp_path, capture_output=True, text=True, timeout=30)
assert second.returncode == 0 and json.loads(first.stdout) == json.loads(second.stdout)
candidates = app.要求正文().列出候选(身份, "diagnosis-ch")
assert len(candidates) == 1 and candidates[0]["decision"] == "undecided"
assert candidates[0]["visible_text"] == "窗外正在下雨。"
assert app.要求正文().读取正文(身份, "diagnosis-ch") == original