- src/muse 新版全模块(装配/共享/上下文/任务运行/作品规划/故事世界/正文写作/审校修订/知识方法/作者经验/效果评测/交付连载/资料研究/正式变更/元数据/接入/基础设施/编排)+ 测试树(单元/契约/集成/架构/迁移/端到端/夹具) - 129 项功能全部实现与自动验证(功能覆盖.json/矩阵),含 W31 补齐的规则与代价/节奏安排/伏笔与承诺 - 旧实现按处置清单退出(702 条中 324 删,保护合同与未迁移条目留存有据);web/app.py 旧工作台退役,新工作台为唯一写入口 - 数据库/旧库迁移:真实旧库内容批次迁移链(端点守卫/PG作品正文映射/质量资产缺省投影) - 运行手册 docs/运行手册.md;W30 本机服务阶段一已运行(infra PG 为正式内容权威) - R2 执行证据与私有运行材料在 .agents.local/改造/R2-20260909/(不入库)
56 lines
1.8 KiB
Python
56 lines
1.8 KiB
Python
"""运行观察的公开请求不接受伪造成功标签或不完整的来源定位。"""
|
|
|
|
from dataclasses import asdict
|
|
from uuid import uuid4
|
|
|
|
import pytest
|
|
from pydantic import TypeAdapter, ValidationError
|
|
|
|
from muse.作者经验.接口 import 运行观察来源, 运行观察请求
|
|
from muse.共享.错误 import Muse错误
|
|
|
|
|
|
def _请求():
|
|
return 运行观察请求(
|
|
(运行观察来源(str(uuid4()), str(uuid4()), 1, "a" * 64),),
|
|
"检查步骤结束",
|
|
"仍需人工判断。",
|
|
"这次运行只记录技术状态。",
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"field,value", [("kind", "win"), ("state", "promoted"), ("effective", True), ("cost_usd", "0")]
|
|
)
|
|
def test_外部请求不能注入效果状态或自报实际费用__265201(field, value):
|
|
payload = {**asdict(_请求()), field: value}
|
|
with pytest.raises(ValidationError):
|
|
TypeAdapter(运行观察请求).validate_python(payload)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"field,value",
|
|
[
|
|
("revision", True),
|
|
("revision", 0),
|
|
("task_id", "arbitrary-run"),
|
|
("attempt_id", ""),
|
|
("content_hash", "x" * 64),
|
|
("business_kind", "skill"),
|
|
("business_ref", "unbound-source"),
|
|
],
|
|
)
|
|
def test_来源必须是完整具名版本__265202(field, value):
|
|
payload = asdict(_请求())
|
|
payload["sources"][0][field] = value
|
|
with pytest.raises((Muse错误, ValidationError)):
|
|
TypeAdapter(运行观察请求).validate_python(payload)
|
|
|
|
|
|
def test_请求序列化仍保留来源原话与未知业务来源__265203():
|
|
request = _请求()
|
|
adapter = TypeAdapter(运行观察请求)
|
|
restored = adapter.validate_json(adapter.dump_json(request))
|
|
assert restored == request and restored.sources[0].business_kind == ""
|
|
assert restored.quote == "仍需人工判断。"
|