Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
143 commits
Select commit Hold shift + click to select a range
3f662fb
Add deterministic viewport-aware phasor label layout
masarray Oct 19, 2026
d2e11cc
Redraw phasors from SSOT with collision-safe labels and low-allocatio…
masarray Oct 19, 2026
c031901
Coalesce phasor redraws by RMS and angle, not instantaneous sample
masarray Oct 19, 2026
8e90603
Remove UI phase-reference overrides and avoid redundant phasor repaints
masarray Oct 19, 2026
86db9a6
Bind phasor freshness directly to selected stream live state
masarray Oct 19, 2026
8b36a0d
Regression-test fast phasor updates and collision-free compact label …
masarray Oct 19, 2026
35447c6
Document phasor SSOT invariants and required physical-bench validation
masarray Oct 19, 2026
31fee58
Add stable Inno Setup 6 Windows installer with offline manuals and up…
masarray Oct 19, 2026
22a5cb1
Compile verified portable stage into reproducible Inno installer arti…
masarray Oct 19, 2026
0082e7a
Separate numeric Windows version resource from friendly prerelease ve…
masarray Oct 19, 2026
f52c624
Add Windows installer install-repair-uninstall smoke test and PDF has…
masarray Oct 19, 2026
ff4466e
Make Inno installer and offline manual smoke testing primary candidat…
masarray Oct 19, 2026
16459ff
Ship signed-ready Inno EXE as primary release download alongside opti…
masarray Oct 19, 2026
633d36e
Document safe offline installation, manual updates and repair/uninsta…
masarray Oct 19, 2026
817de5a
Bundle offline installation and update guide beside user manuals in i…
masarray Oct 19, 2026
e357d2b
Bundle offline install/update guide and validate installer documentation
masarray Oct 19, 2026
3983c60
Bundle offline install/update guide and validate installer documentation
masarray Oct 19, 2026
658fe73
Bundle offline install/update guide and validate installer documentation
masarray Oct 19, 2026
b005b33
Bundle offline install/update guide and validate installer documentation
masarray Oct 19, 2026
ae0b062
Make verified Inno installer recommended Windows download with offlin…
masarray Oct 19, 2026
ccb6f8c
Resolve 64-bit Npcap and Packet DLL from trusted system location for …
masarray Oct 19, 2026
9af8470
Stop fabricating Ethernet index:0; show non-capturable Npcap diagnost…
masarray Oct 19, 2026
22127ae
Pin packet capture P/Invokes to same trusted Npcap DLL as adapter enu…
masarray Oct 19, 2026
834ff69
Disable Run without a real Npcap device and retain adapter diagnostics
masarray Oct 19, 2026
b91b49b
Disable Run without a real Npcap device and retain adapter diagnostics
masarray Oct 19, 2026
17026d8
Disable Run without a real Npcap device and retain adapter diagnostics
masarray Oct 19, 2026
2ad408f
Regression-test trusted Npcap DLL lookup and never-selectable fallback
masarray Oct 19, 2026
1939bbf
Explain native Npcap architecture mismatch and safe verified host rep…
masarray Oct 19, 2026
6e42d5c
Fix all catalog unavailable callsites and preserve actionable archite…
masarray Oct 19, 2026
fc35abb
Disable secondary Start toolbar button when Npcap is unavailable
masarray Oct 19, 2026
20fc355
Polish compact phasor with numeric independent scales, clear 270° axi…
masarray Oct 19, 2026
810f882
Keep phasor scale footer readable in narrow panels
masarray Oct 19, 2026
66c6fce
Clarify live-with-warning and uncalibrated power without clipped N/A …
masarray Oct 19, 2026
c606cd1
Clarify live-with-warning and uncalibrated power without clipped N/A …
masarray Oct 19, 2026
4e028cb
Clarify live-with-warning and uncalibrated power without clipped N/A …
masarray Oct 19, 2026
08d42e0
Regression-test live warning badges and independent current RMS/phaso…
masarray Oct 19, 2026
87f7bc0
Gate public releases on main and explicit field acceptance; never aut…
masarray Oct 19, 2026
e9af76c
Add compact finite-valued U/I RMS scale labels without rounding nonze…
masarray Oct 19, 2026
2ea90cd
Use tested engineering-scale formatter for phasor legend
masarray Oct 19, 2026
7d5e5ca
Test compact phasor U/I scale legends including tiny nonzero and miss…
masarray Oct 19, 2026
68b23d9
Align offline manuals and bench guidance with Inno installer, SSOT an…
masarray Oct 19, 2026
5ccf1e4
Align offline manuals and bench guidance with Inno installer, SSOT an…
masarray Oct 19, 2026
f13e813
Align offline manuals and bench guidance with Inno installer, SSOT an…
masarray Oct 19, 2026
d27da7e
Ship current editable offline manuals alongside PDF editions and veri…
masarray Oct 19, 2026
16dcb14
Ship current editable offline manuals alongside PDF editions and veri…
masarray Oct 19, 2026
00d28e7
Ship current editable offline manuals alongside PDF editions and veri…
masarray Oct 19, 2026
0ac06f1
Add explicit per-commit physical acceptance and automated release gat…
masarray Oct 19, 2026
b596ddb
Align public release notes, checklist and test matrix with verified I…
masarray Oct 19, 2026
d08a19c
Align public release notes, checklist and test matrix with verified I…
masarray Oct 19, 2026
87a80d8
Align public release notes, checklist and test matrix with verified I…
masarray Oct 19, 2026
dac9412
Align public release notes, checklist and test matrix with verified I…
masarray Oct 19, 2026
90e3102
Generate styled offline PDF manuals from canonical Markdown during pa…
masarray Oct 19, 2026
e4a5ab5
Manifest hashes original Markdown bytes exactly for reproducible pack…
masarray Oct 19, 2026
d88edc5
Fail closed on stale PDFs; stage SHA-linked generated manuals from Ma…
masarray Oct 19, 2026
a160d59
Generate version-synchronized offline PDF manuals before Inno and por…
masarray Oct 19, 2026
b6f05d6
Generate version-synchronized offline PDF manuals before Inno and por…
masarray Oct 19, 2026
e116ffc
Verify packaged PDF and Markdown source hashes against generated manu…
masarray Oct 19, 2026
7908c81
Make installed README accurate for both Inno Setup and optional porta…
masarray Oct 19, 2026
8700815
Document SHA-linked PDF regeneration and offline manual release guara…
masarray Oct 19, 2026
f50f843
Record release-candidate scope and require runtime architecture gate …
masarray Oct 19, 2026
036f9b9
Record release-candidate scope and require runtime architecture gate …
masarray Oct 19, 2026
3042bab
Keep phasor regression tests analyzer-clean with ordinal char prefix …
masarray Oct 19, 2026
3422d02
Prepare new v1.4.1 release documentation without overwriting publishe…
masarray Oct 19, 2026
02fbb89
Prepare new v1.4.1 release documentation without overwriting publishe…
masarray Oct 19, 2026
3c2bff3
Preserve historical release notes of already-published v1.4.0
masarray Oct 19, 2026
afcb112
Reference the historic v1.4.0 approval correctly in new v1.4.1 gate
masarray Oct 19, 2026
6d07515
Bump release candidate to 1.4.1; protect published 1.4.0 artifacts
masarray Oct 19, 2026
caaa6b0
Bump release candidate to 1.4.1; protect published 1.4.0 artifacts
masarray Oct 19, 2026
8a8eeec
Bump release candidate to 1.4.1; protect published 1.4.0 artifacts
masarray Oct 19, 2026
4c7a4f7
Bump release candidate to 1.4.1; protect published 1.4.0 artifacts
masarray Oct 19, 2026
0b58cad
Bump release candidate to 1.4.1; protect published 1.4.0 artifacts
masarray Oct 19, 2026
6a112e6
Bump release candidate to 1.4.1; protect published 1.4.0 artifacts
masarray Oct 19, 2026
9c57022
Bump release candidate to 1.4.1; protect published 1.4.0 artifacts
masarray Oct 19, 2026
d2fa86a
Bump release candidate to 1.4.1; protect published 1.4.0 artifacts
masarray Oct 19, 2026
42f2500
Retire superseded 1.4.0 candidate gate; use v1.4.1 without rewriting …
masarray Oct 19, 2026
895f844
Fail closed rather than clobber any existing published release assets
masarray Oct 19, 2026
0be874a
Fail candidate pipeline if stable package version has already been pu…
masarray Oct 19, 2026
2908235
Add exact-tip phasor callout routing with outward two-segment geometry
masarray Oct 19, 2026
7df5f7e
Stabilize near-collinear U/I label lanes without altering measured an…
masarray Oct 19, 2026
f14a60c
Connect every phasor callout to its own arrow tip with family-specifi…
masarray Oct 19, 2026
b92d53b
Reserve upper current callout lane for near-collinear U/I phasors
masarray Oct 19, 2026
2842f9e
Avoid label-order jitter near 12px bin boundaries with deterministic …
masarray Oct 19, 2026
508245f
Add phase-A exact-tip regression for long leader, collinear Ua/Ia and…
masarray Oct 19, 2026
03293d9
Fix release candidate version guard: treat expected 404 as available,…
masarray Oct 19, 2026
4c3a467
Introduce evidence-based per-channel SV freshness shared by live disp…
masarray Oct 20, 2026
d6fcd5c
Propagate channel freshness through SSOT, runtime and stable display …
masarray Oct 20, 2026
2fa7e6c
Propagate channel freshness through SSOT, runtime and stable display …
masarray Oct 20, 2026
ebfc712
Propagate channel freshness through SSOT, runtime and stable display …
masarray Oct 20, 2026
71fde35
Propagate channel freshness through SSOT, runtime and stable display …
masarray Oct 20, 2026
0e5d6bc
Propagate channel freshness through SSOT, runtime and stable display …
masarray Oct 20, 2026
b4c7e2b
Propagate channel freshness through SSOT, runtime and stable display …
masarray Oct 20, 2026
07e426f
Propagate channel freshness through SSOT, runtime and stable display …
masarray Oct 20, 2026
3c973e9
Decode known 4I+4V instMag/q trust per channel without inferring othe…
masarray Oct 20, 2026
a07f2aa
Keep trusted SV channels live while holding only invalid/incomplete i…
masarray Oct 20, 2026
6114d0b
Render waveform live/held per channel and fully mute stale publishers…
masarray Oct 20, 2026
7364cb3
Mute held phasor arrows and callouts individually while peers remain …
masarray Oct 20, 2026
cc619a5
Bind waveform stream freshness and per-channel measurement readout op…
masarray Oct 20, 2026
edb999e
Surface partial SV quality faults as amber LIVE-WARN instead of healt…
masarray Oct 20, 2026
64fa1e7
Require full valid per-channel SV window before clearing held quality…
masarray Oct 20, 2026
a86dd4d
Test single-channel invalid SV quality hold/recovery, healthy peers a…
masarray Oct 20, 2026
04d7bb0
Count first mapped SV frame in quality recovery window; restore exact…
masarray Oct 20, 2026
3c93c62
Use authoritative SCL instMag/q slot for per-channel freshness when c…
masarray Oct 20, 2026
9631074
Create shared compact workspace spacing tokens and unify primary pane…
masarray Oct 20, 2026
7808983
Unify workspace panel gutters and card spacing across Analyzer, Diagn…
masarray Oct 20, 2026
af5f194
Align GOOSE and SCL horizontal gutters with 16-DIP workspace standard
masarray Oct 20, 2026
c08daec
Add enforceable five-workspace WPF spacing and panel inset regression…
masarray Oct 20, 2026
be29f63
Require standardized WPF layout geometry before CI, Inno candidate an…
masarray Oct 20, 2026
9252360
Require standardized WPF layout geometry before CI, Inno candidate an…
masarray Oct 20, 2026
0083498
Require standardized WPF layout geometry before CI, Inno candidate an…
masarray Oct 20, 2026
de94ba8
Fix real WPF Grid gutters: 8 DIP horizontal/vertical, align explorer …
masarray Oct 20, 2026
b44b07e
Apply uniform compact 8-DIP outer panel spacing across all five works…
masarray Oct 20, 2026
eaf342d
Apply uniform compact 8-DIP outer panel spacing across all five works…
masarray Oct 20, 2026
716bfe7
Normalize nine diagnostic evidence-card sibling gutters to the shared…
masarray Oct 20, 2026
c57e4f2
Enforce actual root Grid panel-bottom alignment and consistent diagno…
masarray Oct 20, 2026
de78c50
Stamp installer payload with exact commit, run and EXE hash to identi…
masarray Oct 20, 2026
bc02228
Replace misleading hardcoded About version with actual build and exec…
masarray Oct 20, 2026
dd698ab
Show actual installed assembly version, commit and EXE path in About …
masarray Oct 20, 2026
a6b6a60
Refuse installer/ZIP with mismatched build provenance; verify EXE has…
masarray Oct 20, 2026
6b8a773
Refuse installer/ZIP with mismatched build provenance; verify EXE has…
masarray Oct 20, 2026
30f01c4
Repair source-provenance validation syntax and verify packaged EXE hash
masarray Oct 20, 2026
1ad3044
Repair installer smoke provenance validator and fail on EXE/manifest …
masarray Oct 20, 2026
f4c46bf
Fix provenance packaging PowerShell parse error caused by source hash…
masarray Oct 20, 2026
b3a2145
Remove accidental duplicate PowerShell tail from packaging provenance…
masarray Oct 20, 2026
c2e3dc1
Remove duplicated release verifier suffix and retain sole provenance/…
masarray Oct 20, 2026
03fc365
Remove accidental duplicate installer smoke validator tail
masarray Oct 20, 2026
fc2d952
Add bounded source-faithful diagnostic event presentation aggregation
masarray Oct 20, 2026
9ea443e
Add non-destructive grouped-event occurrence metadata for calm diagno…
masarray Oct 20, 2026
f658615
Bind diagnostics to bounded event summaries, retain raw evidence as SSOT
masarray Oct 20, 2026
d8a7a4f
Polish engineering readouts and bound diagnostic event counts with fu…
masarray Oct 20, 2026
afa4fd3
Make GOOSE empty states accurate for zero publishers vs no matching f…
masarray Oct 20, 2026
0ff6718
Remove pulsing live-dot noise; distinguish RX from quality warnings a…
masarray Oct 20, 2026
45109bc
Regress exact-event grouping, forensic preservation and bounded diagn…
masarray Oct 20, 2026
0ff80a9
Reconcile grouped diagnostic rows incrementally to avoid live ListVie…
masarray Oct 20, 2026
33b5629
Fix clipped U/I scale controls without adding toolbar rows or enlargi…
masarray Oct 20, 2026
59d998a
Record immutable pre-polish SHA and scoped engineering-UX acceptance …
masarray Oct 20, 2026
754ec5d
Avoid labeling inferred smpCnt gaps as confirmed Ethernet packet loss
masarray Oct 20, 2026
39c74c7
Group recognized periodic SV jitter reports by severity and svID, not…
masarray Oct 20, 2026
7213efe
Distinguish periodic diagnostic report counts from raw SV excursion o…
masarray Oct 20, 2026
ee161e1
Keep incremental diagnostic row reconciliation consistent with semant…
masarray Oct 20, 2026
297bb98
Only coalesce periodic SV reports with explicit stream identity; fail…
masarray Oct 20, 2026
7b85c0e
Add positive/negative regression for volatile periodic SV reports, di…
masarray Oct 20, 2026
da797ac
Improve readable SCL identifiers and power figures without changing p…
masarray Oct 20, 2026
93af541
Fix periodic report flag for exact-title plain messages; preserve exi…
masarray Oct 20, 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
73 changes: 70 additions & 3 deletions .github/workflows/candidate-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,17 @@ on:
- "src/**"
- "tests/**"
- "scripts/publish-windows-portable.ps1"
- "scripts/publish-windows-installer.ps1"
- "scripts/render-offline-manuals.py"
- "docs/USER_MANUAL.md"
- "docs/QUICK_START.md"
- "docs/INSTALLATION_AND_UPDATE.md"
- "docs/RELEASE_PACKAGING.md"
- "scripts/verify-windows-installer.ps1"
- "installer/**"
- "scripts/verify-release-package.ps1"
- "scripts/repository-health.ps1"
- "scripts/verify-workspace-spacing.ps1"
- "docs/RELEASE_NOTES_v*.md"
- ".github/workflows/candidate-package.yml"
- ".github/workflows/release-package.yml"
Expand All @@ -38,7 +47,7 @@ jobs:
name: Build verified Windows x64 candidate
if: github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'stabilization/') || startsWith(github.head_ref, 'architecture/') || startsWith(github.head_ref, 'legal/') || startsWith(github.head_ref, 'fix/') || startsWith(github.head_ref, 'feat/')
runs-on: windows-latest
timeout-minutes: 35
timeout-minutes: 50

