DisplaySync

Testing the image

The single best moment to find a problem with your kiosk image is before you Sysprep and clone it across a fleet. Once a defect is in 50 deployed signs, fixing it costs 50× more than fixing it on one build machine.

This page is the pre-capture validation suite. Run all of it on the build machine before the capture step. Plan on 30–45 minutes to do it thoroughly.

Test 1 — Cold boot to QR

The most important property of the image: from a powered-off device, you reach a fullscreen QR claim screen with no human input.

  1. Power the device off (full shutdown, not sleep — shutdown /s /t 0)
  2. Power on
  3. Start a stopwatch when the BIOS POST appears

Acceptance:

  • Auto-login completes within ~10 seconds of the Windows boot screen
  • The DisplaySync sign app launches within ~5 seconds of auto-login
  • A fullscreen QR claim screen appears (the API URL is shown in small text at the bottom)
  • No "Set Network Location" wizard appears
  • No Microsoft tip / consumer feature toast appears
  • No Windows Update reboot prompt appears
  • Cursor disappears within 3 seconds of last mouse movement
  • Network sanity — press Ctrl+Shift+N (kiosk-attached keyboard or RDP). The Network diagnostics overlay should show NIC info + IP + green checkmarks for both internet and backend reachability. If either is red, fix the venue network before continuing — the kiosk won't claim. See Hotkeys → Ctrl+Shift+N.

Total BIOS POST → QR screen should be under 60 seconds on modern thin client hardware. If it's significantly longer, the most common causes are Fast Startup re-enabling itself, a pending Windows Update install, or a misconfigured power plan.

Test 2 — Status dashboard

