#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ collatz_verifier_alternative.py Alternative implementation of Collatz certificate verification. Same interface as collatz_verifier_minimal.py but different validation order and logic (e.g. per-field first, then per-clause). Usage: python collatz_verifier_alternative.py --certificat JSON_PATH --output MD_PATH """ from __future__ import annotations import argparse import json from pathlib import Path from typing import Any REQUIRED_CLAUSE_FIELDS = frozenset({"word", "k", "s", "mod", "residue", "a", "B", "N0"}) def load_certificate(path: str) -> dict[str, Any]: """Load and parse JSON certificate.""" p = Path(path) if not p.exists(): raise FileNotFoundError(f"Certificate not found: {path}") text = p.read_text(encoding="utf-8") return json.loads(text) def get_clauses(data: dict[str, Any]) -> list[dict[str, Any]]: """Extract clauses from certificate (prefer 'clauses' then 'closed').""" if "clauses" in data: return data["clauses"] if "closed" in data: return data["closed"] return [] def validate_clause(clause: Any, index: int) -> list[str]: """Validate a single clause. Different order: check type first, then each field.""" errors: list[str] = [] if isinstance(clause, (int, float)): return [] if not isinstance(clause, dict): errors.append(f"Clause {index}: not a dict (got {type(clause).__name__})") return errors for field in sorted(REQUIRED_CLAUSE_FIELDS): if field not in clause: errors.append(f"Clause {index}: missing required field '{field}'") elif field == "word": w = clause[field] if not isinstance(w, str): errors.append(f"Clause {index}: 'word' must be string") elif w and not all(c in ("0", "1") for c in w): errors.append(f"Clause {index}: 'word' must be binary string") return errors def validate_certificate(data: dict[str, Any]) -> list[str]: """Validate certificate structure.""" errors: list[str] = [] clauses = get_clauses(data) if not clauses: errors.append("Certificate has no 'closed' or 'clauses' array") return errors if isinstance(clauses[0], (int, float)): return [] for i, c in enumerate(clauses): errors.extend(validate_clause(c, i)) return errors def run(cert_path: str, output_path: str) -> None: """Run verification and write output.""" errors: list[str] = [] try: data = load_certificate(cert_path) errors = validate_certificate(data) except FileNotFoundError as e: errors.append(str(e)) except json.JSONDecodeError as e: errors.append(f"Invalid JSON: {e}") if errors: content = "# Verification failed\n\n" + "\n".join(f"- {e}" for e in errors) else: content = "# Verification OK\n\n" Path(output_path).write_text(content, encoding="utf-8") def main() -> None: parser = argparse.ArgumentParser(description="Verify Collatz certificate (alternative)") parser.add_argument("--certificat", required=True, help="Path to certificate JSON") parser.add_argument("--output", required=True, help="Path to output MD file") args = parser.parse_args() run(args.certificat, args.output) if __name__ == "__main__": main()