Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
4ed8f69
fix(studio): acknowledge PTP role/config/start in native guided Timin…
masarray Oct 15, 2026
725b51e
fix(studio): keep PTP START acknowledgements distinct from SV publish…
masarray Oct 15, 2026
a328da1
fix(workbench): preserve bounded initial SCL-assisted MMS q/t evidenc…
masarray Oct 15, 2026
8be7b8a
fix(studio): default native PTP Sync cadence to supported 1000 ms
masarray Oct 15, 2026
fb0457f
ci(studio): package side-by-side native Windows GUI preview with pinn…
masarray Oct 15, 2026
57d028c
build(studio): replace preview NSIS with Inno Setup smart upgrade and…
masarray Oct 15, 2026
d1c4124
feat(installer): gated ownership-safe migration from public NSIS v0.1…
masarray Oct 15, 2026
c375615
test(studio): localize Windows reference-template failure before inst…
masarray Oct 15, 2026
ff64f50
fix(ci): wait on GUI installers and application exit codes in Windows…
masarray Oct 15, 2026
7ce9025
fix(ci): copy pinned firmware/tool contents into canonical native Stu…
masarray Oct 15, 2026
eb7fba2
test(studio): capture baseline vs new native firmware contract failur…
masarray Oct 15, 2026
bc5415b
fix(studio): bundle matched PR-head ESP32-P4 firmware in isolated Inn…
masarray Oct 15, 2026
4b8de64
ci(esp32): isolate reusable preview firmware build from standalone wo…
masarray Oct 15, 2026
82d2f18
fix(esp32): fail closed on invalid firmware source commit provenance
masarray Oct 15, 2026
ebc62a1
fix(studio): stop independent PTP runtime on GUI shutdown before Inno…
masarray Oct 15, 2026
06db65e
fix(studio): bound full serial STOP drain instead of assuming first b…
masarray Oct 15, 2026
305ac0c
fix(installer): unambiguous Inno stable/preview channel and safe PTP-…
masarray Oct 15, 2026
8fa52fa
test(installer): correct PowerShell expression grouping in final NSIS…
masarray Oct 15, 2026
a0adcbd
fix(studio): require PTP role ACK and live PTP2 readback before GUI S…
masarray Oct 15, 2026
61be86f
docs(workbench): canonical ARSAS-inspired GUI/SSOT strategy and cross…
masarray Oct 15, 2026
03fceb0
merge(studio): reconcile native Inno preview with latest canonical Wo…
masarray Oct 15, 2026
58ed859
fix(studio): make PTP STOP fail-closed under queued START and transpo…
masarray Oct 15, 2026
c9c0155
test(studio): validate role-mismatch rollback through STOPPED before …
masarray Oct 15, 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
373 changes: 373 additions & 0 deletions .github/workflows/arstack-studio-native-preview.yml

Large diffs are not rendered by default.

16 changes: 14 additions & 2 deletions .github/workflows/esp32p4-smv-injector.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ permissions:
contents: read

concurrency:
group: esp32p4-smv-${{ github.event.pull_request.head.repo.full_name || github.repository }}-${{ github.event.pull_request.head.ref || github.ref_name }}
group: esp32p4-smv-${{ github.workflow }}-${{ github.event.pull_request.head.repo.full_name || github.repository }}-${{ github.event.pull_request.head.ref || github.ref_name }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}

env:
Expand All @@ -58,6 +58,10 @@ jobs:
working-directory: embedded/esp32p4_smv_injector
steps:
- uses: actions/checkout@v4
with:
# PR packaging must use exactly the reviewed source SHA, not a
# synthetic merge SHA that may change between queue and build.
ref: ${{ github.event.pull_request.head.sha || github.sha }}

- name: Select ESP32-P4 target
run: source /opt/esp/idf/export.sh && idf.py set-target esp32p4
Expand Down Expand Up @@ -130,15 +134,22 @@ jobs:
test -s "build/${image}"

