From af19d46011c3ddac4257bd87db7bebd38c8b1f8d Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Thu, 5 Nov 2026 05:41:18 +0700 Subject: [PATCH 01/10] fix(site): replace invented branding and waveform demo with official logo and real Qt screenshot --- index.html | 55 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/index.html b/index.html index 2bdcde9c3..96de24c33 100644 --- a/index.html +++ b/index.html @@ -8,37 +8,50 @@ ARStack61850 — IEC 61850 Process Bus Simulator + + + + - + +
@@ -58,21 +71,15 @@

A process bus lab.
Without the test rack.

Windows x64 · Setup ZIP   /   Linux x86_64 · AppImage   ·   Release notes & checksums ↗
-
-
-
ARStack Studio / Process Bus● LAB READY
-
-
PROCESS BUS TOPOLOGYREAL ETHERNET OUTPUT
-
ARStack StudioWaveform & SCL
ESP32-P4SV + PTP publisher
IED / AnalyzerLab subscriber
-
SV · 4I + 4VPTP · Grandmaster emulationSCL import
- - - - - -
-
-
+
+ + Genuine native Windows Qt capture: ARStack SMV Injector showing 4I+4V setpoints, phasors, waveform traces, PTP source and capture controls + +
+ Actual Qt Studio capture, committed in this repository (not a mockup) + Capture provenance ↗ +
+
@@ -99,10 +106,6 @@

A process bus lab.
Without the test rack.

VERIFICATION BOUNDARY

Dual firmware, revision-aware provisioning

The stable Studio release offers separate firmware images for ESP32-P4 pre-v3 and v3.x silicon and a matching firmware catalog. v3.x board support remains an engineering preview pending broader physical acceptance.

See supported packages and release notes ↗
-
-
Desktop engineering workspace

Configure and observe from ARStack Studio.

Work with waveform controls, phasor views, stream configuration, firmware management and on-wire observations in a native desktop application.

-
Actual ARStack Studio Windows Qt desktop interface showing engineering controls, phasors and waveform views
Actual Windows Qt Studio screenshot captured by the native GUI test.
-
Fast onboarding

From download to first Ethernet packet.

Try the Studio interface without hardware, then attach a compatible ESP32-P4 to transmit real traffic.

