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 |
|
||||
|
||||
+15
-16
@@ -5,27 +5,24 @@ CLAUDE.md ("Working rules").
|
||||
|
||||
## Current state
|
||||
|
||||
- **Iteration 1, phase 2 (planning and design) started.** Phase 1 is approved (D13);
|
||||
[REQUIREMENTS.md](REQUIREMENTS.md) is the baseline.
|
||||
- **Iteration 1, phase 2 (planning and design).** Phase 1 is approved (D13);
|
||||
[REQUIREMENTS.md](REQUIREMENTS.md) is the baseline. High-level architecture done
|
||||
([DESIGN.md](DESIGN.md)); MVP details next.
|
||||
|
||||
## Next steps
|
||||
|
||||
Phase 2: first the high-level architecture, then the details for the MVP (D8, plus DSH-1 by
|
||||
D28). High-level
|
||||
questions, in this order:
|
||||
Phase 2: the high-level architecture is done (D16–D30, [DESIGN.md](DESIGN.md)). Next, the
|
||||
details for the MVP (D8, plus DSH-1 by D28), in this order:
|
||||
|
||||
1. ~~Process model~~: one process, several threads (D16).
|
||||
2. ~~Layers~~: presentation, business logic, I/O (D17).
|
||||
3. ~~How features plug in~~: object classes (D18), configuration injection (D19), one class
|
||||
per HA entity type with native types preferred (D23).
|
||||
4. ~~HA channels~~: MQTT for the device, own channel for the dashboard later (D24).
|
||||
5. Overlay kinds: dashboard tabs and world overlays (D25), one notification overlay (D26),
|
||||
MVP placement (D27); DSH-1 web UI test in the MVP (D28).
|
||||
6. Runtime model: which work runs in which thread (D16: several threads).
|
||||
7. Test strategy at a high level.
|
||||
1. Topics and payloads: topic scheme, device and entity ids, discovery content, MVP entity
|
||||
list, retain and availability.
|
||||
2. MVP notification: command format and title (MQTT `notify` drops the title).
|
||||
3. Configuration file format, incl. TLS/CA settings.
|
||||
4. Shipping libmosquitto (build, package, licence text).
|
||||
5. NFR-3 measurement method.
|
||||
|
||||
Details afterwards (MQTT library done: D14, D15): topics and payloads, basic notification,
|
||||
configuration, packaging of libmosquitto.
|
||||
Then the platform changes (start-up hook D21, desktop modes D22, world overlay D25, WebEngine
|
||||
initialisation for DSH-1) and the implementation plan for iteration 1.
|
||||
|
||||
## Log
|
||||
|
||||
@@ -42,6 +39,8 @@ configuration, packaging of libmosquitto.
|
||||
present (relevant for Q2/Q3).
|
||||
- libmosquitto ABI check: Debian's 2.0.21 needs at most `OPENSSL_3.0.0`/`GLIBC_2.34`; the
|
||||
Frame has OpenSSL 3.2.1 and glibc 2.39. No libcjson dependency. D14 holds.
|
||||
- Test strategy in four levels (D30). High-level architecture done.
|
||||
- Threads: MQTT client in its own thread, everything else incl. OpenVR in the main thread (D29).
|
||||
- DSH-1 split: web UI out-of-the-box test in the MVP, full dashboard as DSH-2 (D28).
|
||||
- Overlays: two kinds (D25), one overlay for all notifications (D26), MVP placement "spawn in
|
||||
front, then stay" (D27). Researched notification UI in VR (DESIGN.md, Appendix A). Found:
|
||||
|
||||
Reference in New Issue
Block a user