Packaging: containerised CI, Flatpak/AppImage, bundled simd, licence notices, and release-please - #53
Conversation
The only existing CI (ci.yaml) triggers on tag push only, so PRs get zero build or test verification before merge. ENABLE_TESTS looked like a real test-suite toggle but was dead code: never declared as a CMake option(), tests/ had no CMakeLists.txt, and the root CMakeLists.txt instead had an always-on block (outside any ENABLE_TESTS gate) building a handful of tests/*.c files directly as loose executables - most of it commented out, and none of what was live was an actual assertion-based test. Investigating tests/ found nothing there was CI-runnable as-is: three stray committed compiled binaries (a.out, producer, test.bin), vendored third-party example code with no relation to monocoque's own logic (pa_devs.c/patest_longsine.c are PortAudio's own bundled examples; testlibusb.c/testrevburner.c derive from libusb-0.1-compat's own testlibusb example), and manual/interactive/hardware-dependent scratch tools (shared-memory pokers, one of which blocks on raw terminal input; USB/HID/serial device probes needing physical hardware). Removed the stray binaries, moved everything else into tests/manual/ so the split between "automated CI suite" and "manual dev tools" is structural rather than implicit, and built the actual plumbing: - ENABLE_TESTS is now a real option(), and the existing MONOCOQUE_SUBPROJECT guard block had enable_testing() running *after* add_subdirectory(tests) - backwards, meaning CTest would never have discovered any test added there. Fixed the order. - tests/CMakeLists.txt registers one real test via CTest. - confighelper_test.c: a genuine headless unit test (strtodevsubsubtype's string->enum mapping, including the R8/R3->MOZAR5 aliasing and the unknown-input fallback) to prove the plumbing actually works end to end - not an attempt at comprehensive coverage, just a real first case. strtodevsubsubtype already had external linkage but no header declaration; added one to confighelper.h. - .github/workflows/pr-build.yaml: new workflow (existing tag-triggered ci.yaml untouched) building the CLI + test suite and running ctest on every PR and push to master - closing the verification gap. Verified locally: both -DENABLE_TESTS=ON and the default (no flag) build succeed, and `ctest --test-dir build --output-on-failure` passes.
Adds a Flatpak manifest, AppStream metainfo, and CI workflow, mirroring the sibling typiql-tauri/typiql project's own (now fully proven) Flatpak pipeline where the same class of issues would otherwise apply -- using its final recipe from the start (ppa:flatpak/stable for a newer flatpak-builder with the appstreamcli-compose fallback) rather than rediscovering the same bugs. Also adds install() rules to CMakeLists.txt (none existed before; every existing deb/rpm packaging job hand-copies binaries out of the build dir instead) and makes tools/monocoque.desktop's Exec= relative (gmonocoque instead of /usr/bin/gmonocoque) -- both needed for a clean Flatpak install, and harmless for the existing system packaging since /usr/bin is always on PATH regardless. Seven dependencies (libconfig, argtable2, lua5.4, libserialport, libxdg-basedir, hidapi, GLU) aren't in the freedesktop runtime and are built from real, checksum-verified upstream sources as flatpak modules. UNTESTED against real CI at time of writing. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Confirmed via a failed local build: uv.h missing entirely (libuv wasn't in the dependency list at all), and a genuine, real CMakeLists.txt bug -- when pkg-config reports libproc2's version as the literal string "UNKNOWN" (a real packaging quirk, seen in the freedesktop Flatpak SDK, not flatpak-specific), VERSION_GREATER_EQUAL against it silently evaluates false and falls through to the old (pre-4.0.5) PIDS_VAL API, which then fails to compile against an actually-current libproc2 whose real header already uses the new 3-argument macro. Only take the old-API branch when the version string is genuinely parseable and actually old. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Confirmed via a failed local flatpak build: flatpak-builder's cmake-ninja buildsystem runs the automatic build+install step regardless of custom build-commands (they run in addition, not instead), so overriding what gets built there doesn't work around a target that fails during the automatic build. simlighttest fails to link (-lserialport not found, likely a directory-scoping issue since its add_executable() comes after where the working link setup applies to other targets) and isn't part of the actual product -- matching its already-commented-out neighbor (hidtest) and the same "stray scratch tool" characterization from the unmerged feature/ci-test-automation branch. Disabling it the same way. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Real CI run 33321176120 failed immediately on entering the monocoque module: "cp: cannot overwrite non-directory .../simapi/.git with directory .../flatpak-builder/git/https_github.com_spacefreak18_simapi". Self-inflicted: submodules: recursive in the checkout step populates simapi/nappgui_src with real .git files before flatpak-builder even starts, colliding with the manifest's own explicit `type: git` sources for those same paths. Local testing (a plain worktree checkout, which doesn't fetch submodules either) never hit this. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Real CI run 33322472461 confirmed appstreamcli hard-requires any desktop-application to have an icon at all (E: gui-app-without-icon), which the local build only warned about on a more lenient appstreamcli version. The real monocoque.svg is 100x50 (non-square, rejected by Flatpak's export). Added a local copy padded to a square 100x100 viewBox, vertically centering the original artwork via a <g transform="translate(0,25)"> rather than distorting it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The debian-latest, debian-stable and fedora-43 matrix legs used those names as `runs-on` labels, which only ever resolve to self-hosted runners. With none online they queued indefinitely -- four runs observed stuck between 17 and 60 minutes, only the ubuntu-latest leg ever completing, until cancelled by hand. Each distro now builds in its own container on an ordinary GitHub-hosted runner, so no self-hosted infrastructure is needed. matrix.os keeps the distro name (it selects the per-distro control file and names the released artifact); matrix.image is the container. Also adds a fedora-44 leg alongside 43, and fail-fast: false so one distro failing no longer cancels the rest. Supporting changes the container move required: - dependency install moved ahead of actions/checkout and desudo'd -- container jobs run as root, and these images ship no git, without which checkout silently skips the required submodules - actions/checkout@v1 -> v4 with submodules: recursive, replacing the manual `git submodule update` step - the rpm job gains a checkout and builds the spec from the tree rather than curl'ing it from upstream master, so a tag builds its own spec - the rpm output filename is globbed instead of hardcoding monocoque-0.0.5-1.x86_64.rpm, which only matched by coincidence Also adds workflow_dispatch for manual runs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two failures from the first container run (33324476177):
All three deb legs died at Configure CMake with `The source directory
"/home/runner/work/monocoque/monocoque" does not exist`. In a container
job the ${{ github.workspace }} expression still renders the *host* path,
while the repo is mounted at /__w/... inside the container. Switched to
$GITHUB_WORKSPACE, which is set to the container-side path.
The fedora-43 leg died downloading openh264 from Fedora's third-party
Cisco repo (`Curl error (7): Could not connect to server` for
ciscobinary.openh264.org). Transient rather than structural: fedora-44
pulled the identical package from the same repo successfully in the same
run. Wrapped the dnf install in a 3-attempt retry. Deliberately not
disabling that repo -- openh264 is pulled in even with weak deps off, so
something requires it outright and removing the repo would more likely
break resolution than help.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ture/packaging-release
Paul asked for an AppImage; this adds one and, per David, puts every artifact on a single release rather than spreading them across workflows. The AppImage builds on ubuntu-22.04 rather than ubuntu-latest on purpose: an AppImage only runs where glibc is at least as new as the one it linked against, so building on current Ubuntu would silently exclude older distros and defeat the point of shipping one. That runner also needs libprocps-dev instead of libproc2-dev, since 22.04 predates the procps-ng 4.x split -- CMakeLists.txt already accepts either. It populates its AppDir via the install() rules rather than hand-copying binaries the way the deb job does, which is what those rules were added for. The standalone flatpak.yml is folded in as a job here and deleted, so a tag produces deb + rpm + AppImage + Flatpak on one release. It keeps continue-on-error: the Flatpak leg is the newest and least battle-tested, and must never turn a release red or block the other artifacts. The square icon moves from flatpak/ to tools/monocoque.svg, since the AppImage needs a square icon for exactly the same reason the Flatpak did and there was no sense duplicating it. Flatpak rebuild re-verified locally after the move. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The AppImage leg failed on ubuntu-22.04 with `expected identifier or '('
before ':' token`. Root cause is the compiler, not packaging: simapi's F1
2018 headers use C23 enum-with-fixed-underlying-type (`enum TrackID :
uint8_t`), which GCC implements only from 13 onwards, and 22.04 ships GCC
11. Every passing leg builds in a container with GCC 15.
No -std= value rescues 22.04 -- verified separately that the construct is
gated on compiler version rather than the standard flag, so the fix is a
newer base rather than a flag. ubuntu-24.04 (GCC 13) is the oldest usable
one, which sets the AppImage's glibc floor at 2.39. Passing -std=gnu2x
explicitly because GCC 13 still defaults to gnu17, unlike the GCC 15 the
container legs get; gnu2x rather than c2x keeps GNU extensions on, which
simapi needs for asprintf. libprocps-dev reverts to libproc2-dev, which
24.04 has.
Worth raising upstream: this GCC 13+ requirement is undeclared, and it
constrains which distros can build monocoque at all.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… feature/packaging-release # Conflicts: # CMakeLists.txt
flatpak/repo is an OSTree object store -- running flatpak-builder locally produces ~1000 binary files there, and a `git add -A` swept 13 MB of them into this branch. Removed from history; ignoring them so it cannot recur. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Upstream releases currently ship with empty bodies -- 0.3.5 and 0.3.6 both have no notes at all. generate_release_notes lets GitHub assemble the merged PRs and commits since the previous tag, which is the accumulating changelog that was missing, at the cost of one line per upload step and no change to how anyone writes commits. This is deliberately the low-friction option. Proper version management (release-please) is a larger proposal since it needs Conventional Commits, which this history does not use. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Released packages have never carried their own version: the Debian control files hardcode `Version: 1` and fedora.spec hardcodes `Version: 0.0.5`, while real tags are at 0.3.6. Confirmed in shipped artifacts -- an rpm from tag pkgtest-2 installs as monocoque-0.0.5-1. Both are now stamped from the tag at build time, which also takes two hand-maintained values out of the release checklist. Stamped in CI rather than edited into the files so they remain working defaults for local builds. Guarded rather than applied blindly: deb and rpm versions must start with a digit, so a branch build (workflow_dispatch) or a non-release tag like `pkgtest-5` would otherwise make dpkg-deb and rpmbuild fail outright. Anything that doesn't look like a version falls back to 0.0.0; a leading `v` is stripped, so v-prefixed tags would work too. Guard logic verified against tag/branch/scratch-tag inputs. The AppImage carries no package metadata, so it gets the version in its filename instead -- monocoque-<version>-x86_64.AppImage. Both the artifact upload and release globs already match that. Each job now also echoes the identity it actually produced (dpkg-deb --field, rpm -qp) so a wrong version is visible in the log rather than only discoverable by unpacking the artifact. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
gmonocoque died with `cannot open display` under a Wayland session. The cause is not a missing Wayland socket -- a diagnostic inside the sandbox confirmed WAYLAND_DISPLAY=wayland-0 with /run/user/1000/wayland-0 present, and gmonocoque links both libwayland-client and libX11. nappgui goes to X11 regardless, and --socket=fallback-x11 is deliberately inactive whenever Wayland is available, so DISPLAY was empty and there was no X server to reach. Granting real --socket=x11 routes it through XWayland. --socket=wayland is retained in case the toolkit ever uses it directly, and --share=ipc is the standard companion to X11 access (MIT-SHM). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A real launch got a display (the x11 fix worked) but then failed twice: Failed to read config file '/home/david/.config/monocoque/monocoque.config' slog_open_file: Failed to open file: /home/david/.cache/monocoque/...log The manifest granted no filesystem access at all. monocoque builds these paths from $HOME directly -- "%s/.config/monocoque/diameters.config" in monocoque-cli.c -- rather than from XDG_CONFIG_HOME, so it reads and writes the host's real directories, which the sandbox hid. Granting the real directories rather than letting XDG redirection give it a private copy is also what makes a Flatpak monocoque agree with a native one, and what lets typiql (which reaches the same path, for the same reason) actually configure it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`monocoque play` inside the sandbox read its config, connected pulseaudio, and then sat at "setting initial app state" forever with simd running on the host -- never logging "Opening universal shared memory api". The cause is that Flatpak gives the sandbox a private /dev/shm: with simd up, `ls /dev/shm` returned 0 entries inside against 18 on the host, so simapi's mapping of /dev/shm/SIMAPI.DAT (simmapper.c) found nothing and simd looked absent. shm is its own device option -- the --device=all already in this manifest does not imply it. Re-running the identical command with --device=shm reached "Opening universal shared memory api" one second in. Also corrects the --share=network comment: the GraphQL API on port 9000 is typiql's own backend, not monocoque's. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…distros
Both artifacts were uninstallable on the distro they are built for, which no
amount of a green CI run shows -- the packages build fine, they just cannot
be installed:
ubuntu-latest (ubuntu:latest is now 26.04):
monocoque Depends libconfig9 but none of the choices are installable
debian-latest (debian:testing, i.e. forky):
monocoque Depends libxml2 but none of the choices are installable
The names had drifted: libxml2 became libxml2-16 with the soname bump, and
Ubuntu's t64 transition renamed libuv1, libcurl4 and libgtk-3-0. Checked each
name against apt-cache in the same images CI builds in, then verified by
repacking the released .deb with the corrected Depends: it installs on both
Ubuntu 26.04 and Debian forky, and `monocoque --help` runs on Ubuntu.
(On forky it then aborts in monocoquesettingsfree() -- a separate, real bug
in monocoque itself, not a packaging one.)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`monocoque --help` aborted with `free(): invalid pointer` on Debian forky -- found by installing the released debian-latest .deb on the distro it is built for. gdb put it in monocoquesettingsfree() called straight from main(). The early-exit paths (`--help`, `--version`, bad parameters) jump to cleanup_final before any field of Parameters or MonocoqueSettings is assigned, and cleanup_final calls monocoquesettingsfree() and freeparams(), which free every pointer in both. malloc leaves those pointing at whatever was in the heap block. It is undefined behaviour everywhere; forky's glibc is simply the first to check, which is why the same source looked healthy on Debian stable and both Fedoras. calloc in all three entry points -- monocoque.c, monocoque-cli.c (the `monocoque` binary) and monocoque-gui.c. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
gmonocoque died before drawing a window, in libconfig: #0 config_setting_get_member () from libconfig.so.9 #1 config_setting_lookup () #2 populate_device_list () find_default_config() required sim, api and car to all be present on an entry and skipped the entry if any lookup failed, so it returned -1; populate_device_list passed that -1 straight to config_setting_get_elem, got NULL back, and config_setting_lookup dereferenced it. No real config has all three. conf/monocoque.config -- the example this project's own README points at -- sets sim and car and never mentions api, so this crashed for anyone following the documentation. It stayed hidden in the Flatpak build only until that manifest was given access to the real ~/.config/monocoque; against an empty config there was nothing to look up. A key that isn't there no longer disqualifies a match, a -1 falls back to the first entry (which is what a single-entry config means anyway), and both NULL paths now return with a message instead of dereferencing. Verified by rebuilding the Flatpak and launching gmonocoque against the real config that crashed it: the window opens and stays up. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
monocoque does nothing on its own: with no daemon publishing /dev/shm/SIMAPI.DAT, simapi_get_sim() falls through to scanning /proc for the game itself. Packaging the two together makes a monocoque install usable rather than half of a working setup. simapi ships a BUILD_SIMD option in its own CMakeLists, but this tree never invokes it -- src/monocoque/simulatorapi compiles simapi's sources straight into a static `simulatorapi` library. The target is declared here over that same library instead, which also pins the simd in a package to the exact simapi commit monocoque itself was built against. Two things the static linking forced, neither of which upstream hits because it links libsimapi.so: - simd.c and simapi's getpid.c both define is_pid_running(). Against a shared library the executable's definition simply wins; against an archive the linker refuses the duplicate. simd's copy is renamed for its own translation units with a private -D, so both definitions survive and each caller stays bound to the one it was written against -- no patch to the pinned submodule, and no --allow-multiple-definition quietly picking a winner. - a static libyder.a records no dependency on orcania, so every o_malloc and split_string it calls comes back undefined. orcania is now named explicitly after yder, guarded by find_library so the distros whose shared libyder pulls it in on its own are unaffected. Also installs simapi's example simd.config to share/monocoque: without it simd still maps telemetry but logs "Disabling Automatic Bridge Mode" and never launches the Windows bridge under Proton. It can't be installed to $HOME the way simapi's own build does it, and simd looks for it via getpwuid() rather than $HOME. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Follows the new simd target through every packaging leg. deb: libyder-dev added to the build deps, libyder2.0t64 to all three control files (same name on Debian stable, Debian testing and Ubuntu 26.04), and the binary plus the example simd.config copied into the package. rpm: Fedora packages neither yder nor orcania -- `dnf search` finds nothing on 43 or 44 -- so both are built from source as *static* libraries and linked into simd, leaving Requires: satisfiable on a stock system. BUILD_SHARED=OFF as well as BUILD_STATIC=ON, because a stray libyder.so in the prefix would be preferred by the linker and put the runtime dependency straight back. The vendored builds also need -Wno-error via CMAKE_C_FLAGS_RELEASE: both projects append their own -Wall -Werror to CMAKE_C_FLAGS, and orcania 2.3.3's strstr()-to-char* assignment is an error on Fedora's GCC. Rehearsing the whole job in a fedora:44 container caught that, and the undefined orcania symbols after it, before either cost a CI round. The spec's %prep also had to stop cloning upstream master unconditionally: the rpm's contents tracked master rather than the tag being built -- known and tolerated until now, but simd only exists in this tree, so the package would have silently shipped without it. It now builds whatever CI stages in SOURCES, and still clones upstream when nothing is staged so a bare local `rpmbuild -ba` behaves as before. AppImage: just the build dep; its AppDir comes from cmake --install, so simd and the example config arrive on their own. Flatpak: -DBUILD_SIMD=off, and a header note on why. A sandboxed simd cannot work -- it identifies sims by scanning /proc for 19 process names and reads /proc/<pid>/environ for Steam compat vars, while Flatpak gives the sandbox its own PID namespace with no option to share the host's (measured: 5 pids inside against 497 out, unchanged by --allow=devel or --filesystem=host). The build would fail there anyway: no yder in the runtime. pr-build.yaml gains libyder-dev rather than turning BUILD_SIMD off, so a PR that breaks simd fails its own checks. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
%prep no longer clones upstream and pulls submodules itself, so the staged checkout has to carry them: nappgui_src arrived empty and cmake failed with "does not contain a CMakeLists.txt file" on both Fedora legs. The local rehearsal missed it because it mounted a tree whose submodules were already checked out. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The Flatpak now ships libsimapi.so and simd alongside monocoque, built from simapi's own CMakeLists at the commit monocoque's submodule pins, with yder and orcania as modules beneath them (the freedesktop runtime has neither). A sandboxed simd is useless on its own, so simapi-flatpak-host-spawn.patch teaches simapi's process layer to look outside the sandbox. Flatpak gives every app its own PID namespace and no way to share the host's -- 5 pids visible inside against 497 out, unchanged by --allow=devel or --filesystem=host -- and simd finds a sim by scanning /proc for 19 process names, reads /proc/<pid>/environ for the Steam compat vars behind its auto-bridge, and launches that bridge under Proton. All of it now routes through `flatpak-spawn --host`, guarded on /.flatpak-info so native builds keep their original paths byte for byte. Four things only running it could have found, each fixed here: - Output cannot come back through a pipe. popen()ing `flatpak-spawn --host ...` hands the write end to the session helper, and a copy outlives every process the sandbox can see, so reading to EOF never returns -- simd sat in anon_pipe_read with no children left and no further log line. The host now writes to $XDG_RUNTIME_DIR/app/$FLATPAK_ID and renames the file into place, which makes "the file exists" mean "the output is complete", and the sandbox reads an ordinary file. - Exit statuses are worthless here: simd runs a libuv loop whose SIGCHLD handling reaps children these calls never spawned, so system()'s own waitpid fails and the status is lost. Every check reads output instead. Before that, a detected game read as "no longer detected" one second later, forever. - Matching `ps -o args=` in full is looser than the libproc2 path it stands in for, which compares argv[0]. Observed picking up a shell whose arguments merely mentioned AssettoCorsa.exe and tracking that as the game. - does_file_exist() for Proton ran against the sandbox's filesystem, so wineexe stayed NULL, the bridge fork never happened, and nothing was logged above debug level. Those checks ask the host now. Verified end to end against a synthetic sim on the host: detection lands on the right pid, the environ read returns the Steam vars, the bridge launches on the host through the portal, /dev/shm/SIMAPI.DAT is published, and killing the game tears the bridge down again (--watch-bus ties the host process to the wrapper simd signals). The manifest also gains --talk-name=org.freedesktop.Flatpak, which the above depends on and which makes this sandbox largely decorative, and skips the submodule paths in its `dir` source so a local build works whether or not the tree has them checked out. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Only 2 of 24 configured sound devices came up -- "Could not initialize Sound Device" for the other 22 -- and no shaker fired, on a rig whose PipeWire graph looked perfect: monocoque streams connected into all six filter chains, every node running. sounddev_init() is declared int and fell off its end without returning, so new_sound_device() read whatever was left in the return register and treated that as the error code. The PulseAudio streams had already connected by then; the device objects were simply freed and never fed telemetry again, which is why the graph looked right and nothing shook. Undefined behaviour, so it varies by build: the same config drives shakers from a locally compiled monocoque and not from the packaged one. Now returns usb_generic_shaker_init()'s own result. Verified against a live Assetto Corsa session on real hardware: 26 devices initialised, no failures, shakers working. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… names Two defects in the sandbox escape hatch, both found against a live Assetto Corsa session rather than the synthetic one it was written with. `ps -A -o pid=,comm=,args=` cannot be parsed as three fields: comm may contain spaces, and Wine calls Assetto Corsa's process "AC: main thread". A scanf read that as comm="AC:" with argv[0]="main", so nothing matched "acs.exe", simapi_get_sim() never set simstatus, and datacheckcallback's `simstatus >= 2` gate never opened -- simd detected the game, launched the bridge, and mapped no telemetry at all. The two fields now come back on separately tagged lines, which is the same pair libproc2 hands the native path. And host_capture wrapped the command as `sh -c '<cmd> > out.part'`, so once <cmd> became a sequence the redirect bound to its last element only and half the process table went to /dev/null. Grouped with braces now. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A .deb declares only what it ships, because its dependencies stay separate packages carrying their own copyright files. A Flatpak or AppImage distributes those libraries inside the artifact, so the notices have to travel with it -- and for the LGPL ones here (libconfig, argtable2, libserialport, orcania, yder, simapi) that also means stating where the corresponding source can be had. Raised by Paul on the packaging thread; he is right, and neither format was doing it. Flatpak: every bundled module copies its own licence out of its source tree at build time, so the set cannot drift as modules change. lua and glu ship no licence file at all -- Lua's MIT text lives in doc/readme.html, glu's SGI Free Software License B only in source headers -- so checked-in copies are installed instead. nappgui's MIT licence and monocoque's LICENSE.rst come from the tree, and upstream's own Debian copyright file ships verbatim, since it is the authoritative account of what is in this source tree (slog MIT, nappgui MIT, simapi LGPL) rather than anything restated here. THIRD-PARTY-NOTICES.md is generated from the manifest, so every component's source URL and SHA-256 -- the LGPL "corresponding source" -- is exactly what the build fetched. The libraries stay dynamically linked in /app/lib, which is the cleanest footing for relinking. AppImage: linuxdeploy bundles whatever the binary links from the build host, which is the larger surface -- GTK, glib, pango and the rest, mostly LGPL. Rather than research that list, tools/appimage-collect-licenses.sh maps each bundled library back to its Debian package with dpkg and copies that package's copyright file into the image, alongside a manifest naming library, package and version plus the apt-get source line that retrieves the matching source. linuxdeploy now runs twice, deploying before the collection and packaging after, since the AppDir has to be populated to be inspected. Verified: the Flatpak ships notices for all thirteen components, and the collector was exercised against real distribution libraries, correctly resolving Debian's t64 package names (libgtk-3-0t64, libglib2.0-0t64, libuv1t64) and their versions. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A workflow_dispatch run built all seven artifacts correctly and then reported failure on every job, because the release step cannot work without a tag: "GitHub Releases requires a tag". A build that succeeded should not look broken. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Releases are cut from conventional-commit subjects instead of by hand. Merging the release PR tags the version, writes CHANGELOG.md from the commits since the last release, and publishes the deb/rpm/AppImage/Flatpak against that tag. Configured to fit the 79 tags already in this repo rather than starting a parallel series: bare semver, no `v` prefix, no component prefix, seeded at the current 0.3.6. While the major version is 0, a breaking change bumps the minor rather than jumping to 1.0.0 -- reaching 1.0.0 stays deliberate. Only feat and fix appear in the notes; refactor, ci, chore, docs and the rest are recognised but hidden, and can be surfaced later by flipping `hidden` in release-please-config.json. ci.yaml becomes callable rather than gaining a second tag trigger. A tag pushed with the default GITHUB_TOKEN does not start a workflow -- GitHub blocks that to stop workflows triggering each other -- so `push: tags` never fires for a release-please tag. Calling ci.yaml from the same run keeps the release in one place and needs no personal access token stored on a public repo. The three version-stamping steps and the four release uploads take the tag from the input when called, and fall back to github.ref_name for a hand-pushed tag, which keeps working unchanged. Uploads no longer ask for generated release notes when release-please supplied them, since that would overwrite the changelog body it just wrote. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Per review: simd stays separate so nobody is forced onto one shared-memory implementation. Removed from every package rather than defaulted off, so there is no unused build machinery to carry. Dropped: the CMake simd target and BUILD_SIMD option; simd and simd.config from the deb, rpm and AppImage; the Flatpak's simapi module, its orcania/yder dependencies and the host-spawn patch; libyder from the deb Depends and the CI build deps; and the rpm job's vendored static orcania/yder build, which existed only because Fedora packages neither and simd logged through them. monocoque itself links neither. simapi is untouched -- it remains monocoque's own submodule, compiled into the static simulatorapi library exactly as upstream's CMakeLists does. --device=shm stays in the Flatpak and matters more now, not less: it is what lets a sandboxed monocoque read /dev/shm/SIMAPI.DAT from a simd running on the host. simapi_get_sim() checks that map before it ever scans /proc, so a Flatpak monocoque works with a host simd however that simd was installed. The host-spawn patch is preserved in this branch's history; it belongs with simd's own packaging, not here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
are the code changes i just merged still part of this? is there a way we can separate out simd into it's build as part of the simapi/simd project? |
|
like the other change, i might reduce the verbosity of the comments later, especially after I start to understand the new CI better |
|
and what i think we can do is make a common downloads page on the simapi.github.io site, as well as publish flathub/apphub whatever |
They were bugs that I ran into and fixed when I was testing it as a flatpak and appimage. Regarding separating that out. I have removed simd from the monocoque packaging. I am working on a pipeline for simapi. It builds I just haven't tested the release artifacts directly yet. It should work, since I already got it working while bundled. |
Packaging work for monocoque: deb, rpm, AppImage and Flatpak all built and released from CI, with simd bundled alongside. Every leg has been run green, and the Flatpak has been installed and used on a real Bazzite system.
It's a large branch because the pieces depend on each other — release-please is only useful once CI can actually run, and the Flatpak is only useful once simd can see the host. Happy to split it if you'd rather review in stages.
What you'd need to enable (two settings, nothing in code)
1. Required for release-please: Settings → Actions → General → Workflow permissions → tick "Allow GitHub Actions to create and approve pull requests." Without it the action fails the first time it tries to open a release PR. This is the only mandatory one.
2. Optional, but you'll want it: Settings → Actions → General → Fork pull request workflows → set contributor approval to "Require approval for first-time contributors who are new to GitHub." Release-please's PR is authored by
github-actions[bot], and under the stricter default its checks sit at "waiting for approval" until someone clicks. Loosening this means fork PRs from established GitHub accounts start workflows without a click — the token there is read-only and secrets aren't exposed, so the practical risk is compute, not credentials.On merge style: squash works best. The squash commit message is what release-please reads, so contributors never have to learn the commit format — you set or fix the PR title when merging. It also keeps history linear with no merge commits.
Release-please
Merging a
feat:/fix:PR opens a release PR; merging that tags the version, writesCHANGELOG.md, and publishes all the packages. Configured to fit this repo rather than impose anything:vprefix, continuing the existing 79 tags rather than starting a parallel series. Seeded at 0.3.6.featandfixappear in the notes.refactor,ci,chore,docsand friends are recognised and hidden; fliphiddeninrelease-please-config.jsonto surface any of them.ci.yamlbecomes callable rather than gaining a second tag trigger. A tag pushed with the defaultGITHUB_TOKENdoes not start a workflow — GitHub blocks that to stop workflows triggering each other — sopush: tagsnever fires for a release-please tag. Callingci.yamlfrom the same run keeps the release in one place and needs no personal access token on a public repo. A hand-pushed tag still works exactly as before.CI actually runs now
The deb/rpm matrices used
runs-on: ${{ matrix.os }}withdebian-latest/debian-stableas runner labels, which only resolve to self-hosted runners. With none online those legs queued indefinitely — observed four runs stuck 17–60 minutes, only theubuntu-latestleg ever finishing. They now build in containers on ordinary GitHub-hosted runners. Fedora 44 added alongside 43.Package versions are stamped from the tag. The control files carried a hardcoded
Version: 1, so every .deb ever released claimed version 1 regardless of its tag.Packages
libxml2-16,libconfig11,libuv1t64,libcurl4t64,libgtk-3-0t64); corrected per distro.simd, and letting it out of the sandbox
simd is built and shipped in every package, so monocoque isn't inert on a fresh install. Inside the Flatpak it also needs to see the host:
--device=alldoesn't imply/dev/shm, so telemetry was invisible, and process detection ran against the sandbox's own 5-process namespace instead of the host's ~500. Both are handled — the host process table is read viaflatpak-spawn --hostin a way that survives process names containing spaces.Bug fixes found along the way
sounddev_initfell off the end of anintfunction without returning, so USB shakers didn't survive setup.Parameters/MonocoqueSettingsweremalloc'd and not zeroed, so--helpfreed garbage.gmonocoquesegfaulted on a config with no API key.Licence notices
The Flatpak and AppImage bundle dependencies, so their copyright files ship with them: per-component licences in the Flatpak, and an
appimage-collect-licenses.shpass that maps bundled libraries back to their dpkg copyright files (47 collected on the last run) plus aBUNDLED-LIBRARIES.txtmanifest.One thing worth your attention: the simapi submodule is pinned to
50fd1816, which predates theLICENSE.rstyou added inb2e2324e. Bumping the pin would let the bundles carry simapi's own licence text rather than a note about it.🤖 Generated with Claude Code