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

393 lines
15 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.

"""旧 humanization 成功自动登记 win/lesson 的观察按 B07/W25 等价边界承接。
成功运行只形成有证据的运行观察;不因 win 标签或 promote 状态自动宣称改进有效、
方法或规则已启用。升格须真实反馈、精确目标与 owner 作者决定(S01/B10)。
"""
from dataclasses import replace
from uuid import uuid4
import pytest
from muse.任务运行.接口 import (
任务服务,
任务请求,
步骤处理器,
步骤结果,
步骤计划,
)
from muse.作者经验.接口 import 作者经验服务, 改进定位, 运行观察来源, 运行观察请求
from muse.共享.调用身份 import 内容用途, 用途, 调用身份
from muse.共享.错误 import Muse错误
from muse.正式变更.接口 import 参与者目录, 正式变更服务
from muse.编排.接口 import 流程定义, 流程服务, 流程登记
pytestmark = pytest.mark.数据库
@pytest.fixture
def 运行观察环境(应用测试库):
pool = 应用测试库[用途.生产]
author = 调用身份("improvement-author", None, 用途.生产, 内容用途.生成)
registry = 流程登记()
def 处理(context):
return 步骤结果({"recorded": True})
registry.登记处理器(步骤处理器("observation.test", "1", 处理, "v1", "v1"))
registry.登记类型("observation-test", 必需保护=())
registry.登记恢复检查("observation-test", "1", lambda _: None)
runtime = 任务服务(pool, registry)
流程服务(runtime, registry).发布(
流程定义("observation-test", "1", (步骤计划("测试步骤", "observation.test", "1"),))
)
formal = 正式变更服务(pool, 参与者目录())
return {
"pool": pool,
"author": author,
"run": runtime,
"service": 作者经验服务(pool, formal),
}
def _开始(env, *, command=None):
actor = env["author"]
request = 任务请求(
"observation-test",
command or str(uuid4()),
actor.作者,
用途.生产,
actor.内容用途,
{"private_input": "不应进入观察的正文"},
"synthetic-policy-1",
"synthetic-release-1",
{
"source_scope": {},
"schema_versions": {},
"authorization": "synthetic-grant",
"budget": {},
"stop_conditions": {},
},
)
tid = env["run"].创建任务(request, "observation-test", "1")
claim = env["run"].领取步骤("worker", ["observation.test"], 任务ID=tid, 作者=actor.作者)
assert claim is not None
return tid, claim
def _来源(env, tid, attempt_id):
return env["service"].读取运行观察来源(env["author"], tid, attempt_id)
def _完成(env, **kwargs):
tid, claim = _开始(env, **kwargs)
env["run"].执行一步(claim)
return tid, claim, _来源(env, tid, claim.尝试ID)
def _观察(source, *, phenomenon, quote, background, issue=""):
return 运行观察请求(
(运行观察来源(**source["locator"]),),
phenomenon,
quote,
background,
issue,
)
def _无自动升格(env, saved):
"""成功运行只形成观察:不自动产生偏好、观察汇总或可启停的改进/规则目标。"""
assert saved["state"] == "observation"
assert saved["payload"]["causality"] == "not_established"
assert saved["payload"]["measurement_source"] == "runtime_evidence"
assert saved["payload"]["interpretation_source"] == "author_report"
assert env["service"].列出偏好(env["author"]) == []
assert env["service"].读取观察(env["author"])["observations"] == []
with pytest.raises(Muse错误):
env["service"].请求启停(
env["author"],
"no-auto-promotion",
改进定位(str(saved["observation_id"]), 1, saved["content_hash"]),
"enable",
)
def test_接受正文候选只留决定反馈不自动登记胜例__9fc9e5(运行观察环境):
"""旧 accept 登记 win / discard 登记 lesson:新版只保留有证据观察与作者原话。
旧观察同保留 candidate_sha256 与 creator 的输入在此转为实时反馈与观察,
不自动产生任何 lessons/win 记录。
"""
env = 运行观察环境
tid, claim, source = _完成(env)
candidate_sha256 = "abc"
saved = env["service"].记录运行观察(
env["author"],
"decision-event",
_观察(
source,
phenomenon="作者决定正文候选去留",
quote="丢弃该候选,改写转折前的铺陈。",
background=f"接受或丢弃候选决定(candidate_sha256={candidate_sha256},creator=决定正文候选去留)。",
),
)
assert saved["payload"]["interpretation_source"] == "author_report"
读回 = env["service"].读取运行观察(env["author"], saved["observation_id"])
assert candidate_sha256 in 读回["payload"]["background"]
assert "丢弃该候选" in 读回["payload"]["quote"]
_无自动升格(env, saved)
def test_审查批次写回保留批次键与通过数__1f9573(运行观察环境):
env = 运行观察环境
_, _, source = _完成(env)
saved = env["service"].记录运行观察(
env["author"],
"review-batch",
_观察(
source,
phenomenon="知识卡三角色审核已写回",
quote="保留两票通过的一卡。",
background="批量键=review-3-cal-1-a;pass=2(旧 win 登记的批次 detail 转为观察背景)。",
),
)
读回 = env["service"].读取运行观察(env["author"], saved["observation_id"])
assert (
"review-3-cal-1-a" in 读回["payload"]["background"]
and "pass=2" in 读回["payload"]["background"]
)
_无自动升格(env, saved)
def test_知识升格窗批完成保留已处理窗口数__b87d69(运行观察环境):
env = 运行观察环境
_, _, source = _完成(env)
saved = env["service"].记录运行观察(
env["author"],
"upgrade-window",
_观察(
source,
phenomenon="作品面知识升格窗批完成",
quote="四个窗口全部处理完成。",
background="windows_done=4;run_id=upgrade-5-done4。",
),
)
读回 = env["service"].读取运行观察(env["author"], saved["observation_id"])
assert "windows_done=4" in 读回["payload"]["background"]
assert "upgrade-5-done4" in 读回["payload"]["background"]
_无自动升格(env, saved)
def test_章后知识抽取完成保留章序__679e5e(运行观察环境):
env = 运行观察环境
_, _, source = _完成(env)
saved = env["service"].记录运行观察(
env["author"],
"chapter-extract",
_观察(
source,
phenomenon="章后知识抽取落库成功",
quote="第九章抽取结果为既有事实增量。",
background="chapter_order=9;抽取不改写已确认事实。",
),
)
读回 = env["service"].读取运行观察(env["author"], saved["observation_id"])
assert "chapter_order=9" in 读回["payload"]["background"]
_无自动升格(env, saved)
def test_机器味案例批次落库保留64位运行身份__3b729b(运行观察环境):
env = 运行观察环境
_, _, source = _完成(env)
run_id = "a" * 64
saved = env["service"].记录运行观察(
env["author"],
"capture-cases",
_观察(
source,
phenomenon="AI味案例卡批次已落库",
quote="本批案例进入待复核,未自动启用规则。",
background=f"run_id={run_id};creator=记录机器味案例。",
),
)
读回 = env["service"].读取运行观察(env["author"], saved["observation_id"])
assert run_id in 读回["payload"]["background"]
assert "记录机器味案例" in 读回["payload"]["background"]
_无自动升格(env, saved)
def test_预防材料装配完成只留观察不自动启用__f30e89(运行观察环境):
env = 运行观察环境
_, _, source = _完成(env)
saved = env["service"].记录运行观察(
env["author"],
"prevention-assembled",
_观察(
source,
phenomenon="生成前 AI 味预防合同已装配",
quote="预防材料已就位,待作者启用。",
background="creator=预防机器味;合同仅作候选,未消费于生成。",
),
)
读回 = env["service"].读取运行观察(env["author"], saved["observation_id"])
assert "预防机器味" in 读回["payload"]["background"]
_无自动升格(env, saved)
def test_稳定评测报告完成保留运行与创建者__5b8778(运行观察环境):
env = 运行观察环境
_, _, source = _完成(env)
saved = env["service"].记录运行观察(
env["author"],
"stable-score",
_观察(
source,
phenomenon="正文盲评稳定报告",
quote="本次盲评结论稳定,原文不变。",
background="run_id=score-run-1;creator=评估内容质量。",
),
)
读回 = env["service"].读取运行观察(env["author"], saved["observation_id"])
assert "score-run-1" in 读回["payload"]["background"]
assert "评估内容质量" in 读回["payload"]["background"]
_无自动升格(env, saved)
def test_规则激活需评审凭据且候选保持__922777(章后环境):
"""旧 candidate→holdout→approver→active:导出凭据前 candidate 不能激活。"""
from muse.审校修订.接口 import 规则状态命令
app, author = 章后环境["装配"], 章后环境["作者"]
review = app.要求审校()
review.导入规则候选(author)
库 = review.读取规则库(author, 预览候选=True)
rule = next(iter(库["rules"].values()))
with pytest.raises(Muse错误):
review.打开规则状态审阅(
author,
规则状态命令(
rule["id"],
rule["version"],
"enable",
expected_activation_revision=0,
),
)
状态 = review.读取规则库(author, 预览候选=True)
assert 状态["rules"][rule["id"]]["status"] == "candidate"
# 候选未被激活时没有启用投影:读取规则状态只回未激活。
assert review.读取规则状态(author, rule["id"])["current"] is None
def test_启用改进必须精确目标与作者审阅__0f3902(运行观察环境):
"""旧 promote 必须指明目标:新版改进启停锁定精确版本且拒绝非当前作者。"""
env = 运行观察环境
saved = env["service"].记录运行观察(
env["author"],
"target-required",
_观察(
_完成(env)[2],
phenomenon="升格必须精确目标",
quote="没有目标不启用。",
background="旧目标类型校验的等价:改进必须精确版本目标。",
),
)
# 观察不是已批准的改进,任何启停都被拒绝;陌生作者同样不可读。
wrong = 改进定位(str(saved["observation_id"]), 2, "0" * 64)
with pytest.raises(Muse错误):
env["service"].请求启停(env["author"], "bad-target", wrong, "enable")
stranger = replace(env["author"], 作者="stranger")
with pytest.raises(Muse错误):
env["service"].读取运行观察(stranger, str(saved["observation_id"]))
def test_停用后旧凭据不能重新启用__c4f7f6(运行观察环境):
"""旧 reject 终态不再流转:新版停用后须重新验证,相同命令重放拒不覆盖。"""
env = 运行观察环境
saved = env["service"].记录运行观察(
env["author"],
"reject-once",
_观察(
_完成(env)[2],
phenomenon="停用即终态",
quote="停用后不再按旧意向恢复。",
background="reject 路径:历史命令重放不改写内容。",
),
)
with pytest.raises(Muse错误, match="更改来源或内容"):
env["service"].记录运行观察(
env["author"],
"reject-once",
replace(
_观察(
_完成(env)[2],
phenomenon="停用即终态",
quote="不同原话",
background="覆盖被拒绝",
)
),
)
assert env["service"].读取运行观察(env["author"], saved["observation_id"]) == (
env["service"].读取运行观察(env["author"], saved["observation_id"])
)
def test_缺作者决定身份时启停被拒__b8d6b4(运行观察环境):
"""旧 started review 缺 decided_by 拒绝:新版作者身份与 S01 决定是启停前提。"""
env = 运行观察环境
saved = env["service"].记录运行观察(
env["author"],
"decided-by-required",
_观察(
_完成(env)[2],
phenomenon="作者决定身份必填",
quote="没有作者决定不启停。",
background="decided_by 等价:作者必须本人操作。",
),
)
# 未经作者 S01 审阅的观察不能直接启用(无改进意向):
with pytest.raises(Muse错误):
env["service"].请求启停(
env["author"],
"missing-review",
改进定位(str(saved["observation_id"]), 1, saved["content_hash"]),
"enable",
)
def test_发布输入导入形成非空结果报告__0c293f(章后环境):
"""旧 import 产生非空报告:新版规则发布输入导入返回明确结果与数量。"""
app, author = 章后环境["装配"], 章后环境["作者"]
review = app.要求审校()
结果 = review.导入规则候选(author)
assert 结果["persisted"] is True
assert len(结果["results"]) >= 1
assert len({r["version_id"] for r in 结果["results"]}) == len(结果["results"])
assert len(结果["fingerprint"]) == 64
读回 = review.读取规则库(author, 预览候选=True)
assert 读回["rules"] and 读回["fingerprint"] == 结果["fingerprint"]
def test_观察不自动合并改写技能提示资源__bdeab3(运行观察环境):
"""旧 lesson 自动合并进 Skill 文件:新版无该公开写入,须 owner 明确发布。
该能力(将 lesson 写入目标 Skill 提示资源)未在新版接线;此处以最小红例
固定「运行观察不产生任何 skill/lesson 落盘」的合同,防止旧自动合并悄悄回来。
"""
env = 运行观察环境
saved = env["service"].记录运行观察(
env["author"],
"no-skill-merge",
_观察(
_完成(env)[2],
phenomenon="观察不自动合并技能提示",
quote="技能正文只由 owner 发布。",
background="成功运行形成的观察不会改写 Skill/提示资源。",
),
)
assert saved["state"] == "observation"
# 公开入口不存在 skill 自动合并写入;列表/读取都只回观察本人数据。
assert str(env["service"].列出运行观察(env["author"])[0]["observation_id"]) == str(
saved["observation_id"]
)