muse-agent-example/tests/集成/test_作者偏好与反馈.py
zizi d909d1bd1b 后端实现与用例身份:19 包集成落地并修复收尾缺陷
实现侧:
- 上下文:任务范围拆分为 范围校验/范围授权;索引按可发现口径重建、索引新鲜度改对称差;依赖校验统一快照漂移说明。
- 知识方法:方法与材料读取口径统一;超限方法材料按可选省略,核对路径不再二次计费;删除无合同的读时重算。
- 任务运行:新增 context.usage/tool.denied 事件类型;连接池常驻并在装配生命周期内开关;调用结算与核对分列。
- 效果评测/审校修订/交付连载/作者经验/作品规划:凭据冻结、标定消费、导出补证、事实引文核对等收尾修复。
- 资源加载:能力正文不再夹带索引用的导航注记(该注记此前进入角色与技能的模型提示)。
- 元数据:受保护骨架与代码保护属性对齐;字段校验与内置结构口径同步。
- 基础设施:环境预检进入装配生命周期;数据库连接运行期字段不参与相等比较;索引指纹归一化 jsonb 浮点。
- 删除被替代实现:7 份旧提示词模板与空壳 资料来源 读取器。

用例侧:
- 用例身份与导航元信息迁移;夹具补生命周期、同库暴露与模板封存;
- 本轮定向修复:方法材料省略、事实引文、迁移回执、额度与暂停用例、慢用例超时预算等。
2026-09-18 01:15:00 +08:00

