Commit Graph
3 Commits
Author SHA1 Message Date
dtourolle 43f70c4765 Build the Windows installer in CI
The fourth leg of build-and-test.yml, in the shape of the Android one:
an image workflow that builds docker/windows and pushes it tagged by
the directory's tree id, and a job inside that image that lints the
Windows target — the only place the cfg(windows) branches are ever
compiled by CI — builds, runs the smoke tests docs/windows.md §6
specifies, packages, installs and uninstalls under Wine, and uploads
the installer. Every step was run by hand in the same container first.

The spec's open list closes with this: the four §3.2 items, the
licence page, and the leg. What remains is what Wine cannot show, and
§10 now lists it as the first real Windows run's checklist.
2026-09-12 07:34:10 +02:00
dtourolle b718c70b11 Specify a Windows installer built by the Linux CI
The tree is closer to Windows than a Linux-only project usually is:
every image library, the TLS stack and the inference engine are pure
Rust, and dr-plat already keeps the Linux-only code behind cfgs with a
loud fallback where none exists for another platform. What remains is
a short list above dr-plat — five XDG path lookups, an xdg-open, the
secret store's third implementation, the models' lookup beside the
executable — and none of it touches core, which is the NFR-PORT-3 test
this would be the first real run of.

docs/windows.md decides the GNU target over MSVC-via-xwin, Vulkan only
as on every other platform, a per-user NSIS installer that leaves the
library alone on uninstall, and a CI leg in the shape of the Android
one. It is explicit about what a runner with no Windows can verify —
that it links, is PE32+, starts under Wine and installs under Wine —
and what it cannot, which is everything involving a real GPU driver.
Three FR-PLAT-WIN requirements and a channel row record the decisions;
the ordering puts a first cross-compile on the developer machine before
any container exists, because the list of cfg gaps is a reading of the
source and the compiler's list will be longer.
2026-09-11 23:30:16 +02:00
dtourolleandClaude Opus 5 95847e3a31 Say which channels v1 ships through, and that the Flatpak cannot reach a library
NFR-COMPAT-2 asks for the v1 channels to be stated, and says why in its own
second sentence: the channel decision and the storage design are coupled. There
was nowhere that statement lived. packaging/ held a PKGBUILD and a desktop
entry, which is a recipe rather than a decision, and the coupling the
requirement points at was therefore invisible.

docs/distribution.md states five channels and, more usefully, which two of them
exist only as promises. It also records what every channel has to get right
independently of format — the one identifier that appears in four places, the
metainfo, Vulkan being a requirement rather than a preference while NFR-R8 is
open, a secrets daemon being optional rather than required, and the LFS pointer
check that stops a package shipping 130 bytes where an 11 MB model should be.

§4 is the part worth reading. Preparing a Flatpak is what surfaced that
FR-PLAT-LIN-3 is not satisfied and cannot be satisfied by packaging alone: a
folder library is chosen by typing an absolute path into an EndpointOnly field
that checks it with std::fs, and nothing in the tree calls the FileChooser
portal. Inside a sandbox that path does not exist, so the launch screen refuses
it. Import fails one step earlier, because a sandboxed process reads its own
mount namespace and a card mounted on the host is not in it.

That is written down rather than fixed with --filesystem=host, and the argument
for not fixing it that way is §2: the Arch package and an AppImage both hand the
application the same unrestricted process the developer runs it in, so Flatpak
is the only Linux channel that tests whether a design assumed unrestricted
access. Granting the permission removes the only reason to ship it.

The reverse coupling on Android is recorded too. NFR-COMPAT-2 says Play
distribution is what makes ARCH §6.9 binding; §6.9 is verified rather than
assumed, so SAF is already unconditional and a sideloaded build would gain
nothing by asking for more. Play is deferred over the GPLv3 question, which is
a licence-reading exercise and blocks nothing in the storage design.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-29 20:18:20 +02:00