Skip to content

feat: LED preview surface, Hue transport correctness, and full IPC status-code coverage - #176

Merged
voyvodka merged 28 commits into
mainfrom
feat/led-preview-and-fixes
Aug 11, 2026
Merged

feat: LED preview surface, Hue transport correctness, and full IPC status-code coverage#176
voyvodka merged 28 commits into
mainfrom
feat/led-preview-and-fixes

Conversation

@voyvodka

Copy link
Copy Markdown
Owner

Twenty-three commits covering a correctness pass over the Hue transport and the
lighting hot path, the new LED preview surface, a contract-coverage overhaul,
and the first real test infrastructure for this app.

Correctness

  • Solid colour changes were silently dropped. The Hue health poll stripped
    targets from activeOutputTargets one way and never put them back, so the
    quick solid path saw an empty target set and updated the UI and the persisted
    state while nothing reached any device. It appeared to "heal itself" whenever a
    later slow-path mode transition repopulated the set. The poll is now a two-way
    reconciler keyed on the selected targets, and the Rust-side pending-colour
    flush no longer depends on a status code that the DTLS path never writes.
  • The HTTP fallback sender exceeded the bridge rate limit by roughly 66x.
    HUE_SENDER_MIN_INTERVAL_MS gated loop iterations rather than requests, and
    the timestamp was stamped after the whole fan-out, so an N-light area issued N
    writes per tick with no spacing. Replaced with a per-request pacer at 10 req/s,
    a 429/Retry-After arm in the classifier, and a single-threaded round-robin
    in place of the nested thread::scope.
  • DTLS handshake abandonment could race the deactivate token. The timeout
    branch now wins the token via a shared AtomicBool.
  • Live output ignored the registered WLED sink. ActiveSinkRegistry was
    populated but never read: Solid bypassed LedSink entirely, and the
    DEVICE_NOT_CONNECTED gate consulted only the serial state, so a WLED-only
    session was rejected outright. Colour correction and brightness now apply to
    the WLED path too.
  • Test patterns ignored the configured output settings — chip type, firmware
    profile, and colour correction were unset, driving an SK6812 RGBW strip
    through the WS2812B encoder and an Adalight controller through the LumaSync v1
    header, on exactly the hardware the test exists to verify.
  • The serial send rate under-budgeted RGBW by 33%, hard-coding three bytes
    per pixel in derive_base_interval_ms.

Performance

  • Per-frame LUT construction hoisted out of the ambilight worker loop; the
    previous-colour buffer is allocated only when Hue output is attached.
  • One shared, single-flight Hue area-readiness cache behind both poll paths:
    1.073 → 0.670 req/s measured.
  • Frontend: tray listener leak fixed, duplicate 1 Hz telemetry polls deduped,
    a 10 Hz edge signal no longer re-renders the lights section, and LedGlowDot's
    memo is effective again.
  • Fonts are declared directly instead of through seven aggregate imports, which
    removes the visible swap on load; live telemetry numbers no longer reflow the
    row they sit in.

LED preview

A digital-twin overlay and a control popup: patterns apply the moment they are
selected, the chase pattern is a true per-LED comet weighted by real perimeter
length and holding phase across the worker rebuild each tweak forces, edge
ribbons align with the dots they mirror, the overlay opens on the display chosen
in LED Setup, and the popup persists its position behind a single
always-available close. Hex input is validated and capped at six digits.

Contracts

Every status code crossing the IPC boundary is now declared and enforced by the
verifier, which grew from 221 to 274 checks: derived lighting parity, telemetry
field parity, VID/PID allowlist parity, and a phantom-code ratchet with six
baselined entries. Two transposed codes (UNSUPPORTED_PORT vs
PORT_UNSUPPORTED, PERMISSION_DENIED vs CONNECT_PERMISSION_DENIED) and a
harvest bug that truncated lighting_mode.rs at line 58 of ~3400 are fixed —
the Rust code harvest went from 135 to 198.

ShellState drops ledTwinEnabledLive, which was declared but neither read nor
written. The field was optional, so no schema bump is needed and on-disk states
are unaffected.

Tests

  • Twelve Rust IPC integration tests through tauri::test's mock runtime.
  • A six-test WebdriverIO E2E smoke suite via @wdio/tauri-service with the
    embedded driver provider — the only path that works on macOS, where WKWebView
    exposes no WebDriver endpoint.

Verification

typecheck, verify:shell-contracts (274/274), vitest (519 passed, 2 todo),
build, cargo fmt, clippy --all-targets --all-features -D warnings,
cargo test --all-features (398 + 36), and cargo audit all pass.

Not verified on hardware: the WLED output path (no device available), and the
comet rendering has not been watched live.

@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown

Dependency Review

The following issues were found:

  • ✅ 0 vulnerable package(s)
  • ❌ 1 package(s) with incompatible licenses
  • ✅ 0 package(s) with invalid SPDX license definitions
  • ✅ 0 package(s) with unknown licenses.
  • ⚠️ 53 packages with OpenSSF Scorecard issues.

View full job summary

@voyvodka
voyvodka merged commit cbe8d39 into main Aug 11, 2026
8 checks passed
@voyvodka
voyvodka deleted the feat/led-preview-and-fixes branch August 11, 2026 11:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant