Design: threads and test strategy; high-level architecture done
D29: only the MQTT client runs in its own thread; OpenVR and the HA layer stay in the main thread. D30: four-level test strategy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+50
-3
@@ -1,14 +1,41 @@
|
||||
# Design
|
||||
|
||||
Status: **in progress**, iteration 1, phase 2 (planning and design). High-level architecture
|
||||
first, then the details for the MVP. Requirements and their decisions (D1–D15):
|
||||
done; next: the details for the MVP. Requirements and their decisions (D1–D15):
|
||||
[REQUIREMENTS.md](REQUIREMENTS.md). Design decisions start at D16.
|
||||
|
||||
## Process and threads
|
||||
|
||||
- **One process** started by SteamVR does everything: HA connection, sensors, services, all
|
||||
overlays (D16).
|
||||
- Several threads inside it for concurrent work. Which work runs in which thread is still open.
|
||||
- Several threads inside it for concurrent work (D16). **A thread is added only where work can
|
||||
block** and would stall rendering and SteamVR events (D29):
|
||||
|
||||
| Thread | Runs |
|
||||
|---|---|
|
||||
| main | Qt event loop, QML, off-screen rendering of all surfaces, SteamVR event polling and texture submission, **all OpenVR calls** (I/O wrappers), HA device and entities, managers |
|
||||
| MQTT | the MQTT client (libmosquitto): DNS lookup, TCP and TLS connect block for seconds when the broker is unreachable |
|
||||
|
||||
- OpenVR stays in the main thread: it isn't documented as thread-safe, and all events come
|
||||
through one queue.
|
||||
- The boundary is three signals with value arguments (queued connections):
|
||||
|
||||
```
|
||||
main thread MQTT thread
|
||||
HA device ── publish(topic, payload) ──▶ MQTT client
|
||||
HA device ◀── messageReceived(topic, payload) ── MQTT client
|
||||
HA device ◀── connectionChanged(state, error) ── MQTT client
|
||||
```
|
||||
|
||||
- The MQTT client lives in its thread via `moveToThread()`; it creates its socket notifiers
|
||||
and timers there, after the move.
|
||||
- Not needed as own threads: WebEngine (own processes), Qt Multimedia and QtNetwork
|
||||
(asynchronous), later D-Bus and `QProcess` for network/audio (asynchronous). Rendering stays
|
||||
in the main thread as long as NFR-3 holds.
|
||||
- Rules: no direct calls on objects of another thread (signals or
|
||||
`QMetaObject::invokeMethod` with `Qt::QueuedConnection`); lambdas connected across threads
|
||||
always get a context object; no `BlockingQueuedConnection`; only values, no shared
|
||||
pointers, cross the boundary.
|
||||
|
||||
## Layers
|
||||
|
||||
@@ -160,7 +187,25 @@ Notes for later:
|
||||
|
||||
## Open
|
||||
|
||||
1. High-level points 3–7 (see [PROGRESS.md](PROGRESS.md), "Next steps").
|
||||
1. MVP details (see [PROGRESS.md](PROGRESS.md), "Next steps").
|
||||
|
||||
## Test strategy
|
||||
|
||||
Four levels (D30), implementing NFR-8:
|
||||
|
||||
| Level | What | How | Where |
|
||||
|---|---|---|---|
|
||||
| 1. Unit tests | configuration (CFG-2), discovery payloads, throttling (SEN-14), availability logic (SEN-15), entities, notification manager | QtTest with **fakes at the boundaries**: a fake MQTT client for the three signals (D29), fake I/O wrappers instead of OpenVR | host and test container, `ctest` |
|
||||
| 2. Integration tests with a real broker | CON-1–4: connect, last will when killed, reconnect after broker restart, login/TLS | the test starts a local `mosquitto` on a free port (host: installed; test container: add the package) | host and test container, `ctest` |
|
||||
| 3. UI and rendering | main tab and notification cards, transparency | existing tools: `--snapshot`, `tst_render`, desktop modes | host |
|
||||
| 4. Manual | against the user's HA: entities appear, no deprecation warnings (NFR-7). On the Frame: sensors, notification in VR and in a game, DSH-1, premultiplied alpha, NFR-3 | checklist per iteration, results documented in `docs/` | user's HA, the Frame |
|
||||
|
||||
- OpenVR wrappers stay thin; logic goes into the testable parts behind them. The wrappers
|
||||
themselves are only checked on the device (level 4).
|
||||
- HA itself is tested manually for now (an HA container would be possible but costly);
|
||||
revisit later (NFR-8 allows adjusting the strategy).
|
||||
- The NFR-3 measurement method is a detail (idea: compare SteamVR compositor statistics, e.g.
|
||||
missed frames, with and without FrameAssistant).
|
||||
|
||||
## Appendix A: notification UI in VR (research)
|
||||
|
||||
@@ -222,3 +267,5 @@ Collected 2026-10-05 for the notification design.
|
||||
| D25 | 2026-10-05 | Two overlay kinds in the platform: dashboard tabs and world overlays (MVP: one placement, not interactive). Set `VROverlayFlags_IsPremultiplied`. Runtime surfaces and interactive world overlays later | Notifications need world overlays; Qt Quick renders premultiplied alpha |
|
||||
| D26 | 2026-10-05 | One world overlay for all notifications; QML lays out the cards | No runtime surfaces, fewer resources; per-notification placement isn't required |
|
||||
| D27 | 2026-10-05 | MVP notification placement: spawn in front (about 1 m, slightly below the line of sight), then stay | Research favours non-head-locked placement; no continuous tracking needed |
|
||||
| D29 | 2026-10-05 | Threads: only the MQTT client runs in its own thread; everything else, incl. all OpenVR calls and the HA layer, in the main thread. New threads only for work that can block | Blocking connect must not stall rendering; OpenVR isn't documented as thread-safe; the narrowest possible thread boundary |
|
||||
| D30 | 2026-10-05 | Test strategy in four levels: unit tests with fakes at the boundaries, integration tests against a local mosquitto, UI/render tools, manual checklist (user's HA, the Frame) | Covers NFR-8; the narrow boundaries (D29, I/O wrappers) make fakes cheap; HA automation deferred |
|
||||
|
||||
Reference in New Issue
Block a user