Skip to content

feat(simu): unify UI automation harness - #7668

Draft
bultodepapas wants to merge 13 commits into
EdgeTX:mainfrom
bultodepapas:docs/simu-ui-automation-consolidation
Draft

feat(simu): unify UI automation harness#7668
bultodepapas wants to merge 13 commits into
EdgeTX:mainfrom
bultodepapas:docs/simu-ui-automation-consolidation

Conversation

@bultodepapas

@bultodepapas bultodepapas commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Fixes: N/A

Summary

This draft is the single collaborative replacement direction for the overlapping simulator UI automation work in #7337 and #7646.

It keeps the strongest parts of both:

It deliberately leaves out duplicate or product-specific surfaces: the WIDGET_STUDIO build option, simulator-only Lua simu API, append-only command-file transport, native PNG encoding, and MCP integration.

Delivery

This branch and this draft PR contain both the plan and implementation. There is no second implementation branch and no branch per phase.

  • Technical baseline 0T passed at 0c07a3d648a929732190ab9b7378a7f6c272ab55.
  • Phase 1 at 05672defb9 adds the bounded SDL-independent protocol and state model.
  • Phase 2 at 91638a4b1e adds opt-in cross-platform non-blocking stdio transport and SDL-loop integration.
  • Phase 3 at 035df2770f adds the dependency-free Python session/CLI lifecycle, strict status/describe discovery, and real first-frame readiness.
  • Phase 4 at f957a23c76 adds target-filtered key/rotary/touch primitives, release-all, real-LCD frame barriers, timed host composites, and cleanup fallback.
  • Phase 5 at 1992a3d805 adds render-complete RGB565 capture, static-screen LVGL invalidation, exclusive PPM publication, verified host-side PNG conversion, deterministic SHA-256 metadata, and focused coverage.
  • Phase 6 at 5bc741d203 adds switch/analog/telemetry state injection, generation-observed Lua reload, deterministic warm restart, and isolated cold process restart.
  • Phase 7 at c6afd45793 adds the strict flow runner, minimal TX16S fixture, representative smoke scenario, verified run manifest, protocol/stderr logs, artifact hashes, and one-command developer workflow.
  • Phase 8 at 34fbdb1ee7 hardens stdout backpressure and shutdown, adds exact protocol boundary coverage, isolates Emscripten sources, adds the reproducible hardening runner, and introduces Ubuntu/Windows host CI. Commit e3fb2b7f22 records the completed local evidence and the still-open external gate.

The plan records the Phase 6 owner/thread and restart invariants, the Phase 7 strict-schema and fixture contract, and the Phase 8 backpressure deviation, hardening matrix, scope-isolation evidence, and R01–R04 runner coverage.

Contract review G0 remains open. It is required before this PR leaves draft or is merged; it does not block small reviewable implementation commits.

Phase 5 design

  • Capture uses simuLcdBuf at a strictly newer simuLcdNotify, not SDL texture readback.
  • A one-shot flag asks the firmware-owned LVGL loop to invalidate a static screen.
  • The LCD callback performs one bounded copy into preallocated RGB565 storage; conversion and filesystem work run on one session worker.
  • The native artifact is canonical P6 PPM, published without replacing an existing path.
  • The dependency-free Python client strictly validates PPM, writes and independently decodes PNG, and records stable hashes and capture metadata.
  • Capture is advertised only by tested 16-bit LCD targets. Native capture remains excluded from Emscripten/WASM.

Phase 6 design

  • Switches stay on the SDL owner thread and use the existing simulator switch driver; analog overrides use one lock-free packed atomic per discovered ADC input.
  • Telemetry and Lua requests cross into firmware context through fixed 16-entry SPSC request/completion queues, with at most two requests consumed per periodic UI cycle.
  • Telemetry reuses the existing Lua telemetry path while temporarily and locally enabling explicit sensor allocation; repeated tuples update the same sensor.
  • Lua reload succeeds only after the requested generation is observed in running; interpreter panic is a correlated failure.
  • Warm restart joins firmware tasks, starts a new epoch before the first new frame can arrive, and preserves a process-monotonic display sequence.
  • Cold restart fully reaps the old child, copies immutable settings and SD-card fixtures into a unique run directory, and returns a new session object.
  • Automation startup skips interactive splash/calibration checks; normal simulator startup is unchanged. Native-only guards keep the runtime out of physical firmware and WASM builds.

