## Open questions

- **Dashboard upload path ambiguity** — Two upload structures documented in [`dashboard-upload/`](dashboard-upload/) (Path A session 0x01 FF-prefix vs Path B session 0x04 sub-msg 1/2). Not yet confirmed whether these are:
  - (a) Two different upload paths firmware supports in parallel
  - (b) Same path described from different capture/understanding eras (one is stale)
  - (c) Different firmware versions (2026-04 vs 2025-11)

  Plugin currently implements Path B. Needs side-by-side capture on both firmware versions to resolve whether Path A is still needed on older firmware.

- **Dashboard byte limit configuration** — stored at config object offset `+0x30`, set during dashboard upload (group 0x40). Exact mechanism for setting this limit not yet traced.

- **Cold-start initialization** — EEPROM persistence across power cycles confirmed for channel config; unclear for session state.

- **MDD (standalone dash)** — no captures of telemetry sent to device 0x14; protocol may differ.

- **Dashboard upload: per-field pacing** — Plugin sends all upload chunks (across all 3 FF-prefixed fields) in a single burst, then waits for ack. PitHouse may instead pace by field: send field 0 chunks → wait for ack → send field 1 → wait → send field 2. Burst approach matches how tier definitions are sent (also tight-loop, working). If large dashboards fail while small ones succeed, try adding per-field ack waits.

- **Dashboard upload: seq=2 assumes port=1** — Data chunks on mgmt session start at seq=2, assuming session open used seq=1 (i.e. mgmtPort=1). Session open frame uses seq=port, so data should start at port+1. Since serial port is exclusive (PitHouse cannot run simultaneously), port probing always finds ports 1 and 2, making seq=2 correct in practice. Same assumption in tier definition code (seq=3, assumes telemetry port=2). If this changes (e.g. multi-client over network), both need to use `port + 1` instead of hardcoded values.

- **EEPROM direct access** — group 10 protocol found in rs21_parameter.db but never observed in USB captures; needs live verification.

- **Partner-API teardown on iRacing exit** — Plugin replicates PitHouse's iRacing-engage path (`base-feedforward` grp 0x2A cmd 0x40, `base-high-freq-torque` grp 0x2A cmd 0x41, `base-motor-run-state` grp 0x2C cmd 0x01 — see `Sdk/Resources/Motor/Motor{Feedforward,HighFrequencyTorque,SetMotorRunState}Resource.cs`). These writes persist to EEPROM (Tables 11 and 5 per firmware `param_manage.c` log echoes). **Unverified:** does PitHouse re-write these to a "disabled" value when iRacing exits or PitHouse disengages? If yes, the wheel stays in iRacing mode after a non-iRacing sim takes over, and the plugin needs a matching teardown path. Need a capture of iRacing-exit → 30 s idle (or PitHouse close) to see if a parallel CoAP DELETE / write-zero occurs. The 2026-05-23 capture ran for 215 s post-POST with no teardown write observed but did not include an exit event.

- **PitHouse UDP control protocol — additional PacketIds.** Plugin implements PacketId 3 (SteerLock write) and PacketId 4 (SteerLock read) on the plain-CBOR UDP control surface at port 40288 — see [`pithouse-udp/README.md`](pithouse-udp/README.md). These are the only IDs the RallySimFans launcher uses. PitHouse almost certainly handles others (FFB strength write, profile switching, calibration triggers, possibly volume / chime / LED commands) on the same port. The plugin's `MozaControlUdpServer` logs unknown PacketIds at sample 1/60. **Capture-driven follow-up:** one PitHouse session with the configuration UI exercised end-to-end (rotation, FFB, profile load, calibrate) would surface the full PacketId catalog. Extension on our side is one handler class per ID; no listener changes needed.

- **PitHouse UDP control — `Version` field semantics.** PacketId 3 (write) carries `"1.0.0"`; PacketId 4 (read) carries `"1.0.4"`. Plugin currently accepts any string. Open whether PitHouse rejects unknown versions or treats the field as advisory — affects whether we need to pin allowed versions per-PacketId or accept everything.

- **PitHouse UDP control — settings.ini write-out.** Real PitHouse persists its UDP port to `%USERPROFILE%\Documents\Moza Pit House\settings.ini` `[Application] udpPort`, which third-party clients (RSF observed) read to discover non-default ports. Our plugin defaults to 40288 but does not write the file — so a user with `MozaPluginSettings.ControlUdpPort` set to anything else would be unreachable by clients that only do file-based discovery. Decision needed before shipping a non-default port: either write the file (clean PitHouse-replacement behaviour) or document the port override requirement out-of-band.

