Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
76 changes: 76 additions & 0 deletions docs/PHYSICAL_BENCH_QUICK_START.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Physical test quick start — DigSubAnalyzer / Process Bus Insight

This folder is included in the **Windows x64 release candidate ZIP** so the bench
does not need a .NET SDK. Run only on an authorized, isolated engineering process
bus. The analyzer is **receive-only** and cannot operate or protect an IED.

## 1. Run the desktop application

1. Extract the entire ZIP, not just the EXE, to a local folder.
2. Install Npcap separately with appropriate raw Ethernet capture rights.
3. Run `ProcessBusInsight.exe` in the package root.
4. Select the verified adapter connected to an independent TAP/SPAN (preserve
802.1Q tags and multicast). Start capture and select the **canonical** SV
stream, not the diagnostic mirror.
5. Load the actual deployed `.scd`/`.cid`/`.iid` via the SCL workflow.
6. In **Validation → Inspect PCAP**, select a local classic Ethernet PCAP
recording. Read the short verdict; detailed evidence is in the report from
the CLI below. For large captures progress/Cancel are supported.

If canonical VLAN multicast traffic is not visible but `AR_DIAG_SV1` is,
the result is **mirror-only**. This does not prove the injector dropped VLAN
or ignored SCL; verify TAP/SPAN and NIC filtering. PTP messages observed on
the NIC do **not** establish clock discipline or lock.

## 2. Screen the same wire recording with the bundled CLI

Open PowerShell in the extracted package directory. Replace file paths with
files collected on your **own local bench**:

```powershell
.\Bench\ProcessBus.InteropCli.exe --help
.\Bench\ProcessBus.InteropCli.exe --pcap "C:\lab\sv-ptp.pcap" --scl "C:\lab\deployed.scd" --max-frames 50000000 --json "C:\lab\interop-report.json"
```

The bundled CLI is a **self-contained Windows executable**. It parses classic
Ethernet PCAP, not PCAPNG. Convert PCAPNG to classic PCAP locally without
losing Ethernet/VLAN headers if necessary. A full 60-minute recording with
both canonical SV and a mirror may exceed 28 million SV packets alone
(at 4000 samples/s and nofASDU=1). Use the explicit frame limit or split
the PCAP into indexed windows; **CAPTURE_INCOMPLETE** must not be recorded as
a clean acceptance.

Exit codes: **0** screening completed with no failing configured comparison
(not IED conformance); **3** missing/ambiguous/conflicting/incomplete evidence;
**2** invalid or unsupported input. For a trustworthy SCL comparison always
supply `--scl`. The local JSON contains wire MAC and IED identities; do
**not** upload it or raw SCL/PCAP to a public issue.

## 3. Measure application load and physical truth separately

While the desktop app receives simultaneous 4000/4800-profile SV, diagnostic
mirror and L2 PTP, record local process metrics:

```powershell
.\Bench\measure-m4-bench.ps1 -DurationMinutes 60 -IntervalSeconds 5 -ProcessName ProcessBusInsight -OutputPath "C:\lab\m4-process-metrics.csv"
```

If PowerShell blocks scripts, follow your organization's signed-script policy;
do not turn off system-wide execution protection for this task. Collect
Npcap capture-driver/interface drops and ARStack device TX failure/missed-slot
telemetry separately; a zero `smpCnt` gap count does not prove zero wire loss.

Before any **physical acceptance** claim, independently verify:

- Canonical APPID/MAC/VLAN/PCP/svID/confRev/nofASDU/layout and 4000/4800
cadence with the actual deployed SCL and applicable counter policy;
- `AR_DIAG_SV1` (broadcast, APPID 0x4F01) remains a separate debug stream;
- PTP Announce/Sync/Follow_Up/peer-delay and sync flags remain observed facts,
not unmeasured lock or precision claims;
- 60-minute concurrent stability, driver drops, resource behavior and IED
subscriber acceptance with qualified bench equipment.

The detailed step-by-step sign-off matrix is in
`Bench/M4_ARSTACK_INTEROP_ACCEPTANCE.md`. Record the candidate artifact run
ID and checksums with your evidence. This candidate is not a stable/certified
release and provides no switching, control or protection-action authority.
31 changes: 31 additions & 0 deletions scripts/publish-windows-portable.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,33 @@ if ($singleFile) {
Copy-Item (Join-Path $publishDir "*") $appStageDir -Recurse -Force
}

# Physical acceptance needs a reproducible capture-vs-SCL inspector, not only
# a Windows UI EXE. Publish the existing read-only CLI self-contained into a
# separate tools folder; never stage raw PCAP/SCL or customer identities.
$interopProject = Join-Path $repoRoot "tools/ProcessBus.InteropCli/ProcessBus.InteropCli.csproj"
$interopPublishDir = Join-Path $repoRoot "$OutputRoot/publish/$portableName/interop-cli"
Comment on lines +87 to +88

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Trigger candidate packaging for bundled CLI changes