Phase 7 design

  • The dependency-free flow interpreter validates the entire canonical schema before launching and rejects unknown fields, duplicate JSON keys, undeclared capabilities, unsafe names, and out-of-range target values.
  • Every run copies the immutable TX16S settings and SD-card templates into a unique writable directory; the source fixture hash is checked again after execution.
  • The representative flow covers readiness, key/rotary/touch input, switch/analog/telemetry injection, Lua reload, a real frame barrier, static PPM/PNG capture, release, and clean stop.
  • The run manifest records environment, commit, target/LCD, fixture and flow hashes, every step and protocol exchange, artifact SHA-256 values, termination, and exact failure step. Protocol and bounded stderr remain separate.
  • The minimal fixture derives from Add TX16S UI harness #7337 and is migrated to the current settings schema; its generated CRLF representation is preserved cross-platform.

Phase 8 hardening

  • Stdout responses are written outside the SDL loop by a dedicated writer thread with a bounded 128-record FIFO and a 64-record high-water admission limit.
  • POSIX handles non-blocking EAGAIN; Windows teardown cancels a blocked synchronous write before joining. Stop flushes cooperatively without blocking an SDL iteration.
  • The edgetx-ui harden command creates isolated fixture/run directories and emits one machine-readable report covering process reaping, 10,000 requests, Lua generations, restart epochs, captures, hashes, fixture integrity, and temporary-artifact cleanup.
  • Exact 1,024-byte capture paths and 16-KiB request/response limits plus their overflow cases are covered natively.
  • The protocol, capture, and stdio implementation are excluded from Emscripten. Physical firmware and WASM artifacts were independently inspected for automation strings and symbols.

Provenance

The implementation provenance from source PRs is recorded in the technical plan and commit history. Progress updates will not tag individual accounts.

Current validation

  • Host suite: 71/71 tests pass on Windows and 71/71 in the clean Linux container; Python byte-compilation and workflow YAML parsing pass.
  • Native suite: 173/173 radio tests pass with AddressSanitizer in the clean Linux container; the final Windows TX16S simulator compiles and links with Clang 22.
  • Full real TX16S hardening passes: 100/100 lifecycle cycles reaped, 10,000/10,000 correlated pings, 20/20 Lua generations, 20/20 warm restart epochs, and no stale completion crossing epochs.
  • Slow-reader testing preserved 64 ordered responses after 500 ms without draining stdout; the 64/65 boundary returned 64 correlated responses plus one queue_full event and stopped cleanly.
  • 20/20 static PPM/RGB captures are byte-identical; a deliberate rotary mutation changes the framebuffer. The fixture remains unchanged and no temporary artifacts remain.
  • TX16S WASI artifact: 5,233,532 bytes, zero automation markers.
  • TX16S physical ARM firmware: 1,612,948-byte BIN, zero automation strings in BIN/ELF and zero automation symbols in ELF.
  • The Phase 8 head passed 49/49 repository checks, including the new Ubuntu and Windows host jobs.

This PR intentionally remains draft. Technical Phase 8 hardening and CI are complete; explicit contract review G0 is the remaining gate before it can leave draft.

@bultodepapas

bultodepapas commented Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

Correction to the delivery rule above: this effort now stays deliberately simple.

Implementation proceeds in this same draft PR and branch; there is no second implementation branch and no branch per phase. G0 remains an explicit review requirement before the PR leaves draft or is merged, but it does not block small implementation commits.

Phase 1 is now concrete at 5139415071686414f19fa6227e9bdd0835da8080: one pure bounded protocol/state module plus focused tests, with no SDL transport or runtime activation yet. Local validation passed 122/122 tests with ASan, and the complete GitHub test/build/documentation/packaging matrix is green.

@onliner10 and @pfeerick are invited to review this concrete slice and shape the next one. Credit and provenance from #7337 and #7646 remain explicit, and neither source PR needs to close until parity is demonstrated.

@bultodepapas bultodepapas changed the title docs(simu): plan unified UI automation harness feat(simu): unify UI automation harness Aug 17, 2026
@bultodepapas

Copy link
Copy Markdown
Contributor Author

Phase 2 is now published at c1be4bd5fb on this same branch and draft PR.

This slice adds the opt-in cross-platform stdio transport and SDL-loop activation while keeping the scope narrow: ping and stop work now; input, telemetry, Lua, restart, and framebuffer capture stay for later phases.

Validation completed:

  • 129/129 gtests-radio tests passed with ASan in the official Linux environment;
  • native Linux simulator built and passed real-pipe probes, including clean JSON-only stdout, EOF, malformed input, queue limits, paths with spaces, and dormant normal mode;
  • parser/protocol/transport compiled on Windows with both Clang and MinGW under -Wall -Wextra -Werror;
  • POSIX and Windows protocol vectors produced the same byte hash;
  • strict documentation build and git diff --check passed.

The implementation intentionally does not add a permanent Python client yet; a disposable probe was enough to validate this transport slice. @onliner10 and @pfeerick remain invited to review the contract and retained behavior before the draft is marked ready.

