muse-agent-example/tests/e2e/test_sqlite_write_path.py
zizi 76d38f2dc7 修复: 派发链硬门失败关闭与测试账本隔离
- 模型锁定完整 ID 等值:role_policy 废弃子串匹配,前置校验+事后
  MODEL_POLICY_VIOLATION 熔断+回执 modelMatch,治理链角色放行 BUDGET_CHAIN
- 工具白名单只读机械强制:任务包 allowlist ⊆ 只读注册表,TOOL_NOT_READONLY
- 本地向量检索 truthful 化:aiContext 裁剪、指针行跳过、资格失败关闭
  (bindingStatus/productionRetrievalEligible 不再伪造 active)
- 角色提示词 name 回归英文系统 ID;planner 补 fine_outline 绑定;
  writer 数据契约对齐 writer-candidate-body-v1
- 测试账本隔离:sqlite_path 三层透传(bridge/two_phase),9 处派发测试
  改用临时库;清除 muse.db 测试残留 5 runs+26 events+reviews 5/6(有备份)
- test-inventory 补 3 条登记并机械重算 summary;评测场景补
  output_contract/fail_closed 与 stability 两类;死代码清理
  (project_paths.py、offline_only 死参数、harness/harness 残骸)
- 新增 metaphysical-diff-review 技能(红线 4.2 载体)并登记,共 59 技能
2026-08-30 23:06:19 +08:00

151 lines
5.7 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.

"""P0.3 写路径:dispatch/flow 落 sqlite run+events,revise 带 diff,同输入可重跑 diff。"""
from __future__ import annotations
import json
import pathlib
import subprocess
import sys
import tempfile
import unittest
ROOT = next(
parent
for parent in (pathlib.Path(__file__).resolve().parent, *pathlib.Path(__file__).resolve().parents)
if (parent / "AGENTS.md").is_file() and (parent / ".git").exists()
)
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
DISPATCH_SCRIPTS = (
ROOT / "muse" / "lifecycle" / "dispatch" / "skills" / "dispatch-agent-task" / "scripts"
)
EVIDENCE_DIR = ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts"
DISPATCH_TESTS = ROOT / "tests" / "skills" / "dispatch-agent-task"
for path in (DISPATCH_SCRIPTS, EVIDENCE_DIR, DISPATCH_TESTS):
if str(path) not in sys.path:
sys.path.insert(0, str(path))
from framework.adapters.pi.runner import ExecutionPolicy # noqa: E402
from muse.flow.dispatch import run_dispatch # noqa: E402
from muse.store import add_review, connect, get_run, list_events # noqa: E402
from test_dispatch_agent_task import ( # noqa: E402
FIXED_MODEL,
fake_launcher,
make_spec,
pi_stream_lines,
)
class SqliteWritePathTest(unittest.TestCase):
def setUp(self) -> None:
self.tmp = pathlib.Path(tempfile.mkdtemp())
self.db = self.tmp / "muse.db"
self.spec = make_spec(self.tmp)
def _dispatch(self, run_id: str, run_dir: pathlib.Path):
return run_dispatch(
self.spec,
repo_root=ROOT,
policy=ExecutionPolicy(provider="p", model=FIXED_MODEL),
run_id=run_id,
run_dir=run_dir,
launcher=fake_launcher(
pi_stream_lines(
'{"title":"重启","beats":["警报","分歧","决断"]}', model=FIXED_MODEL
)
),
trigger_source="diagnostic",
sqlite_path=self.db,
)
def test_write_path_run_events_revise_and_rerun_diff(self) -> None:
before = subprocess.check_output(["git", "status", "--short"], cwd=ROOT, text=True)
receipt, code = self._dispatch("p03-write-1", self.tmp / "run-1")
self.assertEqual(code, 0, receipt)
self.assertEqual(receipt["status"], "completed")
self.assertEqual((receipt.get("evidence") or {}).get("status"), "sqlite")
row = get_run("p03-write-1", self.db)
self.assertIsNotNone(row)
self.assertEqual(row["kind"], "agent.planner")
self.assertIn("重启", row["output_text"])
events = list_events("p03-write-1", self.db)
kinds = [item["kind"] for item in events]
self.assertIn("run.started", kinds)
self.assertIn("run.completed", kinds)
self.assertTrue(any(kind.startswith("model.") or kind == "agent.started" for kind in kinds))
with connect(self.db) as conn:
mode = conn.execute("PRAGMA journal_mode").fetchone()[0]
self.assertEqual(str(mode).lower(), "wal")
add_review(
run_id="p03-write-1",
target="candidate",
action="revise",
reviewer="qingse",
reason="钩子再紧一寸",
before_text=row["output_text"],
after_text='{"title":"重启","beats":["警报","摊牌","决断"]}',
path=self.db,
)
with connect(self.db) as conn:
review = conn.execute(
"SELECT * FROM reviews WHERE run_id=?", ("p03-write-1",)
).fetchone()
revision = conn.execute(
"SELECT * FROM revisions WHERE review_id=?", (review["id"],)
).fetchone()
self.assertEqual(review["action"], "revise")
self.assertNotEqual(revision["before_text"], revision["after_text"])
receipt2, code2 = self._dispatch("p03-write-2", self.tmp / "run-2")
self.assertEqual(code2, 0, receipt2)
replay = get_run("p03-write-2", self.db)
first_input = json.loads(row["input_json"])
second_input = json.loads(replay["input_json"])
self.assertEqual(first_input["specSha256"], second_input["specSha256"])
self.assertEqual(row["output_text"], replay["output_text"])
after = subprocess.check_output(["git", "status", "--short"], cwd=ROOT, text=True)
self.assertEqual(before, after)
ignored = subprocess.run(
["git", "check-ignore", "-q", "data/muse.db"],
cwd=ROOT,
)
self.assertEqual(ignored.returncode, 0)
def test_search_and_freeze_recall_share_sqlite_vectors(self) -> None:
from muse.store import upsert_card
freeze_scripts = ROOT / "muse" / "lifecycle" / "context" / "skills" / "freeze-context" / "scripts"
search_scripts = ROOT / "muse" / "lifecycle" / "context" / "skills" / "search-knowledge" / "scripts"
sys.path.insert(0, str(freeze_scripts))
sys.path.insert(0, str(search_scripts))
import recall
from search import search_cards
upsert_card(
card_id="c1",
kind="craft",
title="递进揭示",
payload={"型": "craft", "名称": "递进揭示", "一句话摘要": "逐层加压"},
embedding=[1.0, 0.0],
path=self.db,
)
cards = search_cards(
"揭示",
sqlite_path=self.db,
embedder=lambda _intent: [1.0, 0.0],
)
recalled = recall.recall_cards([1.0, 0.0], kind="craft", sqlite_path=self.db)
self.assertEqual(cards[0]["cardId"], "c1")
self.assertEqual(recalled[0]["cardId"], "c1")
self.assertAlmostEqual(cards[0]["score"], 1.0)
if __name__ == "__main__":
unittest.main()