"""Decide whether native event-send (HCAL R2.1) rides WCF or the storage-engine pipe. Reads the both-hooks capture produced by scripts/Capture-EventSend.ps1 and, for every outgoing WCF.WriteMessage.Body, tries to recognise the SOAP action / operation name. It then renders a verdict: * If a storage/event delivery op (AddStreamValues / EnqueueEventDataPacket / OpenEventConnection / StartStorage / AddS2 / AddStreamValues2) appears on the WRITE path, event-send is a WCF op → M2 is implementable over WCF and that body carries the PackToVtq event value blob to decode (R2.2). * If NO such op appears on the WRITE path, the queued event was delivered via the storage-engine shared-memory pipe (not WCF) — M2 is architecturally blocked as a pure-managed-WCF SDK, the same conclusion as the revision-write path. Output is diagnostic. Sanitize before copying into docs/. """ import base64 import json import sys from pathlib import Path REPO_ROOT = Path(__file__).resolve().parent.parent CAPTURE = (REPO_ROOT / "artifacts" / "reverse-engineering" / "instrumented-wcf-event-send" / "event-send-capture-latest.ndjson") # Operation-name markers we care about. The MDAS binary SOAP body carries the action / # operation name as readable text (ASCII and/or UTF-16LE). We scan for both encodings. EVENT_OR_STORAGE_OPS = [ "AddStreamValues2", "AddStreamValues", "EnqueueEventDataPacket", "OpenEventConnection2", "OpenEventConnection", "StartStorage", "AddS2", "ForwardEventSnapshot", "AddStreamedValue", "AddNonStreamValues", ] # Other ops we expect to see on a healthy event-send connection (auth/open/registration), # printed for context so a "no event op" result is clearly "delivery left WCF", not "nothing ran". KNOWN_OPS = [ "GetV", "ValCl", "Open2", "OpenConnection", "GETHI", "GetSystemParameter", "UpdC3", "UpdateClientStatus3", "RTag2", "RegisterTags2", "EnsT2", "EnsureTags2", "IsOriginalAllowed", "StartQuery", "GetInterfaceVersion", ] def find_ops(body, candidates): hits = [] for op in candidates: a = op.encode("ascii") u = op.encode("utf-16-le") if a in body or u in body: hits.append(op) return hits def main() -> int: if not CAPTURE.exists(): print(f"Capture not found: {CAPTURE}") print("Run: scripts/Capture-EventSend.ps1") return 1 with CAPTURE.open(encoding="utf-8-sig") as fh: records = [json.loads(line) for line in fh if line.strip()] writes = [r for r in records if r.get("Phase") == "WCF.WriteMessage.Body"] reads = [r for r in records if r.get("Phase") == "WCF.ReadMessage.Body"] print(f"Records: {len(records)} (write={len(writes)} read={len(reads)})\n") event_write_hits = [] print("== Outgoing WCF.WriteMessage.Body ops ==") for i, r in enumerate(writes): body = base64.b64decode(r["Base64"]) known = find_ops(body, KNOWN_OPS) event = find_ops(body, EVENT_OR_STORAGE_OPS) if event: event_write_hits.extend(event) label = ", ".join(event + known) or "" flag = " <<< EVENT/STORAGE OP" if event else "" print(f" write[{i:02d}] {len(body):6d}B {label}{flag}") print("\n== Verdict ==") if event_write_hits: uniq = sorted(set(event_write_hits)) print(f" EVENT/STORAGE op(s) on the WCF WRITE path: {uniq}") print(" => event-send IS a WCF op. M2 viable over WCF; decode the PackToVtq value") print(" blob in that body for R2.2.") return 0 print(" NO event/storage delivery op on the WCF WRITE path.") print(" => the queued event did NOT leave via WCF. If the native AddStreamedValue") print(" returned success (see harness JSON), delivery used the storage-engine") print(" shared-memory pipe — M2 is blocked as a pure-managed-WCF SDK, same as the") print(" revision-write path (docs/plans/revision-write-path.md).") return 0 if __name__ == "__main__": sys.exit(main())