steps:
- name: Checkout
Expand Down Expand Up @@ -66,10 +75,38 @@ jobs:
"value=$version" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
Write-Host "Candidate version: $version"

- name: Reject already-published version
shell: pwsh
env:
GH_TOKEN: ${{ github.token }}
run: |
$tag = "v${{ steps.version.outputs.value }}"
# GitHub CLI exits 1 for an expected 404. On modern PowerShell runners
# a failed native command can terminate the step BEFORE LASTEXITCODE
# is inspected. Query the REST status explicitly; 404 is an unused
# version, 200 is already published, and other statuses fail closed.
$uri = "https://api.github.com/repos/${{ github.repository }}/releases/tags/$tag"
$response = Invoke-WebRequest -Uri $uri -Method Get -SkipHttpErrorCheck -Headers @{
Authorization = "Bearer $env:GH_TOKEN"
Accept = "application/vnd.github+json"
"X-GitHub-Api-Version" = "2022-11-28"
}
if ($response.StatusCode -eq 200) {
throw "Version $tag was already published. Bump VersionPrefix; never replace historical public binaries."
}
if ($response.StatusCode -ne 404) {
throw "Unable to establish release-version availability: HTTP $($response.StatusCode)."
}
Write-Host "Unused release version verified: $tag"

- name: Repository health gate
shell: pwsh
run: .\scripts\repository-health.ps1 -ExpectedVersion '${{ steps.version.outputs.value }}'

- name: Workspace spacing geometry gate
shell: pwsh
run: .\scripts\verify-workspace-spacing.ps1

- name: Restore
run: dotnet restore .\ProcessBusSuite.sln

Expand All @@ -79,6 +116,14 @@ jobs:
- name: Test
run: dotnet test .\ProcessBusSuite.sln -c Release --no-build --logger "trx;LogFileName=candidate-tests.trx" --results-directory .\TestResults

- name: Generate current offline PDF manuals
shell: pwsh
run: |
python -m pip install --disable-pip-version-check reportlab==4.4.9
if ($LASTEXITCODE -ne 0) { throw 'Pinned ReportLab PDF build dependency unavailable.' }
python .\scripts\render-offline-manuals.py
if ($LASTEXITCODE -ne 0) { throw 'Offline manual PDF generation failed.' }

- name: Publish portable package
shell: pwsh
run: .\scripts\publish-windows-portable.ps1 -Version '${{ steps.version.outputs.value }}' -Configuration Release -Runtime win-x64
Expand All @@ -89,6 +134,24 @@ jobs:
$zip = ".\artifacts\release\ProcessBusInsight-v${{ steps.version.outputs.value }}-win-x64-portable.zip"
.\scripts\verify-release-package.ps1 -PackageZip $zip

