#!/usr/bin/env python3 """Standalone verifier for the public MAIC Frozen Live Forward JSONL ledger. Usage: python verify_maic_live_forward.py maic_live_forward_ledger.jsonl The verifier is dependency-free and does not require access to MAIC strategy code. It checks canonical SHA-256 hashes, previous-hash linkage, chronology, freeze boundary, duplicate base intervals, and correction references. """ from __future__ import annotations import copy import hashlib import json import sys from datetime import datetime, timezone from pathlib import Path from typing import Any, Mapping FREEZE_AT = "2026-09-30T14:35:19Z" MODEL_GENERATION = "MAIC_LIVE_FORWARD_G1_20260930" EXPECTED_MODEL_SHA256 = "3c35c804875d621a75c1f1356a1d5c0cd1645814b3683c7411c1f70ebe458a1d" FROZEN_COMPONENT_GIT_BLOBS = { "protected_asset_identity_memory.py": "ce5b45bc649b5ce5ba71b14a03a0abf27bfa4ad6", "cycle_authority_publication.py": "9a30a2700a07f30c8a156d6c73a5274e454e864a", "cycle_authority_final_live_projection.py": "0dedc2dcd472053ffb61fe6e6efac9707cdfae50", "cycle_authority_live_projection.py": "42b0ea6411cc75e6cc826eb70c72b49e559e1c78", "authority_pas_live_oos.py": "1bf9bdd5e35757c97d88992113f0dd8bd218a837", } STRATEGY_SOURCE_HASH = hashlib.sha256( json.dumps( FROZEN_COMPONENT_GIT_BLOBS, sort_keys=True, separators=(",", ":"), ensure_ascii=False, ).encode("utf-8") ).hexdigest() def dt(value: Any) -> datetime | None: raw = str(value or "").strip() if not raw: return None if raw.endswith("Z"): raw = raw[:-1] + "+00:00" try: parsed = datetime.fromisoformat(raw) except ValueError: return None if parsed.tzinfo is None: parsed = parsed.replace(tzinfo=timezone.utc) return parsed.astimezone(timezone.utc) def canonical(value: Any) -> str: return json.dumps( value, sort_keys=True, separators=(",", ":"), ensure_ascii=False, default=str, ) def record_hash(record: Mapping[str, Any]) -> str: material = {key: copy.deepcopy(value) for key, value in record.items() if key != "record_hash"} return hashlib.sha256(canonical(material).encode("utf-8")).hexdigest() def verify(records: list[dict[str, Any]]) -> dict[str, Any]: freeze = dt(FREEZE_AT) failures: list[str] = [] previous_hash: str | None = None known_hashes: set[str] = set() seen_base: set[tuple[str, str]] = set() for ordinal, row in enumerate(records): expected = record_hash(row) actual = str(row.get("record_hash") or "") if actual != expected: failures.append(f"ROW_{ordinal}:RECORD_HASH_MISMATCH") if row.get("previous_record_hash") != previous_hash: failures.append(f"ROW_{ordinal}:PREVIOUS_HASH_MISMATCH") if row.get("model_generation") != MODEL_GENERATION: failures.append(f"ROW_{ordinal}:MODEL_GENERATION_MISMATCH") if row.get("model_hash") != EXPECTED_MODEL_SHA256: failures.append(f"ROW_{ordinal}:MODEL_HASH_MISMATCH") if row.get("strategy_source_hash") != STRATEGY_SOURCE_HASH: failures.append(f"ROW_{ordinal}:STRATEGY_SOURCE_HASH_MISMATCH") published = dt(row.get("published_at")) generated = dt(row.get("generated_at")) cutoff = dt(row.get("source_cutoff_at")) effective = dt(row.get("effective_at")) start = dt(row.get("interval_start")) end = dt(row.get("interval_end")) if not all((published, generated, cutoff, effective, start, end)): failures.append(f"ROW_{ordinal}:TIMESTAMP_MISSING_OR_INVALID") else: if not cutoff <= generated <= published: failures.append(f"ROW_{ordinal}:TIMESTAMP_ORDER_VIOLATION") if freeze is not None and start < freeze: failures.append(f"ROW_{ordinal}:PRE_FREEZE_INTERVAL") if effective != start: failures.append(f"ROW_{ordinal}:EFFECTIVE_INTERVAL_MISMATCH") if end <= start: failures.append(f"ROW_{ordinal}:NONPOSITIVE_INTERVAL") kind = str(row.get("record_type") or "BASE") pair = (str(row.get("interval_start") or ""), str(row.get("interval_end") or "")) if kind == "BASE": if pair in seen_base: failures.append(f"ROW_{ordinal}:DUPLICATE_BASE_INTERVAL") seen_base.add(pair) if int(row.get("revision") or 0) != 0 or row.get("correction_of") is not None: failures.append(f"ROW_{ordinal}:BASE_REVISION_INVALID") elif kind == "CORRECTION": target = str(row.get("correction_of") or "") if not target or target not in known_hashes: failures.append(f"ROW_{ordinal}:CORRECTION_TARGET_INVALID") if int(row.get("revision") or 0) < 1: failures.append(f"ROW_{ordinal}:CORRECTION_REVISION_INVALID") else: failures.append(f"ROW_{ordinal}:UNKNOWN_RECORD_TYPE") if actual: known_hashes.add(actual) previous_hash = actual return { "status": "VERIFIED" if not failures else "FAILED", "hash_algorithm": "SHA-256", "freeze_timestamp": FREEZE_AT, "model_generation": MODEL_GENERATION, "expected_model_sha256": EXPECTED_MODEL_SHA256, "strategy_source_hash": STRATEGY_SOURCE_HASH, "record_count": len(records), "base_interval_count": len(seen_base), "latest_record_hash": previous_hash, "failures": failures, } def main() -> int: if len(sys.argv) != 2: print("Usage: python verify_maic_live_forward.py ", file=sys.stderr) return 2 path = Path(sys.argv[1]) records: list[dict[str, Any]] = [] for line_no, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1): if not line.strip(): continue try: value = json.loads(line) except json.JSONDecodeError as exc: print(json.dumps({"status": "FAILED", "failures": [f"LINE_{line_no}:INVALID_JSON:{exc.msg}"]}, indent=2)) return 1 if not isinstance(value, dict): print(json.dumps({"status": "FAILED", "failures": [f"LINE_{line_no}:NOT_OBJECT"]}, indent=2)) return 1 records.append(value) result = verify(records) print(json.dumps(result, indent=2, sort_keys=True)) return 0 if result["status"] == "VERIFIED" else 1 if __name__ == "__main__": raise SystemExit(main())