#!/usr/bin/env python3
"""Validate GCC-4241N E7/HL dispatcher traces.

Supports the v38-v69 zero-length bootstrap, len4 transfer,
len4 patterned payload, len8 patterned payload, len16 patterned payload,
v42-v69 len20 ring-wrap patterned payload, v43-v69 len40
double-ring-wrap patterned payload probes, the v44-v69 len4
offset0FFF source-boundary probe, the v45-v69 len1/len3
odd-length patterned probes, and the v46-v69 len8 offset0FFE
source-boundary stride-ramp probe. v51 requires the GCC transfer model to use
address-driven DF94 readout (completion_read_pc="any") for transfer configs; v52 also
requires address/state-driven status readout (status_read_pc="any"); v53 validates the same behavior using minimal transfer configs where those are defaults; v54 keeps those defaults and removes explicit hardware status seed injections from the active GCC transfer configs; v55 also removes the explicit 0x002C default/non-disc-path clear injection; v56 moves active GCC E7/HL command staging from raw memory_injections into a semantic gcc_e7_hl_command block; v57 defaults fixed opcode/subcode/magic/base/source_offset fields in that semantic block; v58 validates implicit enable defaults for the semantic command block and transfer source model; v59 validates that the active GCC transfer model is supplied as a top-level semantic block instead of nested inside trace; v60 validates the combined gcc_e7_hl_subcode2 descriptor that expands into both semantic command staging and transfer modeling; v61 keeps that baseline and adds separate GCC HL subcode-sweep probes; v62 introduces a generic gcc_e7_hl descriptor for both the subcode-2 baseline and the neighboring sweep paths; v63 keeps that baseline while the separate sweep validator adds len8/len16 host-output probes for subcodes 0, 1, and 4; v68 keeps the subcode-2 baseline unchanged while the separate sweep validator adds odd host-output probes for those same subcodes; v69 uses stable test filenames without `.example` or per-test version suffixes. 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]",
    "SKIPPED BY JSON CALL_POLICY",
    "EMULATOR HALTED",
    "CRITICAL",
    "Max cycles (20000) reached",
    "Max cycles (60000) reached",
    "Max cycles (70000) reached",
    "Max cycles (90000) reached",
    "Max cycles (120000) reached",
    "Max cycles (140000) reached",
    "Max cycles (160000) reached",
    "Max cycles (170000) reached",
    "Max cycles (260000) reached",
    "Max cycles (300000) reached",
]

COMMON_REQUIRED = [
    "GCC-4241N E7 HL dispatcher",
    "Config version check OK: v",
    "0x9003109A:",
    "0x900311FB:",
    "0x90031216:",
    "0x9002332B:",
    "0x90031213: DF 00 04",
    "HALT: no return target",
    "Trace event summary:",
]

ZERO_REQUIRED = [
    "zero-length output bootstrap",
    "movhu d0, (0x08D8)",
    "W16: 0x000008D8 <- 0x0000",
    "Emulation stopped after 91 cycles",
]

LEN4_REQUIRED = [
    "len4 hardware-transfer probe",
    "0x90031244:",
    "0x9000C372:",
    "0x9000C3C9:",
    "0x90037E2D:",
    "F1 5E          add a3, d2",
    "W16: 0x000008D8 <- 0x0004",
    "Emulation stopped after 345 cycles",
]

LEN4_PATTERN_REQUIRED = [x for x in LEN4_REQUIRED if x != "len4 hardware-transfer probe"] + [
    "patterned hardware-transfer probe",
    "0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x2211]",
    "0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x4433]",
    "W8: 0xB01F7800 <- 0x11",
    "W8: 0xB01F7801 <- 0x22",
    "W8: 0xB01F7802 <- 0x33",
    "W8: 0xB01F7803 <- 0x44",
]


LEN1_ODD_PATTERN_REQUIRED = [
    "len1 odd patterned hardware-transfer probe",
    "0x90031244:",
    "0x9000C372:",
    "0x9000C3C9:",
    "0x90037E2D:",
    "F1 5E          add a3, d2",
    "W16: 0x00000DBC <- 0x0001",
    "W16: 0x000008D8 <- 0x0001",
    "0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x2211]",
    "W8: 0xB01F7800 <- 0x11",
    "W8: 0xB01F7801 <- 0x22",
    "Emulation stopped after 218 cycles",
]

LEN3_ODD_PATTERN_REQUIRED = [
    "len3 odd patterned hardware-transfer probe",
    "0x90031244:",
    "0x9000C372:",
    "0x9000C3C9:",
    "0x90037E2D:",
    "F1 5E          add a3, d2",
    "W16: 0x00000DBC <- 0x0003",
    "W16: 0x000008D8 <- 0x0003",
    "0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x2211]",
    "0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x4433]",
    "W8: 0xB01F7800 <- 0x11",
    "W8: 0xB01F7801 <- 0x22",
    "W8: 0xB01F7802 <- 0x33",
    "W8: 0xB01F7803 <- 0x44",
    "Emulation stopped after 345 cycles",
]


LEN4_OFFSET0FFF_PATTERN_REQUIRED = [x for x in LEN4_PATTERN_REQUIRED if x != "patterned hardware-transfer probe" and x != "Emulation stopped after 345 cycles"] + [
    "offset0FFF boundary hardware-transfer probe",
    "0x9003121E: 83          mov d0, d3                 [d3=0xFFF]",
    "0x90031244: 8E          mov d3, d2                 [d2=0xFFF]",
    "0x90031246: 88          mov d2, d0                 [d0=0xFFF]",
    "W16: 0x003FDFD6 <- 0x0FFF",
    "W16: 0x0000DF72 <- 0x0FFF",
    "0x90031268: 4C          inc d3                     [d3=0x1000]",
    "0x90031244: 8E          mov d3, d2                 [d2=0x1000]",
    "0x90031246: 88          mov d2, d0                 [d0=0x1000]",
    "W16: 0x003FDFD6 <- 0x1000",
    "W16: 0x0000DF72 <- 0x1000",
    "0x90031265: C2 04       bge -> 0x90031269 [TAKEN]",
    "W16: 0x000008D8 <- 0x0004",
    "Emulation stopped after 343 cycles",
]

LEN8_PATTERN_REQUIRED = [
    "len8 patterned hardware-transfer probe",
    "0x90031244:",
    "0x9000C372:",
    "0x9000C3C9:",
    "0x90037E2D:",
    "F1 5E          add a3, d2",
    "W16: 0x00000DBC <- 0x0008",
    "W16: 0x000008D8 <- 0x0008",
    "0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x2211]",
    "0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x4433]",
    "0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x6655]",
    "0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x8877]",
    "W8: 0xB01F7800 <- 0x11",
    "W8: 0xB01F7801 <- 0x22",
    "W8: 0xB01F7802 <- 0x33",
    "W8: 0xB01F7803 <- 0x44",
    "W8: 0xB01F7804 <- 0x55",
    "W8: 0xB01F7805 <- 0x66",
    "W8: 0xB01F7806 <- 0x77",
    "W8: 0xB01F7807 <- 0x88",
    "Emulation stopped after 599 cycles",
]


LEN8_OFFSET0FFE_PATTERN_REQUIRED = [x for x in LEN8_PATTERN_REQUIRED if x != "len8 patterned hardware-transfer probe" and x != "Emulation stopped after 599 cycles"] + [
    "len8 offset0FFE boundary-ramp hardware-transfer probe",
    "0x9003121E: 83          mov d0, d3                 [d3=0xFFE]",
    "0x90031244: 8E          mov d3, d2                 [d2=0xFFE]",
    "0x90031246: 88          mov d2, d0                 [d0=0xFFE]",
    "W16: 0x003FDFD6 <- 0x0FFE",
    "W16: 0x0000DF72 <- 0x0FFE",
    "0x90031268: 4C          inc d3                     [d3=0xFFF]",
    "0x90031244: 8E          mov d3, d2                 [d2=0xFFF]",
    "0x90031246: 88          mov d2, d0                 [d0=0xFFF]",
    "W16: 0x003FDFD6 <- 0x0FFF",
    "W16: 0x0000DF72 <- 0x0FFF",
    "0x90031268: 4C          inc d3                     [d3=0x1000]",
    "0x90031244: 8E          mov d3, d2                 [d2=0x1000]",
    "0x90031246: 88          mov d2, d0                 [d0=0x1000]",
    "W16: 0x003FDFD6 <- 0x1000",
    "W16: 0x0000DF72 <- 0x1000",
    "0x90031265: C2 04       bge -> 0x90031269 [TAKEN]",
    "0x90031244: 8E          mov d3, d2                 [d2=0x1002]",
    "0x90031246: 88          mov d2, d0                 [d0=0x1002]",
    "W16: 0x003FDFD6 <- 0x1002",
    "W16: 0x0000DF72 <- 0x1002",
    "W16: 0x000008D8 <- 0x0008",
    "Emulation stopped after 595 cycles",
]

LEN16_PATTERN_REQUIRED = [
    "len16 patterned hardware-transfer probe",
    "0x90031244:",
    "0x9000C372:",
    "0x9000C3C9:",
    "0x90037E2D:",
    "F1 5E          add a3, d2",
    "W16: 0x00000DBC <- 0x0010",
    "W16: 0x000008D8 <- 0x0010",
    "0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x2211]",
    "0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x4433]",
    "0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x6655]",
    "0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x8877]",
    "0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0xAA99]",
    "0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0xCCBB]",
    "0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0xEEDD]",
    "0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0xFF]",
    "W8: 0xB01F7800 <- 0x11",
    "W8: 0xB01F7801 <- 0x22",
    "W8: 0xB01F7802 <- 0x33",
    "W8: 0xB01F7803 <- 0x44",
    "W8: 0xB01F7804 <- 0x55",
    "W8: 0xB01F7805 <- 0x66",
    "W8: 0xB01F7806 <- 0x77",
    "W8: 0xB01F7807 <- 0x88",
    "W8: 0xB01F7808 <- 0x99",
    "W8: 0xB01F7809 <- 0xAA",
    "W8: 0xB01F780A <- 0xBB",
    "W8: 0xB01F780B <- 0xCC",
    "W8: 0xB01F780C <- 0xDD",
    "W8: 0xB01F780D <- 0xEE",
    "W8: 0xB01F780E <- 0xFF",
    "W8: 0xB01F780F <- 0x00",
    "Emulation stopped after 1109 cycles",
]


LEN20_PATTERN_REQUIRED = [
    "len20 patterned ring-wrap hardware-transfer probe",
    "0x90031244:",
    "0x9000C372:",
    "0x9000C3C9:",
    "0x90037E2D:",
    "F1 5E          add a3, d2",
    "W16: 0x00000DBC <- 0x0014",
    "W16: 0x000008D8 <- 0x0014",
    "0x9000C33B: 01 48 02    mov d0, (0x0248)           [W8: 0x00000248 <- 0x28",
    "0x9000C342: 00          clr d0                     [d0=0x0]",
    "0x9000C343: 01 48 02    mov d0, (0x0248)           [W8: 0x00000248 <- 0x00",
    "0x9000C329: F0 50          movbu d0, (a0)          [W8: 0x00000220 <- 0xA5]",
    "0x9000C329: F0 50          movbu d0, (a0)          [W8: 0x00000225 <- 0xA5]",
    "0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x2211]",
    "0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x4433]",
    "0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x6655]",
    "0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x8877]",
    "0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0xAA99]",
    "0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0xCCBB]",
    "0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0xEEDD]",
    "0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0xFF]",
    "0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x2110]",
    "0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x4332]",
    "W8: 0xB01F7800 <- 0x11",
    "W8: 0xB01F7801 <- 0x22",
    "W8: 0xB01F7802 <- 0x33",
    "W8: 0xB01F7803 <- 0x44",
    "W8: 0xB01F7804 <- 0x55",
    "W8: 0xB01F7805 <- 0x66",
    "W8: 0xB01F7806 <- 0x77",
    "W8: 0xB01F7807 <- 0x88",
    "W8: 0xB01F7808 <- 0x99",
    "W8: 0xB01F7809 <- 0xAA",
    "W8: 0xB01F780A <- 0xBB",
    "W8: 0xB01F780B <- 0xCC",
    "W8: 0xB01F780C <- 0xDD",
    "W8: 0xB01F780D <- 0xEE",
    "W8: 0xB01F780E <- 0xFF",
    "W8: 0xB01F780F <- 0x00",
    "W8: 0xB01F7810 <- 0x10",
    "W8: 0xB01F7811 <- 0x21",
    "W8: 0xB01F7812 <- 0x32",
    "W8: 0xB01F7813 <- 0x43",
    "Emulation stopped after 1363 cycles",
]


LEN40_PATTERN_REQUIRED = [
    'len40 patterned double-ring-wrap hardware-transfer probe',
    '0x90031244:',
    '0x9000C372:',
    '0x9000C3C9:',
    '0x90037E2D:',
    'F1 5E          add a3, d2',
    'W16: 0x00000DBC <- 0x0028',
    'W16: 0x000008D8 <- 0x0028',
    '0x9000C33B: 01 48 02    mov d0, (0x0248)           [W8: 0x00000248 <- 0x28',
    '0x9000C342: 00          clr d0                     [d0=0x0]',
    '0x9000C343: 01 48 02    mov d0, (0x0248)           [W8: 0x00000248 <- 0x00',
    '0x9000C329: F0 50          movbu d0, (a0)          [W8: 0x00000220 <- 0xA5]',
    '0x9000C329: F0 50          movbu d0, (a0)          [W8: 0x00000225 <- 0xA5]',
    '0x9000C329: F0 50          movbu d0, (a0)          [W8: 0x0000023E <- 0xA5]',
    '0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x2211]',
    '0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x4433]',
    '0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x6655]',
    '0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x8877]',
    '0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0xAA99]',
    '0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0xCCBB]',
    '0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0xEEDD]',
    '0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0xFF]',
    '0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x2110]',
    '0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x4332]',
    '0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x6554]',
    '0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x8776]',
    '0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0xA998]',
    '0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0xCBBA]',
    '0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0xEDDC]',
    '0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0xFFE]',
    '0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x3120]',
    '0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x5342]',
    '0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x7564]',
    '0x9000C34F: 30 94 DF    mov (0xDF94), d0           [d0=0x9786]',
    'W8: 0xB01F7800 <- 0x11',
    'W8: 0xB01F7801 <- 0x22',
    'W8: 0xB01F7802 <- 0x33',
    'W8: 0xB01F7803 <- 0x44',
    'W8: 0xB01F7804 <- 0x55',
    'W8: 0xB01F7805 <- 0x66',
    'W8: 0xB01F7806 <- 0x77',
    'W8: 0xB01F7807 <- 0x88',
    'W8: 0xB01F7808 <- 0x99',
    'W8: 0xB01F7809 <- 0xAA',
    'W8: 0xB01F780A <- 0xBB',
    'W8: 0xB01F780B <- 0xCC',
    'W8: 0xB01F780C <- 0xDD',
    'W8: 0xB01F780D <- 0xEE',
    'W8: 0xB01F780E <- 0xFF',
    'W8: 0xB01F780F <- 0x00',
    'W8: 0xB01F7810 <- 0x10',
    'W8: 0xB01F7811 <- 0x21',
    'W8: 0xB01F7812 <- 0x32',
    'W8: 0xB01F7813 <- 0x43',
    'W8: 0xB01F7814 <- 0x54',
    'W8: 0xB01F7815 <- 0x65',
    'W8: 0xB01F7816 <- 0x76',
    'W8: 0xB01F7817 <- 0x87',
    'W8: 0xB01F7818 <- 0x98',
    'W8: 0xB01F7819 <- 0xA9',
    'W8: 0xB01F781A <- 0xBA',
    'W8: 0xB01F781B <- 0xCB',
    'W8: 0xB01F781C <- 0xDC',
    'W8: 0xB01F781D <- 0xED',
    'W8: 0xB01F781E <- 0xFE',
    'W8: 0xB01F781F <- 0x0F',
    'W8: 0xB01F7820 <- 0x20',
    'W8: 0xB01F7821 <- 0x31',
    'W8: 0xB01F7822 <- 0x42',
    'W8: 0xB01F7823 <- 0x53',
    'W8: 0xB01F7824 <- 0x64',
    'W8: 0xB01F7825 <- 0x75',
    'W8: 0xB01F7826 <- 0x86',
    'W8: 0xB01F7827 <- 0x97',
    'Emulation stopped after 2635 cycles',
]


def read_text(path: Path) -> str:
    raw = path.read_bytes()
    for enc in ("utf-8-sig", "utf-16", "utf-16-le"):
        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 validate_one(path: Path) -> None:
    text = read_text(path)
    missing = [s for s in COMMON_REQUIRED if not needle_present(s, text)]
    bad = [s for s in BAD_PATTERNS if s in text]

    is_len1_odd_pattern = "len1 odd patterned hardware-transfer probe" in text or "W16: 0x000008D8 <- 0x0001" in text
    is_len3_odd_pattern = "len3 odd patterned hardware-transfer probe" in text or "W16: 0x000008D8 <- 0x0003" in text
    is_len8_offset0ffe = "offset0FFE boundary-ramp hardware-transfer probe" in text or "W16: 0x0000DF72 <- 0x1002" in text
    is_len4_offset0fff = ("offset0FFF boundary hardware-transfer probe" in text or "W16: 0x0000DF72 <- 0x1000" in text) and not is_len8_offset0ffe
    is_len40_pattern = "len40 patterned double-ring-wrap hardware-transfer probe" in text or "W8: 0xB01F7827 <- 0x97" in text
    is_len20_pattern = ("len20 patterned ring-wrap hardware-transfer probe" in text or "W8: 0xB01F7813 <- 0x43" in text) and not is_len40_pattern
    is_len16_pattern = ("len16 patterned hardware-transfer probe" in text or "W8: 0xB01F780F <- 0x00" in text) and not is_len20_pattern and not is_len40_pattern
    is_len8_pattern = ("len8 patterned hardware-transfer probe" in text or "W8: 0xB01F7807 <- 0x88" in text) and not is_len8_offset0ffe and not is_len16_pattern and not is_len20_pattern and not is_len40_pattern
    is_pattern = ("patterned hardware-transfer probe" in text or "W8: 0xB01F7803 <- 0x44" in text) and not is_len1_odd_pattern and not is_len3_odd_pattern and not is_len4_offset0fff and not is_len8_offset0ffe and not is_len8_pattern and not is_len16_pattern and not is_len20_pattern and not is_len40_pattern
    is_len4 = is_len4_offset0fff or is_len8_offset0ffe or is_pattern or is_len8_pattern or is_len16_pattern or is_len20_pattern or is_len40_pattern or "len4 hardware-transfer probe" in text or "W16: 0x000008D8 <- 0x0004" in text
    if is_len1_odd_pattern:
        required = LEN1_ODD_PATTERN_REQUIRED
    elif is_len3_odd_pattern:
        required = LEN3_ODD_PATTERN_REQUIRED
    elif is_len4_offset0fff:
        required = LEN4_OFFSET0FFF_PATTERN_REQUIRED
    elif is_len8_offset0ffe:
        required = LEN8_OFFSET0FFE_PATTERN_REQUIRED
    elif is_len40_pattern:
        required = LEN40_PATTERN_REQUIRED
    elif is_len20_pattern:
        required = LEN20_PATTERN_REQUIRED
    elif is_len16_pattern:
        required = LEN16_PATTERN_REQUIRED
    elif is_len8_pattern:
        required = LEN8_PATTERN_REQUIRED
    elif is_pattern:
        required = LEN4_PATTERN_REQUIRED
    elif is_len4:
        required = LEN4_REQUIRED
    else:
        required = ZERO_REQUIRED
    missing.extend(s for s in required if not needle_present(s, text))

    is_v47_or_later = (
        "Config version check OK: v47" in text or "-v47-" in str(path) or "_v47" in str(path) or
        "Config version check OK: v48" in text or "-v48-" in str(path) or "_v48" in str(path) or
        "Config version check OK: v49" in text or "-v49-" in str(path) or "_v49" in str(path) or
        "Config version check OK: v50" in text or "-v50-" in str(path) or "_v50" in str(path) or
        "Config version check OK: v51" in text or "-v51-" in str(path) or "_v51" in str(path) or
        "Config version check OK: v52" in text or "-v52-" in str(path) or "_v52" in str(path) or
        "Config version check OK: v53" in text or "-v53-" in str(path) or "_v53" in str(path) or
        "Config version check OK: v54" in text or "-v54-" in str(path) or "_v54" in str(path) or
        "Config version check OK: v55" in text or "-v55-" in str(path) or "_v55" in str(path) or
        "Config version check OK: v56" in text or "-v56-" in str(path) or "_v56" in str(path) or
        "Config version check OK: v57" in text or "-v57-" in str(path) or "_v57" in str(path) or
        "Config version check OK: v58" in text or "-v58-" in str(path) or "_v58" in str(path) or
        "Config version check OK: v59" in text or "-v59-" in str(path) or "_v59" in str(path) or
        "Config version check OK: v60" in text or "-v60-" in str(path) or "_v60" in str(path) or
        "Config version check OK: v61" in text or "-v61-" in str(path) or "_v61" in str(path) or
        "Config version check OK: v62" in text or "-v62-" in str(path) or "_v62" in str(path) or
        "Config version check OK: v63" in text or "-v63-" in str(path) or "_v63" in str(path) or
        "Config version check OK: v68" in text or "-v68-" in str(path) or "_v68" in str(path) or
        "Config version check OK: v69" in text or "-v69-" in str(path) or "_v69" in str(path)
    )
    is_v48 = "Config version check OK: v48" in text or "-v48-" in str(path) or "_v48" in str(path)
    is_v49 = "Config version check OK: v49" in text or "-v49-" in str(path) or "_v49" in str(path)
    is_v50 = "Config version check OK: v50" in text or "-v50-" in str(path) or "_v50" in str(path)
    is_v51 = "Config version check OK: v51" in text or "-v51-" in str(path) or "_v51" in str(path)
    is_v52 = "Config version check OK: v52" in text or "-v52-" in str(path) or "_v52" in str(path)
    is_v53 = "Config version check OK: v53" in text or "-v53-" in str(path) or "_v53" in str(path)
    is_v54 = "Config version check OK: v54" in text or "-v54-" in str(path) or "_v54" in str(path)
    is_v55 = "Config version check OK: v55" in text or "-v55-" in str(path) or "_v55" in str(path)
    is_v56 = "Config version check OK: v56" in text or "-v56-" in str(path) or "_v56" in str(path)
    is_v57 = "Config version check OK: v57" in text or "-v57-" in str(path) or "_v57" in str(path)
    is_v58 = "Config version check OK: v58" in text or "-v58-" in str(path) or "_v58" in str(path)
    is_v59 = "Config version check OK: v59" in text or "-v59-" in str(path) or "_v59" in str(path)
    is_v60 = "Config version check OK: v60" in text or "-v60-" in str(path) or "_v60" in str(path)
    is_v61 = "Config version check OK: v61" in text or "-v61-" in str(path) or "_v61" in str(path)
    is_v62 = "Config version check OK: v62" in text or "-v62-" in str(path) or "_v62" in str(path)
    is_v63 = "Config version check OK: v63" in text or "-v63-" in str(path) or "_v63" in str(path)
    is_v68 = "Config version check OK: v68" in text or "-v68-" in str(path) or "_v68" in str(path)
    is_v69 = "Config version check OK: v69" in text or "-v69-" in str(path) or "_v69" in str(path)
    is_zero = required is ZERO_REQUIRED
    if is_v47_or_later and not is_zero and "GCC transfer model enabled:" not in text:
        missing.append("GCC transfer model enabled banner")
    if is_v48 and not is_zero and "completion byte stream=" not in text:
        missing.append("GCC transfer model byte-stream banner")
    if (is_v49 or is_v50 or is_v51 or is_v52 or is_v53 or is_v54 or is_v55 or is_v56 or is_v57 or is_v58 or is_v59 or is_v60 or is_v61 or is_v62 or is_v63 or is_v68 or is_v69) and not is_zero:
        if "source byte stream=" not in text:
            missing.append("GCC transfer model source-byte-stream banner")
        if "source map=" not in text:
            missing.append("GCC transfer model source-map banner")
    if (is_v50 or is_v51 or is_v52 or is_v53 or is_v54 or is_v55 or is_v56 or is_v57 or is_v58 or is_v59 or is_v60 or is_v61 or is_v62 or is_v63 or is_v68 or is_v69) and not is_zero:
        if "source binding=first_seen" not in text:
            missing.append("GCC transfer model first-seen source binding banner")
    if (is_v51 or is_v52 or is_v53 or is_v54 or is_v55 or is_v56 or is_v57 or is_v58 or is_v59 or is_v60 or is_v61 or is_v62 or is_v63 or is_v68 or is_v69) and not is_zero:
        if "completion read=any" not in text:
            missing.append("GCC transfer model address-driven completion-read banner")
    if (is_v52 or is_v53 or is_v54 or is_v55 or is_v56 or is_v57 or is_v58 or is_v59 or is_v60 or is_v61 or is_v62 or is_v63 or is_v68 or is_v69) and not is_zero:
        if "status read=any" not in text:
            missing.append("GCC transfer model address/state-driven status-read banner")

    if is_v54 or is_v55 or is_v56 or is_v57 or is_v58 or is_v59 or is_v60 or is_v61 or is_v62 or is_v63 or is_v68 or is_v69:
        for seed_msg in (
            "[*] Injecting: hardware ready seed",
            "[*] Injecting: D905 initial clear",
            "[*] Injecting: D905 clear",
            "[*] Injecting: D954 ready state seed",
            "[*] Injecting: D950 clear",
            "[*] Injecting: D955 initial clear",
        ):
            if seed_msg in text:
                bad.append(seed_msg)
    if (is_v55 or is_v56 or is_v57 or is_v58 or is_v59 or is_v60 or is_v61 or is_v62 or is_v63 or is_v68 or is_v69) and "[*] Injecting: 0x002C default/non-disc-path clear" in text:
        bad.append("[*] Injecting: 0x002C default/non-disc-path clear")
    if is_v56 or is_v57 or is_v58 or is_v59 or is_v60 or is_v61 or is_v62 or is_v63 or is_v68 or is_v69:
        if "GCC E7/HL command staged:" not in text:
            missing.append("GCC E7/HL semantic command staging banner")
        for raw_cmd_msg in (
            "[*] Injecting: GCC E7/HL command header",
            "[*] Injecting: HL subcode-2 source offset word",
            "[*] Injecting: HL subcode-2 transfer length word",
        ):
            if raw_cmd_msg in text:
                bad.append(raw_cmd_msg)

    if is_v57 or is_v58 or is_v59 or is_v60 or is_v61 or is_v62 or is_v63 or is_v68 or is_v69:
        if "defaults=base,opcode,subcode,magic" not in text:
            missing.append("GCC E7/HL semantic command defaults banner")



    if is_v58 or is_v59 or is_v60 or is_v61 or is_v62 or is_v63 or is_v68 or is_v69:
        if "command enable=implicit" not in text:
            missing.append("GCC E7/HL implicit command-enable banner")
        if "command enable=explicit" in text:
            bad.append("command enable=explicit")
        if not is_zero:
            if "transfer enable=implicit" not in text:
                missing.append("GCC transfer implicit-enable banner")
            if "transfer enable=explicit" in text:
                bad.append("transfer enable=explicit")
    if is_v59:
        if not is_zero:
            if "transfer config scope=top-level" not in text:
                missing.append("GCC transfer top-level config-scope banner")
            if "transfer config scope=trace" in text:
                bad.append("transfer config scope=trace")

    if is_v60 or is_v61:
        if "GCC E7/HL subcode-2 descriptor active:" not in text:
            missing.append("GCC E7/HL subcode-2 compound descriptor banner")
        if "command source=e7_hl_subcode2" not in text:
            missing.append("GCC E7/HL command source compound banner")
        if not is_zero:
            if "transfer config scope=e7_hl_subcode2" not in text:
                missing.append("GCC transfer compound config-scope banner")
            if "transfer config scope=trace" in text or "transfer config scope=top-level" in text:
                bad.append("old GCC transfer config scope")

    if is_v62 or is_v63 or is_v68 or is_v69:
        if "GCC E7/HL descriptor active:" not in text:
            missing.append("GCC E7/HL generic descriptor banner")
        if "command source=gcc_e7_hl" not in text:
            missing.append("GCC E7/HL command source generic banner")
        if "GCC E7/HL subcode-2 descriptor active:" in text:
            bad.append("old GCC E7/HL subcode-2 compound descriptor banner")
        if not is_zero:
            if "transfer config scope=gcc_e7_hl" not in text:
                missing.append("GCC transfer generic config-scope banner")
            if "transfer config scope=trace" in text or "transfer config scope=top-level" in text or "transfer config scope=e7_hl_subcode2" in text:
                bad.append("old GCC transfer config scope")

    if is_len40_pattern:
        reset_sig = "0x9000C343: 01 48 02    mov d0, (0x0248)           [W8: 0x00000248 <- 0x00"
        if text.count(reset_sig) < 2:
            missing.append("at least two 0x0248 command-ring resets")
        if text.count("0x9000C342: 00          clr d0                     [d0=0x0]") < 2:
            missing.append("at least two ring-reset clr d0 operations")

    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)

    if is_len1_odd_pattern:
        kind = "GCC-4241N E7/HL subcode-2 len1 odd patterned payload baseline"
    elif is_len3_odd_pattern:
        kind = "GCC-4241N E7/HL subcode-2 len3 odd patterned payload baseline"
    elif is_len4_offset0fff:
        kind = "GCC-4241N E7/HL subcode-2 len4 offset0FFF source-boundary patterned payload baseline"
    elif is_len8_offset0ffe:
        kind = "GCC-4241N E7/HL subcode-2 len8 offset0FFE source-boundary stride-ramp patterned payload baseline"
    elif is_len40_pattern:
        kind = "GCC-4241N E7/HL subcode-2 len40 double-ring-wrap patterned payload baseline"
    elif is_len20_pattern:
        kind = "GCC-4241N E7/HL subcode-2 len20 ring-wrap patterned payload baseline"
    elif is_len16_pattern:
        kind = "GCC-4241N E7/HL subcode-2 len16 patterned payload baseline"
    elif is_len8_pattern:
        kind = "GCC-4241N E7/HL subcode-2 len8 patterned payload baseline"
    elif is_pattern:
        kind = "GCC-4241N E7/HL subcode-2 len4 patterned payload baseline"
    elif is_len4:
        kind = "GCC-4241N E7/HL subcode-2 len4 hardware-transfer baseline"
    else:
        kind = "GCC-4241N E7/HL subcode-2 zero-length dispatcher baseline"
    print(f"[OK] {path}: {kind}")


def main(argv: list[str]) -> int:
    if len(argv) < 2:
        print("usage: validate_gcc4241n_e7_hl_trace.py <log> [<log> ...]", file=sys.stderr)
        return 2
    for arg in argv[1:]:
        validate_one(Path(arg))
    return 0


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