D029 - Contracts and swappable backends, abstracted at guest semantics
decided ยท 2026-08-19
Nothing is hardcoded where a contract will do. One graphics backend exists today; adding another must never require surgery on the translator.
The refinement that makes this work: abstract at the
level of what the guest asks for, not what the host API
provides. A RenderBackend trait designed by looking at
Vulkan ends up carrying descriptor sets, render passes, and explicit
barriers - and then a second backend fits badly anyway, because one
API's model got baked into the contract. Each backend maps guest
semantics onto its own primitives. Same rule for audio (submit samples
at a rate, not WASAPI concepts), input (pad state, not XInput), and
filesystem (guest path semantics, not Win32).
The test for whether a seam is premature: if it only
pays off hypothetically, it is speculation. If it buys testability or
swappability now, it is structural. The render backend passes -
a RecordingBackend lets command-stream translation be unit
tested with no GPU, no window, and no driver, on CI and in the Linux
VM.
Any string that crosses a boundary is a named constant declared once
- env var names, path components, config keys, protocol message names.
The pub const ENV_PORTABLE pattern, carried from another
project of mine.