Release notes

SIRECORD

Release notes — broadcast verification platform running on Korra OS.

Every release is cryptographically signed, SHA-256 verified on delivery, and applied atomically with automatic rollback on health-check failure. Stations receive updates over-the-air every 6 hours on Linux and Korra OS appliances.

Changelog

All notable changes to GlueArrow Box OS will be documented in this file.

The format is based on Keep a Changelog.

[1.6.6] - 2026-05-01

Fixed — Tauri sidecar lifecycle (root cause of every "Connect screen scans forever" report since v1.6.0)

src-tauri/src/main.rs stored the spawned CommandChild as a local variable inside setup(). Tauri's CommandChild::Drop kills the spawned process — so the moment setup() returned, the api.exe sidecar got killed and the connect screen had nothing to find. Pressing "Launch OS" at the end of the wizard then opened the main window pointing at http://localhost:5002/, which loaded blank (dead socket). Fix: CommandChild now lives in a Tauri-managed handle that keeps it alive for the app's lifetime. Receiver is drained on tauri::async_runtime and forwarded into the log file as [sidecar] lines.

Fixed — complete_setup blank-window race

After Launch OS, complete_setup opened the main window before the sidecar was actually ready. The new window loaded a dead socket and rendered blank — even on machines where the sidecar would have come up a second later. complete_setup and complete_dj_setup now wait for the sidecar to bind before opening the window.

Fixed — Tauri updater plugin actually fires now

The endpoint + pubkey was wired since v1.6.0 but the plugin never queried — Tauri v2's updater plugin requires explicit plugin:updater|check invocation; endpoint config alone is not enough. frontend/connect.html now invokes the check 2 seconds after DOMContentLoaded and surfaces a confirm dialog when an update is available. From v1.6.6 onward OTA works without uninstall + reinstall.

Fixed — Phone field is no longer Ghana-only

v1.6.5 had +233 XX XXX XXXX as the phone placeholder + a Ghana-only regex. The platform ships globally per pricing v1.3 (Africa GHS + Diaspora USD). v1.6.6 replaces the input with a country-code dropdown (15 starter countries) plus a local-part input. New /api/setup/geo-default endpoint auto-defaults the dropdown to the operator's network country with a graceful fallback to GH if the IP lookup fails.

[1.6.5] - 2026-04-29

Added — Live system telemetry on the producer-desk status bar

  • CPU / MEM / DISK percentages now populate on every sync_pulse_update_system_telemetry() runs once per run_automation() tick (~1 s cadence) and writes psutil.cpu_percent(), psutil.virtual_memory().percent, psutil.disk_usage(...).percent onto SERVER_STATE. The producer-desk JS already gated on data.cpu !== undefined so the status bar lit up immediately after the first pulse instead of staying on --% forever.
  • psutil is lazy-imported inside the helper — first attempt put import psutil + a pre-warm cpu_percent(interval=None) at module load, which made the PyInstaller --onefile bundle hang silently at boot before reaching socketio.run(). The fix moves the import inside _get_psutil() so the Flask app is up and serving long before psutil is touched. Any future bundling-side issue with psutil's native .pyd surfaces as a logged exception during the first sync_pulse rather than an opaque silent boot hang.

Operational note — first-boot time on Defender-active machines

PyInstaller --onefile extracts the bundle (~645 MB) to %TEMP%\_MEIxxxxxx\ on every spawn. On Windows machines with active real-time antivirus scanning, that extraction can take several minutes the first time as Defender inspects every freshly-written .pyd and .dll. Subsequent launches reuse the cached extraction and are fast. If first-boot consistently exceeds 5 minutes, add a Defender exclusion for %TEMP%\_MEI* and C:\Program Files\GlueArrow Control\ (admin-required).

[1.6.4] - 2026-04-29

Added — Pre-ship smoke test gate

  • tools/preship_smoke_test.py — every shippable bundle is now gated by a static + runtime test suite. Static checks read tauri.conf.json, api.py, templates/setup.html, and frontend/connect.html and refuse the build if any historical fix from v1.6.0–v1.6.3 has regressed (CSP connect-src http:, flask_cors.CORS(app), custom User-Agent on cloud calls, focusFirstInput() + autofocus). Runtime checks boot dist/api.exe on a free port and probe /health (incl. ACAO header), /api/station/config, /api/license/validate. Optional Playwright check drives headless Chromium against /setup and asserts the licence input accepts keyboard input.
  • build.py --smoke gatebuild.py runs preship_smoke_test.py after every build and exits non-zero if it fails. --no-smoke exists for local iteration only; never used for shipped builds.