- name: Create release manifest and SHA-256 contract
env:
# Container git may lack safe.directory or even be unavailable.
# The checkout explicitly selected this verified PR-head SHA.
ARSTACK_SOURCE_COMMIT: ${{ github.event.pull_request.head.sha || github.sha }}
run: |
set -euo pipefail
image="arstack-esp32p4-smv-${ARSTACK_FIRMWARE_VERSION}.bin"
sha="$(sha256sum "build/${image}" | awk '{print $1}')"
python3 - "$image" "$sha" "$GITHUB_SHA" <<'PY'
python3 - "$image" "$sha" "$ARSTACK_SOURCE_COMMIT" <<'PY'
import json
import os
import re
import sys
image, sha256, source_commit = sys.argv[1:]
if not re.fullmatch(r"[0-9a-f]{40}", source_commit):
raise SystemExit("Firmware source SHA unavailable/invalid; refusing a zero-provenance package")
manifest = {
"schema": "arstack.studio.firmware.v1",
"product": "ARStack ESP32-P4 SMV Injector",
Expand Down Expand Up @@ -171,6 +182,7 @@ jobs:
assert 'PTP-P2' in manifest['capabilities']
assert 'SMPSYNCH-AUTO' in manifest['capabilities']
assert 'PROFILE-BINARY-V1' in manifest['capabilities']
assert __import__('re').fullmatch(r'[0-9a-f]{40}', manifest['sourceCommit'])
assert actual == manifest['sha256']
print(f"Firmware package: PASS · {manifest['image']} · PTP-P2 · pre-v3 · SHA-256 {actual}")
PY
Expand Down
2 changes: 1 addition & 1 deletion AI_READ_FIRST.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This repository contains protocol behavior that has been reconstructed from stan

Read the topic contract before changing the corresponding code:

- **Current native Qt Workbench / IED Browser progress, exact baseline, red PR and optimized coding handoff:** [`docs/WORKBENCH_CURRENT_HANDOFF.md`](docs/WORKBENCH_CURRENT_HANDOFF.md). Read this before working on `apps/ied_simulator` Browser/Reports/DataSets/Global Data/q/t.
- **Native Qt Workbench / IED Browser cross-thread strategy, ARSAS design reference, SSOT, milestones, ownership and merge gates:** [`docs/WORKBENCH_ARSAS_GUI_SSOT_STRATEGY.md`](docs/WORKBENCH_ARSAS_GUI_SSOT_STRATEGY.md). **Current checkpoint and active PRs:** [`docs/WORKBENCH_CURRENT_HANDOFF.md`](docs/WORKBENCH_CURRENT_HANDOFF.md). Read **both** before editing `apps/ied_simulator` Browser/Reports/DataSets/Global Data/SG/q/t.
- **Live IP discovery vs trusted-SCL online connect:** [`docs/ONLINE_MODEL_CONNECT_DECISION.md`](docs/ONLINE_MODEL_CONNECT_DECISION.md), then [`LIVE_DISCOVERY_PROFILE.md`](LIVE_DISCOVERY_PROFILE.md).
- **RCB reporting, URCB/BRCB activation, report bit semantics, replay/recovery:** [`RCB_REPORTING.md`](RCB_REPORTING.md).
- **Open SCL, live MMS reconstruction, canonical model normalization, IED-name resolution, and Edition 2 / Edition 1 export:** [`SCL_EXPORT.md`](SCL_EXPORT.md), then [`docs/SCL_IMPORT_NORMALIZATION_PROFILE.md`](docs/SCL_IMPORT_NORMALIZATION_PROFILE.md) and [`docs/SCL_EXPORT_RECONSTRUCTION_PROFILE.md`](docs/SCL_EXPORT_RECONSTRUCTION_PROFILE.md).
Expand Down
2 changes: 1 addition & 1 deletion PROJECT_HANDOFF.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This file is the **current-state handoff** for a new engineer or AI thread. Read [`NORTH_STAR.md`](NORTH_STAR.md) first for the long-term direction, then use this file to continue active development without reconstructing the bench history from chat.

> **Current native IEC 61850 Workbench / Browser engineering track (M2A–M2G):** read [docs/WORKBENCH_CURRENT_HANDOFF.md](docs/WORKBENCH_CURRENT_HANDOFF.md) before resuming Qt Browser, DataSets, Global Data, Reports, typed q/t, CI or Windows Workbench work. This is a dated, SHA-backed checkpoint and lists the active red PR. The SMV/ESP32-P4 release history below belongs to a separate product track.
> **Current native IEC 61850 Workbench / Browser engineering track (M2A–M2J merged; M2K PR #176 active as of 2026-10-15):** read [docs/WORKBENCH_ARSAS_GUI_SSOT_STRATEGY.md](docs/WORKBENCH_ARSAS_GUI_SSOT_STRATEGY.md) for the shared ARSAS-inspired GUI/SSOT execution plan, cross-thread ownership and CI/merge gates; then read [docs/WORKBENCH_CURRENT_HANDOFF.md](docs/WORKBENCH_CURRENT_HANDOFF.md) for the latest checkpoint and active blockers. **Always refresh GitHub refs**. The SMV/ESP32-P4 release history below is a separate product track.

Last major product milestone update: **2026-09-15 — stable public SMV Injector v0.1.0 released**.

Expand Down
6 changes: 6 additions & 0 deletions apps/arstack_studio/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,12 @@ target_compile_features(arstack_session_harness PRIVATE cxx_std_20)
target_compile_definitions(arstack_studio PRIVATE
ARSTACK_STUDIO_VERSION="${PROJECT_VERSION}"
)

# Opt-in Windows engineering preview identity; OFF for all stable builds.
option(ARSTACK_STUDIO_ENGINEERING_PREVIEW "Mark this Studio build as an isolated preview" OFF)
if(ARSTACK_STUDIO_ENGINEERING_PREVIEW)
target_compile_definitions(arstack_studio PRIVATE ARSTACK_STUDIO_ENGINEERING_PREVIEW=1)
endif()
target_compile_definitions(arstack_session_harness PRIVATE
ARSTACK_STUDIO_VERSION="${PROJECT_VERSION}"
)
Expand Down
151 changes: 151 additions & 0 deletions apps/arstack_studio/packaging/ARStackStudio.iss
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
; ARStack Studio Windows installer - Inno Setup 6
; Stable and Preview use separate AppId and install directories. Never run
; the old NSIS uninstaller implicitly: safe migration is separately gated.

#ifndef STAGE_DIR
#error STAGE_DIR is mandatory
#endif
#ifndef STUDIO_VERSION
#define STUDIO_VERSION "0.1.1"
#endif

#ifdef ARSTACK_PREVIEW
#define ProductName "ARStack Studio Preview"
#define ProductId "ARStack61850.Studio.Preview"
#define ProductFolder "ARStack Studio Preview"
#define ProductOutput "ARStack-Studio-Preview-win-x64-setup"
#define ProductRegistry "Software\ARStack61850\ARStack Studio Preview"
#else
#define ProductName "ARStack Studio"
#define ProductId "ARStack61850.Studio.Stable"
#define ProductFolder "ARStack Studio"
#define ProductOutput "ARStack-Studio-win-x64-setup"
#define ProductRegistry "Software\ARStack61850\ARStack Studio"
#endif

[Setup]
AppId={#ProductId}
AppName={#ProductName}
AppVerName={#ProductName} {#STUDIO_VERSION}
AppVersion={#STUDIO_VERSION}
AppPublisher=ARStack61850
AppPublisherURL=https://github.com/masarray/arstack61850
AppSupportURL=https://github.com/masarray/arstack61850/issues
AppUpdatesURL=https://github.com/masarray/arstack61850/releases
UninstallDisplayName={#ProductName}
DefaultDirName={localappdata}\Programs\{#ProductFolder}
DefaultGroupName={#ProductName}
OutputBaseFilename={#ProductOutput}
PrivilegesRequired=lowest
ArchitecturesAllowed=x64compatible
CloseApplications=yes
CloseApplicationsFilter=ARStackStudio.exe,*.dll
RestartApplications=no
SetupMutex=ARStackStudioInstaller
UsePreviousAppDir=yes
UsePreviousGroup=yes
DisableDirPage=auto
DisableProgramGroupPage=auto
WizardStyle=modern
Compression=lzma2
SolidCompression=yes
SetupLogging=yes
UninstallLogging=yes
Uninstallable=yes
MinVersion=10.0

[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"

[Files]
Source: "{#STAGE_DIR}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs

[Icons]
Name: "{group}\{#ProductName}"; Filename: "{app}\ARStackStudio.exe"
Name: "{group}\Uninstall {#ProductName}"; Filename: "{uninstallexe}"
Name: "{autodesktop}\{#ProductName}"; Filename: "{app}\ARStackStudio.exe"; Tasks: desktopicon

[Tasks]
Name: "desktopicon"; Description: "Create a desktop shortcut"; GroupDescription: "Additional shortcuts:"

[Registry]
Root: HKCU; Subkey: "{#ProductRegistry}"; Flags: uninsdeletekeyifempty
Root: HKCU; Subkey: "{#ProductRegistry}"; ValueType: string; ValueName: "InstallDir"; ValueData: "{app}"; Flags: uninsdeletevalue

[Run]
Filename: "{app}\ARStackStudio.exe"; Description: "Launch {#ProductName}"; Flags: nowait postinstall skipifsilent


; This migration is compiled only for the STABLE channel. Preview cannot
; remove or update the public NSIS installation. The old NSIS uninstaller
; recursively deletes {app}; do not execute it as part of a new installation.
; Instead, after verified Inno replacement succeeds, retire only its
; proven-owned old uninstall executable and ARP registration.
#ifdef ARSTACK_PREVIEW
; Preview upgrades use Inno's native same-AppId uninstall-log tracking.
#else
[Code]
const
LegacyNsisUninstallKey =
'Software\Microsoft\Windows\CurrentVersion\Uninstall\ARStackStudio';

function VerifiedLegacyNsis: Boolean;
var
OldName, OldVersion, OldDir, OldUninstall: String;
ExpectedDir, ExpectedUninstall: String;
begin
Result := False;
if not RegKeyExists(HKCU, LegacyNsisUninstallKey) then
Exit;
if not RegQueryStringValue(HKCU, LegacyNsisUninstallKey,
'DisplayName', OldName) then Exit;
if not RegQueryStringValue(HKCU, LegacyNsisUninstallKey,
'DisplayVersion', OldVersion) then Exit;
if not RegQueryStringValue(HKCU, LegacyNsisUninstallKey,
'InstallLocation', OldDir) then Exit;
if not RegQueryStringValue(HKCU, LegacyNsisUninstallKey,
'UninstallString', OldUninstall) then Exit;

ExpectedDir := ExpandConstant('{localappdata}\Programs\ARStack Studio');
ExpectedUninstall := '"' + AddBackslash(ExpectedDir) + 'Uninstall.exe"';
Result :=
(CompareText(OldName, 'ARStack Studio') = 0) and
(CompareText(OldVersion, '0.1.1') = 0) and
(CompareText(OldDir, ExpectedDir) = 0) and
(CompareText(OldUninstall, ExpectedUninstall) = 0) and
FileExists(AddBackslash(ExpectedDir) + 'Uninstall.exe') and
FileExists(AddBackslash(ExpectedDir) + 'ARStackStudio.exe');
end;

function PrepareToInstall(var NeedsRestart: Boolean): String;
begin
Result := '';
if RegKeyExists(HKCU, LegacyNsisUninstallKey) and
not VerifiedLegacyNsis then
begin
Result := 'An older ARStack Studio installation was detected, but its ' +
'ownership, version or install path could not be verified. ' +
'No files were changed. Please contact ARStack support for a safe upgrade.';
end;
end;

procedure CurStepChanged(CurStep: TSetupStep);
var
OldUninstaller: String;
begin
if (CurStep <> ssPostInstall) or
not RegKeyExists(HKCU, LegacyNsisUninstallKey) then
Exit;
if not VerifiedLegacyNsis then
RaiseException('Legacy ARStack Studio identity changed during installation.');

OldUninstaller := ExpandConstant('{app}\Uninstall.exe');
if not DeleteFile(OldUninstaller) then
RaiseException('Could not retire the verified old NSIS uninstaller.');

if not RegDeleteKeyIncludingSubkeys(HKCU, LegacyNsisUninstallKey) then
RaiseException('Could not remove the old NSIS uninstall registration.');

Log('Verified NSIS v0.1.1 registry and old uninstaller retired after Inno setup.');
end;
#endif
53 changes: 33 additions & 20 deletions apps/arstack_studio/packaging/ARStackStudio.nsi
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,29 @@ Unicode true
!define APP_VERSION "0.1.0"
!endif

Name "ARStack Studio"
!ifdef ARSTACK_PREVIEW
!define PACKAGE_NAME "ARStack Studio Preview"
!define PACKAGE_DIR "$LOCALAPPDATA\Programs\ARStack Studio Preview"
!define PACKAGE_REG "Software\ARStack61850\ARStack Studio Preview"
!define PACKAGE_UNINSTALL "Software\Microsoft\Windows\CurrentVersion\Uninstall\ARStackStudioPreview"
!define PACKAGE_MENU "ARStack Studio Preview"
!else
!define PACKAGE_NAME "ARStack Studio"
!define PACKAGE_DIR "$LOCALAPPDATA\Programs\ARStack Studio"
!define PACKAGE_REG "Software\ARStack61850\ARStack Studio"
!define PACKAGE_UNINSTALL "Software\Microsoft\Windows\CurrentVersion\Uninstall\ARStackStudio"
!define PACKAGE_MENU "ARStack Studio"
!endif
Name "${PACKAGE_NAME}"
OutFile "${OUTPUT_FILE}"
InstallDir "$LOCALAPPDATA\Programs\ARStack Studio"
InstallDirRegKey HKCU "Software\ARStack61850\ARStack Studio" "InstallDir"
InstallDir "${PACKAGE_DIR}"
InstallDirRegKey HKCU "${PACKAGE_REG}" "InstallDir"
RequestExecutionLevel user
SetCompressor /SOLID lzma
SetCompressorDictSize 32

VIProductVersion "${APP_VERSION}.0"
VIAddVersionKey "ProductName" "ARStack Studio"
VIAddVersionKey "ProductName" "${PACKAGE_NAME}"
VIAddVersionKey "CompanyName" "ARStack61850"
VIAddVersionKey "FileDescription" "IEC 61850 Sampled Values Injector / Generator"
VIAddVersionKey "FileVersion" "${APP_VERSION}"
Expand All @@ -42,27 +55,27 @@ Section "ARStack Studio" SEC_MAIN
SetOutPath "$INSTDIR"
File /r "${SOURCE_DIR}\*"

WriteRegStr HKCU "Software\ARStack61850\ARStack Studio" "InstallDir" "$INSTDIR"
WriteRegStr HKCU "${PACKAGE_REG}" "InstallDir" "$INSTDIR"
WriteUninstaller "$INSTDIR\Uninstall.exe"

CreateDirectory "$SMPROGRAMS\ARStack Studio"
CreateShortcut "$SMPROGRAMS\ARStack Studio\ARStack Studio.lnk" "$INSTDIR\ARStackStudio.exe"
CreateShortcut "$SMPROGRAMS\ARStack Studio\Uninstall ARStack Studio.lnk" "$INSTDIR\Uninstall.exe"
CreateDirectory "$SMPROGRAMS\${PACKAGE_MENU}"
CreateShortcut "$SMPROGRAMS\${PACKAGE_MENU}\${PACKAGE_NAME}.lnk" "$INSTDIR\ARStackStudio.exe"
CreateShortcut "$SMPROGRAMS\${PACKAGE_MENU}\Uninstall ${PACKAGE_NAME}.lnk" "$INSTDIR\Uninstall.exe"

WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\ARStackStudio" "DisplayName" "ARStack Studio"
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\ARStackStudio" "DisplayVersion" "${APP_VERSION}"
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\ARStackStudio" "Publisher" "ARStack61850"
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\ARStackStudio" "InstallLocation" "$INSTDIR"
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\ARStackStudio" "UninstallString" '"$INSTDIR\Uninstall.exe"'
WriteRegDWORD HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\ARStackStudio" "NoModify" 1
WriteRegDWORD HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\ARStackStudio" "NoRepair" 1
WriteRegStr HKCU "${PACKAGE_UNINSTALL}" "DisplayName" "${PACKAGE_NAME}"
WriteRegStr HKCU "${PACKAGE_UNINSTALL}" "DisplayVersion" "${APP_VERSION}"
WriteRegStr HKCU "${PACKAGE_UNINSTALL}" "Publisher" "ARStack61850"
WriteRegStr HKCU "${PACKAGE_UNINSTALL}" "InstallLocation" "$INSTDIR"
WriteRegStr HKCU "${PACKAGE_UNINSTALL}" "UninstallString" '"$INSTDIR\Uninstall.exe"'
WriteRegDWORD HKCU "${PACKAGE_UNINSTALL}" "NoModify" 1
WriteRegDWORD HKCU "${PACKAGE_UNINSTALL}" "NoRepair" 1
SectionEnd

Section "Uninstall"
Delete "$SMPROGRAMS\ARStack Studio\ARStack Studio.lnk"
Delete "$SMPROGRAMS\ARStack Studio\Uninstall ARStack Studio.lnk"
RMDir "$SMPROGRAMS\ARStack Studio"
Delete "$SMPROGRAMS\${PACKAGE_MENU}\${PACKAGE_NAME}.lnk"
Delete "$SMPROGRAMS\${PACKAGE_MENU}\Uninstall ${PACKAGE_NAME}.lnk"
RMDir "$SMPROGRAMS\${PACKAGE_MENU}"
RMDir /r "$INSTDIR"
DeleteRegKey HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\ARStackStudio"
DeleteRegKey HKCU "Software\ARStack61850\ARStack Studio"
DeleteRegKey HKCU "${PACKAGE_UNINSTALL}"
DeleteRegKey HKCU "${PACKAGE_REG}"
SectionEnd
Loading
Loading