python / evaluate_report.py
"""Offline mechanical checks. Does not judge translated conditions or risk semantics."""
import argparse
import json
import re
from pathlib import Path
from review import build_review
def evaluate(report: dict, markdown: str) -> dict:
review, _ = build_review(report, render_markdown=False)
normalized = markdown.replace("\r\n", "\n")
errors = []
if review["fixed_tables_markdown"].rstrip() not in normalized:
errors.append("fixed_tables_changed_or_missing")
headings = list(re.finditer(r"^### (\d+)\. ([a-z][a-z0-9_]*)(?:[ \t((].*)?$", normalized, re.M))
expected = [(r["rank"], r["finding"]) for r in review["finding_rows"]]
actual = [(int(h[1]), h[2]) for h in headings]
if actual != expected:
errors.append("finding_sections_missing_reordered_or_renamed")
if actual == expected:
for i, (heading, row) in enumerate(zip(headings, review["finding_rows"])):
section = normalized[heading.end():headings[i + 1].start() if i + 1 < len(headings) else len(normalized)]
block = re.search(r"成立条件[^\n]*\n(.*?)条件付き影響", section, re.S)
entries = re.findall(r"^\s*(\d+)\.\s+\S", block[1], re.M) if block else []
if entries != [str(n) for n in range(1, row["required_conditions_count"] + 1)]:
errors.append(f"condition_list_count_or_numbering_mismatch:{row['rank']}")
if report.get("review", {}).get("report_contract", {}).get("copy_protected_markdown_verbatim"):
if row["protected_markdown"].rstrip() not in section:
errors.append(f"protected_text_changed_or_missing:{row['rank']}")
if report.get("review", {}).get("report_contract", {}).get("copy_mandatory_caveats_verbatim"):
if review["mandatory_caveats_markdown"].rstrip() not in normalized:
errors.append("mandatory_caveats_changed_or_missing")
return {"mechanical_checks_passed": not errors, "errors": errors,
"expected_findings": len(expected), "detected_sections": len(headings),
"semantic_review_required": True,
"not_checked": ["translation fidelity", "unsupported claims in prose", "conditions meaning", "prose summary reranking"]}
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("json_file", type=Path)
parser.add_argument("report_file", type=Path)
args = parser.parse_args()
result = evaluate(json.loads(args.json_file.read_text(encoding="utf-8-sig")), args.report_file.read_text(encoding="utf-8-sig"))
print(json.dumps(result, ensure_ascii=False, indent=2))
raise SystemExit(0 if result["mechanical_checks_passed"] else 1)
if __name__ == "__main__":
main()
python / evaluate_report.py
"""Offline mechanical checks. Does not judge translated conditions or risk semantics."""
import argparse
import json
import re
from pathlib import Path
from review import build_review
def evaluate(report: dict, markdown: str) -> dict:
review, _ = build_review(report, render_markdown=False)
normalized = markdown.replace("\r\n", "\n")
errors = []
if review["fixed_tables_markdown"].rstrip() not in normalized:
errors.append("fixed_tables_changed_or_missing")
headings = list(re.finditer(r"^### (\d+)\. ([a-z][a-z0-9_]*)(?:[ \t((].*)?$", normalized, re.M))
expected = [(r["rank"], r["finding"]) for r in review["finding_rows"]]
actual = [(int(h[1]), h[2]) for h in headings]
if actual != expected:
errors.append("finding_sections_missing_reordered_or_renamed")
if actual == expected:
for i, (heading, row) in enumerate(zip(headings, review["finding_rows"])):
section = normalized[heading.end():headings[i + 1].start() if i + 1 < len(headings) else len(normalized)]
block = re.search(r"成立条件[^\n]*\n(.*?)条件付き影響", section, re.S)
entries = re.findall(r"^\s*(\d+)\.\s+\S", block[1], re.M) if block else []
if entries != [str(n) for n in range(1, row["required_conditions_count"] + 1)]:
errors.append(f"condition_list_count_or_numbering_mismatch:{row['rank']}")
if report.get("review", {}).get("report_contract", {}).get("copy_protected_markdown_verbatim"):
if row["protected_markdown"].rstrip() not in section:
errors.append(f"protected_text_changed_or_missing:{row['rank']}")
if report.get("review", {}).get("report_contract", {}).get("copy_mandatory_caveats_verbatim"):
if review["mandatory_caveats_markdown"].rstrip() not in normalized:
errors.append("mandatory_caveats_changed_or_missing")
return {"mechanical_checks_passed": not errors, "errors": errors,
"expected_findings": len(expected), "detected_sections": len(headings),
"semantic_review_required": True,
"not_checked": ["translation fidelity", "unsupported claims in prose", "conditions meaning", "prose summary reranking"]}
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("json_file", type=Path)
parser.add_argument("report_file", type=Path)
args = parser.parse_args()
result = evaluate(json.loads(args.json_file.read_text(encoding="utf-8-sig")), args.report_file.read_text(encoding="utf-8-sig"))
print(json.dumps(result, ensure_ascii=False, indent=2))
raise SystemExit(0 if result["mechanical_checks_passed"] else 1)
if __name__ == "__main__":
main()