@bultodepapas

bultodepapas commented Aug 18, 2026

Copy link
Copy Markdown
Contributor Author

Phase 3 slice 3A is now published at 49f2e3db9b on this same branch and draft PR.

This keeps the scope intentionally narrow: a dependency-free, binary-pipe Python session and minimal edgetx-ui probe for the native commands that exist today (ping and stop). It adds strict ID/JSON validation, separate bounded stderr draining, command deadlines, crash detection, and guaranteed process/thread cleanup without select or startup sleeps.

Validation:

  • 22/22 focused tests pass with warnings treated as errors on Windows Python 3.11 and official-image Linux Python 3.10;
  • the suite includes malformed/partial stdout, wrong/repeated IDs, stderr flooding, command errors, crash, timeout, terminate fallback, CLI failure exit, and 100 subprocess cycles on each host;
  • the real Linux TX16S simulator built and completed 100 start/ping/stop cycles with exit code zero and no live reader thread;
  • the exact CLI also passed end-to-end with SDL offscreen and paths containing spaces;
  • strict docs and git diff --check pass.

Credit: the reusable host-session and CLI direction comes from #7337 by @onliner10. I reviewed that implementation, but this protocol-v1/Windows-safe lifecycle is a substantial rewrite with no coherent source block copied; the provenance ledger records that distinction. A co-author trailer remains intentionally absent unless approved.

Phase 3 remains open for a real Windows-simulator run, explicit kill-fallback injection, and status/frame/capability readiness. @onliner10 and @pfeerick are invited to review this concrete host boundary before those pieces are added.

CI update: the complete GitHub test, firmware-build, documentation, and packaging matrix passed for this head (45/45).

@bultodepapas

bultodepapas commented Aug 18, 2026

Copy link
Copy Markdown
Contributor Author

Phase 3 is now complete at f6c104e on this same branch and draft PR.

This final slice adds only the readiness boundary needed before inputs: bounded status/describe responses, target/LCD/command/capability validation, and startup completion after the simulator owns a real first LCD frame. It intentionally does not advertise or implement input, capture, telemetry, Lua, or restart yet.

Validation completed:

  • 29/29 host tests pass with warnings as errors on Windows Python 3.11 and official-image Linux Python 3.10, including 100 lifecycle cycles on each host and forced kill-then-wait cleanup;
  • 131/131 native TX16S tests pass;
  • the real Linux simulator completes 100 readiness/stop cycles without an orphan;
  • the exact current Windows simulator build completes ping/describe/first-frame-ready/stop with paths containing spaces and exit code zero;
  • git diff --check passes.

Thank you again, @onliner10 and @pfeerick. This slice combines the reusable host-session direction from #7337 with the guarded epoch/first-frame model from #7646. Please review the resulting boundary and help shape Phase 4 inputs; G0 remains open before this draft can be marked ready.

CI update: the complete current-head GitHub Actions and CodeRabbit matrix passed 45/45 for f6c104e.

bultodepapas added a commit to bultodepapas/edgetx-GR that referenced this pull request Aug 18, 2026
Implement Phase 4 of the consolidated simulator automation plan: target-filtered key, rotary, and touch primitives; an asynchronous real-LCD frame barrier; host-side timed composites; release cleanup; and focused native/Python coverage.

This combines the portable host-side composition direction from EdgeTX#7337 with the direct simulator helpers and explicit touch transitions explored in EdgeTX#7646. Thanks to Mateusz Urban (@onliner10) for the original harness direction; review remains explicitly invited in EdgeTX#7668.
@bultodepapas

Copy link
Copy Markdown
Contributor Author

Hi @onliner10 — Phase 4 of the consolidated simulator UI automation work is now available in this PR.

Thank you again for the work and direction you established in #7337, especially the reusable host-side harness and action model. Those ideas have materially shaped this consolidation, and I have tried to keep that provenance clear in both the plan and the PR history.

I would genuinely value your review of the protocol, host API, and retained behavior before this draft is marked ready. Please feel free to challenge the design or suggest a simpler direction where appropriate.

If you are comfortable with commit-level attribution for the parts substantially derived from your work, I would also be happy to add a Co-authored-by trailer. I will not rewrite commit history or use an email address without your approval; if you would like that attribution, please confirm the GitHub-associated email you prefer (a GitHub noreply address is completely fine).

No pressure either way — your review and feedback would already be greatly appreciated.

@bultodepapas

Copy link
Copy Markdown
Contributor Author

Phase 5 is now published at bfd59db236 on this same branch and draft PR.

