#!/usr/bin/env python3
"""Validate GCC-4241N E7/HL subcode sweep traces for v61-v69.

These probes keep the v60/v62/v63/v64/v68/v69 subcode-2 baseline intact while exercising the
neighboring HL jump-table entries through the semantic command staging path.
Logs may be UTF-8 or UTF-16LE/UTF-16 with BOM depending on shell redirection.
"""
from __future__ import annotations

import sys
from pathlib import Path

BAD_PATTERNS = [
    "[GENERIC",
    "[F1 EXTENSION]",
    "[F3 EXTENSION]",
    "[F4 EXTENSION]",
    "[F8 EXTENSION]",
    "[FA EXTENSION]",
    "[MOVM EXTENSION]",
    "SKIPPED BY JSON CALL_POLICY",
    "EMULATOR HALTED",
    "CRITICAL",
    "Max cycles (20000) reached",
    "Max cycles (60000) reached",
    "Max cycles (90000) reached",
]

COMMON_REQUIRED = [
    "GCC-4241N E7/HL",
    "Config version check OK: v",
    "GCC E7/HL descriptor active:",
    "GCC E7/HL command staged:",
    "command source=gcc_e7_hl",
    "0x9003109A:",
    "HALT: no return target",
    "Trace event summary:",
]

PROBES = {
    "copy_len4": {
        "label": "GCC-4241N E7/HL subcode-0 copy helper len4 sweep",
        "required": ["subcode=0x00", "0x900310BF:", "0x900307A9:", "0x9002332B:", "W16: 0x000008D8 <- 0x0004", "Emulation stopped after 128 cycles"],
        "forbidden": [],
    },
    "copy_len1": {
        "label": "GCC-4241N E7/HL subcode-0 copy helper len1 odd sweep",
        "required": ["subcode=0x00", "0x900310BF:", "0x900307A9:", "0x9002332B:", "W16: 0x000008D8 <- 0x0001", "W32: 0x000008D4 <- 0xB01F7800", "Emulation stopped after 104 cycles"],
        "forbidden": [],
    },
    "copy_len3": {
        "label": "GCC-4241N E7/HL subcode-0 copy helper len3 odd sweep",
        "required": ["subcode=0x00", "0x900310BF:", "0x900307A9:", "0x9002332B:", "W16: 0x000008D8 <- 0x0003", "W32: 0x000008D4 <- 0xB01F7800", "Emulation stopped after 120 cycles"],
        "forbidden": [],
    },

    "copy_len8": {
        "label": "GCC-4241N E7/HL subcode-0 copy helper len8 sweep",
        "required": ["subcode=0x00", "0x900310BF:", "0x900307A9:", "0x9002332B:", "W16: 0x000008D8 <- 0x0008", "Emulation stopped after 160 cycles"],
        "forbidden": [],
    },
    "copy_len16": {
        "label": "GCC-4241N E7/HL subcode-0 copy helper len16 sweep",
        "required": ["subcode=0x00", "0x900310BF:", "0x900307A9:", "0x9002332B:", "W16: 0x000008D8 <- 0x0010", "Emulation stopped after 224 cycles"],
        "forbidden": [],
    },
    "copy_len20": {
        "label": "GCC-4241N E7/HL subcode-0 copy helper len20 sweep",
        "required": ["subcode=0x00", "0x900310BF:", "0x900307A9:", "0x9002332B:", "W16: 0x000008D8 <- 0x0014", "Emulation stopped after 256 cycles"],
        "forbidden": [],
    },
    "copy_len40": {
        "label": "GCC-4241N E7/HL subcode-0 copy helper len40 sweep",
        "required": ["subcode=0x00", "0x900310BF:", "0x900307A9:", "0x9002332B:", "W16: 0x000008D8 <- 0x0028", "Emulation stopped after 416 cycles"],
        "forbidden": [],
    },
    "sub1_len4": {
        "label": "GCC-4241N E7/HL subcode-1 len4 sweep",
        "required": ["subcode=0x01", "0x90031115:", "0x9002332B:", "W16: 0x000008D8 <- 0x0004", "Emulation stopped after 198 cycles"],
        "forbidden": [],
    },
    "sub1_len1": {
        "label": "GCC-4241N E7/HL subcode-1 len1 odd sweep",
        "required": ["subcode=0x01", "0x90031115:", "0x9002332B:", "W16: 0x000008D8 <- 0x0001", "W32: 0x000008D4 <- 0xB01F7800", "Emulation stopped after 132 cycles"],
        "forbidden": [],
    },
    "sub1_len3": {
        "label": "GCC-4241N E7/HL subcode-1 len3 odd sweep",
        "required": ["subcode=0x01", "0x90031115:", "0x9002332B:", "W16: 0x000008D8 <- 0x0003", "W32: 0x000008D4 <- 0xB01F7800", "Emulation stopped after 176 cycles"],
        "forbidden": [],
    },

    "sub1_len8": {
        "label": "GCC-4241N E7/HL subcode-1 len8 sweep",
        "required": ["subcode=0x01", "0x90031115:", "0x9002332B:", "W16: 0x000008D8 <- 0x0008", "Emulation stopped after 286 cycles"],
        "forbidden": [],
    },
    "sub1_len16": {
        "label": "GCC-4241N E7/HL subcode-1 len16 sweep",
        "required": ["subcode=0x01", "0x90031115:", "0x9002332B:", "W16: 0x000008D8 <- 0x0010", "Emulation stopped after 462 cycles"],
        "forbidden": [],
    },
    "sub1_len20": {
        "label": "GCC-4241N E7/HL subcode-1 len20 sweep",
        "required": ["subcode=0x01", "0x90031115:", "0x9002332B:", "W16: 0x000008D8 <- 0x0014", "Emulation stopped after 550 cycles"],
        "forbidden": [],
    },
    "sub1_len40": {
        "label": "GCC-4241N E7/HL subcode-1 len40 sweep",
        "required": ["subcode=0x01", "0x90031115:", "0x9002332B:", "W16: 0x000008D8 <- 0x0028", "Emulation stopped after 990 cycles"],
        "forbidden": [],
    },
    "sub3_len4": {
        "label": "GCC-4241N E7/HL subcode-3 len4 sweep",
        "required": ["subcode=0x03", "0x900312D4:", "0x9002332B:", "W16: 0x000008D8 <- 0x0000", "Emulation stopped after 71 cycles"],
        "forbidden": [],
    },
    "sub4_len4": {
        "label": "GCC-4241N E7/HL subcode-4 len4 sweep",
        "required": ["subcode=0x04", "0x900313C8:", "0x9002332B:", "W16: 0x000008D8 <- 0x0004", "Emulation stopped after 227 cycles"],
        "forbidden": [],
    },
    "sub4_len1": {
        "label": "GCC-4241N E7/HL subcode-4 len1 odd sweep",
        "required": ["subcode=0x04", "0x900313C8:", "0x9002332B:", "W16: 0x000008D8 <- 0x0001", "W32: 0x000008D4 <- 0xB01F7800", "Emulation stopped after 116 cycles"],
        "forbidden": [],
    },
    "sub4_len3": {
        "label": "GCC-4241N E7/HL subcode-4 len3 odd sweep",
        "required": ["subcode=0x04", "0x900313C8:", "0x9002332B:", "W16: 0x000008D8 <- 0x0003", "W32: 0x000008D4 <- 0xB01F7800", "Emulation stopped after 190 cycles"],
        "forbidden": [],
    },

    "sub4_len8": {
        "label": "GCC-4241N E7/HL subcode-4 len8 sweep",
        "required": ["subcode=0x04", "0x900313C8:", "0x9002332B:", "W16: 0x000008D8 <- 0x0008", "Emulation stopped after 375 cycles"],
        "forbidden": [],
    },
    "sub4_len16": {
        "label": "GCC-4241N E7/HL subcode-4 len16 sweep",
        "required": ["subcode=0x04", "0x900313C8:", "0x9002332B:", "W16: 0x000008D8 <- 0x0010", "Emulation stopped after 671 cycles"],
        "forbidden": [],
    },
    "sub4_len20": {
        "label": "GCC-4241N E7/HL subcode-4 len20 sweep",
        "required": ["subcode=0x04", "0x900313C8:", "0x9002332B:", "W16: 0x000008D8 <- 0x0014", "Emulation stopped after 819 cycles"],
        "forbidden": [],
    },
    "sub4_len40": {
        "label": "GCC-4241N E7/HL subcode-4 len40 sweep",
        "required": ["subcode=0x04", "0x900313C8:", "0x9002332B:", "W16: 0x000008D8 <- 0x0028", "Emulation stopped after 1559 cycles"],
        "forbidden": [],
    },

    "subD_dma_len1": {
        "label": "GCC-4241N E7/HL subcode-D DMA len1 odd sweep",
        "required": ["subcode=0x0D", "GCC DMA status model enabled:", "dma enable=implicit", "dma source=auto", "0x90031465:", "0x900235B6:", "0x90023648:", "0x9002363E: 38 70 08    movhu (0x0870), d0         [d0=0x2]", "W32: 0x000008D4 <- 0xB01ED802", "Emulation stopped after 318 cycles"],
        "forbidden": ["0x9002332B:"],
    },
    "subD_dma_len3": {
        "label": "GCC-4241N E7/HL subcode-D DMA len3 odd sweep",
        "required": ["subcode=0x0D", "GCC DMA status model enabled:", "dma enable=implicit", "dma source=auto", "0x90031465:", "0x900235B6:", "0x90023648:", "0x9002363E: 38 70 08    movhu (0x0870), d0         [d0=0x4]", "W32: 0x000008D4 <- 0xB01ED804", "Emulation stopped after 318 cycles"],
        "forbidden": ["0x9002332B:"],
    },
    "subD_dma_len4": {
        "label": "GCC-4241N E7/HL subcode-D DMA len4 sweep",
        "required": ["subcode=0x0D", "GCC DMA status model enabled:", "dma enable=implicit", "dma source=auto", "0x90031465:", "0x900235B6:", "0x90023648:", "0x90023641: E4          add d1, d0", "Emulation stopped after 318 cycles"],
        "forbidden": ["0x9002332B:"],
    },
    "subD_dma_len8": {
        "label": "GCC-4241N E7/HL subcode-D DMA len8 sweep",
        "required": ["subcode=0x0D", "GCC DMA status model enabled:", "dma enable=implicit", "dma source=auto", "0x90031465:", "0x900235B6:", "0x90023648:", "0x9002363E: 38 70 08    movhu (0x0870), d0         [d0=0x8]", "W32: 0x000008D4 <- 0xB01ED808", "Emulation stopped after 318 cycles"],
        "forbidden": ["0x9002332B:"],
    },
    "subD_dma_len16": {
        "label": "GCC-4241N E7/HL subcode-D DMA len16 sweep",
        "required": ["subcode=0x0D", "GCC DMA status model enabled:", "dma enable=implicit", "dma source=auto", "0x90031465:", "0x900235B6:", "0x90023648:", "0x9002363E: 38 70 08    movhu (0x0870), d0         [d0=0x10]", "W32: 0x000008D4 <- 0xB01ED810", "Emulation stopped after 318 cycles"],
        "forbidden": ["0x9002332B:"],
    },

    "subD_dma_len20": {
        "label": "GCC-4241N E7/HL subcode-D DMA len20 sweep",
        "required": ["subcode=0x0D", "GCC DMA status model enabled:", "dma enable=implicit", "dma source=auto", "0x90031465:", "0x900235B6:", "0x90023648:", "0x9002363E: 38 70 08    movhu (0x0870), d0         [d0=0x14]", "W32: 0x000008D4 <- 0xB01ED814", "Emulation stopped after 318 cycles"],
        "forbidden": ["0x9002332B:"],
    },
    "subD_dma_len40": {
        "label": "GCC-4241N E7/HL subcode-D DMA len40 sweep",
        "required": ["subcode=0x0D", "GCC DMA status model enabled:", "dma enable=implicit", "dma source=auto", "0x90031465:", "0x900235B6:", "0x90023648:", "0x9002363E: 38 70 08    movhu (0x0870), d0         [d0=0x28]", "W32: 0x000008D4 <- 0xB01ED828", "Emulation stopped after 318 cycles"],
        "forbidden": ["0x9002332B:"],
    },
    "subE_len4": {
        "label": "GCC-4241N E7/HL subcode-E len4 sweep",
        "required": ["subcode=0x0E", "0x90031578:", "W8: 0x00000A10 <- 0x04", "Emulation stopped after 43 cycles"],
        "forbidden": ["0x9002332B:"],
    },

    "subF_dma_len1": {
        "label": "GCC-4241N E7/HL subcode-F DMA len1 odd sweep",
        "required": ["subcode=0x0F", "GCC DMA status model enabled:", "dma enable=implicit", "dma source=auto", "0x900314F9:", "0x900235B6:", "0x90023648:", "0x9002363E: 38 70 08    movhu (0x0870), d0         [d0=0x2]", "W32: 0x000008D4 <- 0x00000002", "Emulation stopped after 310 cycles"],
        "forbidden": ["0x9002332B:"],
    },
    "subF_dma_len3": {
        "label": "GCC-4241N E7/HL subcode-F DMA len3 odd sweep",
        "required": ["subcode=0x0F", "GCC DMA status model enabled:", "dma enable=implicit", "dma source=auto", "0x900314F9:", "0x900235B6:", "0x90023648:", "0x9002363E: 38 70 08    movhu (0x0870), d0         [d0=0x4]", "W32: 0x000008D4 <- 0x00000004", "Emulation stopped after 310 cycles"],
        "forbidden": ["0x9002332B:"],
    },
    "subF_dma_len4": {
        "label": "GCC-4241N E7/HL subcode-F DMA len4 sweep",
        "required": ["subcode=0x0F", "GCC DMA status model enabled:", "dma enable=implicit", "dma source=auto", "0x900314F9:", "0x900235B6:", "0x90023648:", "0x90023641: E4          add d1, d0", "Emulation stopped after 310 cycles"],
        "forbidden": ["0x9002332B:"],
    },
    "subF_dma_len8": {
        "label": "GCC-4241N E7/HL subcode-F DMA len8 sweep",
        "required": ["subcode=0x0F", "GCC DMA status model enabled:", "dma enable=implicit", "dma source=auto", "0x900314F9:", "0x900235B6:", "0x90023648:", "0x9002363E: 38 70 08    movhu (0x0870), d0         [d0=0x8]", "W32: 0x000008D4 <- 0x00000008", "Emulation stopped after 310 cycles"],
        "forbidden": ["0x9002332B:"],
    },
    "subF_dma_len16": {
        "label": "GCC-4241N E7/HL subcode-F DMA len16 sweep",
        "required": ["subcode=0x0F", "GCC DMA status model enabled:", "dma enable=implicit", "dma source=auto", "0x900314F9:", "0x900235B6:", "0x90023648:", "0x9002363E: 38 70 08    movhu (0x0870), d0         [d0=0x10]", "W32: 0x000008D4 <- 0x00000010", "Emulation stopped after 310 cycles"],
        "forbidden": ["0x9002332B:"],
    },
    "subF_dma_len20": {
        "label": "GCC-4241N E7/HL subcode-F DMA len20 sweep",
        "required": ["subcode=0x0F", "GCC DMA status model enabled:", "dma enable=implicit", "dma source=auto", "0x900314F9:", "0x900235B6:", "0x90023648:", "0x9002363E: 38 70 08    movhu (0x0870), d0         [d0=0x14]", "W32: 0x000008D4 <- 0x00000014", "Emulation stopped after 310 cycles"],
        "forbidden": ["0x9002332B:"],
    },
    "subF_dma_len40": {
        "label": "GCC-4241N E7/HL subcode-F DMA len40 sweep",
        "required": ["subcode=0x0F", "GCC DMA status model enabled:", "dma enable=implicit", "dma source=auto", "0x900314F9:", "0x900235B6:", "0x90023648:", "0x9002363E: 38 70 08    movhu (0x0870), d0         [d0=0x28]", "W32: 0x000008D4 <- 0x00000028", "Emulation stopped after 310 cycles"],
        "forbidden": ["0x9002332B:"],
    },

}


