"""候选状态与并发:CAS 定位、编辑后旧候选拒绝、并发采纳唯一成功。""" import pytest from pydantic import TypeAdapter from muse.共享.错误 import Muse错误 from muse.正式变更.接口 import 作者动作 from muse.正文写作.接口 import 文本节点, 正文草稿, 段落 pytestmark = pytest.mark.数据库 def _建候选(环境, 命令: str, 文本: str, 预期版本: int = 0): 作者 = 环境["作者"] 候选 = ( 环境["装配"] .要求正文() .创建人工候选( 作者, 命令, "ch-1", 预期版本, 正文草稿((段落("p1", (文本节点(文本),)),)), ) ) 候选ID = next( r["candidate_id"] for r in 候选["results"] if isinstance(r, dict) and "candidate_id" in r ) 候选行 = 环境["装配"].要求正文().读取候选(作者, 候选ID) from muse.正文写作.接口 import 候选定位 定位 = 候选定位( 候选行["candidate_id"], 候选行["revision"], 候选行["candidate_hash"], 候选行["document_id"], 候选行["current_document_revision"], ) 审阅 = 环境["装配"].要求正文().打开候选审阅(作者, 定位) return 定位, 审阅 def test_候选哈希不匹配采纳拒绝__16d013(章后环境, 章后工具): 环境 = 章后环境 from muse.正文写作.接口 import 候选定位 定位, 审阅 = _建候选(环境, "cas-cand-1", "林深在码头。") 坏定位 = 候选定位( 定位.candidate_id, 定位.candidate_revision, "0" * 64, 定位.target_ref, 定位.expected_revision, ) with pytest.raises(Muse错误) as 异常: 环境["装配"].要求正文().决定候选( 环境["作者"], "cas-adopt-bad", 坏定位, 作者动作.采纳, 审阅["review_id"], 审阅["review_hash"], ("document",), ) assert 异常.value.错误码 in {"REVISION_CONFLICT", "SCOPE_DENIED"} def test_正文编辑后旧候选采纳拒绝但明确弃用允许__16d024(章后环境, 章后工具): 环境 = 章后环境 定位, 审阅 = _建候选(环境, "stale-cand-1", "候选版本的正文。") # 正文前进一格:旧候选基线陈旧。 环境["剧本"].append(章后工具.抽取输出("编辑后的摘要。", [])) 章后工具.保存一章("ch-1", "作者直接改过的新正文。") with pytest.raises(Muse错误) as 异常: 环境["装配"].要求正文().决定候选( 环境["作者"], "stale-adopt-1", 定位, 作者动作.采纳, 审阅["review_id"], 审阅["review_hash"], ("document",), ) assert 异常.value.错误码 in {"SOURCE_STALE", "REVISION_CONFLICT"} # 陈旧候选仍可明确弃用:作者端对当前版本重开审阅后拒绝。 from muse.正文写作.接口 import 候选定位 当前行 = 环境["装配"].要求正文().读取候选(环境["作者"], 定位.candidate_id) 重开定位 = 候选定位( 当前行["candidate_id"], 当前行["revision"], 当前行["candidate_hash"], 当前行["document_id"], 当前行["current_document_revision"], ) 重开审阅 = 环境["装配"].要求正文().打开候选审阅(环境["作者"], 重开定位) 环境["装配"].要求正文().决定候选( 环境["作者"], "stale-reject-1", 重开定位, 作者动作.拒绝, 重开审阅["review_id"], 重开审阅["review_hash"], (), ) 行 = 环境["装配"].要求正文().读取候选(环境["作者"], 定位.candidate_id) assert 行["decision"] == "reject" # 作者正文不受影响。 正文 = 环境["装配"].要求正文().读取正文(环境["作者"], "ch-1") assert TypeAdapter(正文草稿).validate_python(正文["document"]) def test_并发采纳唯一成功且正文版本唯一__16d035(章后环境, 章后工具): 环境 = 章后环境 正文服务 = 环境["装配"].要求正文() 定位1, 审阅1 = _建候选(环境, "conc-cand-1", "并发候选甲。") 定位2, 审阅2 = _建候选(环境, "conc-cand-2", "并发候选乙。") 环境["剧本"].append(章后工具.抽取输出("并发摘要一。", [])) 回执1 = 正文服务.决定候选( 环境["作者"], "conc-adopt-1", 定位1, 作者动作.采纳, 审阅1["review_id"], 审阅1["review_hash"], ("document",), ) # 第二个候选基于同一旧版本:采纳时基线已前进,必须被拒绝。 with pytest.raises(Muse错误) as 异常: 正文服务.决定候选( 环境["作者"], "conc-adopt-2", 定位2, 作者动作.采纳, 审阅2["review_id"], 审阅2["review_hash"], ("document",), ) assert 异常.value.错误码 in {"SOURCE_STALE", "REVISION_CONFLICT"} 正文 = 正文服务.读取正文(环境["作者"], "ch-1") assert 正文["revision"] == 1 assert 回执1["receipt_id"]