#!/usr/bin/env python3 """Export the approved S03 binary record layout to a derived CSV artifact.""" import argparse import csv import hashlib import os import struct import sys import tempfile from pathlib import Path UINT32_TYPE_HEX = "0408" SIGNAL_HEADER_BYTES = 38 EXPECTED_SIGNALS = ( ("Counter", 1), ("Time", 1), ("State1_Thread1_CycleTime", 1), ("SentinelScalarA", 1), ("SentinelScalarB", 1), ("SentinelVector", 3), ) EXPECTED_HEADER_BYTES = 4 + len(EXPECTED_SIGNALS) * SIGNAL_HEADER_BYTES EXPECTED_RECORD_BYTES = 32 CSV_COLUMNS = ( "Counter", "Time", "CycleTime", "SentinelScalarA", "SentinelScalarB", "SentinelVector0", "SentinelVector1", "SentinelVector2", ) class ExportError(Exception): """A fail-closed binary or publication error.""" def decode_name(raw): try: return raw.split(b"\x00", 1)[0].decode("ascii") except UnicodeDecodeError as exc: raise ExportError("NON_ASCII_SIGNAL_NAME") from exc def read_records(binary_path): try: data = binary_path.read_bytes() except OSError as exc: raise ExportError(f"BINARY_READ_FAILED:{exc}") from exc if len(data) < EXPECTED_HEADER_BYTES: raise ExportError( f"HEADER_TOO_SMALL:EXPECTED_{EXPECTED_HEADER_BYTES}:OBSERVED_{len(data)}" ) signal_count = struct.unpack_from("