muse-agent-example/harness/test_run_selected.py
zizi d80df3ed7c 治理: 剩余问题收口——humanization 规则/样例数据库权威 + PG 集成全通过 + 行为评测脚手架 + raw 冲突备忘录
范围(不含 design-story-foundation、docs/design、docs/write-chapter、
craft/、humanization/README.md 等进行中改动):

1. humanization 规则/样例运行时数据库权威
   - db/ddl/111:example_ai_flavor_rule / example_ai_flavor_sample /
     example_ai_flavor_rule_event(append-only 生命周期留痕),已应用到 muse-example
   - deai/load_db.py:数据库装载器,激活门/重复检测/指纹与文件装载器同源;
     数据库失败关闭,不静默回退 Git 文件资产
   - humanization/tools/seed_rules_db.py:YAML 种子单事务同步,幂等、
     变化留痕、--strict 对 db-only 行失败关闭;真实库已种入 26 规则/107 样例
   - prevent/diagnose/revise 生产路径切到数据库读取(--offline 显式读文件),
     落库前新鲜度检查与合同声明来源一致;四个 SKILL.md 数据库合同同步
   - 真实库验证:规则库指纹与文件种子一致(v-609bc40e21d0b5db),
     三个生产脚本端到端从库装载通过

2. PostgreSQL 集成:显式授权后 9/9 通过
   - 此前被依赖门阻断的 6 个 _db/smoke 测试全部通过
   - extract rollback 冒烟改为回滚事务内自给夹具(pending 窗/草稿缺失时自建),
     不再依赖瞬时生产状态;夹具残留核验为 0

3. Skill 行为评测脚手架(真实执行数量仍为 0)
   - harness/evals/skill_eval.py:场景合同、六类评测范畴、适配器和结构化裁决报告
   - diagnose-ai-flavor 参考场景 4 条 + 管道自测 7 项通过
   - 真实模型适配器未授权时以稳定码 EVAL_ADAPTER_UNAVAILABLE 失败关闭;
     清单登记 skill_behavior_eval 条目,默认被依赖门阻断

4. evaluate-frozen-replay raw 存储边界冲突
   - docs/2026-08-19 备忘录:平台 DB-first 合同(创始人批准)与回放链
     仓外 vault 强制的冲突事实、两个选项和裁决前约束;运行时合同未单方面改写

5. harness 自身修复
   - runner 对账语义:行为评测入口不参与测试资产双向等值,但登记文件必须存在;
     manifest 保留 skill_behavior_eval 布尔字段并校验类型
   - 新增 2 条对账回归用例

验证证据: harness 三组自测 15+15+7 通过;静态审计 32 Skill / 0 问题;
76 个非数据库条目通过;9 个 PostgreSQL 集成条目显式授权后通过;
行为评测条目默认阻断;py_compile 与 git diff --check 通过。
未调用真实模型、embedding 或额度;真实行为评测执行数量仍为 0。
2026-08-19 02:41:25 +08:00

501 lines
19 KiB
Python

