midi-harbor/specs/013-windows-support/plan.md
2026-09-28 13:59:10 -05:00

89 lines
6.6 KiB
Markdown

# Implementation Plan: Windows support
**Branch**: `002-windows-support`, this spec's original name | **Date**: 2026-09-26 | **Spec**: [spec.md](./spec.md)
**Input**: Feature specification from `/specs/013-windows-support/spec.md`
## Summary
Give each of the four platform seams a Windows implementation, move the two pieces that were
Unix-only outside the seams (the IPC transport and service installation) onto a Windows
equivalent, and cross-compile from macOS with mingw-w64. The Windows test machine runs the
cross-compiled test binaries; nothing is compiled on it.
## Technical Context
**Target**: `x86_64-pc-windows-gnu`, linked by `x86_64-w64-mingw32-gcc` (Homebrew `mingw-w64`),
configured in `.cargo/config.toml`.
**New dependencies**: `windows` 0.62, `windows-core` 0.62 and `windows-collections` 0.3, for the
WinRT classes of Windows MIDI Services, whose bindings `scripts/midi2-bindings` generates from
Microsoft's metadata with `windows-bindgen` 0.64; `windows-sys` 0.61 (already in the tree through tokio), for WinMM, the power
manager, DNS-SD, events and loading DLLs; `socket2` 0.6 (already in the tree), for dual-stack
sockets on every platform. `zeroconf` moves from the daemon to the platform crate and is not built
on Windows, where it would need Apple's Bonjour SDK.
**Test machine**: Windows 11 Pro 25H2 (build 26200), with rtpMIDI 1.1.14 and so teVirtualMIDI
1.3.0.43, and the Windows MIDI Services SDK Runtime and Tools RC4 (1.0.17-rc.4.25) against the
in-box service 10.0.26100.7705; no Bluetooth radio and no USB MIDI hardware.
## Decisions
| Area | Windows implementation | Why |
|---|---|---|
| Virtual ports | Windows MIDI Services virtual devices, one function block and group per connector: through `Windows.Devices.Midi2` when Windows registers it, otherwise through the App SDK runtime | teVirtualMIDI may not be distributed without its author's clearance. Windows carries the API from its late-2026 update; the App SDK serves until then (R-093). |
| Service calls | Each on a thread of its own, waited for 5 s, 30 s when opening a session; once one outlives its wait, virtual ports are refused until it returns | The service before the late-2026 update never answers a device's disconnection (R-093). |
| Devices | WinMM, input by callback into the ring, output by short and long messages | Every other interface's ports appear in WinMM. |
| Device identity | Interface path for hardware; name alone for application ports; this process's own ports by their connector names and by the service's group names | teVirtualMIDI numbers the halves of a port separately and renumbers them (R-086); the service before the late-2026 update names ports after groups (R-093). |
| Hot-plug | The lists compared once a second | WinMM announces nothing without a window to post to. |
| IPC | Named pipe, remote clients refused, random name recorded at the socket path | Tokio has no AF_UNIX on Windows; the recorded name keeps a file permission as the gate (R-087). |
| Stopping | A named event in the session namespace, set by `service stop` | Windows has no SIGTERM; ending the task would skip releasing notes. |
| Service | Task Scheduler logon task, interactive token, least privilege, normal priority, `conhost --headless` | A Windows service runs in session 0 and needs an administrator. |
| Crash restart | `daemon --supervise`, restarting after 2 s, doubling to 60 s while failures come quickly | Task Scheduler does not restart a program that exits with an error (R-083). |
| Advertising | The DNS Client service's `DnsServiceRegister`, looked up at run time | The system responder answers other machines for as long as the registration lasts; dots become hyphens (R-084). |
| Sockets | `IPV6_V6ONLY` cleared explicitly | Windows defaults to IPv6-only (R-085). |
| Sleep and wake | `PowerRegisterSuspendResumeNotification`, holding a suspend up to 1.9 s | The polled watcher runs underneath, as on the other platforms. |
| Bluetooth | Central through btleplug's WinRT backend; peripheral not built | No radio was available to verify either role; the central code is shared with the other platforms. |
## Constitution Check
- **I. Resilience**: crash restart by the supervisor; opens retried while the device list moves;
a stalled Windows MIDI Service costs virtual ports and nothing else.
- **II. Daemon owns state**: unchanged; the service is a logon task.
- **III. Real-time safety**: the WinMM and Windows MIDI Services callbacks only translate and scan
into the ring and, for WinMM, hand system-exclusive buffers back. They allocate, lock and log nothing. Buffers are
allocated when an input opens.
- **IV. Parity**: every seam has a Windows implementation except the BLE peripheral, declared in
the Platform Support Matrix and reported unavailable (amendment 1.1.0).
- **V. Protocol correctness**: unchanged code; a Windows daemon joined a session with Linux.
- **VI. Testable without hardware**: device identity, port naming, UMP translation, message packing, service
definitions and the supervisor's pacing are pure and tested on every platform.
- **VII. Observable**: unchanged.
- **Unsafe code**: confined to the platform crate, each block with a `SAFETY` comment.
## Complexity Tracking
| Deviation | Why | Simpler alternative rejected |
|---|---|---|
| BLE peripheral not built on Windows | No Windows machine with a radio to verify it | Enabling `ble-peripheral-rust`'s WinRT backend unverified |
| A supervisor mode in the binary | Task Scheduler does not restart a failed program (R-083) | A task repeating every minute, which restarts after up to a minute and also restarts a daemon the user stopped |
## Project Structure
```
.cargo/config.toml the mingw-w64 linker for the Windows target
crates/platform/src/dll.rs run-time DLL loading
crates/platform/src/responder/ advertising: zeroconf, or DNS-SD on Windows
crates/platform/src/stop.rs the stop event
crates/platform/src/midi/windows.rs the backend behind the MIDI seam
crates/platform/src/midi/winmm.rs WinMM inputs and outputs
crates/platform/src/midi/wms/ Windows MIDI Services ports, in-box and App SDK
crates/platform/src/midi/ump.rs Universal MIDI Packet translation, tested everywhere
crates/platform/src/midi/winmm_identity.rs identity and message packing, tested everywhere
crates/platform/src/sysevents/windows.rs suspend and resume
crates/platform/tests/windows_midi.rs the Windows integration tests
crates/ipc/src/transport/windows.rs the named pipe
crates/service/src/taskscheduler.rs the logon task
crates/service/src/supervisor.rs restarting after a crash
scripts/midi2-bindings/ generating the Windows MIDI Services bindings
```