From 9982938b0b7d3f5fd792b31a0b92d400f21056e7 Mon Sep 17 00:00:00 2001 From: serversdown Date: Sun, 6 Sep 2026 07:48:54 +0000 Subject: [PATCH] fix(offset): read the real serial from the file body, not "BE" + the number MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The BW filename encodes only the serial NUMBER — `<3 digits>` where letter = chr(ord('B') + serial // 1000), so `L895…` decodes to 10895. The two-letter family prefix is not in the filename at all, and every offset scanner synthesized it as f"BE{num}". Four of the 43 archive units are BA, not BE. Their binaries say so plainly: BA9229, BA10060, BA10895, BA15957. Brian caught BA10895 by recognising that no such unit as BE10895 exists. serial_of() now reads the serial string out of the file body and falls back to the old synthesis only when no matching string is found. No analysis changes: grouping was by the numeric part, which was always correct, and no unit number maps to more than one serial (checked across all 43). The same assumption is live in two production sites and is NOT touched here, because fixing ingest renames rows a running store and Terra-View already reads them: - sfm/waveform_store.py:870 `return f"BE{serial_num}"` on import - minimateplus/client.py:2538 `raw_data.find(b"BE")` in the monitor-log partial-record decode, which yields serial=None on a BA unit Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01HgTe8CamXAHcAmaQ6QNcog --- scratch/offset_hist_scan.py | 27 +++++++++++++++++++++++---- scratch/offset_scan3.py | 30 ++++++++++++++++++++++++++---- 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/scratch/offset_hist_scan.py b/scratch/offset_hist_scan.py index 1a2b9a1..a43a097 100644 --- a/scratch/offset_hist_scan.py +++ b/scratch/offset_hist_scan.py @@ -62,12 +62,31 @@ _STEM = re.compile(r"^([B-Z])(\d{3})") _B36 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" -def serial_of(name: str) -> str: - """`P036L318.C80H` -> `BE14036`. See CLAUDE.md, serial encoding.""" +_SERIAL_RE = re.compile(rb"\b([A-Z]{2}\d{3,6})\b") + + +def serial_of(name: str, path=None) -> str: + """Real serial for a BW file. + + The filename encodes only the NUMBER: `<3 digits>` where + letter = chr(ord('B') + serial // 1000). The two-letter family prefix + ("BE", "BA", ...) is **not** in the filename, so it must be read out of + the file body. Four units in the DL2 archive are BA, not BE — assuming + "BE" mislabels BA9229, BA10060, BA10895 and BA15957. + """ m = _STEM.match(name) if not m: return "?" - return f"BE{(ord(m.group(1)) - ord('B')) * 1000 + int(m.group(2))}" + num = (ord(m.group(1)) - ord("B")) * 1000 + int(m.group(2)) + if path is not None: + try: + for s in _SERIAL_RE.findall(Path(path).read_bytes()): + s = s.decode() + if s[2:].lstrip("0") == str(num): + return s + except Exception: + pass + return f"BE{num}" # last-resort fallback; prefix unverified def stem_time(name: str): @@ -141,7 +160,7 @@ def scan(path_str: str): for ch, st in stats.items(): others = [stats[o]["p5"] for o in stats if o != ch] rows.append({ - "serial": serial_of(p.name), + "serial": serial_of(p.name, p), "timestamp": stamp, "filename": p.name, "channel": ch, diff --git a/scratch/offset_scan3.py b/scratch/offset_scan3.py index 2c2b953..3a3cde6 100644 --- a/scratch/offset_scan3.py +++ b/scratch/offset_scan3.py @@ -28,9 +28,31 @@ from minimateplus.event_file_io import read_blastware_file GEO=("Tran","Vert","Long"); K=10.0/32000.0 _WAVE=re.compile(r"\.[A-Za-z0-9]{2}0[Ww]$"); _STEM=re.compile(r"^([B-Z])(\d{3})") -def serial_of(n): - m=_STEM.match(n) - return f"BE{(ord(m.group(1))-ord('B'))*1000+int(m.group(2))}" if m else "?" +_SERIAL_RE = re.compile(rb"\b([A-Z]{2}\d{3,6})\b") + + +def serial_of(name: str, path=None) -> str: + """Real serial for a BW file. + + The filename encodes only the NUMBER: `<3 digits>` where + letter = chr(ord('B') + serial // 1000). The two-letter family prefix + ("BE", "BA", ...) is **not** in the filename, so it must be read out of + the file body. Four units in the DL2 archive are BA, not BE — assuming + "BE" mislabels BA9229, BA10060, BA10895 and BA15957. + """ + m = _STEM.match(name) + if not m: + return "?" + num = (ord(m.group(1)) - ord("B")) * 1000 + int(m.group(2)) + if path is not None: + try: + for s in _SERIAL_RE.findall(Path(path).read_bytes()): + s = s.decode() + if s[2:].lstrip("0") == str(num): + return s + except Exception: + pass + return f"BE{num}" # last-resort fallback; prefix unverified def scan(ps): p=Path(ps) @@ -48,7 +70,7 @@ def scan(ps): mid, end = a[t:2*t], a[2*t:] if not pre or not mid or not end: continue v=[statistics.median(x)*K for x in (pre,mid,end)] - out.append({"serial":serial_of(p.name),"timestamp":stamp, + out.append({"serial":serial_of(p.name, p),"timestamp":stamp, "filename":p.name,"channel":ch, "pretrig_n": pre_n or 0, "pre":round(v[0],4),"mid":round(v[1],4),"end":round(v[2],4),