Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
bba1953
perf(sv): add bounded amortized O(1) jitter ring statistics
masarray Oct 17, 2026
f7f1331
perf(sv): eliminate O(window) per-sample jitter scans and cache SCL m…
masarray Oct 17, 2026
6a15aa2
test(sv): verify bounded O(1) jitter rolling max under sustained stream
masarray Oct 17, 2026
70f7f9b
feat(sv): classify ARStack 4I4V quality without guessing arbitrary SC…
masarray Oct 17, 2026
00ef925
feat(sv): gate invalid ARStack sample quality, coalesce mapping and d…
masarray Oct 17, 2026
d465f6d
test(sv): support precise 4I4V wire quality word fixtures
masarray Oct 17, 2026
59a0d5c
test(sv): reject invalid 4I4V quality, recover coherently and label t…
masarray Oct 17, 2026
01625bf
perf(snapshot): reuse a single coherent SV window across waveform and…
masarray Oct 17, 2026
1b991b7
feat(ptp): bound and isolate passive source/domain evidence with trut…
masarray Oct 17, 2026
f6f53fa
test(ptp): isolate interleaved domain sources and expire stale Announ…
masarray Oct 17, 2026
c5bba17
fix(ptp): preserve transportSpecific and avoid unsupported profile cl…
masarray Oct 17, 2026
17166c9
fix(ptp): strictly validate PTPv2 lengths/version before accepting so…
masarray Oct 17, 2026
634a590
test(ptp): reject truncated Announce and preserve transportSpecific
masarray Oct 17, 2026
1dc91b9
perf(sv): stack-local 4I4V channel projection and change-driven mappi…
masarray Oct 17, 2026
dba8c4e
fix(test): compare nullable PTP domain using precise byte type
masarray Oct 17, 2026
c583d07
perf(sv): remove unused per-channel counter dictionary and 1024-eleme…
masarray Oct 17, 2026
a2ad81f
fix(sv): distinguish multi-ASDU frame rate from samples and suppress …
masarray Oct 17, 2026
798a533
test(sv): preserve multi-ASDU continuity without false per-sample arr…
masarray Oct 17, 2026
08303a8
perf(ui): coalesce SCL joins and show stale PTP sources without misle…
masarray Oct 17, 2026
4080764
perf(capture): prevent hot idle spin on immediate-mode empty Npcap reads
masarray Oct 17, 2026
47ff03d
perf(memory): bound SV stream state with safe stale-only eviction and…
masarray Oct 17, 2026
9f2beb3
test(memory): cap synthetic SV identity churn and preserve operator s…
masarray Oct 17, 2026
0111781
fix(sv): never treat ASDU smpRate as authoritative smpCnt modulus
masarray Oct 17, 2026
96bc891
test(sv): allow explicit smpRate/smpMod fixtures independent of count…
masarray Oct 17, 2026
1ea1323
test(sv): reject naive samples-per-period counter modulus inference
masarray Oct 17, 2026
fc4f696
docs: record M1/M2 invariants, tested software scope and outstanding …
masarray Oct 17, 2026
2d5fc8e
fix(sv): treat unknown quality bits as untrusted, preserving explicit…
masarray Oct 17, 2026
10c5be1
test(sv): fail closed for substituted and reserved unknown quality bits
masarray Oct 17, 2026
4892f00
feat(m3): compare complete engineering frame values to suppress redun…
masarray Oct 17, 2026
a55bf07
feat(m3): coalesce waveform and phasor UI publication and reuse per-s…
masarray Oct 17, 2026
167f150
test(m3): suppress duplicate frames but preserve tiny transients, qua…
masarray Oct 17, 2026
59c7274
refactor(m3): remove dead interpolation/render-loop engine; draw only…
masarray Oct 17, 2026
7569eaf
feat(m3): one calm context-aware capture summary without conflating P…
masarray Oct 17, 2026
160b241
feat(m3): collapse five duplicate status chips into one operator-cent…
masarray Oct 17, 2026
bc0d733
perf(ptp): use fixed-space rate buckets instead of unbounded per-mess…
masarray Oct 17, 2026
9b23088
feat(ptp): source-scoped two-step correlation and constant-memory rat…
masarray Oct 17, 2026
25f1089
test(ptp): burst rates, out-of-order timestamps and source-locked two…
masarray Oct 17, 2026
85b2f33
feat(m2): expose bounded on-demand Npcap driver-drop counters without…
masarray Oct 17, 2026
03f50cc
feat(m2): separate NIC capture-drop evidence from SV sequence-loss di…
masarray Oct 17, 2026
8354f36
feat(m2): sample Npcap drop statistics at 1 Hz and publish separate t…
masarray Oct 17, 2026
89c09e2
perf(m3): throttle diagnostic navigator and managed-memory polling; e…
masarray Oct 17, 2026
66529ff
feat(m3): put driver-drop evidence in Diagnostics/Advanced panels rat…
masarray Oct 17, 2026
8ffc1b6
feat(m1/m3): label ARStack diagnostic mirror explicitly and never imp…
masarray Oct 17, 2026
111c63f
test(interop): explicitly distinguish ARStack canonical multicast fro…
masarray Oct 17, 2026
7aba62d
perf(m2/m3): persistent bounded event dedup indexes and O(1) stream r…
masarray Oct 17, 2026
3d85e3a
test(m2/m3): persistent dedup buffers, stream-row identity and reset …
masarray Oct 17, 2026
cdc8d32
perf(m3): stop redundant selected-stream and capture-state notificati…
masarray Oct 17, 2026
dcd558f
feat(m3): compact engineering tables and enable WPF row recycling/vir…
masarray Oct 17, 2026
0d5008e
feat(m3): concise contextual footer prioritizes mirror warning, inval…
masarray Oct 17, 2026
df09310
feat(m1): surface PTP two-step sequence correlation as passive eviden…
masarray Oct 17, 2026
68d30f4
feat(m1): surface PTP two-step sequence correlation as passive eviden…
masarray Oct 17, 2026
26cf5f6
feat(m3): expose concise passive PTP sequence-pair evidence in timing…
masarray Oct 17, 2026
abe33f3
feat(m3): show compact PTP two-step pairing evidence only on Timing w…
masarray Oct 17, 2026
0db133d
docs(m3): record operator workflow, correctness gates and honest phys…
masarray Oct 17, 2026
75afba1
perf(m2/m3): prune orphaned per-stream waveform/phasor workspace cach…
masarray Oct 17, 2026
044a6e0
fix(m1): reject truncated, fragmented and invalid UDP/IP PTP length e…
masarray Oct 17, 2026
68b67ca
test(m1): IPv4/IPv6 PTP rejects malformed UDP lengths, fragmentation …
masarray Oct 17, 2026
31d2a57
fix(m3): remove duplicate WPF CanContentScroll attribute found by CI …
masarray Oct 17, 2026
3501462
fix(m1): remove unreachable UDP parser rejection exposed by IPv4/IPv6…
masarray Oct 17, 2026
bd101a9
fix(m1): reject truncated SV/GOOSE APDU length rather than silently t…
masarray Oct 17, 2026
7552ca5
test(m4): require strict SV/GOOSE length boundaries for trusted wire …
masarray Oct 17, 2026
b333171
feat(m4): bounded PCAP wire-fingerprint and SCL-vs-observed acceptanc…
masarray Oct 17, 2026
8494d51
fix(m4): recognize SCL four-hex-digit VLAN IDs and permit bounded 60-…
masarray Oct 17, 2026
e87fe3d
test(m4): synthetic mixed canonical VLAN SV, separate broadcast mirro…
masarray Oct 17, 2026
4f2985c
feat(m4): provide local read-only PCAP+SCL interop screening CLI for …
masarray Oct 17, 2026
168c82b
feat(m4): provide local read-only PCAP+SCL interop screening CLI for …
masarray Oct 17, 2026
e74d4e5
build(m4): include read-only interop CLI in Windows .NET solution CI
masarray Oct 17, 2026
3255c94
feat(m4): show measured local replay throughput and allocation withou…
masarray Oct 17, 2026
b51bea8
perf(m2): bound GOOSE publisher state and retire evicted SV scale/map…
masarray Oct 17, 2026
f5daae2
test(m2): preserve bounded GOOSE memory under publisher identity churn
masarray Oct 17, 2026
7200a94
docs(m4): reproducible PCAP+SCL checker and independent 60-minute wir…
masarray Oct 17, 2026
9e7830d
perf(m2): format MAC addresses without two per-frame byte-array alloc…
masarray Oct 17, 2026
d4dcd94
test(m2): verify no-allocation MAC formatting preserves exact 48-bit …
masarray Oct 17, 2026
fa53169
feat(m4): local bounded process CPU/memory sampling during sustained …
masarray Oct 17, 2026
b796ba4
docs(m4): include local 60-minute CPU/memory capture command beside w…
masarray Oct 17, 2026
545bd1b
feat(m4): add one-click background PCAP+SCL wire screening to Validat…
masarray Oct 17, 2026
13a0337
feat(m4): compact one-click PCAP inspection card in WPF Validation, n…
masarray Oct 17, 2026
ad0fff3
fix(test): compare exact nullable ushort VLAN and byte PCP in M4 acce…
masarray Oct 17, 2026
35445df
test(m1): align legacy truncation test with strict fail-closed APDU l…
masarray Oct 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions ProcessBusSuite.sln
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProcessBus.Iec61850.Raw", "
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProcessBus.Tests", "tests\ProcessBus.Tests\ProcessBus.Tests.csproj", "{2F4B9C6E-7A31-4E8D-9B5A-6C1D82E4A0F7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProcessBus.InteropCli", "tools\ProcessBus.InteropCli\ProcessBus.InteropCli.csproj", "{6F21A42B-A4EE-4901-8336-05A85E40D15F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -50,6 +52,14 @@ Global
{2F4B9C6E-7A31-4E8D-9B5A-6C1D82E4A0F7}.Release|Any CPU.Build.0 = Release|Any CPU
{2F4B9C6E-7A31-4E8D-9B5A-6C1D82E4A0F7}.Release|x64.ActiveCfg = Release|x64
{2F4B9C6E-7A31-4E8D-9B5A-6C1D82E4A0F7}.Release|x64.Build.0 = Release|x64
{6F21A42B-A4EE-4901-8336-05A85E40D15F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6F21A42B-A4EE-4901-8336-05A85E40D15F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6F21A42B-A4EE-4901-8336-05A85E40D15F}.Debug|x64.ActiveCfg = Debug|x64
{6F21A42B-A4EE-4901-8336-05A85E40D15F}.Debug|x64.Build.0 = Debug|x64
{6F21A42B-A4EE-4901-8336-05A85E40D15F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6F21A42B-A4EE-4901-8336-05A85E40D15F}.Release|Any CPU.Build.0 = Release|Any CPU
{6F21A42B-A4EE-4901-8336-05A85E40D15F}.Release|x64.ActiveCfg = Release|x64
{6F21A42B-A4EE-4901-8336-05A85E40D15F}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
78 changes: 78 additions & 0 deletions docs/M1_M2_RUNTIME_HARDENING_2026-10-17.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# M1/M2 receiver hardening — 17 October 2026

Scope: Process Bus Insight / DigSubAnalyzer receive-only application. This record
describes the bounded software tranche proposed in PR #29. Physical interoperability
and timestamp accuracy require separate evidence.

## Non-negotiable IEC 61850 boundaries

- The ARStack injector's canonical SCL-derived multicast/VLAN/APPID/svID identity and
broadcast `AR_DIAG_SV1` mirror are distinct streams. A mirror observation cannot
establish canonical multicast/VLAN acceptance.
- One frame may contain multiple SV ASDUs; each ASDU contributes to sample sequence,
but the frame has only one host receive timestamp. Do not invent intra-frame jitter.
- `SmpRate/SmpMod` are sampling metadata, not universal sample-counter modulo rules.
Counter wrap conclusions remain bounded by observed and profile-supported evidence.
- The eight (INT32 instMag, UINT32 q) pairs are a 64-byte 4I+4V *profile-specific*
decoding authority. Never apply their quality interpretation to arbitrary SCL
layouts solely because the payload is 64 bytes.
- Quality with unusable validity/detail flags immediately invalidates displayed
engineering measurements; wait for a new complete coherent window before resuming.
A TEST or operator-blocked quality remains visible with its truthful context.
- PTP observations are scoped to domain/sourcePortIdentity/transport; observation
does not imply clock lock, grandmaster traceability, power-profile compliance,
or reliable software receive timing.

## Data plane and UI rules

- One dedicated capture pump preserves input ordering. Do not introduce independent,
unordered parallel SV workers or silent lossy queues merely to increase thread count.
- Npcap owns raw frame memory only until its next API read. The source transfers
a newly allocated owned frame to the analyzer. The latest payload is retained for
debug-on-demand; indiscriminate ArrayPool return would corrupt this evidence.
- Per-ASDU projections use direct bounded INT32 reads and stack-local eight-channel
values. SCL eligibility and explanatory labels refresh when mapping/sequence state
changes, not for each SV frame.
- Rolling jitter maximum uses a bounded monotonic ring rather than scanning the
entire window for each sample. Retire the unused counter dictionary/linear scan.
- The active per-stream coherent waveform buffer is the single snapshot authority.
RMS/phasor/waveform projections of the same generation reuse that window; an
invalid quality state must invalidate prior measurements, never show stale values
as live.
- User-visible SCL comparisons may be coalesced to 500 ms, with explicit user SCL
reload forcing immediate recomputation.
- Stream history has a 256-identity guard. Reclaim only stale unselected state;
when at active capacity, report rejection rather than silently evicting a stream
currently being inspected.
- PTP source history is bounded and stale sources are labeled STALE instead of
green OBSERVED; the interface should emphasize the fault and next diagnostic
action rather than flooding raw details.

## Automated acceptance

`dotnet build ProcessBusSuite.sln -c Release` and `dotnet test
ProcessBusSuite.sln -c Release` plus repeated RuntimeStability acceptance must pass.

New regressions include:

- O(1) rolling jitter reference equivalence under a 30,000-sample run;
- invalid-quality suppression, complete coherent recovery, and TEST labeling;
- multi-ASDU continuity with a single frame timestamp and independent frame count;
- per-domain PTP source isolation and stale Announce;
- strict PTPv2 length/transportSpecific parsing;
- bounded stream identity churn and preserved selected stream;
- rejection of `SmpRate` as an unverified counter modulus.

## Evidence still required before field/product claims

1. Trusted independent canonical multicast/VLAN capture from ARStack ESP32-P4.
2. Same-run canonical SV (4000/4800 samples/s) plus Announce, Sync, Follow_Up,
Pdelay and `smpSynch` transition stimuli.
3. Npcap/adapter drop counters, host CPU/GC/memory, sustained capture throughput,
and 60+ minute bench soak with no cross-stream contamination.
4. Hardware timestamp validation for any measurement-grade jitter/offset statement.
5. Multi-vendor profile/SCL fixtures, arbitrary `nofASDU` and vendor DataSet layouts,
and receiver/IED behavior with real devices.

The software tranche avoids claiming those field results. A green CI result means
the bounded software regressions passed, not that an IED accepted the traffic.
94 changes: 94 additions & 0 deletions docs/M3_OPERATOR_WORKSPACE_AND_M1_M2_CLOSEOUT_2026-10-17.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# M3 operator workspace and M1/M2 closeout — 17 October 2026

This engineering handoff describes the implemented changes on PR #29, and
distinguishes a successful software acceptance run from hardware interoperability.

## Operating contract

Process Bus Insight remains a **receive-only** IEC 61850 SV/GOOSE/PTP analyzer.
The operator workflow is:

1. Select the physical Ethernet/Npcap adapter.
2. Press **Start** to observe traffic.
3. Choose an SV publisher in the explorer to inspect waveform, RMS, phasors,
stream identity, quality and counter continuity.
4. Read the one-line context-aware status for the current situation.
5. Open **Diagnostics** for capture-driver drops vs SV sequence evidence, and
**Timing/PTP** for passive source-specific PTP evidence.
6. Open **SCL/Validation** only to compare engineering-file expectations with
actual wire-observed identities; **Advanced** holds low-level raw evidence.

No value inferred from the diagnostic broadcast mirror is presented as proof
of canonical multicast, APPID, VLAN, PCP or SCL profile acceptance.

## M3 implementation

- Main capture-status strip displays one concise contextual message instead of
five overlapping status chips. The persistent footer is short and conditional:
it surfaces diagnostic-mirror, invalid-quality and stale-stream concerns.
- Real SV measurements are never tweened/interpolated between capture snapshots.
Dead 30 FPS composition-loop/interpolation code was removed from the waveform
control: WPF paints the latest decoded, coherent snapshot atomically.
- `LiveRenderCoalescer` compares **every numeric waveform sample** plus
series/shape/status metadata and channel RMS/angle/instant/units. It suppresses
equivalent redraw notifications while preserving tiny real transients, shape
changes, quality invalidations, stream selections and cleared values.
- Phasor lists and per-stream UI workspace objects are reused while unchanged.
Periodic SelectedStream/IsRunning re-notifications were eliminated to prevent
selection churn.
- Diagnostic navigator refresh is capped to the passive UI cadence;
managed-memory sampling runs at 1 Hz; SCL binding joins are coalesced.
- Engineering tables use recycling/row virtualization and shorter minimum row
heights. Static flow instructions were removed from the main content.
- PTP two-step sequence correlation is passive and displayed only in the Timing
workspace; there is **no** claim of measured PTP lock or UTC traceability.

## M1/M2 additional correctness/efficiency

- PTP packet-rate tracking uses fixed 5-second buckets, not an unbounded list
of packet arrival timestamps per source.
- Announce/Sync/Follow_Up evidence is isolated by source/domain/transport;
Sync+Follow_Up pairing additionally requires matching sequence and bounded
freshness. Source history and pending correlators have hard capacity limits.
- Diagnostic/event collection indexes persist across UI refreshes, and remain
bounded at 200 visible rows; reset removes both rows and indexes.
- Stable SV explorer rows are retained rather than replaced on every update.
- Npcap native drop statistics are polled at 1 Hz off the capture hot path.
Driver drop counters are displayed as **capture-path evidence**, and are never
folded into IEC 61850 sample-counter packet-loss inferences.
- Full IEEE 61850 profile compliance, PTP servo discipline, calibrated host
jitter, and physical IED subscription are not asserted here.

## Automated regression gates

Windows .NET 8 full build and complete xUnit suite must pass together with
repeated RuntimeStability, CodeQL, and Dependency Security Review workflows on
the **same final commit**.

New coverage includes render-coalescing correctness, multi-ASDU timing,
quality invalidation/recovery, rate-window boundedness, cross-source two-step
correlation, stream catalog pressure and reset-safe UI event deduplication.
Do not merge if final-commit CI is red or incomplete.

## Physical and measured acceptance still necessary

The following must be collected on real hardware before an
**interoperable/field-ready** release claim:

- independent preserved-VLAN TAP/SPAN capture of ARStack canonical multicast
alongside the separately labeled diagnostic mirror;
- 4000/4800 SV samples/s and concurrent L2 PTP source / receiving profile;
- verified observed APPID, VLAN, MAC, confRev, svID, quality, smpCnt rollover,
two-step matching, source expiry and smpSynch transition evidence;
- actual Npcap drop counters, process CPU, allocation rate, Gen0/Gen1/Gen2 GC,
heap/working set, UI frame responsiveness during sustained mixed traffic;
- 60+ minute hardware soak and multi-vendor IED capture/acceptance matrix.

**Receiver-worker decision:** maintain one ordered dedicated capture worker until
independent profiling demonstrates its insufficiency. Unbounded independent
workers or lossy frame queues would violate sample continuity. A multi-worker
dispatcher requires bounded queues, source-preserving ordering and explicit
drop accounting and remains a future measured-design gate, not a hidden
"optimization" in this PR.

The software milestone can be reviewed independently of that bench evidence.
146 changes: 146 additions & 0 deletions docs/M4_ARSTACK_INTEROP_ACCEPTANCE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# M4 — ARStack Injector ↔ DigSubAnalyzer interoperability acceptance

Date: 17 October 2026
Repositories: `masarray/DigSubAnalyzer` (consumer, **receive-only**) and
`masarray/arstack61850` (ESP32-P4 SMV Injector).

## Three different evidence levels

1. **Software replay gate (automated):** anonymous synthetic PCAPs and SCL-intent
fixtures exercise the **same production parser** used by live reception.
This demonstrates decoder behavior but not a physical process bus.
2. **Independent observed-wire gate (operator bench):** capture on an independent
TAP or correctly configured SPAN port that preserves multicast and 802.1Q
tags. Compare observed frames with the actually deployed SCL profile.
3. **Device/IED gate (external equipment):** verify subscriber/IED acquisition,
quality, synchronization and sustained operation with equipment-approved
tools. DigSubAnalyzer alone cannot certify relay subscription, functional
safety, protection action or hardware PTP synchronization.

The M4 software utility intentionally reports **WIRE_FIELDS_MATCH** instead
of “compliant”, “certified”, “locked” or “accepted by IED”.

## Run the offline acceptance inspector

Windows with .NET 8 SDK installed:

```powershell
dotnet build .\ProcessBusSuite.sln -c Release
dotnet test .\ProcessBusSuite.sln -c Release --no-build --filter Category=M4Interop
dotnet run --project .\tools\ProcessBus.InteropCli -c Release -- --pcap C:\lab\arstack-canonical.pcap --scl C:\lab\current-profile.scd --max-frames 20000000 --json C:\lab\interop-report.json
```

The tool supports classic Ethernet PCAP 2.4 (microsecond/nanosecond). If the
capture application creates PCAPNG, export/copy the packet recording as
**classic PCAP** with full Ethernet headers before inspecting it.

`--scl` is optional for wire fingerprint only; mandatory for automated
expected-vs-observed verdicts. The CLI prints a short operator summary,
keeps raw details in optional local JSON, and returns:

- **0**: screening executed and no specified SCL comparison failed; **not**
certification and **not** proof of capture-path visibility. For a capture
without SCL, there are no configured fields to validate.
- **3**: observed/configured mismatch, unresolved SCL identity or expected
stream not observed; this includes **MIRROR_ONLY**.
- **2**: malformed arguments, unreadable/unsupported PCAP, or no useful
successfully decoded traffic.

Bench files, identities, MAC addresses, PCAP, JSON logs and original SCL stay
on the authorized **local machine**; do not push them to GitHub.

### Verdicts

| Verdict | Interpretation | Operator action |
| --- | --- | --- |
| `WIRE_FIELDS_MATCH` | Visible fields match configured SCL stream | Verify TAP/SPAN provenance and independent IED behavior |
| `MIRROR_ONLY` | Only ARStack diagnostic broadcast identified | Fix capture visibility; do not infer canonical multicast/VLAN |
| `NOT_OBSERVED` | Configured svID absent | Check VLAN membership, multicast filtering, SPAN/TAP and NIC |
| `CONFLICT` | APPID/MAC/VID/PCP/confRev/nofASDU differs | Inspect deployed SCL and exact wire identity; do not normalize away |
| `INCOMPLETE_INTENT` | Some observed fields match but SCL lacks authority | Load the deployed full SCL/profile; do not auto-fill defaults |
| `UNRESOLVED` | No trustworthy SCL svID | Correct/resolve engineering intent before claiming match |

Capture **VLAN absence on a Windows USB-NIC is not proof of untagged wire TX**.
A mirrored `AR_DIAG_SV1`, APPID `0x4F01`, broadcast/untagged stream is diagnostic
evidence only, always separate from the canonical SCL stream.

## Physical bench procedure

1. Record ARStack Injector firmware build/manifest, selected immutable profile,
source identity, configured DataSet order, 4I+4V payload authority, APPID,
multicast MAC, VLAN ID/PCP, confRev, nofASDU, sample cadence, smpCnt modulus
policy and intended `smpSynch`. The SCL is **configured intent**, not
automatically the deployed firmware identity.
2. Connect a trusted independent TAP or SPAN that demonstrably retains VLAN
tags, **without trusting a diagnostic mirror as a canonical substitute**.
Capture timestamp source, precision, NIC/driver version and driver drops.
3. With an ARStack `LAB_SOURCE` release-candidate profile, observe L2 PTPv2,
domain 0, Announce ~1/s, two-step Sync ~4/s, matching Follow_Up and peer
delay response **when requested**. clockClass 248 and clockAccuracy Unknown
do **not** constitute external UTC traceability; AUTO `smpSynch=0` remains
truthful for undisciplined source mode.
4. With the same capture path, observe independent canonical SV and diagnostic
mirror identities and intentionally verify **different** APPID, destination
MAC, VLAN visibility and counters. Check `nofASDU`, channel layout,
instMag/q quality and `smpCnt` continuity for the selected profile.
5. Test nominal **4000 and 4800 samples/s**, including appropriate
profile-validated counter rollover, TEST/bad-quality stimuli, stream restart
and multi-source isolation. A PCAP's host-arrival jitter is
screening only, not on-wire timestamp quality.
6. Run mixed SV/PTP for at least **60 minutes** per acceptance scenario.
A 4000 sample/s stream produces ~14.4m SV frames in 60 minutes if
`nofASDU=1`; canonical plus mirror doubles the SV frames. Ensure
`--max-frames` covers all traffic, or split recordings into explicitly
indexed windows and inspect each.
7. Record capture-driver counters alongside publisher firmware telemetry
(TX failure, missed slots and timestamp quality). A zero sequence-gap result
on the reader does **not** imply an independent NIC dropped zero frames.
8. Independently verify receiving IED/subscriber behavior. A matched stream
in DigSubAnalyzer is not proof the IED subscribed or acted on samples.

## Performance and UX acceptance

While the live analyzer displays mixed traffic, record every 5 seconds:

```powershell
.\\scripts\\measure-m4-bench.ps1 -DurationMinutes 60 -IntervalSeconds 5 -OutputPath C:\\lab\\m4-local-metrics.csv
```

This is a local process CPU/working-set sampler, **not** a substitute for
`dotnet-counters`, native Npcap driver statistics or hardware wire timestamps.


- CPU utilization and process memory/working set;
- .NET allocation rate and GC collections (`dotnet-counters` or equivalent);
- NIC driver/interface drops where supported;
- SV sample/counter anomalies, rejected frames and identity counts;
- selection-to-coherent-snapshot latency and scope redraw responsiveness.

Inspect the main workspace for these user-facing invariants:

- changing selected SV publisher never carries waveform, RMS, phasor or
engineering scaling from the previous publisher;
- TEST and invalid quality are labeled; invalid data never appears as
valid calibrated measurements;
- canonical and mirror traffic remain distinct;
- PTP observation, pairing, domain and freshness are not misrepresented as
servo LOCKED;
- the one-line status remains calm, and detailed raw evidence lives under
Timing/Diagnostics/Advanced, not in an overwhelming initial screen.

There is no synthetic CPU/heap reduction percentage quoted here. Measure
**before/after** on the same hardware/NIC/driver/traffic scenario and record
absolute values and drop counters. Without such measurements, resource
optimization is implementation-level, not performance-certified.

## Release gate and signed-off evidence

The engineering reviewer should retain, locally or in an authorized evidence
store: sanitizer-approved capture checksum, SCL version, firmware manifest,
analyzer commit/build, report JSON, port/TAP diagram and VLAN settings,
NIC/drop counters, 60-minute performance measurements and IED independent
results. Publish only sanitized summaries.

M4 cannot be called **physically complete** without this independently
collected evidence. The automated replay suite is suitable for a software
checkpoint and for detecting compatibility regressions.
Loading
Loading