muse-agent-example/tests/集成/test_原观察返修比较.py
zizi 9e6f1c4481 R2 改造交付:新版模块化单体全量成果
- src/muse 新版全模块(装配/共享/上下文/任务运行/作品规划/故事世界/正文写作/审校修订/知识方法/作者经验/效果评测/交付连载/资料研究/正式变更/元数据/接入/基础设施/编排)+ 测试树(单元/契约/集成/架构/迁移/端到端/夹具)
- 129 项功能全部实现与自动验证(功能覆盖.json/矩阵),含 W31 补齐的规则与代价/节奏安排/伏笔与承诺
- 旧实现按处置清单退出(702 条中 324 删,保护合同与未迁移条目留存有据);web/app.py 旧工作台退役,新工作台为唯一写入口
- 数据库/旧库迁移:真实旧库内容批次迁移链(端点守卫/PG作品正文映射/质量资产缺省投影)
- 运行手册 docs/运行手册.md;W30 本机服务阶段一已运行(infra PG 为正式内容权威)
- R2 执行证据与私有运行材料在 .agents.local/改造/R2-20260909/(不入库)
2026-09-15 12:47:42 +08:00

310 lines
12 KiB
Python

"""两条旧观察以新版真实持久返修、规则复扫和固定双盲比较重放。"""
from __future__ import annotations
import hashlib
import json
from dataclasses import asdict
from pathlib import Path
import pytest
import test_持久返修会话 as 返修测试
import test_模型修订任务 as 修订测试
import test_返修独立比较 as 比较测试
from muse.审校修订.接口 import 允许选区, 核对规则库, 模型修订授权, 诊断文本
from muse.正式变更.接口 import 固定哈希
from muse.正文写作.接口 import 文本节点, 正文草稿, 段落, 选区坐标, 选段写作授权
from muse.编排.审校修订 import 发起有限返修, 读取有限返修
pytestmark = pytest.mark.数据库
生成环境 = 比较测试.生成环境
修订环境 = 比较测试.修订环境
比较环境 = 比较测试.比较环境
def _规则副本(env, 诊断报告: dict) -> dict:
服务 = env["装配"].要求审校()
当前 = 服务.读取规则库(env["作者"], 预览候选=True)
规则, 例证 = [], {}
for rule in 当前["rules"].values():
version = 服务.读取规则版本(env["作者"], rule["id"], rule["version"])
assert version["payload"]["rule"] == rule
规则.append(version["payload"]["rule"])
for sample_id, sample in version["payload"]["samples"].items():
assert sample_id not in 例证 or 例证[sample_id] == sample
例证[sample_id] = sample
frozen = 核对规则库(规则, list(例证.values()))
assert frozen["fingerprint"] == 诊断报告["rule_library_version"]
return frozen
def _完成并读取证明(env, experiment: dict) -> dict:
face = 比较测试._启动并运行(env, experiment)
assert len(face["units"]) == 2
proof = (
env["eval_app"]
.要求评测()
.导出返修比较证明(
env["eval_actor"],
experiment["experiment_id"],
env["pools"][比较测试.用途.维护],
env["maint_actor"],
)
)
return (
env["装配"]
.要求审校()
.读取返修比较证明(env["作者"], env["装配"].任务运行, proof["receipt_id"])
)
def test_full_patch_chain_passes_gates__446746(比较环境):
env = 比较环境
# 保留旧 RevisionContractTest 的 CLEAN_TEXT 与确切候选观察。
original = "值得注意的是,门外已经下起了雨。"
env["正文"].保存人工(
env["作者"],
"simple-original",
"ch-2",
0,
正文草稿((段落("simple", (文本节点(original),)),)),
)
saved = env["正文"].读取正文(env["作者"], "ch-2")
target = {
k: saved[k] for k in ("work_id", "chapter_id", "revision", "document_hash", "branch_id")
}
diagnosis = env["装配"].要求审校().生成诊断(env["作者"], target, 预览候选=True)
finding = next(f for f in diagnosis["report"]["findings"] if f["rule_id"] == "l002")
env["授权"] = 模型修订授权(
diagnosis["diagnosis_id"],
固定哈希(diagnosis["report"]),
(允许选区("simple", 0, 7),),
(finding["id"],),
"删除无功能套语",
)
env["发现"] = finding["id"]
session, candidate_id, _, _, experiment = 比较测试._准备实验(env, "tc-446746f1ed42")
result = session["rounds"][0]["result"]
assert result["checks"]["mechanical_pass"] and result["report"]["verdict"] == "passed"
candidate = env["正文"].读取候选(env["作者"], candidate_id)
assert candidate["visible_text"] == "门外已经下起了雨。"
rescanned = 诊断文本(
candidate["visible_text"],
work_id="gen-work",
规则库=_规则副本(env, diagnosis["report"]),
预览候选=True,
)
assert rescanned["findings"] == []
read = _完成并读取证明(env, experiment)
assert read["proof"]["version"] == "revision-comparison-proof-v1"
assert read["proof"]["outcome"] == "candidate"
assert read["proof"]["comparison_complete"] and len(read["proof"]["decisions"]) == 2
assert read["current"]["selection"] == "candidate"
assert not read["current"]["automatic_adoption"]
assert env["正文"].读取正文(env["作者"], "ch-2") == saved
def _唯一坐标(lines: list[str], original: str) -> 选区坐标:
matches = [
(index, line.index(original))
for index, line in enumerate(lines)
if line.count(original) == 1
]
assert len(matches) == 1, original
index, start = matches[0]
return 选区坐标(f"u0-{index}", start, start + len(original), original)
def test_full_pipeline_replay__98ee99(比较环境):
env = 比较环境
fixture = json.loads((Path(__file__).parents[1] / "夹具/返修回放/U0原观察.json").read_text())
original = fixture["text"]
assert len(original) == 408
assert hashlib.sha256(original.encode()).hexdigest() == fixture["text_sha256"]
assert fixture["patches"][1]["original"] not in original
after_first = original.replace(
fixture["patches"][0]["original"], fixture["patches"][0]["replacement"], 1
)
assert fixture["patches"][1]["original"] in after_first
lines = original.split("\n")
document = 正文草稿(
tuple(
段落(f"u0-{index}", (文本节点(line),) if line else ())
for index, line in enumerate(lines)
)
)
env["正文"].保存人工(env["作者"], "u0-original", "ch-2", 0, document)
saved = env["正文"].读取正文(env["作者"], "ch-2")
assert saved["visible_text"] == original
target = {
key: saved[key]
for key in ("work_id", "chapter_id", "revision", "document_hash", "branch_id")
}
diagnosis = env["装配"].要求审校().生成诊断(env["作者"], target, 预览候选=True)
findings = diagnosis["report"]["findings"]
assert len(findings) == 7
assert "也许这就是命运吧" not in {
original[finding["start"] : finding["end"]] for finding in findings
}
combined = "**那伙计上下打量了她一眼,**嘴角微微上扬"
intents = [(combined, "那伙计上下打量了她一眼")]
intents.extend((patch["original"], patch["replacement"]) for patch in fixture["patches"][2:])
selections = tuple(
env["正文"].读取选段定位(
env["作者"],
"gen-work",
"ch-2",
"main",
saved["revision"],
saved["document_hash"],
tuple(_唯一坐标(lines, text) for text, _ in intents),
)
)
protected = tuple(
env["正文"].读取选段定位(
env["作者"],
"gen-work",
"ch-2",
"main",
saved["revision"],
saved["document_hash"],
tuple(_唯一坐标(lines, text) for text in fixture["protected"]),
)
)
authorization = 选段写作授权(
"gen-work",
"ch-2",
"main",
saved["revision"],
saved["document_hash"],
"rewrite",
"按作者明确的八处编辑意图改写;前两项合并为同一原文上的不重叠选区",
selections,
protected,
)
started = 发起有限返修(
env["装配"],
env["作者"],
"u0-selection-session",
authorization,
配置ID="gen-config",
最大轮数=3,
)
task_id = started["rounds"][0]["task_id"]
返修测试.批准轮预算(env, task_id)
output = {
"edits": [
{
"selection_id": selection.selection_id,
"action": "replace",
"replacement": replacement,
"reason": "作者明确选段编辑意图",
}
for selection, (_, replacement) in zip(selections, intents, strict=True)
]
}
env["剧本"].append({"类型": "文本", "文本": output})
assert 修订测试.跑(env, task_id).状态.value == "completed"
session = 读取有限返修(env["装配"], env["作者"], started["session_id"])
result = session["rounds"][0]["result"]
candidate_id = session["rounds"][0]["candidate_id"]
assert result["source_kind"] == "selection" and result["diagnosis_id"] is None
assert result["checks"]["mechanical_pass"] and result["report"]["verdict"] == "passed"
candidate = env["正文"].读取候选(env["作者"], candidate_id)
candidate_text = candidate["visible_text"]
assert all(patch["marker"] not in candidate_text for patch in fixture["patches"])
assert all(text in candidate_text for text in fixture["protected"])
assert all(
text in candidate_text
for text in (
"「姑娘,这东西值三百两银子,不是您一枚铜钱就能当的。」",
"「三百年?我说小子,你这铺子也就立了三百年,可我手里这枚铜钱——」",
"「它传了三千年。」",
"三天后",
)
)
assert env["正文"].读取正文(env["作者"], "ch-2") == saved
rescanned = 诊断文本(
candidate_text,
work_id="gen-work",
规则库=_规则副本(env, diagnosis["report"]),
预览候选=True,
保护表达=tuple(fixture["protected"]),
)
assert rescanned["findings"] == []
session, same_candidate, publication, data, experiment = 比较测试._从既有返修会话准备实验(
env, "tc-98ee99c7cf24", session
)
assert same_candidate == candidate_id
svc = env["eval_app"].要求评测()
loaded_data = svc.读取数据集(env["eval_actor"], data["version_id"])
assert loaded_data["public_manifest"]["schema_version"] == "fixed-revision-pair-dataset-v2"
with pytest.raises(比较测试.Muse错误, match="没有生成输入"):
svc.读取生成输入(
env["eval_actor"], experiment["experiment_id"], experiment["sample_ids"][0]
)
assert data["source_hash"]
duplicate = 比较测试.评测服务(env["pools"][比较测试.用途.维护]).发布返修比较数据集(
env["maint_actor"], publication, env["库"], env["装配"].任务运行
)
assert duplicate["duplicate"] and duplicate["source_hash"] == data["source_hash"]
read = _完成并读取证明(env, experiment)
source = read["proof"]["source"]
assert read["proof"]["version"] == "revision-comparison-proof-v2"
assert source["version"] == "revision-comparison-source-v2"
assert "diagnosis" not in source
assert source["selection_authorization"] == {
"authorization_hash": 固定哈希(asdict(authorization)),
"basis_hash": session["source"]["basis_hash"],
"mode": "rewrite",
"purpose_hash": 固定哈希(authorization.purpose),
"selection_ids": [selection.selection_id for selection in selections],
"selections_hash": 固定哈希(asdict(authorization)["selections"]),
"protected_range_ids": [selection.selection_id for selection in protected],
"protected_ranges_hash": 固定哈希(asdict(authorization)["protected_ranges"]),
}
assert source["original"]["text_hash"] == fixture["text_sha256"]
assert source["candidate"]["text_hash"] == hashlib.sha256(candidate_text.encode()).hexdigest()
assert source["target"] == {
"work_id": "gen-work",
"chapter_id": "ch-2",
"branch_id": "main",
"original_revision": saved["revision"],
"original_document_hash": saved["document_hash"],
}
assert source["delivery"]["task_id"] == task_id
assert source["delivery"]["config_id"] == "gen-config"
assert source["delivery"]["resource_release"] == env["装配"].配置.资源发布身份
assert source["invariance"]["report_id"] == result["report"]["report_id"]
assert read["proof"]["outcome"] == "candidate"
assert read["proof"]["comparison_complete"] and len(read["proof"]["decisions"]) == 2
assert read["current"]["selection"] == "candidate"
assert not read["current"]["automatic_adoption"]
calls = len(env["received_judges"])
replay = (
env["eval_app"]
.要求评测()
.导出返修比较证明(
env["eval_actor"],
experiment["experiment_id"],
env["pools"][比较测试.用途.维护],
env["maint_actor"],
)
)
assert replay["receipt_id"] == read["receipt_id"]
assert len(env["received_judges"]) == calls
assert (
env["装配"]
.要求审校()
.读取返修比较证明(env["作者"], env["装配"].任务运行, read["receipt_id"])
== read
)
assert len(env["received_judges"]) == calls
assert env["正文"].读取正文(env["作者"], "ch-2") == saved