#!/usr/bin/env python3 """Deterministic local checks for the three design-direction coded slices.""" from __future__ import annotations import hashlib import json import struct from pathlib import Path ROOT = Path(__file__).resolve().parents[1] DIRECTIONS = { "ledger-studio": ("ledger-desktop.png", "ledger-mobile.png"), "signal-trace": ("signal-desktop.png", "signal-mobile.png"), "field-manual": ("manual-desktop.png", "manual-mobile.png"), } REQUIRED = ( "개념을 알고 있어요", "증상만 알고 있어요", "Predict", "Observe", "Compare", "Explain", "Transfer", ) def sha256(path: Path) -> str: return hashlib.sha256(path.read_bytes()).hexdigest() def png_size(path: Path) -> tuple[int, int]: raw = path.read_bytes()[:24] if len(raw) != 24 or raw[:8] != b"\x89PNG\r\n\x1a\n" or raw[12:16] != b"IHDR": raise AssertionError(f"not a PNG: {path}") return struct.unpack(">II", raw[16:24]) def main() -> None: records = [] previews = ROOT / "previews" for direction, (desktop_name, mobile_name) in DIRECTIONS.items(): folder = ROOT / "directions" / direction html = folder / "index.html" concept = folder / "concept.yaml" assert html.is_file(), html assert concept.is_file(), concept source = html.read_text(encoding="utf-8") for marker in REQUIRED: assert marker in source, f"{direction}: missing {marker}" assert "focus-visible" in source, f"{direction}: focus style missing" assert "prefers-reduced-motion" in source, f"{direction}: reduced-motion missing" assert "http://" not in source and "https://" not in source, f"{direction}: external dependency" desktop = previews / desktop_name mobile = previews / mobile_name assert png_size(desktop) == (1280, 1100), f"{desktop}: wrong dimensions" assert png_size(mobile) == (390, 844), f"{mobile}: wrong dimensions" records.append({ "direction": direction, "coded_slice_sha256": sha256(html), "concept_sha256": sha256(concept), "desktop_sha256": sha256(desktop), "mobile_sha256": sha256(mobile), }) gallery = previews / "comparison.png" assert gallery.is_file(), gallery width, height = png_size(gallery) assert width >= 1500 and height >= 1000, "comparison preview is not full-size" print(json.dumps({ "status": "pass", "representative_screen": "dual-entry-shared-lab", "directions": records, "comparison": {"sha256": sha256(gallery), "size": [width, height]}, }, ensure_ascii=False, sort_keys=True)) if __name__ == "__main__": main()