Files
mdpolish/tests/reviewer_fixture.py
T

213 lines
7.1 KiB
Python

from __future__ import annotations
import json
from hashlib import sha256
from pathlib import Path
from typing import Any, TypedDict, cast
class ReviewFixture(TypedDict):
run_directory: Path
source_path: Path
manifest_path: Path
locator_path: Path
result_path: Path
original: str
cleaned: str
def digest(text: str) -> str:
return sha256(text.encode()).hexdigest()
def write_json(path: Path, payload: object) -> None:
path.write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
def read_json(path: Path) -> dict[str, Any]:
return cast(dict[str, Any], json.loads(path.read_text(encoding="utf-8")))
def create_review_run(
root: Path,
*,
status: str = "success",
with_locator: bool = True,
) -> ReviewFixture:
run_directory = root / "artifacts/2026-08-23/runs/review-run"
document_directory = run_directory / "documents/paper"
document_directory.mkdir(parents=True)
source_path = root / "paper.md"
original = "\ufeff😀 old\r\nCafe\u0301\n"
cleaned = "\ufeff😀 new\r\nCafe\u0301\n"
source_path.write_text(original, encoding="utf-8")
input_hash = digest(original)
current_hash = digest(cleaned) if status == "success" else input_hash
changes: list[dict[str, object]] = []
if status == "success":
changes.append(
{
"component_id": "paper.rule",
"component_version": "1.0.0",
"component_position": 0,
"proposal_ref": {
"component_position": 0,
"snapshot_sha256": input_hash,
"proposal_index": 0,
},
"edit_index": 0,
"reason": "替换测试单词",
"span": {"start": 3, "end": 6},
"location": {"line": 1, "column": 4},
"before": "old",
"after": "new",
"before_sha256": input_hash,
"after_sha256": current_hash,
}
)
errors: list[dict[str, object]] = []
if status == "failed":
errors.append(
{
"component_id": "paper.rule",
"component_version": "1.0.0",
"component_position": 0,
"stage": "transform",
"error_type": "SyntheticError",
"message": "测试组件失败。",
}
)
residuals: list[dict[str, object]] = []
if status == "unstable":
residuals.append(
{
"component_id": "paper.rule",
"component_version": "1.0.0",
"component_position": 0,
"proposal_ref": {
"component_position": 0,
"snapshot_sha256": input_hash,
"proposal_index": 0,
},
"proposal": {
"snapshot_sha256": input_hash,
"reason": "仍可替换测试单词",
"edits": [
{
"snapshot_sha256": input_hash,
"span": {"start": 3, "end": 6},
"expected_text": "old",
"replacement": "new",
}
],
},
}
)
result = {
"schema_version": 1,
"document": {"document_id": "paper", "source_label": "inputs/paper.md"},
"status": status,
"input_sha256": input_hash,
"current_sha256": current_hash,
"changes": changes,
"errors": errors,
"residual_proposals": residuals,
"output": {
"cleaned_path": "cleaned.md" if status == "success" else None,
"diff_path": "changes.diff" if status == "success" else None,
},
}
result_path = document_directory / "result.json"
write_json(result_path, result)
if status == "success":
(document_directory / "cleaned.md").write_text(cleaned, encoding="utf-8")
(document_directory / "changes.diff").write_text("synthetic diff\n", encoding="utf-8")
manifest = {
"schema_version": 1,
"run": {
"run_id": "review-run",
"run_date": "2026-08-23",
"utc_offset": "+08:00",
"status": status,
"started_at_utc": "2026-08-23T01:00:00Z",
"completed_at_utc": "2026-08-23T01:01:00Z",
"retention_until": "2026-09-22T01:01:00Z",
},
"tool": {
"name": "mdpolish",
"package_version": "0.1.0",
"python_version": "3.13.11",
"platform": "linux-x86_64",
"git_commit": None,
"git_dirty": None,
},
"pipeline": {
"components": [
{
"component_id": "paper.rule",
"version": "1.0.0",
"parameters": [],
"applicability": "替换测试单词。",
},
{
"component_id": "paper.zero",
"version": "1.0.0",
"parameters": [],
"applicability": "不修改当前测试文档。",
},
]
},
"documents": [
{
"document_id": "paper",
"source_label": "inputs/paper.md",
"status": status,
"input_sha256": input_hash,
"current_sha256": current_hash,
"change_count": len(changes),
"result_path": "documents/paper/result.json",
"cleaned_path": "documents/paper/cleaned.md" if status == "success" else None,
"diff_path": "documents/paper/changes.diff" if status == "success" else None,
}
],
"summary": {
"document_count": 1,
"success_count": int(status == "success"),
"failed_count": int(status == "failed"),
"unstable_count": int(status == "unstable"),
"change_count": len(changes),
},
}
manifest_path = run_directory / "manifest.json"
write_json(manifest_path, manifest)
locator_path = run_directory / "review-locator.json"
if with_locator:
write_json(
locator_path,
{
"schema_version": 1,
"run": {
"run_id": "review-run",
"run_directory": str(run_directory.resolve()),
"manifest_path": "manifest.json",
},
"documents": [
{
"document_id": "paper",
"source_path": str(source_path.resolve()),
"input_sha256": input_hash,
}
],
},
)
return {
"run_directory": run_directory,
"source_path": source_path,
"manifest_path": manifest_path,
"locator_path": locator_path,
"result_path": result_path,
"original": original,
"cleaned": cleaned,
}