Fixed

  • Setup wizard licence input dropped keyboard focus on first paint — WebView2 sometimes leaves the page focused but no element selected after a navigation, so the operator could click the licence field and see no keystrokes register. focusFirstInput() now runs after each step transition (goTo()), on DOMContentLoaded, and on the first user interaction (mousemove/focus) as a belt-and-braces fallback. The licence input also gets the autofocus HTML attribute. Same fix mirrored to frontend/connect.html for the manual-IP input.
  • Cloudflare WAF blocked outbound licence calls with HTTP 403 (error 1010)cloud.gluearrow.com is fronted by Cloudflare, whose default ruleset blocks any User-Agent matching Python-urllib/x.y. The Box's licence-validate proxy now sends User-Agent: GlueArrow-Box-OS/1.6.4 on every cloud call. Workaround for v1.6.3 installs: set cloud_url in %APPDATA%\glueArrow Box OS\station_config.json to https://gluearrow-admin-h5ouzu4p7q-uc.a.run.app (no Cloudflare).

[1.6.3] - 2026-04-29

Fixed

  • Tauri webview couldn't read sidecar responses — v1.6.2 fixed the CSP at the webview layer but the Python sidecar still rejected the cross-origin request. Wired flask_cors.CORS(app, resources={r"/*": {"origins": "*"}}) so every endpoint serves Access-Control-Allow-Origin. Same change opens socketio = SocketIO(app, cors_allowed_origins="*", ...). Box OS only runs on the operator's own machine + LAN so a permissive policy is correct here.
  • build.py picked stale .sig filesos.listdir() is unordered, so when both v1.6.2 and v1.6.3 .sig files were left in the bundle dir from successive builds, [0] would silently grab the older one and write it into latest-tauri.json alongside the new MSI URL — Tauri then refused every OTA update because the downloaded MSI's bytes didn't match the embedded signature. Sort sig files by mtime descending so the freshest always wins.

[1.6.2] - 2026-04-29

Fixed

  • Tauri webview blocked fetch() to the local sidecar — added an explicit app.security.csp to src-tauri/tauri.conf.json with connect-src 'self' tauri: http: https: ws: wss:. Without this the webview default CSP blocked every fetch from connect.html to http://127.0.0.1:5002/health, so the connect screen always showed "No boxes found / Could not reach GlueArrow Box at 127.0.0.1:5002" even when the sidecar was healthy.
  • build.py bundled stale api.exe under the target-triple name — Tauri's externalBin lookup expects api-x86_64-pc-windows-msvc.exe. build.py was only copying to api.exe, leaving the older target-triple file in place and shipping a broken sidecar. Now copies to both names every build.

Added

  • UTF-8 stdio everywherelaunch.bat, start_server.bat, main.js (Electron path), and deploy/gluearrow-box-os.service now set PYTHONUTF8=1 + PYTHONIOENCODING=utf-8 so the Python sidecar's emoji prints don't crash boot on Windows under cp1252 codepage.

[1.6.1] - 2026-04-28

Fixed

  • First-install MSI shipped with a broken sidecar — v1.6.0's bundled api.exe was missing the python-engineio packet drivers because the rebuild skipped the PyInstaller step that copies the sidecar into src-tauri/binaries/. v1.6.1 rebuilds the sidecar from clean and verifies it boots before signing the Tauri MSI. v1.6.0 installs need a one-time manual reinstall before OTA can take over.

[1.6.0] - 2026-03-27

Added

  • AES-256-CTR encryption.glue v2 format for audio file protection, matching SmartVault v2 implementation; cryptographically secure, 141x faster than v1 XOR

Changed

  • v1 backward compatibility — existing XOR-encrypted .glue v1 files remain readable; all new encryptions use AES-256-CTR v2

[1.5.0] - 2026-03-26

Added — Geo-Priority Scanning, Artist Reference & Cloud Scan Log

  • Baked-in artist reference (artist_reference.py) — 200+ major artists across all continents with country codes and genres; ships with every Box OS build; works fully offline for artist recognition from filenames
  • Geo-priority scanning — vault scanner sorts audio files by country relevance before processing. Three-layer scoring: exact artist match from baked-in reference (+20), partial match in filename (+15), folder keyword hints (+10)
  • Auto-detect country from IP — when STATION_COUNTRY env var is not set, falls back to ip-api.com detection before scanning
  • Cloud scan log — every file scanned (matched/duplicate/submitted/audd) is logged to Playtunes cloud vault_scan_log with original_name, corrected_title, match_method, country_hint, session_id, and status
  • Cloud artist merge — fetches /artists/countries from Playtunes when online and merges new artist data into the baked-in reference
  • Country keyword hints — 8 countries supported (GH, NG, KE, ZA, TZ, US, GB, JM) with genre and location-based folder matching