While the QR screen is showing, press Ctrl + Shift + S to open the Status Dashboard overlay. Confirm:

  • Connection Status: Connected
  • Sign ID: a fresh UUID (write it down — you'll compare after a reboot)
  • Backend URL: matches what you wrote to .env
  • WS URL: WebSocket connected, not retrying
  • IP Address: the device's local IP
  • Tailscale IP: populated if Tailscale is configured, blank otherwise
  • Cache Status: Active (it'll say Items Cached: 0 since nothing is assigned yet)

Press Esc to dismiss the overlay.

Test 3 — Heartbeat in the dashboard

From a separate machine, log into the dashboard with the org you'll claim against. You should see the build sign appear under Unclaimed Signs with:

  • A short code matching the QR screen
  • Last heartbeat: less than 5 seconds ago
  • Device info populated (platform, memory, CPU, screen resolution)

If the sign doesn't appear, see Troubleshooting → Sign won't claim.

Test 4 — Claim, assign, verify

Run a full claim flow against an event you've created for testing.

  1. From the mobile app, scan the QR code
  2. Pick the test event
  3. The sign should transition from QR screen → "Claimed" briefly → assigned content (or a "ready, no content assigned" state)
  4. From the dashboard, assign a known-good URL (e.g., https://demo.displaysync.live)
  5. The sign updates within ~5 seconds
  6. From the dashboard, Reboot the sign
  7. After reboot, the sign auto-resumes the assigned URL — no QR screen, no claim flow

This proves the offline cache is persisting both identity (C:\ProgramData\DisplaySync\) and the assigned URL across reboots.

Don't keep this claim

Once you've finished testing, unclaim the sign from the dashboard, then see Capturing the image → Clean before Sysprep for clearing the local identity. Otherwise every cloned image boots pre-claimed to your test event.

Test 5 — Offline mode

The desktop sign keeps the most recent content cached locally and continues to display it when the backend is unreachable. Validate this:

  1. With assigned content displaying correctly, pull the network cable (or disable WiFi)
  2. Wait 30 seconds
  3. Acceptance:
    • Content continues to display — no "disconnected" overlay, no QR screen
    • The status dashboard (Ctrl + Shift + S) shows Connection Status: Disconnected and Cache Status: Items Cached > 0
  4. Plug the cable back in
  5. Within 10 seconds:
    • The dashboard shows the sign back online
    • The status dashboard shows Connection Status: Connected

If the kiosk goes blank or shows an error during the disconnected window, the cache isn't picking up the content URL — see Troubleshooting → Content not loading.

Test 6 — Content reachability

The desktop sign does an HTTP HEAD on the assigned content URL every 60 seconds and notifies subscribers when the URL stops responding. Validate this end-to-end:

  1. Assign a URL you control (or use a demo URL)
  2. Confirm the dashboard shows the sign as Online with Content reachable
  3. Take the content URL down (block it at your firewall, or stop its origin)
  4. Within 90 seconds, the dashboard should:
    • Mark the sign's content as Unreachable
    • Generate a notification (in-app + email if subscribed)
  5. Restore the content URL
  6. Within 90 seconds, the dashboard:
    • Marks content Reachable again
    • Generates a recovery notification

This proves both the reachability monitor and your notification subscriptions are wired correctly.

Test 7 — Remote command round trip

From the dashboard, exercise the Remote Control commands one by one:

CommandExpected result
RefreshThe displayed content reloads within ~2 seconds
Reboot appThe sign app exits, the watchdog relaunches it within ~60 seconds
Reboot deviceThe Windows machine restarts cleanly, returns to displayed content within ~90 seconds
Fetch logsThe dashboard receives and displays sign.log content
Settings updateA non-content setting (e.g., display orientation) propagates to the sign

If Reboot device fails with a UAC prompt or no-effect, the kiosk user is missing shutdown privilege — re-run the shutdown privilege grant and retest.

Test 8 — Maintenance mode round trip

Validate the maintenance-mode escape hatch:

  1. While the sign is showing content, plug in a keyboard
  2. Press Ctrl + Shift + Q
  3. The app exits cleanly, the desktop appears, the dashboard reflects the sign as Maintenance
  4. Confirm C:\ProgramData\DisplaySync\.maintenance exists
  5. Reboot the device
  6. After reboot, the sign should be back in normal operation, .maintenance cleared, dashboard shows the sign as online

Test 9 — Crash recovery validation

This pre-Sysprep test confirms the three resilience watchdogs (FrameWatchdog, PageWatchdog, GpuMonitor) actually fire on this hardware. Run all three checks before capturing the image.

9a — GpuMonitor renderer crash

Force a renderer crash and verify the kiosk auto-recovers within ~1 second.

# Open Task Manager → Details tab. Find the renderer process for
# DisplaySync Sign (it'll be a child electron.exe with the highest
# memory among the DisplaySync child processes).

# Right-click → End task. The wall will go briefly blank.

# Within 1 second, GpuMonitor schedules a deferred reload(). The wall
# should come back with the assigned URL freshly loaded.

Expected: brief blank, then the URL reloads. In error.log, you should see one [INFO] GpuMonitor: renderer crashed; scheduling reload in 1000ms.

9b — PageWatchdog frozen JS

Navigate the sign to a URL that hangs the renderer's main thread for >30s. The simplest reproducer:

<!-- Save as a local file, host on a quick `python -m http.server`,
     point the kiosk's URL at it. -->
<script>while(true) {}</script>

Expected: within ~30 seconds, the kiosk reloads. In sign.log, you should see [WARN] PageWatchdog: page frozen for >30000ms; reloading.

Recover the kiosk by setting its URL back to whatever your normal test URL is.

9c — FrameWatchdog white screen

Navigate to a URL that returns a blank white page (any style="background:white" empty body works).

Expected: within 5-15 seconds, FrameWatchdog samples the framebuffer (5×5 grid; >95% white triggers), and the kiosk fires invalidate()reload(). The reload doesn't fix the white-by-design page, so you'll see continuous reload-flash unless RecoveryCooldown (60s) is also active and rate-limits the reloads.

This test is the one you can stop early once you see one reload-flash — leaving it running spams the log.

What you've validated

If all three sub-tests pass, the watchdogs are functional on this hardware. If any one fails (e.g., GpuMonitor doesn't reload), check error.log and sign.log for handler-registration errors. The watchdogs are conditional on the right Electron API being available — most thin-client GPUs are fine, but extreme-low-end hardware (Atom-class with old graphics) sometimes lacks the renderer-crash event.

See Stability over features → Self-healing signs for the operator-facing framing of these signals.

Verify before capture

Final pre-capture checklist:

# No active claim — APPDATA folder either empty or just contains a fresh-build config
Get-ChildItem "$env:APPDATA\DisplaySync Sign" -ErrorAction SilentlyContinue

# No maintenance sentinel
Test-Path "C:\ProgramData\DisplaySync\.maintenance"

# Scheduled task is Ready (or Running), not Disabled
(Get-ScheduledTask -TaskName "DisplaySync Sign").State

# No pending Windows Updates
Get-WindowsUpdate 2>$null   # PSWindowsUpdate; or check Settings → Windows Update

If everything passes, you're ready to capture. Continue to Capturing the image.