From 7927506e021e72da87cc213e8c6cb9b637e43aba Mon Sep 17 00:00:00 2001 From: Codex Date: Mon, 21 Sep 2026 05:08:36 +0000 Subject: [PATCH] Research native Void Linux requirements for VoidKontrol --- docs/research/void-linux.md | 384 ++++++++++++++++++++++++++++++++++++ 1 file changed, 384 insertions(+) create mode 100644 docs/research/void-linux.md diff --git a/docs/research/void-linux.md b/docs/research/void-linux.md new file mode 100644 index 0000000..039abb4 --- /dev/null +++ b/docs/research/void-linux.md @@ -0,0 +1,384 @@ +# VoidKontrol: Void Linux runtime, access, and packaging research + +Research date: 2026-09-21. Decision ticket: [Establish the Void Linux runtime, +permissions, and packaging requirements](https://git.bongbetic.com/xavierk/voidkontrol/issues/2). + +This is a researched platform contract and a set of recommendations, not an +implemented or hardware-tested controller. The user's accepted boundary is the +currently observed USB presentation first, with other modes admitted only after +separate validation; firmware flashing and factory-reset UI remain outside v1. +The supplied [control specification](../../KREO-SWARM75-LINUX-CONTROL-SPEC.md) +owns protocol requirements. No packages were installed, services restarted, +udev rules changed, or device reports exchanged during this research. + +## Findings that change the starting assumptions + +1. **Hidraw support is already present on this host.** The running kernel reports + `CONFIG_HIDRAW=y`; the Swarm has `/dev/hidraw4` and `/dev/hidraw5`, with interface + 1 at the latter path. Both are currently `0600 root:root`. The present barrier + is access policy and protocol evidence, not a demonstrated need to replace the + kernel. Node numbers are observations, never identifiers to hard-code. + See the local evidence below and [Linux hidraw documentation][hidraw]. +2. **`CONFIG_HIDRAW=m` is not a valid alternative.** `HIDRAW` is a Boolean Kconfig + option; `hidraw.o` is linked into the HID core, which itself can be a module. + Consequently, failure of `modprobe hidraw` does not diagnose missing support. + The supplied spec's earlier inference required a dated correction, now + recorded in the [device evidence](../evidence/2026-09-21-swarm75.md). + [Linux Kconfig][kconfig], [HID Makefile][hidmake] +3. **Void-native does not require a permanently root daemon.** A dedicated + system account can receive access to the matching hidraw node and run under + runit's `chpst`. This preserves the spec's privileged service boundary while + restricting its privilege to device access and its private data directory. + It is a design recommendation grounded in [Void service packaging][manual] + and [chpst][chpst], not a claim that the daemon has been built. +4. **Distro availability and upstream buildability differ.** WebKitGTK 4.1 and + Qt 6 have relevant current Void templates, including musl handling. The + current `electron35` template is explicitly marked broken, even though the + host's cached repository index lists an Electron binary. Noctalia installed + here is locally packaged; the inspected upstream Void tree contains no + Noctalia template. [Package inventory](#ui-runtime-and-libc-options), local + evidence below. + +## Evidence and method + +The required Context7 lookup resolved `Void Linux` to the official +`/void-linux/void-docs` collection, then fetched runit service and session/seat +management documentation. Those results were checked against complete relevant +Void Handbook pages, the Void packaging manual, package source, Linux source, +and upstream eudev/runit/polkit specifications. There was no Context7 quota +failure or fallback to uncited recollection. + +Package claims below refer to upstream `void-linux/void-packages` commit +[`954278b83979958bcfdff05f22cf699c9dc20346`][vp] retrieved on the research date. +The recursive tree response was not truncated. This is a source snapshot, not +a promise that every architecture's current binary mirror is synchronized. + +Read-only local evidence, collected in the active session: + +| Check | Observed result | Implication | +| --- | --- | --- | +| `/etc/os-release`, `uname -a`, `ps -p 1 -o comm=` | Void; x86_64; Linux `7.2.6_1`; PID 1 `runit` | This machine can validate x86_64 glibc/runit, not other targets. | +| `xbps-query -p pkgver glibc` / installed package listing | `glibc-2.41_1` | Do not describe this as a musl test. | +| `zcat /proc/config.gz` | `CONFIG_HIDRAW=y`, `CONFIG_HID=m`, `CONFIG_HID_GENERIC=m`, `CONFIG_USB_HID=m` | Hidraw is compiled into the loaded HID core. | +| `lsusb -d 258a:010c`; `/sys/class/hidraw/*/device/uevent` | `258a:010c`, `BY Tech Kreo Swarm`; hidraw4 interface 0; hidraw5 interface 1; `hid-generic` | Normal kernel HID ownership is intact. No feature ioctl was performed. | +| `ls -l /dev/hidraw4 /dev/hidraw5` | Both `crw------- root root`, no ACL indicator | The ordinary desktop user has no device access through these nodes. | +| `udevadm info --query=property --name=/dev/hidraw5` | Only `DEVNAME`, `DEVPATH`, `MAJOR`, `MINOR`, `SUBSYSTEM` | Do not assume `ID_VENDOR_ID` or `ID_USB_INTERFACE_NUM` is already populated on this hidraw node. | +| `udevadm info --attribute-walk --name=/dev/hidraw5` | `bInterfaceNumber=01` on the USB interface; VID/PID/product on the higher USB device | A single rule combining all those `ATTRS` matches cannot work; use separate parent-matching stages. | +| `loginctl show-session 2` | Local, active, `seat0`, Wayland; `LockedHint=no` | Active-session authorization can be tested here. This is not a seatd-only setup. | +| Selected environment | `XDG_CURRENT_DESKTOP=niri`, `XDG_RUNTIME_DIR=/run/user/1000`, `WAYLAND_DISPLAY=wayland-1` | UI runs in a graphical user session; system daemon must not inherit these assumptions. | +| Installed package listing / `/var/service/` | runit `2.3.1_1`, eudev `3.2.14_2`, elogind `252.39_1`, D-Bus `1.16.2_2`, polkit `127_1`; dbus and udevd enabled | Elogind is operational despite no explicit elogind service symlink, consistent with D-Bus activation. | +| Installed UI packages | GTK3 `3.24.52_1`, GTK4 `4.22.4_1`, Qt6 `6.11.2_1`, `libwebkitgtk60-2.50.4_1`, IBM Plex fonts | GTK4 WebKit being installed does not satisfy a GTK3 WebKit 4.1 dependency. | +| Installed desktop packages | niri `26.04_1`, noctalia `5.1.0_1` | Version-specific desktop integration remains a separate research decision. | +| `xbps-query -p repository noctalia` | Local `void-packages/hostdir/binpkgs` repository | This installation is not proof of an official Noctalia package. | +| `xbps-query -Rs webkit` / `electron35` | Cached index lists `libwebkit2gtk41-2.50.4_1` and `electron35-35.7.2_1` | Index metadata only; no installation or fresh mirror synchronization was performed. | + +## Service lifetime and privilege + +Void uses runit; packaged service directories live in `/etc/sv/`, and linking a +directory into `/var/service/` enables immediate start and subsequent supervision. +The service's executable `run` script must `exec` a foreground process. A `check` +script reports readiness, `finish` runs after termination, and a `log` subservice +can receive output. An administrative `down` file prevents automatic start. +[Void services][services] + +Recommended service contract: + +- Keep one system service, provisionally `voidkontrold` (the spec calls the + responsibility `swarm75d`). The UI and CLI are ordinary users. The service + runs as `_voidkontrol:_voidkontrol`, with no membership in `input`, `video`, + `wheel`, or a general hardware group. `chpst -u` removes inherited + supplementary groups. A root supervisor creating a runtime directory does + not require the long-lived service process to be root. [chpst][chpst] +- Have the `run` script create `/run/voidkontrol` with explicit owner and mode, + then change credentials and `exec` the daemon. Permanent private state belongs + under `/var/lib/voidkontrol`, created by packaging. This follows Void's + distinction between service-created volatile directories and `make_dirs` + for persistent directories. [Void packaging manual][manual] +- With D-Bus IPC, the package's system-bus policy should grant only the service + account ownership of the selected bus name. Startup waits for/retries the + system bus; do not add a second D-Bus process or depend on a user's session + bus. With a Unix socket instead, use kernel-authenticated peer credentials + and an equivalent per-call authorization check. The final IPC choice is a + decision, not a requirement imposed by Void. [Void sessions][sessions] +- Readiness means the daemon can serve a diagnostic/capability request even + when the keyboard is unplugged. Device absence should be an application + state, not a restart loop. A system service must work without niri, Noctalia, + `DISPLAY`, or `XDG_RUNTIME_DIR`; runit's clean environment makes this + separation particularly important. [Void services][services] +- Handle `SIGTERM`: stop accepting mutations, bound the wait for an outstanding + transaction, durably record any uncertain outcome, close the device and IPC, + and exit. `sv down` sends TERM and CONT; `sv stop` waits by default for seven + seconds, and force variants may kill on timeout. Do not rely on `finish` to + restore hardware or guarantee completion after power loss. [sv manual][sv] +- Let runit restart a crashed daemon, but obey the spec's no-auto-write rule: + an interrupted transaction becomes uncertain and requires fresh readback. + Restart, hotplug, login, wake, and service upgrade must never replay saved + frames or apply a profile automatically. This is a project invariant from + the supplied control spec, not distro behavior. +- Use bounded logs with an explicit logging setup. Void installs no syslog + daemon by default, while the packaging `vsv` helper creates a `vlogger` + subservice by default. Decide between that documented syslog prerequisite + and an explicit `svlogd` log subservice; do not silently depend on journald. + Logs should contain transaction metadata/errors, not keystrokes, macro + contents, complete backups, or raw transport buffers. [Void logging][logging], + [vsv documentation][manual] + +## Device discovery and narrow udev access + +Linux recommends discovering hidraw nodes through libudev instead of assuming a +stable `/dev/hidrawN`; hidraw feature-report ioctls use the control endpoint. +For the spec's report ID 6, a 519-byte payload requires a **520-byte ioctl +buffer**, whose first byte is report ID 6. This is a framing distinction, not +permission to send the currently unverified command payloads. Plain hidraw +`read()` receives interrupt input reports, and plain `write()` is not a +substitute for the specified feature-report exchange. [Linux hidraw][hidraw] + +Required project invariants remain: no input-device grabs, no kernel HID +detach/unbind, no access to the unrelated 5-byte feature report, no arbitrary +raw-report RPC, and validation of VID/PID, product, interface, usage collection, +report IDs/sizes, and authenticated device identity before writes. A udev rule +can reduce access, but cannot replace that protocol gate or physical-layout +validation. Interface 1 also contains keyboard input reports; daemon code must +not turn device access into a general key-event collector. + +**Recommended access model:** give the service account access to only the +matching interface and mediate all users through IPC. Do not grant ordinary +users membership in the service account's group or install `MODE="0666"`. +Do not add `TAG+="uaccess"` for this controller: elogind processes that tag to +grant active-user device access, which would let a GUI or unrelated user +process bypass the policy-owning daemon. Existing administrator-added device +ACLs/rules must be diagnosed; this package cannot prevent root from opening +the device. [elogind seat rule][seat-rule], [eudev rule language][udev] + +The following is a **candidate rule design for later isolated testing**, not a +rule installed or verified with udev on this host: + +```udev +# Example package path: /usr/lib/udev/rules.d/70-voidkontrol.rules +SUBSYSTEM!="hidraw", GOTO="voidkontrol_end" +ACTION=="remove", GOTO="voidkontrol_end" +ENV{.VOIDKONTROL_MATCH}="" +ATTRS{idVendor}=="258a", ATTRS{idProduct}=="010c", ATTRS{product}=="Kreo Swarm", ENV{.VOIDKONTROL_MATCH}="1" +ENV{.VOIDKONTROL_MATCH}=="1", ATTRS{bInterfaceNumber}=="01", GROUP="_voidkontrol", MODE="0660" +LABEL="voidkontrol_end" +``` + +The first matching stage evaluates attributes on the USB device; the second +evaluates the interface ancestor. Eudev requires all parent matches within a +single rule to match the same ancestor. Dot-prefixed temporary properties are +not stored in the database or exported. The rule intentionally does not assume +`ID_USB_INTERFACE_NUM` is populated, since it is absent in this host's hidraw +properties. [eudev rule language][udev], local attribute walk above. + +A service-held lock prevents two VoidKontrol instances from controlling the +same keyboard, but is not a claim of kernel-enforced exclusivity against root +or another driver. Root/administrator access remains outside the ordinary-user +isolation boundary. Reconnect must rediscover and revalidate the descriptor; +USB topology and a hidraw index are not durable identity. The lack of a serial +number makes multiple identical devices a separate identity decision. + +## Active-user policy, elogind, and seatd + +Void distinguishes the system and per-session D-Bus buses. Elogind manages +login sessions, device access, and power; it needs system D-Bus and may activate +on demand. Seatd only manages seats. Seatd does not replace elogind's login +session information, its uaccess processing, or `XDG_RUNTIME_DIR` creation. +Void recommends elogind or turnstile for runtime-directory management and +documents a seatd plus turnstile alternative. [Void session management][sessions] + +Void's current polkit template explicitly builds with +`-Dsession_tracking=elogind`. Polkit defines separate defaults for any caller, +inactive local callers, and active local callers, and provides a system-bus +unique-name subject. These are usable on Void without systemd. +[Void polkit template][polkit-pkg], [polkit policy][polkit], [polkit subject][subject] + +Recommended v1 policy, pending the explicit security decision: + +- Use the actual authenticated IPC sender, never a UID/PID/username supplied + in request JSON. With system D-Bus, authorize the caller's unique bus name. + The UI, CLI, and Noctalia integration use the same policy. +- Allow customization only from the active local session associated with the + keyboard's seat; deny remote, inactive, and unidentifiable callers. Recheck + authorization when a queued mutation begins, and invalidate it on session + or seat change. Read-only diagnostics may be less restricted; configuration + exports/macros contain user data and need separate privacy treatment. +- If the product must deny writes while locked, check the session lock state + explicitly and test the actual locker integration. `Active=yes` alone does + not express the desired locked-screen policy. This report's host was + unlocked; it did not validate lock-state propagation. +- Do not use a silent "any local group member" fallback when elogind or polkit + is unavailable. Report authorization unavailable, or implement an explicit + administrator-approved alternate mode after a separate security decision. + A group alone does not prove active seat ownership. + +An elogind-based session is the smallest evidenced release baseline here. +Supporting a seatd-only session with identical active-user guarantees is an +additional feature requiring an independently specified authority; it is not +an automatic consequence of running on Void. This baseline recommendation does +not require replacing a working user's seat manager or altering the host. + +## Storage and XBPS lifecycle + +The XDG specification separates config, data, state, cache, and runtime files. +Defaults are `~/.config`, `~/.local/share`, `~/.local/state`, and `~/.cache`; +runtime storage must be user-owned mode 0700, local, and tied to login lifetime. +Only absolute XDG paths are valid. [XDG Base Directory specification][xdg] + +Recommended ownership: + +| Data | Location/owner recommendation | Reason | +| --- | --- | --- | +| UI preferences, selected theme | `$XDG_CONFIG_HOME/voidkontrol`, desktop user | User preferences follow XDG config semantics. | +| User-created named configurations/exports | `$XDG_DATA_HOME/voidkontrol` or explicitly chosen export path, user | Portable user data; writes performed by the client. | +| UI session/history state | `$XDG_STATE_HOME/voidkontrol`, user | Persisted application state, independent of device transactions. | +| Service backup and pending-transaction journal | `/var/lib/voidkontrol`, `_voidkontrol`, private | The service must not depend on a logged-in user's environment or accept an arbitrary root-write path over IPC. | +| Service locks/socket, if used | `/run/voidkontrol`, explicit private/service policy | Recreated each service start; no backups here. | +| User-only IPC/instance state, if needed | `$XDG_RUNTIME_DIR/voidkontrol`, user, private | Session lifetime and ownership required by XDG. | + +Import validates a bounded document supplied by the client; export returns data +to the authorized client, which writes the selected user path. Do not make the +service open arbitrary paths supplied by an unprivileged caller. Restore must +validate schema, device/firmware compatibility, and capability bounds, preserve +a pre-change backup, then use the normal serialized/readback transaction path. +User data must survive an uninstall; a separate explicitly requested purge can +be considered later. These are proposed application rules supporting the +supplied spec's backup/restore requirement. + +For native packaging, provide an `xbps-src` template with release source and +checksum, correct `hostmakedepends`/`makedepends`/runtime dependencies, licenses, +desktop entry/icon, daemon/CLI, service directory, udev rule, and chosen IPC +policy. Void templates are Bash descriptions compiled into XBPS packages; +`vsv` installs a service directory and supervision links, not the running +`/var/service` enablement link. Use `system_accounts="_voidkontrol"` with a +dynamically allocated UID/GID, a non-login shell, `make_dirs` for persistent +directories, and `conf_files` for administrator configuration. New system +accounts must use an underscore prefix. [Void packaging manual][manual] + +The native build path is a separate `xbps-src` masterdir. The upstream README +documents `./xbps-src pkg ` and same-architecture musl builds via +`./xbps-src -A x86_64-musl pkg `. Build as an ordinary user with the +documented chroot method. Pin source and application dependency lockfiles; +record the package tree revision and resolved dependency versions. Do not +claim bit-for-bit reproducibility merely because a template builds. +[void-packages README][vp-readme], [Cargo build style][cargo-style] + +Lifecycle requirements and native behavior: + +- Install must not implicitly enable hardware writes, start a GUI as root, + enroll all users in a group, or change desktop configuration. Document the + separate service-enable step. Verify account and rule availability before + starting the daemon; bootstrap the current attached device permissions by a + controlled replug or targeted administrator action during installation QA. +- XBPS **does not automatically restart updated services**. Preserve that + behavior and document the required controlled daemon restart; negotiate + IPC version compatibility so a newly installed UI can explain an old + running service. [Void XBPS handbook][xbps] +- Package removal needs an explicit tested service-stop/disable procedure, + including in-flight transaction handling and stale enablement links. + `INSTALL`/`REMOVE` scripts must distinguish real removal from upgrade and + work with alternate installation roots. Avoid unrelated host mutations or + deleting backups. [Void packaging manual][manual] +- Void's system-account trigger disables rather than deletes the service + account on real removal and does not do that for upgrades. The `mkdirs` + trigger uses `rmdir`, not recursive deletion, for package-created + directories. Preserve that non-destructive model. [Account trigger][accounts], + [mkdirs documentation][manual] +- A locally built XBPS repository can be used for initial distribution; a + remotely shared repository and packages must be signed. Official Void + repository acceptance is a separate process, not required for being a + native XBPS package. [Void repositories][repos], [signing documentation][vp-readme] + +## UI runtime and libc options + +Void officially supports musl as well as glibc, but software portability and +binary availability vary; i686 musl binaries and musl multilib are not offered. +Source-level compatibility is not release qualification. [Void musl handbook][musl] + +| Candidate component | Current source evidence | Consequence for VoidKontrol | +| --- | --- | --- | +| Rust daemon | `rust`/`cargo` 1.98.0 templates, explicit musl handling; Void has a Cargo build style | Viable native backend candidate; build dependencies must come from the selected target toolchain. This is not a language decision. [Rust][rust], [Cargo][cargo], [build style][cargo-style] | +| Direct hidraw or HIDAPI hidraw backend | `hidapi` 0.14.0 template uses eudev/libusb build dependencies | If HIDAPI is selected, choose its hidraw backend explicitly and prove no kernel detach path exists. Direct Linux ioctls are also a viable small implementation. [HIDAPI package][hidapi-pkg], [Linux API][hidraw] | +| GTK3/WebKitGTK 4.1 web UI host | `gtk+3` 3.24.52 and `libwebkit2gtk41` 2.50.4; `libwebkit2gtk41-devel` exports `webkitgtk-4.1` headers/pkg-config; Wayland enabled | Available foundation for the Carbon researcher's Tauri option. GTK4's `libwebkitgtk60` is a different ABI, not a substitute. [GTK3][gtk3], [WebKit][webkit] | +| WebKit on musl | x86_64-musl/aarch64-musl target patterns enable JIT; sampling profiler is glibc-only; bubblewrap and xdg-dbus-proxy enabled by default | Musl is not ruled out. Validate the chosen wrapper/build, webview sandbox, accessibility, portal dialogs, and rendered Carbon components on actual Void musl before promising support. Do not disable the webview sandbox to pass tests. [WebKit][webkit] | +| Qt 6 native UI | `qt6-base` 6.11.2, Wayland enabled; separate `qt6-wayland-client`; musl-aware checks; declarative/QML packages present | Technically viable native UI, but Carbon widget fidelity/accessibility implementation cost belongs to the design decision. [Qt base][qt] | +| Qt 6 WebEngine host | Built from `qt6-pdf` 6.11.2; musl compatibility dependency; Widevine disabled on musl; word-size/architecture restrictions | Technically possible web host, but Chromium build/runtime surface is substantially larger; do not assume every Void architecture. [Qt WebEngine source][qtweb] | +| Electron | `electron35` 35.7.2 permits x86_64*/aarch64*, includes musl compatibility, but explicitly `broken` with Python >=3.14 | Existing binary availability is not a reproducible native build path. Resolve packaging and maintenance before choosing it for a native Void v1. [Electron template][electron] | +| niri and Noctalia | Upstream niri 26.04 template enables `dbus,xdp-gnome-screencast`, no systemd feature; Noctalia absent from this source snapshot, locally packaged here | Do not hard-require systemd activation or claim Noctalia is in official Void repositories. Version the supported integration separately. [niri template][niri], [source snapshot][vp], local evidence above | + +Recommended release-matrix decision: qualify **x86_64 glibc + runit + +eudev + elogind + system D-Bus + the accepted niri/Noctalia versions** first, +because that is the actual available hardware environment. Keep musl support +architecturally possible and add an x86_64-musl build/smoke lane early. Whether +musl must also block the v1 release is a user-facing support promise still to +settle, not a fact inferred from "Void Linux." Other CPU architectures likewise +require an explicit matrix and evidence; none was tested here. + +## Requirements and acceptance matrix + +"Required" below means required by the supplied spec/user boundary or necessary +to support the selected native platform contract. "Recommended" marks a design +choice that the decision map must adopt or replace explicitly. + +| Area | Requirement or recommendation | Smallest sufficient release proof | Current status | +| --- | --- | --- | --- | +| Kernel | Required: effective HIDRAW support, intact kernel typing | Running config and matched descriptor; normal typing/media/LED behavior before/after control | Config/nodes confirmed; no control test performed | +| Device access | Required: service can open only intended interface under ordinary service credentials | Install rule in disposable setup; interface 1 accessible, interface 0/unrelated devices denied; replug and node renumbering | Two-stage candidate researched, not installed/tested | +| Ownership | Required: one controller transaction at a time | Concurrent UI/CLI clients and attempted second daemon; no interleaving | Not implemented | +| Authorization | Recommended: active local caller/seat policy, fail closed | Active, inactive, remote, locked, multi-seat, denied, and missing authority cases; repeat with queued requests | Elogind active session observed only | +| Service lifecycle | Required: runit foreground process and bounded shutdown; no automatic writes | `sv` start/stop/restart; crash in each transaction phase; no-device boot; reconnect/resume | Native requirements researched | +| Backup/restore | Required: durable complete backup before first write; no uninstall data loss | Interrupted write/restart followed by validated explicit restore; install/upgrade/remove/reinstall | Awaiting protocol and implementation | +| GUI native behavior | Required for promised matrix: Wayland launch as user, no root dialog loop | Clean target installation, app launcher, scaling/input/accessibility, portal file dialogs, service-unavailable state | Runtime packages inventoried only | +| Packaging | Required: self-contained XBPS dependency declaration and reproducible recipe | Clean `xbps-src` build; clean-machine install; upgrade/old-daemon handshake; removal preserving data | No application/template exists yet | +| glibc | Recommended primary release target | Build/package/UI/service tests on x86_64 glibc and real keyboard | Host available | +| musl | Decide release promise; never label supported from compilation alone | Separate musl package build plus real graphical/service/control tests | Source plausibility established; no musl environment tested | +| Noctalia | Required integration for accepted version, independent daemon | Locally reproducible package/runtime provenance and versioned client integration | Locally packaged version observed; desktop researcher owns integration | + +## Remaining decisions and implementation evidence + +- Adopt the primary glibc/elogind matrix or make musl and/or seatd-only support + release blockers. The research identifies consequences; it cannot choose + this support promise on behalf of the user. +- Choose system D-Bus with existing Void polkit/elogind versus a Unix socket + with equivalent session authorization. Define locked-screen, multiple-session, + same-seat, and administrator override policy explicitly. +- Choose the UI runtime after the Carbon and desktop findings are combined. + Package source evidence supports several options; no GUI stack was built. +- Prove the proposed udev rule against real eudev events in an isolated test + setup, and specify safe package install/update/remove handling. Read-only + inspection was deliberately insufficient to claim that operational proof. +- Set durable transaction/backup format and compatibility/recovery rules; + decide identity behavior for identical no-serial devices. The protocol + capture and authenticated-device evidence remain prerequisites for writes. + +[vp]: https://github.com/void-linux/void-packages/tree/954278b83979958bcfdff05f22cf699c9dc20346 +[services]: https://docs.voidlinux.org/config/services/index.html +[logging]: https://docs.voidlinux.org/config/services/logging.html +[sessions]: https://docs.voidlinux.org/config/session-management.html +[xbps]: https://docs.voidlinux.org/xbps/index.html +[repos]: https://docs.voidlinux.org/xbps/repositories/index.html +[musl]: https://docs.voidlinux.org/installation/musl.html +[manual]: https://github.com/void-linux/void-packages/blob/954278b83979958bcfdff05f22cf699c9dc20346/Manual.md +[vp-readme]: https://github.com/void-linux/void-packages/blob/954278b83979958bcfdff05f22cf699c9dc20346/README.md +[accounts]: https://github.com/void-linux/void-packages/blob/954278b83979958bcfdff05f22cf699c9dc20346/srcpkgs/xbps-triggers/files/system-accounts +[kconfig]: https://github.com/torvalds/linux/blob/master/drivers/hid/Kconfig +[hidmake]: https://github.com/torvalds/linux/blob/master/drivers/hid/Makefile +[hidraw]: https://docs.kernel.org/hid/hidraw.html +[udev]: https://github.com/eudev-project/eudev/blob/master/man/udev.xml +[seat-rule]: https://github.com/elogind/elogind/blob/d7956ed0b1496db7ff404d1765c31cbd9f6c7aab/rules.d/73-seat-late.rules.in +[sv]: https://smarden.org/runit/sv.8.html +[chpst]: https://smarden.org/runit/chpst.8.html +[xdg]: https://specifications.freedesktop.org/basedir/latest/ +[polkit]: https://www.freedesktop.org/software/polkit/docs/latest/polkit.8.html +[subject]: https://www.freedesktop.org/software/polkit/docs/latest/PolkitSystemBusName.html +[polkit-pkg]: https://github.com/void-linux/void-packages/blob/954278b83979958bcfdff05f22cf699c9dc20346/srcpkgs/polkit/template +[rust]: https://github.com/void-linux/void-packages/blob/954278b83979958bcfdff05f22cf699c9dc20346/srcpkgs/rust/template +[cargo]: https://github.com/void-linux/void-packages/blob/954278b83979958bcfdff05f22cf699c9dc20346/srcpkgs/cargo/template +[cargo-style]: https://github.com/void-linux/void-packages/blob/954278b83979958bcfdff05f22cf699c9dc20346/common/build-style/cargo.sh +[hidapi-pkg]: https://github.com/void-linux/void-packages/blob/954278b83979958bcfdff05f22cf699c9dc20346/srcpkgs/hidapi/template +[gtk3]: https://github.com/void-linux/void-packages/blob/954278b83979958bcfdff05f22cf699c9dc20346/srcpkgs/gtk+3/template +[webkit]: https://github.com/void-linux/void-packages/blob/954278b83979958bcfdff05f22cf699c9dc20346/srcpkgs/libwebkit2gtk41/template +[qt]: https://github.com/void-linux/void-packages/blob/954278b83979958bcfdff05f22cf699c9dc20346/srcpkgs/qt6-base/template +[qtweb]: https://github.com/void-linux/void-packages/blob/954278b83979958bcfdff05f22cf699c9dc20346/srcpkgs/qt6-pdf/template +[electron]: https://github.com/void-linux/void-packages/blob/954278b83979958bcfdff05f22cf699c9dc20346/srcpkgs/electron35/template +[niri]: https://github.com/void-linux/void-packages/blob/954278b83979958bcfdff05f22cf699c9dc20346/srcpkgs/niri/template +{"content_type":"terminal","tokens_before":7229,"tokens_after":7229,"token_count_basis":"o200k_base","ratio":0,"basis":"inferred"}