This slice adds one focused capability: render-complete framebuffer capture. It combines the portable PPM and host-conversion direction from #7337 with the static-screen invalidation requirement explored in #7646. Native capture waits for a strictly newer RGB565 framebuffer, publishes without replacing an existing artifact, and keeps file I/O out of the LCD notification. The Python client validates the PPM, converts and independently decodes PNG, and writes deterministic SHA-256 metadata.

Validation is complete:

  • 34/34 focused native tests pass under AddressSanitizer;
  • 49/49 host tests pass;
  • the Windows TX16S simulator compiles, links, and captures through real binary pipes;
  • 20 static captures are byte-identical with increasing display sequences;
  • an ENTER interaction produces a different framebuffer hash;
  • Unicode-and-space paths work, metadata hashes match, and no temporary artifacts remain;
  • the complete current-head GitHub matrix passes 45/45.

Thank you, @onliner10, for the original harness and capture direction in #7337. I would especially value your review of the freshness boundary, artifact contract, and host API. @pfeerick, your review of the simulator/LVGL integration would also be very welcome. G0 remains open, so the PR stays draft.

@bultodepapas

bultodepapas commented Aug 18, 2026

Copy link
Copy Markdown
Contributor Author

Phase 6 is now published at ada9972144 on this same branch and draft PR. This slice completes the state/lifecycle layer without adding another control surface: discovered switches and analogs use the existing simulator drivers, firmware-owned telemetry and Lua work cross a bounded SPSC mailbox, warm restart completes on the first frame of a new epoch, and cold restart returns a new process backed by fresh fixture copies. Automation uses deterministic no-splash startup, while normal simulator behavior and physical/WASM builds remain outside the change. Final local validation: - 38/38 focused native SimuAutomation* tests pass under AddressSanitizer; - 57/57 host protocol/session tests pass; - the Windows TX16S simulator compiles and links; - a real run passed switch and analog control, telemetry create/update, generation-observed Lua reload, warm restart, and cold restart with a new PID and a fully reaped old child; - formatting, compileall, and git diff --check pass. Thank you again, @onliner10, for the reusable harness/session direction established in #7337. Phase 6 deliberately keeps that direction while integrating the state-injection and restart goals from #7646. I would genuinely value your review of the host API, mailbox boundary, and restart semantics, and any simplification or correction you would like to propose. @pfeerick, review of the firmware/UI hook placement would also be very welcome. Current-head GitHub Actions, firmware builds, documentation, packaging, and CodeRabbit passed 45/45. G0 remains open, so the PR stays draft.

@pfeerick

Copy link
Copy Markdown
Member

Just a friendly FYI ... tell your AI assistant to be less eager to tag and mention people... it's the quickest way to get yourself ignored if you are pinging people every couple of hours. Commits generally also speak for themselves if well written and described, so iteratively updating the initial PR body post would have been more than sufficient here, and better than individual progress comments with each commit, as the posts here also flow into things like discord channels, meaning there are will be several effectively "noise" posts there about this PR.

Add a dependency-free binary-pipe session for the implemented start, ping, and stop lifecycle, with strict response correlation and bounded cleanup tests.\n\nThe reusable host-session and CLI direction builds on EdgeTX#7337 by Mateusz Urban. This implementation is substantially rewritten for protocol v1, Windows-compatible reader threads, and deterministic process cleanup; no coherent source block is imported.
Add bounded status and describe responses backed by the simulator session state, then validate discovery and poll first-frame readiness from the cross-platform host session.

This consolidates the host lifecycle and discovery direction from EdgeTX#7337 with the guarded epoch and first-frame state model from EdgeTX#7646. Credit to @onliner10 and @pfeerick for the two approaches brought together here.
Implement Phase 4 of the consolidated simulator automation plan: target-filtered key, rotary, and touch primitives; an asynchronous real-LCD frame barrier; host-side timed composites; release cleanup; and focused native/Python coverage.

This combines the portable host-side composition direction from EdgeTX#7337 with the direct simulator helpers and explicit touch transitions explored in EdgeTX#7646. Thanks to Mateusz Urban (@onliner10) for the original harness direction; review remains explicitly invited in EdgeTX#7668.
Capture a strictly newer RGB565 framebuffer after an LVGL invalidation, publish deterministic PPM artifacts without replacement, and convert them to verified PNG metadata in the host client.

This combines the portable PPM and client direction from EdgeTX#7337 with the static-screen invalidation approach from EdgeTX#7646.

Thanks to @onliner10 for the original harness and capture direction.
@bultodepapas
bultodepapas force-pushed the docs/simu-ui-automation-consolidation branch 2 times, most recently from 651220c to c6afd45 Compare August 31, 2026 21:11
The fixture layout and declarative scenario requirements derive from EdgeTX EdgeTX#7337. The implementation is rewritten for the consolidated v1 protocol.
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.

2 participants