Now that the release artifact is built from tools/ProcessBus.InteropCli, a PR changing only that project will not trigger .github/workflows/candidate-package.yml: its pull_request.paths list includes src/** and tests/** but not tools/**. Such changes receive the ordinary compile/test job but skip the self-contained publish and packaged --help smoke test added here, so a candidate can be merged without exercising the new artifact path; add the bundled tool path (and the other newly copied bench inputs) to that workflow's triggers.

Useful? React with 👍 / 👎.

$interopStageDir = Join-Path $stageDir "Bench"
New-Item -ItemType Directory -Path $interopStageDir -Force | Out-Null
dotnet restore $interopProject -r $Runtime /p:ContinuousIntegrationBuild=true
if ($LASTEXITCODE -ne 0) { throw "Interop CLI runtime-specific restore failed." }
$interopPublishArgs = @(
"publish", $interopProject, "--no-restore", "-c", $Configuration,
"-r", $Runtime, "-o", $interopPublishDir,
"/p:Version=$Version", "/p:VersionPrefix=$versionPrefix", "/p:VersionSuffix=$versionSuffix",
"/p:PublishSingleFile=true", "/p:IncludeNativeLibrariesForSelfExtract=true",
"/p:EnableCompressionInSingleFile=true", "/p:PublishTrimmed=false",
"/p:DebugType=None", "/p:DebugSymbols=false",
"/p:ErrorOnDuplicatePublishOutputFiles=true", "--self-contained", "true"
)
dotnet @interopPublishArgs
if ($LASTEXITCODE -ne 0) { throw "Interop CLI publish failed." }
$interopExe = Join-Path $interopPublishDir "ProcessBus.InteropCli.exe"
if (-not (Test-Path $interopExe)) { throw "Interop CLI publish produced no executable." }
Copy-Item $interopExe (Join-Path $interopStageDir "ProcessBus.InteropCli.exe") -Force
Copy-Item (Join-Path $repoRoot "docs/M4_ARSTACK_INTEROP_ACCEPTANCE.md") (Join-Path $interopStageDir "M4_ARSTACK_INTEROP_ACCEPTANCE.md") -Force
Copy-Item (Join-Path $repoRoot "scripts/measure-m4-bench.ps1") (Join-Path $interopStageDir "measure-m4-bench.ps1") -Force
Comment on lines +107 to +108

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Make the bundled measurement command usable

When an operator follows the copied Bench/M4_ARSTACK_INTEROP_ACCEPTANCE.md, its performance command targets .\scripts\measure-m4-bench.ps1, but the package stages the script under Bench; even after correcting that path manually, the command omits -ProcessName, so the script defaults to ProcessBus.App.Wpf while the packaged executable runs as ProcessBusInsight. The documented 60-minute run therefore either fails immediately or records only missing-process rows, so update the packaged runbook and/or the script default.

Useful? React with 👍 / 👎.

Copy-Item (Join-Path $repoRoot "docs/PHYSICAL_BENCH_QUICK_START.md") (Join-Path $interopStageDir "START_HERE.md") -Force

$packageReadme = @"
Process Bus Insight / DigSubAnalyzer
Windows portable package
Expand All @@ -91,6 +118,10 @@ Community license: GPL-3.0-or-later
2. Extract this ZIP to a local folder.
3. Run $AppName.exe.
4. Use an authorized TAP, mirror port, or isolated engineering test network.
5. For physical SV/PTP test evidence read Bench/START_HERE.md.
6. Bench/ProcessBus.InteropCli.exe works offline and does not need the .NET SDK.
7. Bench/measure-m4-bench.ps1 records local process CPU/memory during a bench run.
A diagnostic broadcast mirror does NOT prove the canonical VLAN SV path.

Included legal documents:
LICENSE.txt, NOTICE.txt, COMMERCIAL-LICENSE.md, COPYRIGHT.md, TRADEMARK.md,
Expand Down
24 changes: 23 additions & 1 deletion scripts/verify-release-package.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ try {
"COPYRIGHT.md",
"TRADEMARK.md",
"THIRD_PARTY_NOTICES.md",
"Licensing.md"
"Licensing.md",
"Bench/ProcessBus.InteropCli.exe",
"Bench/M4_ARSTACK_INTEROP_ACCEPTANCE.md",
"Bench/START_HERE.md",
"Bench/measure-m4-bench.ps1"
)
foreach ($relative in $required) {
if (-not (Test-Path (Join-Path $temp $relative))) {
Expand Down Expand Up @@ -68,6 +72,24 @@ try {
throw "Package verification failed. Expected exactly one root EXE: $AppName.exe. Found: $names"
}

# The GUI remains the only ROOT executable. A separate, self-contained
# read-only inspector is required so field users can screen their actual
# PCAP+SCL evidence without installing the developer SDK.
$interopExe = Join-Path $temp "Bench/ProcessBus.InteropCli.exe"
if ((Get-Item $interopExe).Length -lt 1024) {
throw "Package verification failed. The interop CLI executable is too small."
}
$interopHelp = & $interopExe --help 2>&1 | Out-String
if ($LASTEXITCODE -ne 0 -or $interopHelp -notmatch 'offline interop screening') {
throw "Package verification failed. Bundled offline interop CLI cannot run --help."
}
$benchGuide = Get-Content (Join-Path $temp "Bench/START_HERE.md") -Raw
foreach ($marker in @('ProcessBus.InteropCli.exe', '60-minute', 'TAP/SPAN', 'AR_DIAG_SV1')) {
if ($benchGuide -notmatch [regex]::Escape($marker)) {
throw "Package verification failed. Physical bench quickstart is missing: $marker"
}
}

$size = (Get-Item (Join-Path $temp "$AppName.exe")).Length
if ($size -lt 1024) { throw "Package verification failed. Executable looks too small: $size bytes" }

Expand Down
Loading