Domain objects stay pure
The test model holds data and Guids. It does not touch the file system, the network, or the display. Side effects live in services. That boundary is the rewrite’s north star — learned the hard way from a WinForms client where god objects talked to everything.
Infrastructure is injectable
WebSockets, packaging, image generation, validation, and dialogs are interfaces registered in DI. ViewModels consume contracts, not implementations. MediatR carries transaction events across that boundary so a handler never needs a window.
Geometry is computed, not guessed
Instruction regions, continue strips, and keyed layouts are derived from the interior and key positions. Designers can override; the calculator still owns the defaults. Previews stay locked to the same aspect as the administered test — one math, two surfaces.
Production means the unhappy path
A socket that works once is a demo. Persistent connections, cancellation, exponential backoff, thread-safe send, and transaction completion without tearing down the pipe — that is production. UTF-8 text frames, not binary, because the Java handler is a TextWebSocketHandler.
DTOs stay DTOs
ServerReport is a serializable payload, not an ObservableObject. The ViewModel maps it on the dispatcher and ignores empty reports so a mid-transaction reset cannot blank the Deploy tab. XAML never binds to TransactionState.
Security is a contract, not theater
Handshake is a challenge/response around AES of a random string — ProductKey, nonce, challenge, tag. That cut a WebSocket round-trip that existed only as “security for the sake of security.” Results at rest are AES-GCM plus asymmetric encryption so a stolen database is unreadable.