[1.4.0] - 2026-03-24

Added — PlaytunesDJ Workspace, Production Engine & Bug Fixes

  • PlaytunesDJ workspace — new ws_playtunesdj.html + ws_playtunesdj.css for music library browsing, playback queue, and vault scan trigger; 14th workspace in the control panel
  • /api/music/library endpoint — returns paginated local music library (tracks + total) for PlaytunesDJ workspace, backed by fingerprint_db.get_all_tracks()
  • Command Center (Owner) workspace updates — new ws_owner.html with network overview and cloud control features
  • PlaytunesDJ play context + vault ownership — play context integration for DJ sessions with SmartVault ownership tracking
  • Constants re-export shimstatic/js/constants.js re-exports from control/constants.js to fix broken ES module resolution for viewer-side video.js
  • Logo placeholder — transparent 1x1 PNG at static/graphics/logo.png prevents 404 noise in graphics overlay templates (replace with station logo)

Changed

  • Heartbeat exponential backoff_cloud_heartbeat_loop() now backs off from 10s to 5 minutes on repeated failures (doubles each cycle), resets to 10s on success; only logs the first failure to eliminate log spam when offline
  • /news endpoint fix — replaced sqlite3.Row.get() calls (which don't exist) with direct row["key"] access; fixes AttributeError that caused the endpoint to return empty data

Fixed

  • /news returning empty default_schedule and calendar due to sqlite3.Row not supporting .get() method
  • Heartbeat flooding logs with warnings every 10 seconds per station when cloud is unreachable
  • /static/js/constants.js returning 404 due to static/js/video.js importing ./constants.js relative to itself
  • /static/graphics/logo.png returning 404 in lower-third overlay templates

[1.3.0] - 2026-03-21

Added — SmartVault Pro Integration & Build Pipeline

  • SmartVault Pro batch scanner — new batch_scanner.py runs gevent-based batch scanning with pause/resume, incremental scans, and intra-session deduplication; processes 40,000+ songs in batches with persistent per-file status tracking
  • FTS5 full-text search — new fingerprint_db.py with SQLite FTS5 virtual table for sub-200ms search across title, artist, album, genre; includes cursor-based pagination for 1M+ row result sets
  • Scan session management — new scan_db.py tracks scan sessions with drive fingerprinting (survives USB drive letter changes), file registration in 500-file chunks, and batch processing with resume
  • Offline submission queue — new offline_manager.py detects connectivity loss, queues vault submissions, and retries up to 3 times when connection restores
  • Virtual scroller component — new frontend/js/virtual-scroller.js renders 40,000+ songs with only 15-20 DOM elements at 60 FPS; fixed 44px row height with 5-row buffer
  • Live scanner dashboard — new frontend/stream-scanner.html with SSE-powered real-time drive discovery, song count, elapsed time, and drive selection
  • Library scanner page — new frontend/library.html with session history, status filters (identified/pending/unidentified/error/duplicate), file detail expansion, CSV export, and jump-to-page pagination
  • 25+ new API endpoints — batch scan control (/api/batch/scan/*), session queries (/api/batch/session/*), file detail/retry (/api/batch/file/*), FTS5 search (/api/search, /api/search/cursor), connectivity (/api/connectivity), SSE song discovery (/api/songs/stream), fingerprint stats, submission status
  • Tauri scanner/library windowsopen_scanner and open_library commands registered in main.rs for native desktop window management
  • OTA auto-update systemlaunch.bat checks GCS for sidecar updates with SHA-256 verification and atomic swap; deploy/update-box-os.sh for Linux/Korra OS with automatic rollback on failure
  • systemd update timerdeploy/gluearrow-update.timer checks for updates every 6 hours with 30-minute randomized delay to prevent thundering herd
  • Build pipeline — new build.py with version stamping across api.py, tauri.conf.json, package.json; PyInstaller sidecar compilation; SHA-256 manifest generation
  • Cloud Build CI/CD — new cloudbuild.yaml with test, syntax check, sidecar build, Linux tarball packaging, and optional GCS publish steps
  • Release publishing — new publish_update.py uploads versioned builds to GCS with channel support (stable/beta/dev)

Changed

  • api.py — imported and initialized SmartVault Pro modules (fingerprint_db, scan_db, offline_manager, batch_scanner); added all batch scan routes, SSE streaming, FTS5 search, and connectivity endpoints
  • main.rs — registered open_scanner and open_library Tauri commands; added window builders for scanner (1200x800) and library (1200x800) windows
  • deploy/install-linux.sh — now copies SmartVault Pro modules (fingerprint_db.py, scan_db.py, offline_manager.py, batch_scanner.py) and frontend/ directory; installs OTA update timer
  • requirements.txt — added qrcode[pil] for DJ registration QR codes
  • api.spec — superseded by build.py (dynamic PyInstaller invocation with hidden imports and data bundling)

[1.2.0] - 2026-03-21

Added -- Cross-Platform Support & Linux Appliance Architecture

  • Platform compatibility layer -- new platform_compat.py auto-detects Windows, macOS, or Linux and provides correct config paths, FFmpeg capture inputs (gdigrab/avfoundation/v4l2+pulse), subprocess flags, process priority, and network interface detection
  • Device scanner -- new device_scanner.py enumerates audio/video capture devices on all three platforms (dshow on Windows, avfoundation on macOS, v4l2-ctl + pactl on Linux)
  • GET /api/devices endpoint -- returns available audio and video devices for the setup wizard
  • macOS support -- config stored in ~/Library/Application Support/GlueArrow Box OS/, video capture via avfoundation, audio via avfoundation
  • Linux production deployment -- config in /etc/gluearrow-box-os/, data in /var/lib/gluearrow-box-os/, video via V4L2, audio via PulseAudio
  • systemd service -- new deploy/gluearrow-box-os.service replaces service_wrapper.py and watchdog.py on Linux with built-in auto-restart (Restart=always), hardware watchdog (WatchdogSec=30), and rapid-restart protection (StartLimitBurst)
  • HDMI kiosk mode -- new deploy/gluearrow-kiosk.service and deploy/gluearrow-kiosk.sh launch Chromium in full-screen kiosk mode showing God Mode (?ws=god) when an HDMI monitor is plugged in; auto-detects display connection, hides cursor after 3s inactivity, recovers from crashes
  • Linux installer -- new deploy/install-linux.sh one-command script installs all system dependencies (Python, FFmpeg, Chromium, PulseAudio, V4L2, X11), creates gluearrow system user, sets up Python venv, and enables both systemd services
  • Dynamic VLAN interface detection -- sync_engine.py setup_linux_vlans() now auto-detects the primary network interface instead of hardcoding eth0

Changed

  • api.py, streamer.py, sync_engine.py, restream_engine.py, obs_bridge.py -- replaced hardcoded %APPDATA% config paths with platform_compat.get_config_path() for cross-platform support
  • streamer.py -- FFmpeg pipeline now uses platform-detected video/audio inputs, subprocess launch flags, and process priority boosting via platform_compat; reads device names from station_config.json
  • README.md -- rewritten with cross-platform architecture diagram, workspace table, and dual deployment instructions (Windows + Linux)
  • STATION_ONBOARDING.md -- rewritten as v2.0 with separate instructions for GlueArrow Box hardware (plug-and-play) and Windows PC deployment

[1.1.0] - 2026-03-18

Added — Speaker Calibration, Show Lineups & Tally-to-Speaker Bridge

  • Speaker syncsync_engine.py now pulls calibrated_speakers and show_lineups from Cloud PostgreSQL to local SQLite (local_speakers, local_show_lineups) with MD5 hash-based change detection
  • Speaker creation with cloud pushPOST /api/speakers creates speakers locally and pushes to Cloud API; uses negative temp IDs as offline fallback
  • Voice sample capturePOST /api/speakers/<id>/voice saves .webm voice recordings locally and proxies to Cloud
  • Cross-station speaker searchGET /api/speakers/search proxies to Cloud for network-wide search with local fallback when offline
  • Show lineup managementGET/PUT /api/shows/<id>/lineup and GET /api/shows/current/lineup for assigning speakers to shows with mic channel mapping
  • Tally-to-speaker bridge_resolve_speaker_from_source() maps tally camera sources (cam1-8, mic_ptt, desktop) to calibrated speakers via current show lineup; broadcast_tally() now emits speaker_active with real speaker IDs
  • PTT speaker resolutionradio.js fetches current show lineup on init and resolves PTT speaker ID from mic_ptt channel assignment instead of hardcoded "presenter"
  • Planner lineup UIws_planner.html show detail panel now includes lineup management with search (local + network-wide), mic channel dropdown, inline "Calibrate New" quick-add, and drag-to-reorder
  • Producer desk wiringws_producer.html guest calibration now persists to backend via /api/speakers, searches calibrated speakers network-wide (shows "CALIBRATED" badge), captures 10-second voice samples during mic preview, and auto-loads current show lineup on workspace open

[1.0.0] - 2026-03-13

Added

  • Broadcast automation engine with schedule-driven show switching, 5-tier video failover (stream, camera, main file, program backup, general fallback, system loop), and gevent-based real-time loop
  • Flask-SocketIO control plane for real-time broadcast commands between controller UI and server
  • RTMP/HLS streaming via FFmpeg-based RTMPStreamer with live encoding and segment output
  • Schedule management with SQLite-backed local schedule, CRUD API, Excel import, downloadable templates, and per-show source mode configuration (file, link, camera)
  • Show planner with per-show configuration for video sources, headlines, fallback paths, stream URLs, camera devices, and social metadata overrides
  • Tally system with program/preview bus state, TSL UMD address mapping, and real-time tally API
  • Vision mixer controls — take (cut), fade, and stinger transitions between preview and program via SocketIO
  • Source switching — set preview and program sources (cam1-3, desktop, fallback, bars, black, graphics) with SocketIO events
  • OBS Studio bridge connecting to OBS WebSocket v5 for scene switching, stream start/stop, and status monitoring
  • Restream engine with Restream.io API v2 integration, OAuth2 token lifecycle, multi-platform metadata push (titles, descriptions, hashtags), and auto-social on show change
  • Cloud Relay pusher — background thread watches local HLS folder and pushes .ts segments + .m3u8 playlists to cloud CDN, with 5-second heartbeat
  • YouTube integration with API key storage and stream status monitoring
  • Multi-destination streaming — manage multiple RTMP destinations with CRUD API
  • Station registration with cloud sync, QR-code pairing flow, and Bearer token authentication for all cloud API calls
  • Station configuration API with local config persistence in station_config.json
  • User authentication with local registration, login, QR-session claiming, and user listing
  • License validation endpoint for station licensing
  • Sync engine — bidirectional PostgreSQL-to-SQLite schedule synchronization with cloud, offline-first architecture, VLAN-aware networking
  • SmartVault scanner — standalone drive scanner generating Chromaprint DNA fingerprints, Playtunes DB fingerprint checks, AudD API fallback identification, and pending track submission
  • Music library with drive detection, audio file scanning (mp3, flac, wav, aac, ogg, m4a, aiff, wv, opus), search, and local HTML5 playback with path traversal protection
  • DJ setup workflow for music library configuration
  • Vault scan jobs with SSE (Server-Sent Events) progress streaming
  • Play logging with local ledger and cloud sync via /api/music/sync-ledger
  • Playtunes API proxy forwarding requests to GlueArrow Cloud Playtunes endpoints
  • Artist claims system with local CRUD and cloud sync
  • Music clips per-show assignment with ordering and CRUD operations
  • Ad bid management — create, list, accept/reject ad bids with expiration tracking
  • Marketplace bookings — view, accept/reject bookings, and slot management with cloud sync
  • Traffic log API aggregating daily play counts, ad impressions, and revenue from local database
  • Front desk with visitor check-in, clock-in/out, and attendance tracking
  • QR check-in system with QR code generation and SocketIO-based scan handling
  • Staff check-in via PIN verification with SocketIO events
  • Owner dashboard APIs for detection history and team management
  • News ticker API serving current headlines from schedule data
  • AI Verify content safety system with keyword-based flagging (banned terms) and review queuing (sensitive terms)
  • Prometheus metrics endpoint (/metrics) with circuit breaker failure tracking
  • Health check endpoint for service monitoring
  • VLAN setup wizard with managed switch auto-detection
  • Watchdog process monitor with auto-restart, rapid-restart protection, and Windows Task Scheduler compatibility
  • Service wrapper for running Box OS as a Windows background service
  • Structured logging with JSON format for production (GCP Cloud Logging compatible)
  • Producer commands via SocketIO for remote show control
  • Caller/speaker management via SocketIO for live call-in shows
  • Station heartbeat system for cloud connectivity monitoring
  • Test suite with pytest for API routes, streamer, and sync engine

Security

  • Bearer token authentication for all cloud API calls using station_token from local config
  • Path traversal protection on music file serving (realpath validation against allowed root)
  • Drive path validation blocking .. directory traversal on scan endpoints
  • Circuit breaker pattern on schedule API with Prometheus failure tracking

Looking for security advisories? See the Security Whitepaper or email security@gluearrow.com.