- **PitHouse UDP control — `ReplyPort=0` behaviour.** RSF's client treats local-bind-port-0 as "abort the read" (it never sends the request in that case). PitHouse's server-side behaviour when it does receive a request with `ReplyPort=0` is untested. The plugin's `PitHouseReplyContext.SendReply` drops with a debug log; if PitHouse instead replies to the source port, we may need to match that.

- **PitHouse UDP control — multi-base topology.** The protocol envelope has no device-id field — implicit assumption is one wheelbase per machine. RSF only ever talks to a single base. If a user attaches two bases, both servicing the same write is almost certainly wrong; needs a survey of real PitHouse behaviour before any multi-base shipping.

- **Base ambient LEDs** — groups 32/34 commands found in rs21_parameter.db; not captured in USB traces (requires base with LED strips).

- **Wheel LED groups 2-4** — Single (28), Rotary (56), Ambient (12) groups found in rs21_parameter.db; only groups 0 (Shift/RPM) and 1 (Button) confirmed in captures so far. Plugin commands exist for `1F [G] FF [N]` per-LED color, `1B [G] FF` brightness, `1C [G]` mode. Brightness-read probe is **unreliable** as a presence check (firmware acknowledges reads for parameters with no physical hardware; confirmed on base KS wheel which has no rotary/ambient hardware but responds to all three probes). No live telemetry equivalent (`25 G` / `26 G` bulk+bitmask) confirmed for groups 2-4. **Group 3 (Rotary) per-LED live telemetry attempted 2026-05-19** — speculative wide-form `0x1A 0x03` (u64 active + u64 window, 16-byte payload) with `0x19 0x03` chunks carrying contiguous ring indices 0..47 (CS Pro). Wheel lit each knob as a whole unit only; firmware did not honour per-LED indices. Per-LED live path is **not supported** on current CS Pro firmware (W17). Static path (`0x1F 03 01 [idx]`) remains the only way to drive individual ring LEDs.

- **Group 0x09 semantics** — presence/ready check sent first during probe. Response `00 01` may indicate sub-device count (VGS has 1 Display sub-device). Needs verification with other wheel models.

- **Group 0x28 / 0x29 purpose** — group 0x28 queries base for per-device parameters (values 450, 1000 seen); group 0x29 sets base parameter (value 1100). Possibly FFB or calibration related.

- **Session-0x01 `ff` push: `kind` field semantics** — host→wheel property pushes (see [`findings/2026-04-29-session-01-property-push.md`](findings/2026-04-29-session-01-property-push.md)) carry a `kind:u32` field whose meaning is unclear: brightness=0/25/41/50 use `kind=1` (transient slider) while brightness=100 baseline uses `kind=14` (persisted re-emit), and standby uses `kind=10` (u64 ms duration). Open whether `kind` is a property-id table, a value-encoding selector, or both. Capture other property pushes (RPM colors, flag colors, indicator modes) to disambiguate. Also: are there pushes with `size > 12` (strings, colour triplets, multi-field structs)?

- **Sess=0x02 init kind=8 / kind=11 per-session content** — Canonical doc: [`sessions/session-0x02-ff-init.md`](sessions/session-0x02-ff-init.md). The wheel requires `kind=2 + kind=7 + kind=8 + kind=11` on session 0x02 before it will honour `kind=4` dashboard-switch records. Plugin currently emits only `kind=2 + kind=7`, so dashboard switches are silently ignored. Verified 2026-05-13: shipping the captured `Resources/sess02_init_kind{8,11}_pithouse.bin` bytes verbatim on every `StartInner` cycle **locks the wheel** within a handful of restart cycles (W17 / CS Pro hardware, required physical power-cycle). The records carry session-bound state (kind=2 offsets 12..15 vary per capture; kind=8 body size grows monotonically across a single PitHouse session). Re-enabling kind=8/11 emission requires decoding the inner structure and building per-session-correct bodies — see [`sessions/session-0x02-ff-init.md`](sessions/session-0x02-ff-init.md) for the required-work list and [`findings/2026-05-07-sess02-ff-kinds-reference.md`](findings/2026-05-07-sess02-ff-kinds-reference.md) for the partial body decode.

