from pathlib import Path
import argparse
import copy
import csv
import hashlib
import io
import json
import re

parser = argparse.ArgumentParser()
parser.add_argument("--actual")
parser.add_argument("--local-http", action="store_true")
args = parser.parse_args()
checks = []
def check(condition, label):
    if not condition:
        raise ValueError(label)
    checks.append(label)
def load(name): return json.loads(Path(name).read_text())
def rows(name): return list(csv.DictReader(io.StringIO(Path(name).read_text(encoding="utf-8-sig"))))
def negative(fn, value, label):
    try: fn(value)
    except (ValueError, AssertionError, KeyError, TypeError, IndexError): checks.append(label)
    else: raise AssertionError("Negative input accepted: " + label)
notes=[]
for p in sorted(Path("Research").glob("*.md")):
    content=p.read_text(); props=dict(re.findall(r"^(topic|source|status): (.+)$",content,re.M));props["name"]=p.stem; notes.append(props)
def validate(v):
    if len(v)!=6 or any(not n.get("source") for n in v): raise ValueError("six source-bearing notes required")
validate(notes);checks.append("six original notes")
before=[n["name"] for n in notes if n["status"]=="待复习"]
check(len(before)==2,"two notes match exact property")
next(n for n in notes if n["name"].startswith("02"))["status"]="已复习"
after=[n["name"] for n in notes if n["status"]=="待复习"]
check(after==["05-展览动线"],"changing one property leaves one result")
bad=copy.deepcopy(notes);bad[0]["source"]="";negative(validate,bad,"missing source rejected")
Path("filter-result.json").write_text(json.dumps({"before":before,"after":after,"executed_in":"Python property baseline, not Obsidian"},ensure_ascii=False,indent=2))
report={"layer":"offline/material checks, not proof of unrun product or model", "checks":checks, "count":len(checks)}
Path("verification.json").write_text(json.dumps(report,ensure_ascii=False,indent=2))
print(json.dumps(report,ensure_ascii=False))
