muse-agent-example/tests/单元/test_声音与规则合同.py

737 lines
29 KiB
Python
Raw Permalink 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.

"""声音草案统计不变成认可;规则及持久化观察分别沿实际接缝承接。"""
from copy import deepcopy
import pytest
from pydantic import ValidationError
from muse.共享.错误 import Muse错误
四类例证 = {"sf", "snf", "boundary", "regression"}
def _单规则库(规则库, 规则ID):
from muse.审校修订.接口 import 核对规则库
规则 = 规则库["rules"][规则ID]
引用 = [例证ID for 类型 in 四类例证 for 例证ID in 规则["samples"][类型]]
return 核对规则库([规则], [规则库["samples"][例证ID] for 例证ID in 引用])
def _稿(文本):
from muse.正文写作.接口 import 文本节点, 正文草稿, 段落
return 正文草稿((段落("p1", (文本节点(文本),)),))
def _整段替换(原稿, 替换):
from muse.正文写作.接口 import 段落哈希, 选段修改
段 = 原稿.paragraphs[0]
原文 = 段.content[0].text
return 选段修改("p1", 段落哈希(段), 0, len(原文), 原文, 替换, "finding-1")
@pytest.mark.case_id(
"TC-5efcd58a2596",
environment="离线新版声音/规则公开函数与原合成输入;不认证生产启用或文学效果",
when="调用新公开的声音草案/统计方法",
then=[
"候选状态仍非认可:新proposed且persisted=false替代旧candidate",
"同64句样张满足1000非空白码点与20句规模门,不代表风格代表性",
"人物声音保持unknown_fields中的characters",
"新metrics下句长中位数大于0,统计不推语义",
],
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_声音草案公开采样规模和未知项__5efcd5():
from muse.审校修订.接口 import 生成声音草案
文本 = "".join(f"第{i}句,门外的雨还在落下,青石路上没有一个人。\n" for i in range(1, 65))
草案 = 生成声音草案("synthetic:demo", [{"source_ref": "demo.txt", "text": 文本}])
assert 草案["status"] == "proposed" and 草案["persisted"] is False
assert 草案["sampling"]["sample_sufficient"] is True
assert "characters" in 草案["unknown_fields"]
assert 草案["metrics"]["sentence_length"]["median"] > 0
for 候选 in 草案["example_candidates"]:
assert 文本[候选["start"] : 候选["end"]] == 候选["quote"]
@pytest.mark.case_id(
"TC-f1f21ad8eece",
environment="离线新版声音/规则公开函数与原合成输入;不认证生产启用或文学效果",
when="调用新公开的声音草案/统计方法",
then=["错误source_sha256拒绝;通过新审校错误而不是旧ValueError呈现同含义"],
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_声音草案拒绝来源哈希漂移__f1f21a():
from muse.审校修订.接口 import 生成声音草案
with pytest.raises(Muse错误, match="source_sha256"):
生成声音草案(
"synthetic:demo",
[{"source_ref": "demo.txt", "source_sha256": "0" * 64, "text": "甲走进门。"}],
)
@pytest.mark.case_id(
"TC-3bba023da2a5",
environment="离线新版声音/规则公开函数与原合成输入;不认证生产启用或文学效果",
when="调用新公开的声音草案/统计方法",
then=["相同甲/乙/雨三句重复计算完全相同,小样本不冒充分规模"],
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_声音画像保持确定性__3bba02():
from muse.审校修订.接口 import 统计声音样本
文本 = "甲走进门。乙关上窗。雨落下来。"
assert 统计声音样本(文本) == 统计声音样本(文本)
assert 统计声音样本(文本)["sample_sufficient"] is False
@pytest.mark.case_id(
"NC-w22-22b001",
environment="默认离线",
given="空样张、缺来源或不一致哈希",
when="调用声音统计/预览",
then=["拒绝不完整输入"],
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
@pytest.mark.parametrize(
"输入",
[
[],
[{"source_ref": "a", "text": " "}],
[{"text": "正文"}],
[{"source_ref": "a", "text": "正文", "source_sha256": "bad-hash"}],
],
)
def test_声音预览拒空样张和含糊哈希__22b001(输入):
from muse.审校修订.接口 import 生成声音草案
with pytest.raises(Muse错误):
生成声音草案("synthetic:demo", 输入)
@pytest.mark.case_id(
"NC-w22-22b002",
environment="默认离线",
given="重复来源、长串未闭引号及嵌套引号",
when="调用声音统计/预览",
then=["重复来源不扩大规模;引号率按完整非重叠片段计算,不作语义识别"],
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_重复来源不增加样本且引号统计不冒语义识别__22b002():
from muse.审校修订.接口 import 生成声音草案, 统计声音样本
条 = {"source_ref": "same-source", "text": "同一份样张。"}
with pytest.raises(Muse错误, match="重复"):
生成声音草案("synthetic:demo", [条, 条])
原文 = "「" * 10000 + "未闭合的外引号“甲”“乙”"
assert 统计声音样本(原文)["quoted_span_ratio"] == round(6 / len(原文), 4)
嵌套 = "「引用“文字”仍属同一个外层片段」"
assert 统计声音样本(嵌套)["quoted_span_ratio"] == 1.0
@pytest.mark.case_id(
"TC-3accffa197cb",
environment="离线新版声音/规则公开函数与原合成输入;不认证生产启用或文学效果",
when="生成声音草案、投影保护项或验证规则候选。",
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_内置规则候选逐条具备四类反向可查例证__3accff():
from muse.审校修订.接口 import 核对规则启用, 读取内置规则
规则库 = 读取内置规则()
assert len(规则库["rules"]) >= 10
for 规则 in 规则库["rules"].values():
assert 规则["status"] == "candidate"
assert set(规则["samples"]) == 四类例证
for 类型 in 四类例证:
assert 规则["samples"][类型]
for 例证ID in 规则["samples"][类型]:
例证 = 规则库["samples"][例证ID]
assert 例证["type"] == 类型
assert 规则["id"] in 例证["rules"]
with pytest.raises(Muse错误, match="B10逐例评测和正式批准"):
核对规则启用(next(iter(规则库["rules"].values())), 规则库["samples"], {"pass": True})
@pytest.mark.case_id(
"TC-de273edf8d1a",
environment="离线新版声音/规则公开函数与原合成输入;不认证生产启用或文学效果",
when="生成声音草案、投影保护项或验证规则候选。",
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_规则缺回归例证时拒绝候选合同__de273e():
from muse.审校修订.接口 import 核对规则, 读取内置规则
规则库 = 读取内置规则()
损坏 = deepcopy(规则库["rules"]["l002"])
损坏["samples"]["regression"] = []
with pytest.raises(Muse错误, match="四类例证"):
核对规则(损坏, 规则库["samples"])
@pytest.mark.case_id(
"TC-33e0bde5937f",
environment="离线新版声音/规则公开函数与原合成输入;不认证生产启用或文学效果",
when="生成声音草案、投影保护项或验证规则候选。",
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_规则引用不存在例证时拒绝候选合同__33e0bd():
from muse.审校修订.接口 import 核对规则, 读取内置规则
规则库 = 读取内置规则()
损坏 = deepcopy(规则库["rules"]["l002"])
损坏["samples"]["regression"] = ["不存在的样例id"]
with pytest.raises(Muse错误, match="四类例证"):
核对规则(损坏, 规则库["samples"])
@pytest.mark.case_id(
"TC-680ac77e24a7",
environment="离线新版声音/规则公开函数与原合成输入;不认证生产启用或文学效果",
when="生成声音草案、投影保护项或验证规则候选。",
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_叙述规则屏蔽对白且命中仍只询问__680ac7():
from muse.审校修订.接口 import 诊断文本, 读取内置规则
文本 = "「值得注意的是,这里是对白。」值得注意的是,这里是叙述。"
规则库 = _单规则库(读取内置规则(), "l002")
诊断 = 诊断文本(文本, work_id="synthetic:demo", 规则库=规则库, 预览候选=True)
assert len(诊断["findings"]) == 1
发现 = 诊断["findings"][0]
assert 发现["quote"] == "值得注意的是"
assert 发现["start"] == 文本.rindex("值得注意的是")
assert 发现["carrier"] == "narration"
assert 发现["decision_proposal"] == "ask"
from muse.审校修订.机器味诊断 import 定位载体, 载体区间
assert 定位载体(文本, 1, 7, 载体区间(文本)) == "dialogue"
@pytest.mark.case_id(
"TC-dbe2980ca479",
environment="离线新版声音/规则公开函数与原合成输入;不认证生产启用或文学效果",
when="生成声音草案、投影保护项或验证规则候选。",
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_情态与新增时间数字不能通过保真门__dbe298():
from muse.审校修订.接口 import 核对修订保真
from muse.正文写作.接口 import 应用选段
用例 = [
("多半背景不凡", "背景都不凡", "推测情态"),
("谁也不知道", "那年秋分的夜里,谁也不知道", "新的时间"),
("谁也不知道", "2026年3天后的夜里,谁也不知道", "新的时间"),
]
for 原文, 替换, 错误片段 in 用例:
原稿 = _稿(原文)
修改 = _整段替换(原稿, 替换)
结果 = 核对修订保真(原稿, 应用选段(原稿, (修改,)), (修改,))
assert 结果["mechanical_pass"] is False
assert any(错误片段 in 错误 for 错误 in 结果["errors"])
@pytest.mark.case_id(
"TC-ccc9845fd27d",
environment="离线新版声音/规则公开函数与原合成输入;不认证生产启用或文学效果",
when="生成声音草案、投影保护项或验证规则候选。",
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_无确认声音不能变成文学通过__ccc984():
from muse.审校修订.接口 import 生成审校分片, 组装文学报告
文本 = "甲走进门。乙关上窗。"
片 = 生成审校分片(文本, "a" * 64)
结果 = [
{
"shard_id": 当前.片ID,
"dimensions": {
"continuity": {"status": "reviewed", "summary": "无冲突。", "findings": []},
"craft": {"status": "reviewed", "summary": "已审。", "findings": []},
"voice": {"status": "uncalibrated", "summary": "没有已确认声音。", "findings": []},
},
}
for 当前 in 片
]
报告 = 组装文学报告(文本, "a" * 64, 片, 结果, 允许依据=(), 已确认声音=False)
assert 报告["dimension_status"]["voice"] == "uncalibrated"
assert 报告["model_verified"] is False and 报告["persisted"] is False
assert "pass" not in 报告
with pytest.raises(Muse错误):
组装文学报告(文本, "a" * 64, 片, 结果, 允许依据=(), 已确认声音={"status": "candidate"})
@pytest.mark.case_id(
"TC-43819837fcfe",
environment="离线,固定样张、规则和四类反例",
when="生成声音草案、投影保护项或验证规则候选。",
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_无声音账本时内置规则四类例证完整且为候选__438198():
from muse.审校修订.接口 import 读取内置规则
规则库 = 读取内置规则()
assert len(规则库["rules"]) >= 10
assert {s["type"] for s in 规则库["samples"].values()} >= {
"sf",
"snf",
"boundary",
"regression",
}
assert all(r["status"] == "candidate" for r in 规则库["rules"].values())
@pytest.mark.case_id(
"TC-f104cf5836ec",
environment="离线,固定样张、规则和四类反例",
when="生成声音草案、投影保护项或验证规则候选。",
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_声音提案版本字段值边界拒绝__f104cf():
from muse.审校修订.接口 import 声音提案请求, 声音样张引用
样张 = 声音样张引用("document", "chapter-1", 1, "a" * 64, "main")
with pytest.raises(Muse错误, match="声音候选需要"):
声音提案请求(
work_id="synthetic:demo",
expected_voice_revision=-1,
schema_id="voice",
base_version=1,
narrator={"叙述": "冷峻"},
samples=(样张,),
)
with pytest.raises(Muse错误, match="声音候选需要"):
声音提案请求(
work_id="synthetic:demo",
expected_voice_revision=0,
schema_id="voice",
base_version=0,
narrator={"叙述": "冷峻"},
samples=(样张,),
)
@pytest.mark.case_id(
"TC-b4afca23803b",
environment="离线新版声音/规则公开函数与原合成输入;不认证生产启用或文学效果",
when="生成声音草案、投影保护项或验证规则候选。",
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_声音结构版本拒绝非整数__b4afca():
from muse.审校修订.接口 import 声音提案请求, 声音样张引用
样张 = 声音样张引用("document", "chapter-1", 1, "a" * 64, "main")
with pytest.raises(ValidationError) as 错误:
声音提案请求(
work_id="synthetic:demo",
expected_voice_revision=0,
schema_id="voice",
base_version="nope",
narrator={"叙述": "冷峻"},
samples=(样张,),
)
assert "base_version" in str(错误.value)
@pytest.mark.case_id(
"TC-1fe56c6532f3",
environment="离线新版声音/规则公开函数与原合成输入;不认证生产启用或文学效果",
when="生成声音草案、投影保护项或验证规则候选。",
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_声音提案缺叙述者内容时拒绝__1fe56c():
from muse.审校修订.接口 import 声音提案请求, 声音样张引用
样张 = 声音样张引用("document", "chapter-1", 1, "a" * 64, "main")
with pytest.raises(Muse错误, match="叙述者内容"):
声音提案请求("synthetic:demo", 0, "voice", 1, {}, (样张,))
def _样张():
from muse.审校修订.接口 import 声音样张引用
return 声音样张引用("document", "chapter-1", 1, "a" * 64, "main")
def _案例(case_id, 哈希):
from muse.审校修订.接口 import 案例定位
return 案例定位(case_id, 1, 哈希)
def _确定性规则():
from muse.审校修订.接口 import 读取内置规则
return [
规则
for 规则 in 读取内置规则()["rules"].values()
if 规则["trigger"]["type"] != "model_judgment"
]
@pytest.mark.case_id(
"TC-49204fa147de",
environment="离线,固定样张、规则和四类反例",
when="生成声音草案、投影保护项或验证规则候选。",
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_确定性触发规则可回放四类合同__49204f():
from muse.审校修订.接口 import 核对规则, 读取内置规则
库 = 读取内置规则()
确定性 = _确定性规则()
assert len(确定性) >= 2
assert {规则["trigger"]["type"] for 规则 in 确定性} <= {"regex", "handler", "density"}
for 规则 in 确定性:
引用 = [
例证ID
for 类型 in ("sf", "snf", "boundary", "regression")
for 例证ID in 规则["samples"][类型]
]
核对规则(规则, {例证ID: 库["samples"][例证ID] for 例证ID in 引用})
assert 规则["status"] == "candidate"
assert 规则["default_disposition"] in {"advisory", "blocking", "candidate"}
@pytest.mark.case_id(
"TC-2b1f41398f73",
environment="离线,固定样张、规则和四类反例",
when="生成声音草案、投影保护项或验证规则候选。",
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_未提供样式时上下文不含声音节__2b1f41():
from muse.上下文.声音材料 import 冻结声音身份, 校验声音节
# 无已确认声音=合法空注入:B09 不把任何声音节放入上下文,writer 输入不含样式约束。
assert 校验声音节(None) is None
assert 冻结声音身份(None) is None
@pytest.mark.case_id(
"TC-0ef41b9bcc12",
environment="离线,固定样张、规则和四类反例",
when="生成声音草案、投影保护项或验证规则候选。",
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_确认声音约束冻结且投影只给写手__0ef41b():
import uuid
from muse.上下文.声音材料 import 冻结声音身份, 校验声音节, 身份键
版本 = str(uuid.uuid4())
材料 = {
"version_id": 版本,
"revision": 1,
"content_hash": "a" * 64,
"schema_hash": "b" * 64,
"projection_version": "c",
"材料键": "声音:" + 版本,
"材料哈希": "d" * 64,
}
校验声音节(材料) # 冻结身份完整时可用
assert 冻结声音身份(材料) == {k: 材料[k] for k in 身份键}
for 缺 in ("材料哈希", "version_id", "revision", "schema_hash"):
损坏 = {k: v for k, v in 材料.items() if k != 缺}
with pytest.raises(Muse错误):
校验声音节(损坏)
@pytest.mark.case_id(
"TC-0b66c8424583",
environment="离线,固定样张、规则和四类反例",
when="生成声音草案、投影保护项或验证规则候选。",
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_空白样式约束被丢弃__0b66c8():
from muse.审校修订.接口 import 声音提案请求
for 关键字 in ({"verbal_tics": (" ",)}, {"protected_expressions": ("\n",)}):
with pytest.raises(Muse错误, match="空白"):
声音提案请求("synthetic:demo", 0, "voice", 1, {"叙事": "冷峻"}, (_样张(),), **关键字)
@pytest.mark.case_id(
"TC-e83f562f0ff7",
environment="离线,固定样张、规则和四类反例",
when="生成声音草案、投影保护项或验证规则候选。",
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_声音来源依据不混入写手输入__e83f56():
from pydantic import ValidationError
from muse.上下文.声音材料 import 身份键
# 写手只看到声音内容三键;来源/版本身份只留在冻结节,不进入内容投影。
内容键 = {"narrator", "verbal_tics", "protected_expressions"}
assert not (set(身份键) & 内容键)
from muse.审校修订.接口 import 声音提案请求
# 旧“角色→口痒归属”字段不再成为写手内容的第二通道。
with pytest.raises(ValidationError):
声音提案请求(
"synthetic:demo",
0,
"voice",
1,
{"叙事": "冷峻"},
(_样张(),),
characters={"甲": ["嗯"]},
)
@pytest.mark.case_id(
"TC-c4cde790f809",
environment="离线,固定样张、规则和四类反例",
when="生成声音草案、投影保护项或验证规则候选。",
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_声音草案产物可直接进入确认定位__c4cde7():
from uuid import uuid4
from muse.审校修订.接口 import 声音定位, 声音提案请求
# draft(候选请求)→ confirm(审阅定位)共享作品与基线;提案身份可被审阅定位引用。
请求 = 声音提案请求("synthetic:demo", 0, "voice", 1, {"句式画像": "短句叙述"}, (_样张(),))
定位 = 声音定位("synthetic:demo", str(uuid4()), 1, "a" * 64, 0)
assert 定位.work_id == 请求.work_id
assert 定位.expected_voice_revision == 请求.expected_voice_revision
with pytest.raises(Muse错误):
声音定位("synthetic:demo", "not-uuid", 1, "a" * 64, 0)
@pytest.mark.case_id(
"TC-f1f4ced3f7e6",
environment="离线,固定样张、规则和四类反例",
when="生成声音草案、投影保护项或验证规则候选。",
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_完整声音候选经合同通过可提供确认__f1f4ce():
from muse.审校修订.接口 import 声音提案请求
# grounding 输入齐全(叙述者、样张、口癖与保护均有字段)时合同不误拒。
请求 = 声音提案请求(
"synthetic:demo",
0,
"voice",
1,
{"句式画像": "短句叙述", "达标样张": "甲走进门。"},
(_样张(),),
verbal_tics=("没有再说话",),
protected_expressions=("雨落下来。",),
)
assert 请求.narrator["达标样张"] and 请求.verbal_tics and 请求.protected_expressions
assert len(请求.samples) == 1
@pytest.mark.case_id(
"TC-6111a82b27ea",
environment="离线,固定样张、规则和四类反例",
when="生成声音草案、投影保护项或验证规则候选。",
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_规则草案拒绝不足四类或单边__6111a8():
from muse.审校修订.接口 import 案例规则请求
引用 = (
_案例("00000000-0000-4000-8000-000000000001", "a" * 64),
_案例("00000000-0000-4000-8000-000000000002", "b" * 64),
)
for 数量 in range(0, 4):
with pytest.raises(Muse错误, match="4至64"):
案例规则请求({"id": "candidate-x"}, 引用[:数量])
@pytest.mark.case_id(
"TC-6b7751add3c6",
environment="离线,固定样张、规则和四类反例",
when="生成声音草案、投影保护项或验证规则候选。",
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_额外样例只从已确认案例投影__6b7751():
from muse.审校修订.接口 import 案例规则请求
引用 = tuple(_案例(f"00000000-0000-4000-8000-{i:012d}", chr(97 + i) * 64) for i in range(4))
for 字段 in ("samples", "status", "case_card_ids", "evidence"):
with pytest.raises(Muse错误, match="样例、状态和依据由服务生成"):
案例规则请求({"id": "candidate-x", 字段: {}}, 引用)
@pytest.mark.case_id(
"TC-cb044029fc57",
environment="离线,固定样张、规则和四类反例",
when="生成声音草案、投影保护项或验证规则候选。",
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_已确认声音内容作为写手唯一通道__cb0440():
from pydantic import ValidationError
from muse.审校修订.接口 import 声音提案请求
# 声音内容三键是写手 guidance 的唯一通道;角色级“同时归属”输入被合同拒绝。
with pytest.raises(ValidationError):
声音提案请求(
"synthetic:demo",
0,
"voice",
1,
{"叙事": "冷峻"},
(_样张(),),
角色归属={"甲": ["嗯"]},
)
@pytest.mark.case_id(
"TC-0587dbd22c64",
environment="离线纯规则",
when="持久化、重验或查询诊断、声音、规则与案例。",
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_规则身份重复被公开合同拒绝__0587db():
from muse.审校修订.接口 import 核对规则库, 读取内置规则
库 = 读取内置规则()
规则 = list(库["rules"].values())
with pytest.raises(Muse错误, match="重复"):
核对规则库([*规则, 规则[0]], list(库["samples"].values()))
@pytest.mark.case_id(
"TC-c45d9e768e76",
environment="离线纯规则",
when="持久化、重验或查询诊断、声音、规则与案例。",
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_内置规则与所有四类例证经同一合同校验__c45d9e():
from muse.审校修订.接口 import 核对规则库, 读取内置规则
库 = 读取内置规则()
重验 = 核对规则库(list(库["rules"].values()), list(库["samples"].values()))
assert 重验 == 库
assert {sample["type"] for sample in 库["samples"].values()} == {
"sf",
"snf",
"boundary",
"regression",
}
@pytest.mark.case_id(
"TC-02fcb3e5524a",
environment="离线纯规则",
when="持久化、重验或查询诊断、声音、规则与案例。",
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_内置发布规则全部仅为候选__02fcb3():
from muse.审校修订.接口 import 读取内置规则
库 = 读取内置规则()
assert 库["rules"] and all(rule["status"] == "candidate" for rule in 库["rules"].values())
@pytest.mark.case_id(
"TC-9efb708e26f6",
environment="离线纯合同",
when="持久化、重验或查询诊断、声音、规则与案例。",
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_审校CLI默认走数据库而离线需显式指定__9efb70():
import inspect
from muse.接入.cli.审校命令 import 运行审校命令
assert inspect.signature(运行审校命令).parameters["离线"].default is False
@pytest.mark.case_id(
"TC-477b4a572369",
environment="离线纯合同",
when="持久化、重验或查询诊断、声音、规则与案例。",
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_CLI离线是诊断和修订回放的显式逃生口__477b4a(tmp_path):
import json
from muse.共享.错误 import 配置错误
from muse.接入.cli.审校命令 import 运行审校命令
路径 = tmp_path / "offline.json"
路径.write_text(json.dumps({"text": "值得注意的是。", "work_id": "work-a"}, ensure_ascii=False))
with pytest.raises(配置错误, match="离线模式仅用于"):
运行审校命令(None, "案例清单", str(路径), 离线=True)
assert 运行审校命令(None, "诊断", str(路径), 离线=True)["persisted"] is False
@pytest.mark.case_id(
"TC-10cdc16e5ad7",
environment="离线纯合同",
when="持久化、重验或查询诊断、声音、规则与案例。",
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_离线诊断不写数据库且明示未持久化__10cdc1(tmp_path):
import json
from muse.接入.cli.审校命令 import 运行审校命令
路径 = tmp_path / "receipt.json"
路径.write_text(json.dumps({"text": "值得注意的是。", "work_id": "work-a"}, ensure_ascii=False))
报告 = 运行审校命令(None, "诊断", str(路径), 离线=True)
assert 报告["persisted"] is False and 报告["mode"] == "candidate_preview"
assert 报告["work_id"] == "work-a"
@pytest.mark.case_id(
"TC-5cd6b80a3e5e",
environment="离线,固定样张、规则和四类反例",
when="生成声音草案、投影保护项或验证规则候选。",
contract="docs/系统架构/新版设计/模块设计/B06-审校修订.md",
)
def test_CLI离线诊断不触数据库且明示未持久化__5cd6b8(tmp_path):
import json
from muse.接入.cli.审校命令 import 运行审校命令
路径 = tmp_path / "offline-diag.json"
路径.write_text(json.dumps({"text": "值得注意的是。", "work_id": "work-a"}, ensure_ascii=False))
报告 = 运行审校命令(None, "诊断", str(路径), 离线=True)
assert 报告["persisted"] is False and 报告["mode"] == "candidate_preview"
@pytest.mark.case_id(
"NC-w26-26d103",
environment="离线纯合同",
given="固定请求、来源与作者;按用例环境准备独立测试输入",
when="通过实际公开入口执行并核对拒绝、状态及持久结果",
then=["旧方法改进请求固定字节不增加规则默认字段"],
contract="docs/系统架构/新版设计/模块设计/B07-作者经验.md#有来源的运行观察",
)
def test_旧方法改进请求固定字节不增加规则默认字段__26d103():
from dataclasses import asdict
from muse.作者经验.接口 import 改进请求
from muse.正式变更.接口 import 固定哈希
request = 改进请求(
"11111111-1111-1111-1111-111111111111",
0,
"旧方法标题",
"旧方法理由",
"22222222-2222-2222-2222-222222222222",
("33333333-3333-3333-3333-333333333333",),
)
assert set(asdict(request)) == {
"improvement_id",
"expected_revision",
"title",
"rationale",
"method_version_id",
"feedback_ids",
}
assert (
固定哈希(asdict(request))
== "8c3b0f01e086c99906c9a5e239ea82c26a9b612badb05c234a2465f7c645d955"
)