"""声音草案统计不变成认可;规则及持久化观察分别沿实际接缝承接。""" 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" )