- ~~**Dashboard switch wire signal**~~ — VERIFIED 2026-04-30/05-01. Primary: FF-record on session 0x02, 25-byte payload. Slot = **0-based** index into `configJsonList` (alphabetical names from session 0x09), **NOT** `enableManager.dashboards`. Verified against live wheel: slot→dashboard mapping confirmed correct. PitHouse re-sends tier-def ~800ms later (no preamble, just enable/tier/end records). Secondary: `0x3F 0x17 27:[page]` per-page fingerprint write (state sync, not the switch trigger). See [`findings/2026-04-30-dashboard-switch-3f27.md`](findings/2026-04-30-dashboard-switch-3f27.md). Remaining work: channel catalog uses `\x01` prefix post-switch (parser expanded to handle both forms); tier-def timing needs ~800ms delay after FF-record for correct catalog indices.

- ~~**Tier-flag → package_level mapping inverted between plugin paths**~~ — RESOLVED 2026-04-29. Type02 firmware uses **flag=2 = fastest tier**, NOT flag=0. Wheel binds widgets to the highest flag value. Plugin's `TelemetrySender.Profile` setter now expands single-pkg_level profiles to 3 tiers and assigns the fastest pkg_level to tier 2 (flag=2). Confirmed live: Nebula widgets render value updates only when fast-tick frames carry flag=2.

- ~~**Telemetry-flag count vs package_level count**~~ — RESOLVED 2026-04-30. PitHouse multi-pkg-level dashboards emit `4 broadcasts × N sub-tiers per broadcast`, where each broadcast's sub-tiers cover all `package_level` rates; flag bytes increment monotonically across all sub-tiers. Single-pkg-level dashboards use 3 broadcasts × 1 sub-tier. Plugin formula: `broadcasts = (subCount == 1) ? 3 : max(4, subCount + 1)`. See [`tier-definition/version-2-compact-vgs.md`](tier-definition/version-2-compact-vgs.md) for the full pattern.

- **PitHouse per-dashboard sub-tier split source** — PitHouse's Grids tier-def splits 8 channels into 5+2+1 across `pkg_level` 30/500/2000 sub-tiers, but `Data/Telemetry.json` marks all 8 as pkg=30 only. PitHouse must source the split from somewhere outside `Telemetry.json` (likely embedded in PitHouse's own dashboard catalogs). Plugin currently uses `Telemetry.json` pkg_level grouping (8+12 split for Grids); wheel still renders successfully because tier-def is internally consistent and widget binding goes through channel idx, not flag/sub-tier position. Open whether PitHouse's split is just metadata or actually changes wheel-side decoding behaviour.

- **Type02 inferred compression codes** — `0x10` (`tyre_pressure_1`), `0x11` (`tyre_temp_1`), `0x12` (`track_temp_1`), `0x13` (`oil_pressure_1`), `0x15` (`float_600_2`), `0x16` (`brake_temp_1`) appear in plugin's `TierDefinitionBuilder.CompressionCodes` table marked as "inferred". Live R5+W17 capture 2026-04-30 confirms `0x10`/`0x11` are NOT decoded — tyre widgets stay at 0 until plugin switches the URL to `float` (`0x07`, width 32). Other inferred codes still untested; assume broken on Type02 until proven otherwise. May be valid on older firmware (VGS/CS/KS) but no live capture on those wheels uses tyres.

- **Plugin Telemetry.json sparse SimHub mappings** — As of 2026-04-30, `Data/Telemetry.json` contains 454 channel sectors but only ~17 have non-empty `simhub_property` / `simhub_field`. ABS/TC + 8 tyre channels mapped 2026-04-30; ~437 sectors still rely on the heuristic fallback in `DashboardProfileStore.PickCompressionForUrl` for compression and have no live SimHub data binding. Backfilling these is mechanical (most match `DataCorePlugin.GameData.<URL_suffix>` 1:1); needs a sweep + verification per dashboard.

- ~~**Plugin V0/Type02/V2 dispatch**~~ — RESOLVED 2026-04-29. Type02 firmware uses the **V2 bit-packed `7d:23` path with LEGACY N convention (N = 8+data, NOT 10+data)**. Plugin's `useV0Values = ProtocolVersion == 0` check at `TelemetrySender.cs:2257` routes to V2; `type02NConvention=false` is hard-set in the Profile setter so frames have N=14 instead of N=16. Verified byte-identical to PitHouse 2026-04-29 nebula capture, wheel renders correctly. Earlier guess that Type02 needs V0 chunked path was wrong.