226 lines
9.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""B07真实版本反馈、作者审阅及撤回;无模型响应或私表代写业务结果。"""
from dataclasses import replace
from uuid import uuid4
import psycopg
import pytest
import test_正文候选与作者决定 as 正文测试
from muse.作者经验.接口 import (
作者经验服务,
偏好决定,
偏好范围,
偏好请求,
反馈版本,
反馈请求,
读取偏好材料,
)
from muse.共享.调用身份 import 用途
from muse.共享.错误 import Muse错误
from muse.正文写作.接口 import 读取候选依据
pytestmark = pytest.mark.数据库
候选环境 = 正文测试.候选环境
@pytest.fixture
def 环境(候选环境):
body, author, pools = 候选环境
service = 作者经验服务(pools[用途.生产], body.正式)
_, candidate, _ = 正文测试.新候选(body, author)
original = body.读取正文(author, "chapter-candidate")
with pools[用途.生产].连接(只读=True) as conn:
updated = 读取候选依据(conn, author.作者, candidate["candidate_id"], 1)
feedback = 反馈请求(
"work-candidate",
反馈版本("document", "chapter-candidate", 1, original["document_hash"]),
反馈版本("candidate", candidate["candidate_id"], 1, updated["document_hash"]),
"这一次末段不要解释人物感受。",
"revise",
)
return service, author, pools, feedback
def _请求(**changes):
return 偏好请求(
**{
"preference_id": str(uuid4()),
"topic": "心理描写",
"text": "不解释人物感受。",
"quote": "今后不解释人物感受。",
"scope": 偏好范围(),
**changes,
}
)
def _定位(result, replacements=()):
return 偏好决定(
result["preference_id"], result["revision"], result["content_hash"], replacements
)
def _消费(pools, author):
with pools[用途.生产].连接(只读=True) as conn:
return 读取偏好材料(conn, author.作者, "work-candidate")
@pytest.mark.case_id(
"NC-w26-26a001",
environment="隔离PG;实际S01/B05/B09/S02与合成HTTP,不证明文学效果",
given="真实作者、作品及确切正文反馈版本",
when="保存范围偏好、审阅冲突、确认、撤回及重新消费",
then=["反馈保留确切原版本且不能冒充候选采纳"],
contract="docs/系统架构/新版设计/模块设计/B07-作者经验.md",
)
def test_反馈保留确切原版本且不能冒充候选采纳__26a001(环境):
service, author, pools, request = 环境
saved = service.记录反馈(author, "feedback", request)
assert service.记录反馈(author, "feedback", request) == saved
read = service.读取反馈(author, str(saved["feedback_id"]))
assert "原句「保留」" in read["before_text"]
assert "改过的首句" in read["after_text"]
assert read["payload"]["quote"] == request.quote
with pytest.raises(Muse错误):
service.记录反馈(author, "feedback", replace(request, quote="改了原话"))
with pytest.raises(Muse错误):
service.记录反馈(
author,
"bad-hash",
replace(request, before=replace(request.before, content_hash="0" * 64)),
)
with pools[用途.生产].连接(只读=True) as conn:
assert conn.execute("SELECT count(*) FROM muse_candidate_decision").fetchone()[0] == 0
assert service.列出偏好(author) == []
@pytest.mark.case_id(
"NC-w26-26a002",
environment="隔离PG;实际S01/B05/B09/S02与合成HTTP,不证明文学效果",
given="真实作者、作品及确切正文反馈版本",
when="保存范围偏好、审阅冲突、确认、撤回及重新消费",
then=["推断偏好待作者审阅确认且撤回保留历史"],
contract="docs/系统架构/新版设计/模块设计/B07-作者经验.md",
)
def test_推断偏好待作者审阅确认且撤回保留历史__26a002(环境):
service, author, pools, feedback = 环境
fid = service.记录反馈(author, "feedback", feedback)["feedback_id"]
request = _请求(origin="inferred", feedback_id=str(fid), quote=feedback.quote)
saved = service.保存偏好(author, "infer", request)["results"][0]
assert saved["state"] == "pending" and _消费(pools, author) == []
point = _定位(saved)
review = service.打开偏好审阅(author, point)
confirmed = service.确认偏好(
author, "confirm", point, 审阅ID=review["review_id"], 审阅哈希=review["review_hash"]
)
active = confirmed["results"][0]
assert active["state"] == "active" and _消费(pools, author)[0]["text"] == request.text
service.撤回偏好(author, "revoke", _定位(active))
assert _消费(pools, author) == []
assert service.读取偏好(author, request.preference_id, 2)["state"] == "active"
assert service.读取偏好(author, request.preference_id, 1)["payload"]["quote"] == feedback.quote
assert (
service.确认偏好(
author, "confirm", point, 审阅ID=review["review_id"], 审阅哈希=review["review_hash"]
)
== confirmed
)
@pytest.mark.case_id(
"NC-w26-26a003",
environment="隔离PG;实际S01/B05/B09/S02与合成HTTP,不证明文学效果",
given="真实作者、作品及确切正文反馈版本",
when="保存范围偏好、审阅冲突、确认、撤回及重新消费",
then=["显式范围冲突须点名旧版本而非自动覆盖"],
contract="docs/系统架构/新版设计/模块设计/B07-作者经验.md",
)
def test_显式范围冲突须点名旧版本而非自动覆盖__26a003(环境):
service, author, pools, _ = 环境
first = service.保存偏好(author, "first", _请求())["results"][0]
other = _请求(
text="允许解释人物感受。",
quote="这本书允许解释。",
scope=偏好范围("work", "work-candidate"),
)
second = service.保存偏好(author, "second", other)["results"][0]
assert first["state"] == "active" and second["state"] == "pending"
assert _消费(pools, author)[0]["preference_id"] == first["preference_id"]
point = _定位(second)
review = service.打开偏好审阅(author, point)
with pytest.raises(Muse错误, match="冲突"):
service.确认偏好(
author, "bad-confirm", point, 审阅ID=review["review_id"], 审阅哈希=review["review_hash"]
)
point = _定位(second, ((first["preference_id"], first["revision"]),))
review = service.打开偏好审阅(author, point)
service.确认偏好(
author, "confirm", point, 审阅ID=review["review_id"], 审阅哈希=review["review_hash"]
)
assert [x["text"] for x in _消费(pools, author)] == [other.text]
assert service.读取偏好(author, first["preference_id"])["state"] == "withdrawn"
@pytest.mark.case_id(
"NC-w26-26a004",
environment="隔离PG;实际S01/B05/B09/S02与合成HTTP,不证明文学效果",
given="真实作者、作品及确切正文反馈版本",
when="保存范围偏好、审阅冲突、确认、撤回及重新消费",
then=["审阅后偏好变化拒绝旧批准和旧修改"],
contract="docs/系统架构/新版设计/模块设计/B07-作者经验.md",
)
def test_审阅后偏好变化拒绝旧批准和旧修改__26a004(环境):
service, author, _, feedback = 环境
fid = service.记录反馈(author, "feedback", feedback)["feedback_id"]
req = _请求(origin="inferred", feedback_id=str(fid), quote=feedback.quote)
first = service.保存偏好(author, "infer", req)["results"][0]
point = _定位(first)
review = service.打开偏好审阅(author, point)
service.保存偏好(author, "edit", replace(req, text="保留必要解释。", expected_revision=1))
with pytest.raises(Muse错误):
service.确认偏好(
author, "stale", point, 审阅ID=review["review_id"], 审阅哈希=review["review_hash"]
)
with pytest.raises(Muse错误):
service.保存偏好(author, "stale-edit", replace(req, expected_revision=1))
@pytest.mark.case_id(
"NC-w26-26a005",
environment="隔离PG;实际S01/B05/B09/S02与合成HTTP,不证明文学效果",
given="真实作者、作品及确切正文反馈版本",
when="保存范围偏好、审阅冲突、确认、撤回及重新消费",
then=["偏好及反馈拒绝异作者及评测用途"],
contract="docs/系统架构/新版设计/模块设计/B07-作者经验.md",
)
def test_偏好及反馈拒绝异作者及评测用途__26a005(环境):
service, author, pools, request = 环境
fid = str(service.记录反馈(author, "feedback", request)["feedback_id"])
pref = service.保存偏好(author, "pref", _请求())["results"][0]
stranger = replace(author, 作者="stranger")
for action in [
lambda: service.读取反馈(stranger, fid),
lambda: service.读取偏好(stranger, pref["preference_id"]),
lambda: service.保存偏好(replace(author, 用途=用途.评测), "x", _请求()),
]:
with pytest.raises(Muse错误):
action()
with pools[用途.评测].连接() as conn, pytest.raises(psycopg.errors.InsufficientPrivilege):
conn.execute("SELECT * FROM muse_author_feedback")
@pytest.mark.case_id(
"NC-w26-26a006",
environment="隔离PG;实际S01/B05/B09/S02与合成HTTP,不证明文学效果",
given="真实作者、作品及确切正文反馈版本",
when="保存范围偏好、审阅冲突、确认、撤回及重新消费",
then=["单次要求不被登记为作者长期偏好"],
contract="docs/系统架构/新版设计/模块设计/B07-作者经验.md",
)
def test_单次要求不被登记为作者长期偏好__26a006(环境):
with pytest.raises(Muse错误, match="一次性"):
_请求(duration="request")
with pytest.raises(Muse错误, match="反馈"):
_请求(origin="inferred")