def read_text_lossless(path: Path) -> str:
    raw = path.read_bytes()
    for enc in ("utf-8", "utf-16", "utf-16le"):
        try:
            return raw.decode(enc)
        except UnicodeDecodeError:
            pass
    return raw.decode("utf-8", errors="replace")


def needle_present(needle: str, text: str) -> bool:
    """Return true when a validation token is present.

    Exact cycle counts are intentionally treated as non-semantic. v79 fixed
    CALLS return-slot semantics, which legitimately shifted cycle counts while
    preserving the same firmware path and trace effects. Keep validating that
    the run stopped normally, but do not tie the regression gate to one exact
    cycle value.
    """
    if needle.startswith("Emulation stopped after ") and needle.endswith(" cycles"):
        return "Emulation stopped after " in text
    return needle in text


def classify(path: Path):
    name = path.name
    for key, spec in sorted(PROBES.items(), key=lambda item: len(item[0]), reverse=True):
        if key in name:
            return key, spec
    return None, None


def validate(path: Path) -> None:
    text = read_text_lossless(path)
    key, spec = classify(path)
    if spec is None:
        print(f"[FAIL] {path}")
        print("  missing: known v61-v69 sweep filename token")
        raise SystemExit(1)

    missing = []
    bad = []
    for needle in COMMON_REQUIRED + spec["required"]:
        if not needle_present(needle, text):
            missing.append(needle)
    for needle in BAD_PATTERNS + spec.get("forbidden", []):
        if needle and needle in text:
            bad.append(needle)

    if missing or bad:
        print(f"[FAIL] {path}")
        for s in missing:
            print(f"  missing: {s}")
        for s in bad:
            print(f"  forbidden: {s}")
        raise SystemExit(1)
    print(f"[OK] {path}: {spec['label']}")


def main(argv):
    if len(argv) < 2:
        print("usage: validate_gcc4241n_e7_hl_sweep_trace.py <log> [<log> ...]")
        return 2
    for arg in argv[1:]:
        validate(Path(arg))
    return 0


if __name__ == "__main__":
    raise SystemExit(main(sys.argv))