#!/usr/bin/env python3
"""run_selected 的标准库离线回归测试。
测试项目、manifest 和 .venv/bin/python 均在临时目录中生成,不连接数据库、网络或模型。
"""
from __future__ import annotations
import io
import json
import stat
import sys
import tempfile
import unittest
from contextlib import redirect_stdout
from pathlib import Path
from typing import Any, Iterable
try:
from .run_selected import main
except ImportError: # 允许直接执行 `.venv/bin/python harness/test_run_selected.py`
from run_selected import main
class RunSelectedTests(unittest.TestCase):
def make_project(
self,
entries: Iterable[dict[str, Any]],
*,
generated_scope: str | None = None,
) -> tuple[tempfile.TemporaryDirectory[str], Path]:
temporary = tempfile.TemporaryDirectory()
root = Path(temporary.name)
(root / ".venv" / "bin").mkdir(parents=True)
fake_python = root / ".venv" / "bin" / "python"
fake_python.write_text(
f"#!{sys.executable}\n"
"import pathlib\n"
"import sys\n"
"import time\n"
"script = pathlib.Path(sys.argv[1])\n"
"(pathlib.Path.cwd() / 'invocations.log').open('a', encoding='utf-8').write(script.name + '\\n')\n"
"if script.name == 'empty.py':\n"
" raise SystemExit(0)\n"
"if script.name == 'skip.py':\n"
" print('1 skipped')\n"
" raise SystemExit(0)\n"
"if script.name == 'fail.py':\n"
" print('failure stdout')\n"
" print('failure stderr', file=sys.stderr)\n"
" raise SystemExit(7)\n"
"if script.name == 'sleep.py':\n"
" time.sleep(2)\n"
"if script.name == 'noisy.py':\n"
" print('x' * 5000)\n"
"else:\n"
" print('ran ' + script.name)\n",
encoding="utf-8",
)
fake_python.chmod(fake_python.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
manifest_entries = []
for entry in entries:
entry_copy = dict(entry)
path = root / str(entry_copy["path"])
if entry_copy.pop("create", True):
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text("# temporary test script\n", encoding="utf-8")
manifest_entries.append(entry_copy)
manifest_path = root / "manifest.json"
manifest_payload: dict[str, Any] = {
"schema_version": 1,
"entries": manifest_entries,
}
if generated_scope is not None:
manifest_payload["generated_scope"] = generated_scope
manifest_path.write_text(
json.dumps(manifest_payload, indent=2) + "\n",
encoding="utf-8",
)
self.addCleanup(temporary.cleanup)
return temporary, manifest_path
def invoke(self, root: Path, manifest: Path, *arguments: str) -> tuple[int, dict[str, Any]]:
output = io.StringIO()
with redirect_stdout(output):
return_code = main(
[
"--root",
str(root),
"--manifest",
str(manifest),
*arguments,
"--json",
]
)
return return_code, json.loads(output.getvalue())
@staticmethod
def entry(
path: str,
*,
owner: str = "alpha",
kind: str = "tool_unit",
scope: str = "runtime_skill",
requires: list[str] | None = None,
create: bool = True,
) -> dict[str, Any]:
return {
"path": path,
"owner_skill_or_domain": owner,
"kind": kind,
"scope": scope,
"requires": ["offline"] if requires is None else requires,
"create": create,
}
def test_selector_alias_and_intersection_are_reported_as_json(self) -> None:
_, manifest = self.make_project(
[
self.entry("pass.py", owner="alpha", kind="tool_unit"),
self.entry("other.py", owner="beta", kind="tool_contract"),
]
)
root = manifest.parent
return_code, report = self.invoke(
root,
manifest,
"--skill",
"alpha",
"--kind",
"tool_unit",
"--path",
"pass.py",
)
self.assertEqual(return_code, 0)
self.assertEqual(report["status"], "passed")
self.assertEqual(report["selected_count"], 1)
self.assertEqual(report["entries"][0]["path"], "pass.py")
self.assertEqual(report["entries"][0]["returncode"], 0)
self.assertIn("ran pass.py", report["entries"][0]["stdout"])
def test_offline_dependency_is_blocked_without_running_child(self) -> None:
_, manifest = self.make_project(
[self.entry("db.py", requires=["offline", "postgresql"])]
)
root = manifest.parent
return_code, report = self.invoke(root, manifest, "--path", "db.py")
result = report["entries"][0]
self.assertEqual(return_code, 1)
self.assertEqual(report["status"], "failed")
self.assertEqual(result["status"], "blocked_dependency")
self.assertEqual(result["requires"], ["offline", "postgresql"])
self.assertEqual(result["blocked_requires"], ["postgresql"])
self.assertFalse((root / "invocations.log").exists())
def test_allow_requires_runs_and_still_reports_dependency(self) -> None:
_, manifest = self.make_project(
[self.entry("db.py", requires=["offline", "postgresql"])]
)
root = manifest.parent
return_code, report = self.invoke(
root,
manifest,
"--path",
"db.py",
"--allow-requires",
"postgresql",
)
result = report["entries"][0]
self.assertEqual(return_code, 0)
self.assertEqual(result["status"], "passed")
self.assertEqual(result["requires"], ["offline", "postgresql"])
self.assertEqual((root / "invocations.log").read_text(encoding="utf-8"), "db.py\n")
def test_nonzero_and_timeout_have_distinct_structured_statuses(self) -> None:
_, manifest = self.make_project(
[self.entry("fail.py"), self.entry("sleep.py")]
)
root = manifest.parent
return_code, report = self.invoke(
root,
manifest,
"--path",
"fail.py",
"--path",
"sleep.py",
"--timeout-seconds",
"0.5",
)
self.assertEqual(return_code, 1)
results = {entry["path"]: entry for entry in report["entries"]}
self.assertEqual(results["fail.py"]["status"], "failed")
self.assertEqual(results["fail.py"]["returncode"], 7)
self.assertIn("failure stdout", results["fail.py"]["stdout"])
self.assertIn("failure stderr", results["fail.py"]["stderr"])
self.assertEqual(results["sleep.py"]["status"], "timeout")
self.assertIsNone(results["sleep.py"]["returncode"])
self.assertEqual(results["sleep.py"]["error"]["code"], "timeout")
def test_no_matches_and_missing_path_are_not_silent(self) -> None:
_, manifest = self.make_project(
[
self.entry("missing.py", create=False),
self.entry("present.py"),
]
)
root = manifest.parent
return_code, no_match = self.invoke(root, manifest, "--kind", "does_not_exist")
self.assertEqual(return_code, 1)
self.assertEqual(no_match["status"], "no_matches")
self.assertEqual(no_match["entries"], [])
self.assertEqual(no_match["issues"][0]["code"], "no_matches")
return_code, missing = self.invoke(root, manifest, "--path", "missing.py")
self.assertEqual(return_code, 1)
self.assertEqual(missing["entries"][0]["status"], "not_found")
self.assertEqual(missing["entries"][0]["error"]["code"], "path_not_found")
def test_invalid_manifest_and_selector_requirement_are_structured(self) -> None:
temporary = tempfile.TemporaryDirectory()
self.addCleanup(temporary.cleanup)
root = Path(temporary.name)
manifest = root / "manifest.json"
manifest.write_text("{broken", encoding="utf-8")
return_code, invalid_manifest = self.invoke(root, manifest, "--path", "x.py")
self.assertEqual(return_code, 1)
self.assertEqual(invalid_manifest["status"], "manifest_invalid")
self.assertEqual(invalid_manifest["issues"][0]["code"], "manifest_invalid_json")
valid_root, valid_manifest = self.make_project([self.entry("pass.py")])
return_code, invalid_selector = self.invoke(valid_root, valid_manifest)
self.assertEqual(return_code, 1)
self.assertEqual(invalid_selector["status"], "invalid_selector")
self.assertEqual(invalid_selector["issues"][0]["code"], "selector_required")
def test_all_offline_is_explicit_opt_in_and_output_is_summary_only(self) -> None:
_, manifest = self.make_project(
[
self.entry("pass.py"),
self.entry("db.py", requires=["postgresql"]),
self.entry("noisy.py"),
]
)
root = manifest.parent
return_code, report = self.invoke(root, manifest, "--all-offline")
self.assertEqual(return_code, 1)
self.assertEqual(report["selected_count"], 3)
statuses = {entry["path"]: entry["status"] for entry in report["entries"]}
self.assertEqual(statuses["pass.py"], "passed")
self.assertEqual(statuses["db.py"], "blocked_dependency")
self.assertEqual(statuses["noisy.py"], "passed")
noisy = next(entry for entry in report["entries"] if entry["path"] == "noisy.py")
self.assertLess(len(noisy["stdout"]), 2001)
self.assertIn("output summary truncated", noisy["stdout"])
def test_generated_scope_rejects_unregistered_disk_asset(self) -> None:
_, manifest = self.make_project(
[self.entry("tests/skills/registered/test_registered.py")],
generated_scope="temporary test asset inventory",
)
root = manifest.parent
unregistered = root / "tests" / "skills" / "new" / "test_unregistered.py"
unregistered.parent.mkdir(parents=True)
unregistered.write_text("# unregistered test asset\n", encoding="utf-8")
return_code, report = self.invoke(root, manifest, "--all-offline")
self.assertEqual(return_code, 1)
self.assertEqual(report["status"], "manifest_invalid")
self.assertEqual(report["entries"], [])
self.assertEqual(
[
issue["path"]
for issue in report["issues"]
if issue["code"] == "manifest_test_asset_missing"
],
["tests/skills/new/test_unregistered.py"],
)
self.assertFalse((root / "invocations.log").exists())
def test_generated_scope_rejects_manifest_extra_asset(self) -> None:
_, manifest = self.make_project(
[
self.entry(
"tests/skills/removed/test_removed.py",
create=False,
)
],
generated_scope="temporary test asset inventory",
)
root = manifest.parent
return_code, report = self.invoke(root, manifest, "--all-offline")
self.assertEqual(return_code, 1)
self.assertEqual(report["status"], "manifest_invalid")
self.assertEqual(report["entries"], [])
self.assertEqual(
[
issue["path"]
for issue in report["issues"]
if issue["code"] == "manifest_test_asset_extra"
],
["tests/skills/removed/test_removed.py"],
)
self.assertFalse((root / "invocations.log").exists())
def test_generated_scope_accepts_existing_behavior_eval_entry(self) -> None:
eval_entry = self.entry(
"harness/evals/skills/demo/run_eval.py",
kind="skill_behavior_eval",
requires=["model"],
)
eval_entry["skill_behavior_eval"] = True
_, manifest = self.make_project(
[
self.entry("tests/skills/registered/test_registered.py"),
eval_entry,
],
generated_scope="temporary test asset inventory",
)
root = manifest.parent
registered_test = root / "tests" / "skills" / "registered" / "test_registered.py"
registered_test.write_text("def test_registered():\n assert True\n", encoding="utf-8")
(root / "harness" / "evals" / "skills" / "demo" / "run_eval.py").write_text(
"# eval entry\n", encoding="utf-8"
)
return_code, report = self.invoke(root, manifest, "--kind", "tool_unit")
self.assertEqual(return_code, 0)
self.assertEqual(report["status"], "passed")
self.assertEqual(report["selected_count"], 1)
self.assertEqual(
[issue for issue in report["issues"] if "eval" in issue["code"]], []
)
def test_generated_scope_rejects_missing_behavior_eval_entry(self) -> None:
eval_entry = self.entry(
"harness/evals/skills/demo/run_eval.py",
kind="skill_behavior_eval",
requires=["model"],
create=False,
)
eval_entry["skill_behavior_eval"] = True
_, manifest = self.make_project(
[
self.entry("tests/skills/registered/test_registered.py"),
eval_entry,
],
generated_scope="temporary test asset inventory",
)
root = manifest.parent
registered_test = root / "tests" / "skills" / "registered" / "test_registered.py"
registered_test.write_text("def test_registered():\n assert True\n", encoding="utf-8")
return_code, report = self.invoke(root, manifest, "--kind", "tool_unit")
self.assertEqual(return_code, 1)
self.assertEqual(report["status"], "manifest_invalid")
self.assertEqual(
[
issue["path"]
for issue in report["issues"]
if issue["code"] == "manifest_eval_entry_missing"
],
["harness/evals/skills/demo/run_eval.py"],
)
def test_generated_scope_ignores_non_test_helpers_under_test_roots(self) -> None:
_, manifest = self.make_project(
[self.entry("tests/skills/registered/test_registered.py")],
generated_scope="temporary test asset inventory",
)
root = manifest.parent
registered_test = root / "tests" / "skills" / "registered" / "test_registered.py"
registered_test.write_text("def test_registered():\n pass\n", encoding="utf-8")
(root / "tests" / "skills" / "registered" / "helper.py").write_text(
"VALUE = 1\n", encoding="utf-8"
)
(root / "humanization" / "tests" / "helper.py").parent.mkdir(
parents=True, exist_ok=True
)
(root / "humanization" / "tests" / "helper.py").write_text(
"VALUE = 2\n", encoding="utf-8"
)
return_code, report = self.invoke(root, manifest, "--all-offline")
self.assertEqual(return_code, 0)
self.assertEqual(report["status"], "passed")
self.assertEqual(report["manifest"]["test_assets_scanned"], 1)
self.assertEqual(report["entries"][0]["path"], "tests/skills/registered/test_registered.py")
def test_generated_scope_blocks_empty_and_print_only_scripts_before_child(self) -> None:
entries = [
self.entry("tests/skills/empty/test_empty.py"),
self.entry("tests/skills/print_only/test_print_only.py"),
]
_, manifest = self.make_project(
entries,
generated_scope="temporary test asset inventory",
)
root = manifest.parent
(root / "tests" / "skills" / "empty" / "test_empty.py").write_text(
"", encoding="utf-8"
)
(root / "tests" / "skills" / "print_only" / "test_print_only.py").write_text(
"print('not a test')\n", encoding="utf-8"
)
return_code, report = self.invoke(root, manifest, "--all-offline")
self.assertEqual(return_code, 1)
self.assertEqual(report["status"], "failed")
results = {entry["path"]: entry for entry in report["entries"]}
for path in (
"tests/skills/empty/test_empty.py",
"tests/skills/print_only/test_print_only.py",
):
self.assertEqual(results[path]["status"], "failed")
self.assertIsNone(results[path]["returncode"])
self.assertEqual(results[path]["error"]["code"], "test_shape_missing")
self.assertFalse((root / "invocations.log").exists())
def test_generated_scope_accepts_supported_python_shapes(self) -> None:
entries = [
self.entry("tests/skills/function/test_function.py"),
self.entry("tests/skills/class/test_class.py"),
self.entry("harness/test_main_entry.py"),
]
_, manifest = self.make_project(
entries,
generated_scope="temporary test asset inventory",
)
root = manifest.parent
(root / "tests" / "skills" / "function" / "test_function.py").write_text(
"def test_function():\n pass\n", encoding="utf-8"
)
(root / "tests" / "skills" / "class" / "test_class.py").write_text(
"import unittest\n\nclass Fixture(unittest.TestCase):\n pass\n",
encoding="utf-8",
)
(root / "harness" / "test_main_entry.py").write_text(
"if __name__ == \"__main__\":\n print(\"script\")\n",
encoding="utf-8",
)
return_code, report = self.invoke(root, manifest, "--all-offline")
self.assertEqual(return_code, 0)
self.assertEqual(report["status"], "passed")
self.assertEqual(
[entry["status"] for entry in report["entries"]],
["passed", "passed", "passed"],
)
self.assertEqual(
(root / "invocations.log").read_text(encoding="utf-8").splitlines(),
["test_function.py", "test_class.py", "test_main_entry.py"],
)
def test_zero_exit_without_execution_evidence_fails_closed(self) -> None:
_, manifest = self.make_project(
[self.entry("empty.py"), self.entry("skip.py")]
)
root = manifest.parent
return_code, report = self.invoke(
root,
manifest,
"--path",
"empty.py",
"--path",
"skip.py",
)
self.assertEqual(return_code, 1)
results = {entry["path"]: entry for entry in report["entries"]}
for path in ("empty.py", "skip.py"):
self.assertEqual(results[path]["status"], "failed")
self.assertEqual(results[path]["returncode"], 0)
self.assertEqual(results[path]["error"]["code"], "no_execution_evidence")
if __name__ == "__main__":
unittest.main(verbosity=2)