- name: Install Inno Setup 6
shell: pwsh
run: |
choco install innosetup --yes --no-progress
if ($LASTEXITCODE -ne 0) { throw 'Inno Setup compiler installation failed.' }

- name: Compile Inno installer
shell: pwsh
run: .\scripts\publish-windows-installer.ps1 -Version '${{ steps.version.outputs.value }}'

- name: Smoke test Inno installation and repair
shell: pwsh
run: |
$version = '${{ steps.version.outputs.value }}'
$installer = ".\artifacts\release\ProcessBusInsight-v$version-win-x64-setup.exe"
$stage = ".\artifacts\package\ProcessBusInsight-v$version-win-x64-portable"
.\scripts\verify-windows-installer.ps1 -Installer $installer -StageDir $stage

- name: Create candidate manifest
shell: pwsh
run: |
Expand All @@ -100,6 +163,10 @@ jobs:
sourceRef = '${{ github.head_ref || github.ref_name }}'
runtime = 'win-x64'
framework = 'net8.0-windows'
primaryDistribution = 'inno-setup-exe'
offlineManuals = @('User Manual.pdf', 'Quick Start.pdf')
upgradeMode = 'stable-inno-appid-in-place-repair'
installerSigned = $false
communityLicense = 'GPL-3.0-or-later'
historicalBoundary = '85d43a0fe58a5888a9e8008c168ab76d2333ea87'
timestampUtc = (Get-Date).ToUniversalTime().ToString('o')
Expand All @@ -109,9 +176,9 @@ jobs:
- name: Upload verified candidate
uses: actions/upload-artifact@v7
with:
name: ProcessBusInsight-v${{ steps.version.outputs.value }}-win-x64-candidate-${{ github.run_number }}
name: ProcessBusInsight-v${{ steps.version.outputs.value }}-win-x64-inno-candidate-${{ github.run_number }}
path: |
artifacts/release/ProcessBusInsight-v${{ steps.version.outputs.value }}-win-x64-portable.zip
artifacts/release/ProcessBusInsight-v${{ steps.version.outputs.value }}-win-x64-setup.exe
artifacts/release/SHA256SUMS.txt
artifacts/release/candidate-manifest.json
TestResults/**
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ jobs:
shell: pwsh
run: .\scripts\repository-health.ps1

- name: Workspace spacing geometry gate
shell: pwsh
run: .\scripts\verify-workspace-spacing.ps1

- name: Restore
run: dotnet restore .\ProcessBusSuite.sln

Expand Down
90 changes: 74 additions & 16 deletions .github/workflows/release-package.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
name: Release Windows portable package
name: Release Windows installer and portable package

on:
workflow_dispatch:
inputs:
version:
description: Version label, for example 1.4.0
description: Version label, for example 1.4.1
required: true
default: 1.4.0
default: 1.4.1
publish_release:
description: Create or update a GitHub Release
description: Publish GitHub Release after successful validation (manual only)
required: true
default: false
type: boolean
field_acceptance_verified:
description: "I confirm documented real-NIC capture, injector agreement, and soak acceptance on the target Windows configuration"
required: true
default: false
type: boolean
Expand All @@ -25,7 +30,7 @@ on:
release_notes_file:
description: Markdown file used as release body
required: true
default: docs/RELEASE_NOTES_v1.4.0.md
default: docs/RELEASE_NOTES_v1.4.1.md
push:
tags:
- "v*"
Expand All @@ -45,7 +50,7 @@ jobs:
package:
name: Validate and package Windows x64
runs-on: windows-latest
timeout-minutes: 35
timeout-minutes: 55

steps:
- name: Checkout
Expand All @@ -70,10 +75,30 @@ jobs:
"value=$version" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
Write-Host "Release version: $version"

# Tags can build reproducible packages, but never auto-publish an
# unreviewed stable release simply because a tag was pushed.
- name: Public release authorization gate
if: ${{ github.event_name == 'workflow_dispatch' && inputs.publish_release }}
shell: pwsh
env:
FIELD_ACCEPTANCE: ${{ inputs.field_acceptance_verified }}
RUN_REF: ${{ github.ref }}
run: |
if ($env:RUN_REF -ne 'refs/heads/main') {
throw 'Public releases must be built from the validated main branch.'
}
if ($env:FIELD_ACCEPTANCE -ne 'true') {
throw 'Public release blocked: field acceptance has not been explicitly verified.'
}

- name: Repository health gate
shell: pwsh
run: .\scripts\repository-health.ps1 -ExpectedVersion '${{ steps.version.outputs.value }}'

- name: Workspace spacing geometry gate
shell: pwsh
run: .\scripts\verify-workspace-spacing.ps1

- name: Restore
run: dotnet restore .\ProcessBusSuite.sln

Expand All @@ -83,6 +108,14 @@ jobs:
- name: Test
run: dotnet test .\ProcessBusSuite.sln -c Release --no-build --logger "trx;LogFileName=release-tests.trx" --results-directory .\TestResults

- name: Generate current offline PDF manuals
shell: pwsh
run: |
python -m pip install --disable-pip-version-check reportlab==4.4.9
if ($LASTEXITCODE -ne 0) { throw 'Pinned ReportLab PDF build dependency unavailable.' }
python .\scripts\render-offline-manuals.py
if ($LASTEXITCODE -ne 0) { throw 'Offline manual PDF generation failed.' }

- name: Publish portable package
shell: pwsh
run: .\scripts\publish-windows-portable.ps1 -Version '${{ steps.version.outputs.value }}' -Configuration Release -Runtime win-x64
Expand All @@ -93,6 +126,24 @@ jobs:
$zip = ".\artifacts\release\ProcessBusInsight-v${{ steps.version.outputs.value }}-win-x64-portable.zip"
.\scripts\verify-release-package.ps1 -PackageZip $zip

- name: Install Inno Setup 6
shell: pwsh
run: |
choco install innosetup --yes --no-progress
if ($LASTEXITCODE -ne 0) { throw 'Inno Setup compiler installation failed.' }

- name: Compile Inno installer
shell: pwsh
run: .\scripts\publish-windows-installer.ps1 -Version '${{ steps.version.outputs.value }}'

- name: Smoke test Inno installation and repair
shell: pwsh
run: |
$version = '${{ steps.version.outputs.value }}'
$installer = ".\artifacts\release\ProcessBusInsight-v$version-win-x64-setup.exe"
$stage = ".\artifacts\package\ProcessBusInsight-v$version-win-x64-portable"
.\scripts\verify-windows-installer.ps1 -Installer $installer -StageDir $stage

- name: Create release manifest
shell: pwsh
run: |
Expand All @@ -102,6 +153,11 @@ jobs:
commit = '${{ github.sha }}'
runtime = 'win-x64'
framework = 'net8.0-windows'
primaryDistribution = 'inno-setup-exe'
secondaryDistribution = 'portable-zip'
offlineManuals = @('User Manual.pdf', 'Quick Start.pdf')
upgradeMode = 'stable-inno-appid-in-place-repair'
installerSigned = $false
communityLicense = 'GPL-3.0-or-later'
historicalBoundary = '85d43a0fe58a5888a9e8008c168ab76d2333ea87'
timestampUtc = (Get-Date).ToUniversalTime().ToString('o')
Expand All @@ -111,8 +167,9 @@ jobs:
- name: Upload workflow artifact
uses: actions/upload-artifact@v7
with:
name: ProcessBusInsight-v${{ steps.version.outputs.value }}-win-x64-portable
name: ProcessBusInsight-v${{ steps.version.outputs.value }}-win-x64-installer-and-portable
path: |
artifacts/release/ProcessBusInsight-v${{ steps.version.outputs.value }}-win-x64-setup.exe
artifacts/release/ProcessBusInsight-v${{ steps.version.outputs.value }}-win-x64-portable.zip
artifacts/release/SHA256SUMS.txt
artifacts/release/release-manifest.json
Expand All @@ -121,32 +178,33 @@ jobs:
retention-days: 30

- name: Publish GitHub Release
if: ${{ github.event_name == 'push' || github.event.inputs.publish_release == 'true' }}
if: ${{ github.event_name == 'workflow_dispatch' && inputs.publish_release }}
shell: pwsh
env:
GH_TOKEN: ${{ github.token }}
run: |
$version = '${{ steps.version.outputs.value }}'
$tag = "v$version"
$zip = "artifacts/release/ProcessBusInsight-v$version-win-x64-portable.zip"
$installer = "artifacts/release/ProcessBusInsight-v$version-win-x64-setup.exe"
$sha = "artifacts/release/SHA256SUMS.txt"
$manifest = "artifacts/release/release-manifest.json"
$notesFile = '${{ github.event.inputs.release_notes_file }}'
if ([string]::IsNullOrWhiteSpace($notesFile)) { $notesFile = 'docs/RELEASE_NOTES_v1.4.0.md' }
if ([string]::IsNullOrWhiteSpace($notesFile)) { $notesFile = 'docs/RELEASE_NOTES_v1.4.1.md' }
if (-not (Test-Path $notesFile)) { throw "Release notes file not found: $notesFile" }

$releaseArgs = @('release', 'create', $tag, $zip, $sha, $manifest, '--title', "Process Bus Insight $tag", '--notes-file', $notesFile, '--target', '${{ github.sha }}')
$releaseArgs = @('release', 'create', $tag, $installer, $zip, $sha, $manifest, '--title', "Process Bus Insight $tag", '--notes-file', $notesFile, '--target', '${{ github.sha }}')
$isDraft = '${{ github.event.inputs.draft }}'
$isPrerelease = '${{ github.event.inputs.prerelease }}'
if ('${{ github.event_name }}' -eq 'push') {
$isPrerelease = if ($version -match '-') { 'true' } else { 'false' }
}
# A pre-release version must always remain a prerelease.
if ($version -match '-') { $isPrerelease = 'true' }
if ($isDraft -eq 'true') { $releaseArgs += '--draft' }
if ($isPrerelease -eq 'true') { $releaseArgs += '--prerelease' }

# Immutable release identity: never overwrite a published historical
# EXE/ZIP/checksum with a new binary under the same semver tag.
gh release view $tag *> $null
if ($LASTEXITCODE -eq 0) {
gh release upload $tag $zip $sha $manifest --clobber
} else {
gh @releaseArgs
throw "Release $tag already exists. Bump VersionPrefix; public assets are immutable."
}
gh @releaseArgs
5 changes: 5 additions & 0 deletions .github/workflows/runtime-architecture.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ on:
branches: [main]
paths:
- "src/ProcessBus.Iec61850.Raw/Runtime/**"
- "src/ProcessBus.Iec61850.Raw/Analysis/RawProcessBusAnalyzer.cs"
- "src/ProcessBus.Core/Presentation/**"
- "src/ProcessBus.App.Wpf/Controls/PhasorDiagramControl.cs"
- "tests/ProcessBus.Tests/PhasorPresentationContractTests.cs"
- "tests/ProcessBus.Tests/OperatorPresentationReleaseTests.cs"
- "src/ProcessBus.Iec61850.Raw/Replay/**"
- "tests/ProcessBus.Tests/Pcap*Tests.cs"
- "tests/ProcessBus.Tests/AnalyzerRuntimeSnapshotSourceTests.cs"
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ All notable changes are documented here. The project follows Semantic Versioning

## [Unreleased]

### Implemented in release-candidate branch (public stable acceptance pending)

- Unified selected-stream phasor RMS/angle display without UI-side nominal phase overrides; improved six-vector label collisions, separate measured U/I scales, legible 270° convention, stale data and live-with-warning semantics
- Removed fabricated Ethernet adapter fallback and pinned native Npcap discovery/capture to trusted Windows x64 system library paths
- Added deterministic phasor, compact-caption, adapter and status regression tests
- Made Inno Setup self-contained EXE the primary Windows distribution, with same-version repair, in-place upgrade, offline manuals and install/repair/uninstall CI evidence
- Generated packaged PDF manuals from current Markdown source, with SHA256 provenance and stale-PDF rejection
- Hardened stable publication to manual main-only authorization after documented physical acceptance; no automatic public release on tag push
- Physical target-NIC/injector 60-minute acceptance remains pending for the current candidate; earlier 1.3.0 soak evidence does not substitute

### Planned

- Sanitized golden PCAP/PCAPNG replay corpus with broader interoperability scenarios
Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<NeutralLanguage>en</NeutralLanguage>

<!-- Public release version. Pre-release versions may set VersionSuffix explicitly. -->
<VersionPrefix Condition="'$(VersionPrefix)' == ''">1.4.0</VersionPrefix>
<VersionPrefix Condition="'$(VersionPrefix)' == ''">1.4.1</VersionPrefix>
<VersionSuffix Condition="'$(VersionSuffix)' == ''"></VersionSuffix>
<Version Condition="'$(Version)' == '' and '$(VersionSuffix)' == ''">$(VersionPrefix)</Version>
<Version Condition="'$(Version)' == '' and '$(VersionSuffix)' != ''">$(VersionPrefix)-$(VersionSuffix)</Version>
Expand Down
Loading
Loading