First-run guide ↗
Install StudioExtract the Windows Setup ZIP or run the Linux x86_64 AppImage.
Connect your boardUse USB data and an isolated Ethernet test network.
Load matching firmwareInstall the release-paired pre-v3 or v3.x image from Studio.
Start SV + PTPUse 4I+4V Quick Start and a simulated PTP source, then capture the packets.
From 1f6f97580f0ba3df163474470f8c0ba0bfb0c622 Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Thu, 5 Nov 2026 05:41:50 +0700 Subject: [PATCH 02/10] test(site): guard official brand images, native screenshot provenance and local dimensions --- scripts/check_site_visual_assets.py | 73 +++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 scripts/check_site_visual_assets.py diff --git a/scripts/check_site_visual_assets.py b/scripts/check_site_visual_assets.py new file mode 100644 index 000000000..31e4405db --- /dev/null +++ b/scripts/check_site_visual_assets.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python3 +"""Guard authenticity and deployability of the product landing's repository assets. + +An accepted landing uses the project's own logo and native Qt screenshot, not +invented brand marks or hand-painted UI mockups. Stdlib only; fast documentation CI. +""" +from __future__ import annotations + +import re +import struct +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +HTML = (ROOT / "index.html").read_text(encoding="utf-8") + +REQUIRED = { + "assets/web-app-manifest-192x192.png": (192, 192), + "assets/web-app-manifest-512x512.png": (512, 512), + "assets/favicon-96x96.png": (96, 96), + "assets/screenshots/arstack-studio-windows.png": (960, 680), +} +OTHER = ( + "assets/favicon.ico", + "assets/apple-touch-icon.png", + "assets/site.webmanifest", +) +errors: list[str] = [] + +for path, expected in REQUIRED.items(): + source = ROOT / path + if not source.is_file() or source.stat().st_size < 15000: + errors.append(f"Missing or implausibly small canonical image: {path}") + continue + header = source.read_bytes()[:24] + if len(header) != 24 or header[:8] != b"\x89PNG\r\n\x1a\n" or header[12:16] != b"IHDR": + errors.append(f"Not a valid PNG header: {path}") + continue + size = struct.unpack(">II", header[16:24]) + if size != expected: + errors.append(f"Unexpected image dimensions for {path}: {size} vs {expected}") + +for path in OTHER: + if not (ROOT / path).is_file() or (ROOT / path).stat().st_size == 0: + errors.append(f"Missing required product identity asset: {path}") + +required_html = [ + r']*>\s*', + r']*href="assets/favicon.ico"', + r'', +] +for pattern in required_html: + if not re.search(pattern, HTML): + errors.append(f"Missing canonical landing asset reference: {pattern}") +if HTML.count(' Date: Thu, 5 Nov 2026 05:42:17 +0700 Subject: [PATCH 03/10] fix(pages): publish authentic identity assets and verify live pixel bytes --- .../workflows/m3h-project-pages-publish.yml | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/.github/workflows/m3h-project-pages-publish.yml b/.github/workflows/m3h-project-pages-publish.yml index b7baec090..b44c455ec 100644 --- a/.github/workflows/m3h-project-pages-publish.yml +++ b/.github/workflows/m3h-project-pages-publish.yml @@ -5,6 +5,14 @@ on: branches: [main] paths: - 'index.html' + - 'assets/screenshots/arstack-studio-windows.png' + - 'assets/favicon.ico' + - 'assets/favicon-96x96.png' + - 'assets/apple-touch-icon.png' + - 'assets/site.webmanifest' + - 'assets/web-app-manifest-192x192.png' + - 'assets/web-app-manifest-512x512.png' + - 'scripts/check_site_visual_assets.py' - '.github/workflows/m3h-project-pages-publish.yml' workflow_dispatch: @@ -47,10 +55,15 @@ jobs: grep -Fq 'ARStack-Studio-win-x64-setup.zip' index.html grep -Fq 'firmware-catalog.json' index.html grep -Fq 'PROCESSBUS_AUTONOMOUS_M3H3_OFFICIAL_20261025.md' index.html + python3 scripts/check_site_visual_assets.py mkdir -p _site cp index.html _site/index.html - test -s assets/screenshots/arstack-studio-windows.png mkdir -p _site/assets/screenshots + for asset in favicon.ico favicon-96x96.png apple-touch-icon.png site.webmanifest web-app-manifest-192x192.png web-app-manifest-512x512.png; do + test -s "assets/$asset" + cp "assets/$asset" "_site/assets/$asset" + done + test -s assets/screenshots/arstack-studio-windows.png cp assets/screenshots/arstack-studio-windows.png _site/assets/screenshots/arstack-studio-windows.png touch _site/.nojekyll - uses: actions/configure-pages@v5 @@ -76,7 +89,12 @@ jobs: grep -Fq 'Download for Linux' /tmp/arstack-live.html && grep -Fq '4,705,090' /tmp/arstack-live.html && grep -Fq 'processbus-sim-dual-stable-20261105' /tmp/arstack-live.html; then - echo 'PASS: latest-release links deployed on the public product URL' + for asset in assets/web-app-manifest-192x192.png assets/web-app-manifest-512x512.png assets/favicon-96x96.png assets/screenshots/arstack-studio-windows.png; do + published="/tmp/arstack-live-$(basename "$asset")" + curl --fail --location --silent --show-error "https://masarray.github.io/arstack61850/$asset?build=$GITHUB_SHA" -o "$published" + cmp --silent "$asset" "$published" || { echo "FAIL: published image differs from repository $asset" >&2; exit 1; } + done + echo 'PASS: latest release links, original identity files and native screenshot live on project Pages' exit 0 fi fi From 893c8436357f1eeb00d969efc08fbfc8ffb7c0e7 Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Thu, 5 Nov 2026 05:42:35 +0700 Subject: [PATCH 04/10] test(site): load official logo/native Qt screenshot at desktop and mobile widths --- .github/workflows/m3h-landing-browser-acceptance.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/m3h-landing-browser-acceptance.yml b/.github/workflows/m3h-landing-browser-acceptance.yml index eb9b2cd49..db5ea09d3 100644 --- a/.github/workflows/m3h-landing-browser-acceptance.yml +++ b/.github/workflows/m3h-landing-browser-acceptance.yml @@ -3,9 +3,9 @@ name: ARStack Latest Stable Landing Browser and Mobile Acceptance on: push: branches: [main] - paths: ['index.html', '.github/workflows/m3h-landing-browser-acceptance.yml'] + paths: ['index.html', 'assets/screenshots/arstack-studio-windows.png', 'assets/web-app-manifest-192x192.png', 'assets/web-app-manifest-512x512.png', 'scripts/check_site_visual_assets.py', '.github/workflows/m3h-landing-browser-acceptance.yml'] pull_request: - paths: ['index.html', '.github/workflows/m3h-landing-browser-acceptance.yml'] + paths: ['index.html', 'assets/screenshots/arstack-studio-windows.png', 'assets/web-app-manifest-192x192.png', 'assets/web-app-manifest-512x512.png', 'scripts/check_site_visual_assets.py', '.github/workflows/m3h-landing-browser-acceptance.yml'] workflow_dispatch: permissions: @@ -17,6 +17,8 @@ jobs: timeout-minutes: 12 steps: - uses: actions/checkout@v4 + - name: Validate canonical visual asset sources and dimensions + run: python3 scripts/check_site_visual_assets.py - name: Install isolated browser automation shell: bash run: | @@ -40,6 +42,7 @@ jobs: const page=await browser.newPage({viewport:{width,height:900},deviceScaleFactor:1}); const response=await page.goto('http://127.0.0.1:4173/',{waitUntil:'domcontentloaded',timeout:30000}); if(response.status()!==200)throw new Error('LIVE_HTTP_'+response.status()); + await Promise.all([page.locator('.brand img').evaluate(el=>el.decode()),page.locator('.hero-visual img').evaluate(el=>el.decode())]); const data=await page.evaluate(()=>{ const buttons=[...document.querySelectorAll('a[data-asset="windows"],a[data-asset="portable"],a[data-asset="firmware"]')]; const releaseLink=/^https:\/\/github\.com\/masarray\/arstack61850\/releases\/(latest|download\/[^/]+\/[^/]+)$/; @@ -48,12 +51,16 @@ jobs: buttons:buttons.length, linksValid:buttons.every(el=>releaseLink.test(el.href)), anyVisible:buttons.some(el=>{const r=el.getBoundingClientRect();return r.width>0&&r.height>0}), linuxReady:!!document.querySelector('[data-asset="linux"]'), heroDownloads:[...document.querySelectorAll('.hero-downloads a')].map(el=>({label:el.textContent.trim(),href:el.href,visible:el.getBoundingClientRect().width>0&&el.getBoundingClientRect().height>0})), + officialBrand:(()=>{const el=document.querySelector('.brand img');return el?.naturalWidth===192&&el.getAttribute('src')==='assets/web-app-manifest-192x192.png'})(), + nativeScreenshot:(()=>{const el=document.querySelector('.hero-visual img');return el?.naturalWidth===960&&el?.naturalHeight===680&&el.getAttribute('src')==='assets/screenshots/arstack-studio-windows.png'})(), + noPaintedMock:!document.querySelector('.monitor,.wave'), og:!!document.querySelector('meta[property="og:title"]')}; }); console.log(width,JSON.stringify(data)); await page.screenshot({path:'evidence/m3h-'+width+'.png',fullPage:true}); if(!data.latest||!data.benchmark||!data.og||data.buttons!==4||!data.anyVisible||!data.linksValid||!data.linuxReady)throw new Error('MISSING_LATEST_RELEASE_LINKS_'+width); if(data.heroDownloads.length!==2||!data.heroDownloads.every(x=>x.visible)||data.heroDownloads[0].label!=='Download for Windows'||data.heroDownloads[1].label!=='Download for Linux'||!/ARStack-Studio-win-x64-setup\.zip$/.test(data.heroDownloads[0].href)||!/ARStack-Studio-linux-x86_64\.AppImage$/.test(data.heroDownloads[1].href))throw new Error('HERO_DIRECT_PLATFORM_DOWNLOADS_'+width); + if(!data.officialBrand||!data.nativeScreenshot||!data.noPaintedMock)throw new Error('NONCANONICAL_BRAND_OR_MOCK_SCREEN_'+width); if(data.scroll>data.width+2)throw new Error('HORIZONTAL_OVERFLOW_'+width+':'+data.scroll+'>'+data.width); await page.close(); } From 5c94b2ecbef7c7b1d9ce74e18ead17655f2083a5 Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Thu, 5 Nov 2026 05:44:23 +0700 Subject: [PATCH 05/10] fix(site): use official Studio icon family for header/favicon/OG and app identity --- index.html | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/index.html b/index.html index 96de24c33..79879853a 100644 --- a/index.html +++ b/index.html @@ -8,19 +8,22 @@ ARStack61850 — IEC 61850 Process Bus Simulator - - - - + + + + + - - + + + + - +