Known gaps
This chapter lists what KDOS does not do, and what it does but has never been exercised on real
hardware or against a real peer. It is for anyone using, administering or contributing to KDOS who
has hit something that seems missing and wants to know whether it is a bug, a limitation or a
choice. If what you are looking for is described here, KDOS does not do it, or has not been shown
to; if it is not described here and it misbehaves, it is probably a bug worth reporting. No earlier
chapter is required reading, but Architecture overview gives
context for the component names used below, and terms such as surface, box, pack and rig
are defined in the Glossary.
Each entry is headed by a one-line statement of the gap, followed by what exactly is missing, why,
and what to do instead where there is something. Some entries are known defects: behaviour the
code has today that contradicts its own documentation or usage text. They are listed so that a
reader who meets one knows it is known. The sections follow the shape of the system: the desktop,
applications and boxes, hardware, installation, boot and updates, security, ports built without a
feature, upgrades, building, sources and publishing, testing, and this book. Every entry describes the tree
as it stands; a gap that closes is removed rather than marked as closed (see
Principles).
Three other chapters answer the neighbouring questions. What is absent on purpose, and the
reasoning behind it, is in Decisions; what that costs next to
other distributions is in How KDOS differs;
how mature the parts that do exist are is in Status.
Desktop
Drag and drop carries text and files, and nothing else
text/plain and text/uri-list are offered and accepted; there is no MIME negotiation, no
deferred transfer and no image payload. Only the trash accepts a drop on the desktop, which is a
narrowing rather than a gap; see Decisions. Both
directions are implemented in libkwl, and no test asserts either of them: nothing has been dragged
with a pointer between a KDOS surface and a boxed application. See Status.
KDOS’s own surfaces have not been seen at a fractional scale
On an output scaled by a fraction, such as 1.5, libkwl loads the chrome font at the device size and
hands kdos-comp a buffer of device pixels behind a viewport, so the panel, the menus and the other
surfaces are drawn crisp at 1.5 rather than drawn at 2 and shrunk. What is measured is the arithmetic
and the paint: the device cells in a build container with the image’s fonts, and the real flush
walked through fractional scales in a harness with a simulated compositor. No KDOS surface has been
photographed on a fractional output, on the rig or on hardware, so the look of the result is
unconfirmed. A toplevel such as kdos-term is told its scale only once it is on a screen, so its
first frame is drawn with the font as named and the next at the device size. See
The fractional scale.
Emoji draw everywhere except the text console on tty1
Noto Color Emoji ships, and fontconfig resolves the generic emoji family to it, so every surface
with a pixel layer draws them: a kdos-term window, the panel, a boxed application. The Linux
virtual terminal’s font holds 512 monochrome glyphs, which is a kernel limit, and a character the
font does not carry renders as a blank cell. An emoji on tty1 is therefore a blank cell.
The menu tree is read when the menu opens, and LayoutUpdated is not watched. This is deliberate: a
menu whose rows move under your hand activates the wrong row. AboutToShow is sent first and its
reply is waited for, so whatever the application fills in at that moment is the one update taken.
The rows, their submenus, toggles, icons and shortcuts are all drawn; see
kdos-shell. An item that publishes no menu path is sent
ContextMenu and opens whatever window it has of its own.
Workspace occupancy is inferred, not reported
The workspace protocol reports active, urgent and hidden, but has no “there are windows here”, so
the panel marks a workspace occupied when a window on it is not minimised. That is right for every
workspace you have visited, and says nothing about the rest.
A corporate VPN is a terminal program
openconnect ships and speaks AnyConnect, GlobalProtect, Fortinet and Pulse, with vpnc-script
giving the tunnel its routes, but there is no NetworkManager plugin for it, so it does not appear
in the network surface beside Wi-Fi and OpenVPN. Neither NetworkManager’s openconnect plugin nor its
vpnc plugin is a port. Upstream’s openconnect plugin needs webkit2gtk for the dialog the VPN
service hands authentication to; the webkitgtk port provides that library, and no recipe builds
the plugin. WireGuard and OpenVPN are the two VPN types that do appear.
A fingerprint unlocks sudo and nothing else
pam_fprintd is in sudo’s PAM stack ahead of the password. The lock screen checks the shadow
file through kdos-checkpass, and the console login is shadow’s, built without PAM, so neither
asks for a finger. Enrolment is a terminal command run as root, sudo fprintd-enroll <user>,
because fprintd’s polkit actions allow only an active session, which nothing here ever is. No
surface offers enrolment. For an account with a fingerprint enrolled, sudo over SSH waits on the
machine’s reader before asking for the password: the only remote-login test the module has without
logind is PAM_RHOST, which sudo never sets.
Xwayland gives its X clients no text-input protocol, and fcitx5 is built without the XIM frontend
that X clients use. Qt 5’s Wayland plugin (qtwayland 5.15) speaks only text-input-unstable-v2, and
kdos-comp serves text-input-v3, so a Qt 5 application on Wayland gets no input method either;
there is no fcitx5-qt port that would give Qt 5 a direct route. CJK input and the on-screen
keyboard’s automatic raise therefore reach GTK 3, GTK 4 and Qt 6 applications on Wayland, host or
boxed. See the session.
The one upstream ships, fcitx5-configtool, is a Qt program that is not a port. fcitx5 is configured through
its text files.
A screen reader reads the applications, not the desktop’s own windows
Orca is a host port, with at-spi2-core’s accessibility bus, for the native GTK and Qt
applications, whose toolkits publish a tree of accessible objects. It is set up to speak through
speech-dispatcher and to reach braille through BrlAPI. Neither Orca nor at-spi2-core has been
through a build. Nothing starts it: KDOS runs no autostart agent, so it is started by running
orca. The keys typed into other windows reach it through the compositor’s
keyboard monitor, which is the one interface of
its family kdos-comp serves: there is no pointer locator (PointerLocator), and Orca’s mouse
review reports itself unavailable, because it needs Wnck, which is X11-only and not a port.
The desktop’s own windows are not read. kdos-comp draws pixels, and a KDOS surface composes its
own cells and publishes no accessible tree. Each surface does keep a per-frame record in libktui
of what its widgets would say aloud. On every frame, controls of ten roles (button, check box, radio button, input, list, table, tab, choice, text
area and slider), menus included, write their role and their position in the set to it, and a name
and a value where the widget holds them rather than the caller’s own draw callback. Nothing carries
that record out of the process: there is no socket, no bus name and no bridge, and the only thing
that reads it is the library’s self-test. What is missing is a route and a client rather than the
material. A boxed application has its own accessibility registry, opted into with
~/.config/kdos/a11y; whether the host’s Orca reaches it has not been tried. See
Accessibility.
There is no graphical login screen (greeter)
tty1 is handed to agetty by kdos-login, which logs in the account login.conf names
automatically and otherwise asks for a password at the ordinary text prompt. There is no account
chooser, no session chooser and no surface of any kind before the shell starts. Adding one needs a
Wayland client that runs before the compositor, in the way the lock screen does, and none exists.
Nothing starts the screensaver on idle
kdos-saver has seven effects under eight names (rain, art, bounce, matrix, pipes,
starfield, fire, clock, where bounce is another name for art) and six golden reference
frames under testing/goldens, but the compositor’s idle sequence dims, starts kdos-lock and
powers the outputs off, and never starts a saver. comp.conf has idle_dim, idle_lock and
idle_off and no key for a saver; see Idle, dim, lock and
lid. You reach it with Super+Shift+L, which the
shipped rc.xml binds, or by running it yourself.
The control centre has no pointer page
Pointer speed, acceleration profile, natural scroll, tap-to-click, the tap button map and
disable-while-typing are libinput settings that the compositor’s <libinput> block in
~/.config/kdos-comp/rc.xml accepts, and no surface here offers them. The shipped rc.xml carries
that block commented out, as a template, and sets none of them, so the compositor’s own defaults
apply, with tap-to-click on. The control centre’s Input page says where the template is and stops
there.
Every surface here scrolls in whole wheel ticks, and libkwl makes one tick of a touchpad’s stream
per ten axis units (libinput reports a finger’s travel in units it scales like pointer motion),
which a scrolling list spends as three rows
(SH_WHEEL_ROWS). So a list moves several times further than the finger did. The movement between
ticks glides and a flick coasts, but the ratio stays: matching it to the finger means knowing how
far each surface moves per tick, and the feel has not been judged on a touchpad. See
Input the backend cleans.
The launcher’s files setting does nothing
launcher.conf’s files key is written by the control centre and read by nothing.
kdos-launcher searches applications only, and kdos-palette always includes files once you have
typed three characters, whatever the file says. Neither reads ~/.cache/kdos/plocate.db: the
palette runs fd over $HOME, and the index kdos-updatedb builds nightly is used only by the
locate command.
Nerd Font icons are blank on tty1, and the shipped configurations turn them off everywhere
They are private-use characters, and the console font cannot carry them, for the reason given under
emoji above, so an icon in front of a filename shows as a hole. The face itself is on the image:
nerd-fonts-symbols installs Symbols Nerd Font and its Mono variant under
/usr/share/fonts/nerd-fonts, and its 66-nerd-font-symbols.conf accepts the Mono face as a
fallback for monospace, Terminus and Terminus (TTF) and the proportional face for sans-serif
and serif, so anything with a pixel layer can draw one. What turns them off is each program’s own
configuration: the yazi theme that kdos theme generates empties all five [icon] arrays, the
shipped starship.toml uses plain text and box drawing only, the eza aliases in
/etc/bash.bashrc say --icons=never rather than relying on a default, and lazygit, for which
KDOS installs no configuration, draws none by default. To turn them back on, configure those four
programs one at a time, knowing the same shell on tty1 will show holes. Nothing patches the
console font, so on tty1 the icons cannot be restored.
Two shipped chords and two routes show nothing
The shipped ~/.config/kdos-comp/rc.xml binds W-C-v to bare kdos-clip. Without an argument
that program is the clipboard-history daemon, not the picker, so the chord opens no window; the
second daemon unlinks and rebinds the history socket and takes the history over from the copy the
compositor supervises. Binding the chord to kdos-clip --pick in your own rc.xml opens the
picker. W-C-p runs kdos-energy, the per-application energy report, which prints to standard
output and has no window, so the key shows nothing; a right-click on the panel’s meters strip opens
the same report in a popup.
Two of the routes in /etc/kdos/menu.conf fail the same way. system.power runs the same
windowless kdos-energy. setup.tui runs kdos app tui with no subcommand, which prints a usage
message to standard error and exits with status 2. The Start menu and kdos-palette start a route
with no terminal attached, so choosing either route, from those surfaces or through
kdos menu summon, shows nothing. Adding a terminal program as an application takes
kdos app tui add run in a terminal. See
Keyboard shortcuts,
The clipboard and the route table under
/etc/kdos/menu.conf.
Only two ways of ending the session save the list of open windows
Super+Escape, and Log Out, Restart and Shut Down in the compositor’s root menu (menu.xml), run
kdos-session-save before they act. The Start menu’s footer and the System menu end the session
without it, so the list read back at the next login, when ~/.config/kdos/session-restore exists,
is whatever the last of the first two routes wrote. See
Session, screen and media.
The control centre’s Sync… row opens the network-share window
On the System page of kdos-settings, the row Sync… is described as calendars and address
books through vdirsyncer, and runs kdos-connect, which mounts a share on another machine. No
surface configures vdirsyncer; it is set up through its own configuration file. See
kdos-settings.
kdos-audio refuses the --no-icons its usage line offers
The usage text lists [--font NAME] [--no-icons] [--dump], and the argument loop accepts only
--at-bottom, --font and --dump, so kdos-audio --no-icons prints the usage and exits 2.
Nothing shipped passes the flag. See kdos-audio.
kdos-res draws its selected row in the accent colour
The design language fills a selected row with KT_DIM and keeps KT_ACCENT for one cell
(see A selected row).
The list pages of kdos-res (Processes, Applications, Boxes, Drives and Network) fill the selected
row with KT_ACCENT under KT_SURFACE text and the row under the pointer with KT_MID, rather
than calling ktui_sel_row(). See kdos-res.
Applications and boxes
Changing the accent colour reaches running GTK3 applications, not running libadwaita or KDE ones
GTK rebuilds its style when the portal’s gtk-theme key changes, and kdos theme writes each accent’s
stylesheet under its own name (~/.themes/KDOS-<accent>), so the settings portal’s change signal
is enough for GTK3. libadwaita ignores GTK themes entirely and reads
~/.config/gtk-4.0/gtk.css, which GTK loads once at startup. A Qt 6 application on the host, where
the session sets QT_QPA_PLATFORMTHEME=kde, or in a box on the rt-kde runtime, runs under the KDE
platform theme and reads ~/.config/kdeglobals, which KDE re-reads only
on its own global-settings signal, and there is no KDE daemon here to send it. Both pick up the new
palette the next time they start. libadwaita 1.6 and later follow the portal’s accent-color on
their own, which changes the accent and not the rest of the palette. A Qt application on the
rt-qt runtime uses the GTK3 platform theme instead, and takes its palette from GTK.
A box can be granted only the eight named groups of Wayland globals
A boxed client sees the compositor’s fixed sandbox allowlist, plus whatever its profile’s
grant = line in ~/.config/kdos/boxes/<name>.conf names. The names come from a fixed table in
kdos-comp (kdos-grant.c): screencopy, toplevel-capture, export-dmabuf, data-control,
foreign-toplevel, layer-shell, input-method and output-power, each mapping onto one to three
protocol globals. Any other global cannot be granted to a box, whatever its profile says, and a
grant cannot be narrower than its row: screencopy opens both generations of screen capture
together. The compositor reads a box’s profile at that box’s first bind and again after a
SIGHUP; a running client keeps what it bound. See
The security model for what a grant
costs.
A boxed application is given your location without being asked
The portal front end asks before sharing location only with an application in a sandbox it
recognises (Flatpak, Snap or Linyaps), and a KDOS box is none of them, so it counts as an
unsandboxed host program. GeoClue runs with no consent agent and an empty whitelist, and answers any
client on the system bus. For the same reason, the Camera and Screenshot questions are asked once
for all boxes together, since the front end sees no application id on any of them. No surface shows
or changes a stored answer: each portal’s answers are a file under ~/.local/share/flatpak/db/,
and deleting that file makes it ask again. See
The session.
A catalogue change reaches an installed application only when it is rebuilt
The application catalogue (see kdos-appbox) is
a list of rows, each naming an image and the packages it adds. An installed application is a built
image, so editing its row changes nothing a running system can see until kdos app install <id>
builds it again. For example, the base image’s row carries libva and the VA-API driver set; a
boxed browser built before the row carried them reports no hardware decoder and decodes every
frame on the CPU. Nothing tells you a row changed: the catalogue has no per-row version, so an image
counts as current until somebody removes it.
A live session cannot create a persistent box
The home directory is on the boot overlay, and the kernel refuses to stack a box’s writable layer
on an overlay. When kdos-packd composes a box there, the layer falls back to a tmpfs under
/run/user/<uid>/kdos/boxes/, so whatever a box writes outside the shared home directory ends with
the session. kdos doctor reports this as a warning about where the session’s home directory
lives, not as a failure. kdos-box create <name> base=pack:<id> asks podman for a container on
top of that composition, and when podman refuses on a live session it says that a persistent box
needs an installed system, takes the composition down, and leaves the profile it wrote.
kdos-box create with a box: base never finishes
kdos-box create <name> base=box:<other> copies the other box’s base into the new profile and
calls itself again with the same arguments, which set the base back to box:<other>, so it
recurses until the program crashes. Naming the other box’s own base instead (base=pack:<id> or
base=image:<ref>, as kdos-box profile <other> prints it) gives the same box. `kdos-box clone
` does not take this path, and copies the other box's writable layer as well. See
[create with a box base](/docs/kdos/04-programs/kdos-appbox.html#create-with-a-box-base).
### The *Containers* menu entries have not been opened on a built image
`kdos-podman-api` starts `podman system service` for `podman-tui` and `lazydocker`; what is
measured is its start, lock and idle-restart logic against a stand-in engine, not either tool
connecting to a real service. Pods and `--init` rely on `catatonit`, which is measured to build
statically and run a command, not to start a pod.
### A box is not a security boundary against you
By default it shares your home directory in full, along with your network, process table, `/dev`,
`/sys`, `/tmp` and runtime directory, so a program in it can reach the session bus and connect to
the compositor untagged through `wayland-0`. It limits what an application is offered by the
*desktop*, not what it can do to your data. A profile's `home = private` gives one box a home of its
own. See [The security model](/docs/kdos/03-architecture/security-model.html#what-is-not-protected).
### Twelve applications run on Qt 5, which has no 2026 security fixes
Qt 5.15.19 is the last Qt 5 the tree can build, and no public patch for a 2026 Qt 5 vulnerability
exists. Candle, GNU Radio, KeePassXC, LibreCAD, LMMS, Mumble, QSSTV, Quassel, SMPlayer, DB Browser
for SQLite, VLC and WSJT-X still link it, because no release of any of them builds with Qt 6: each
moves when one does. The reason for each is in
[the ports catalogue](/docs/kdos/06-reference/ports-catalogue.html#qt5). Their TLS goes through QtNetwork, and Mumble's
certificates and Quassel's channel encryption through their own OpenSSL calls, to the OpenSSL 3.5
long-term release in the `openssl3` slot, which does still receive fixes.
### A PyQt5 program that also uses Python's `ssl` or `hashlib` can crash
`python3-pyqt5`'s QtNetwork, QtQml, QtQuick, QtQuickWidgets, QtMultimedia, QtMultimediaWidgets
and QtWebSockets modules load `libQt5Network`, which links OpenSSL 3, while Python's own `_ssl` and
`_hashlib` link OpenSSL 4. musl's loader has one symbol namespace, so a process that loads both
resolves each library's calls into the other, and the first such call can fail or crash. A PyQt5
program is affected only when it loads one of those seven modules and also imports `ssl` or
`hashlib`, directly or through a library; `from PyQt5 import Qt`, which GNU Radio's gr-qtgui runs,
loads all seven. A Python program that needs both uses PyQt6, whose Qt links OpenSSL 4.
### Copying from `iamb` or `atuin` has not been confirmed to reach the clipboard manager
Text you copy in either should appear in `kdos-clip`'s history, and this has not been observed on a
built image. It is expected to work: both programs copy through the Wayland data-control protocol,
compiled into the binary itself, and `kdos-comp` provides that protocol. If a copy from either goes
missing, that is a bug worth reporting.
### A video call has never been placed
`baresip` is the SIP phone here, and its interface is a terminal menu. The far end's picture goes in
an `sdl.so` window; sending your own means enabling `v4l2.so`, which the generated configuration
leaves commented out because which camera to send is your choice. The rig (the QEMU harness that
boots a KDOS image and photographs it; see [Testing](/docs/kdos/05-developer/testing.html#the-qemu-rig)) has
no second endpoint and no camera, so what is measured is that the modules load. GStreamer's
`webrtcbin` is in the same state: it is built, with `libnice`'s `nicesrc` and `nicesink` and
`libsrtp`, and no pipeline has negotiated with a peer.
### `mbsync` has XOAUTH2 but not OAUTHBEARER, and no synchroniser has met a server
`cyrus-sasl` is the mechanism loader and ships no XOAUTH2 of its own, so the mechanism comes from
`cyrus-sasl-xoauth2` beside it, and that plugin implements only the one. A mail server offering only
OAUTHBEARER cannot be mirrored into a local Maildir, and with it goes `notmuch`'s index and offline
search for that account. `aerc` reads such an account and `msmtp` sends through it: measured on the
image, `msmtp --version` reports `Authentication library: built-in` and lists `oauthbearer` and
`xoauth2`, and `aerc` carries `imaps+oauthbearer`, `smtps+oauthbearer` and its own `xoauth2Client`.
Neither mail-and-calendar synchroniser has run against a server. The rig has no account, no network
and no IMAP or CalDAV server, so what is measured of `mbsync` and `vdirsyncer` is that each runs,
reports its version, does nothing and exits cleanly with nothing configured. That a password account
synchronises is unproven here and can only be proven against a real account. For XOAUTH2, what can
be measured on the image is that `libxoauth2.so` is in `/usr/lib/sasl2` and that `mbsync` links
`libsasl2`; that a provider accepts the token `pizauth` mints cannot.
### The list of Windows shares on the network is whatever answered a broadcast
Samba here is built without winbind and without a domain controller, so there is no browse master to
ask: `kdos-mount browse` is an mDNS query plus a NetBIOS one, and a machine that is asleep, on
another subnet, or behind a router that does not forward broadcasts is missing from it. It can still
be reached by name.
The file managers' `network://` view is the same: `gvfs` is built without its WS-Discovery (`wsdd`)
backend, because `wsdd` is not a port, so it lists only the hosts Avahi finds. A Windows machine,
which announces itself over WS-Discovery rather than mDNS, is reached by typing `smb://host`.
### An NFSv3 mount needs `-o nolock`
NFSv4 mounts and the v4-only server (`72_nfsd`) work. There is no `rpcbind` port, so `rpc.statd`
cannot register, and a `vers=3` mount that wants locking is refused. Mounting with `-o nolock`
works and keeps locks local to this machine.
### Kerberos is built and has never been given a ticket
`kinit`, `cifs.upcall` and the `request-key` rule that joins them are on the image, and
`kdos-mount krb5` mounts with `sec=krb5`, but there is no KDC here and no realm to join, since the
server half of krb5 is not installed. What is measured is the request the daemon makes, not that a
domain controller accepts it; no share has been mounted with a ticket on this image. `cifs.idmap` is
not built either: it needs winbind's client library, and this desktop does not need it, because
every share is mounted with an explicit `uid=` and `gid=`.
### The graphical passphrase prompt has not been exercised
`pinentry` is `pinentry-qt`, which draws a Qt dialog when the request from `gpg` carries
`WAYLAND_DISPLAY` or `DISPLAY`, and otherwise asks in the terminal `GPG_TTY` names. A program
started from a launcher should therefore get the dialog, but no signature or decryption has been
made through it on this image, so neither the dialog on `kdos-comp` nor its placement over the
window that asked has been seen.
### `rga` does not search `.htm` files
Its `pandoc` adapter, which reads `.docx`, `.odt`, `.epub`, `.fb2`, `.ipynb` and `.html` into text,
claims `.htm` too and passes the extension as the input format, and pandoc has no reader named
`htm`: each such file is reported as *Unknown input format 'htm'* and yields no match.
`rga --rga-adapters=-pandoc` drops the adapter, and the file is then searched as plain text. The
other formats, `.html` included, are searched through pandoc.
### A transcription has never been read back
What is verified is the model check, the `whisper-cli` command line, starting it and its exit
status. The image carries `base.en` in `/usr/share/whisper.cpp/models`; any other model is fetched
by `kdos speech get`, which picks one from a table, checks its sha256 and writes it to
`~/.local/share/whisper.cpp/models`. What has not been done is running a transcription and checking
its output.
### Live transcription is a terminal program, not a desktop action
`whisper-stream` is built and transcribes a microphone, and nothing on the desktop starts it.
`kdos-rec`'s *Transcribe* runs `whisper-cli` over the file it has just recorded. Both need the same
model, and `base.en` ships.
### The native applications have not been built
The browsers, office suites, editors, games and the rest of the graphical applications are recipes
under `ports/core`, named in the lists of the userland phases, `40_lang` to `44_apps`, with every
source fetched and hashed. None of them has been through a build, and none has been started on a KDOS image, so
what is written about any of them here and in [the ports catalogue](/docs/kdos/06-reference/ports-catalogue.html) describes
its recipe. The published source archive holds almost none of their sources, so `make fetch` on
another clone takes them from upstream. See
[The source archive has one public location](#the-source-archive-has-one-public-location).
### Five applications have no port
- **Anki** needs a cargo and a yarn vendor bundle in one recipe, a musl build of a native rollup
addon, and about seventeen Python ports that do not exist.
- **Ghidra** builds with Gradle, and Gradle's own build needs a Gradle seed and several hundred
Maven artifacts that `ports/fetch` has no mode to bundle.
- **LanguageTool** pulls in well over a hundred Java libraries, each of which would have to be
compiled from its sources, since upstream's prebuilt jars are not accepted.
- **Weasis** needs a Maven build and its own fork of OpenCV's Java binding, whose DICOM codecs have
no public source. `dcmtk` is the DICOM toolkit on the host.
- **YAAC** ships 58 prebuilt jars, some carrying glibc native libraries, and they fit no class of
[what is not built from source](/docs/kdos/01-philosophy/why-kdos.html#what-is-not-built-from-source).
### A saved login needs KeePassXC running
Programs that keep a password through the Secret Service (libsecret in GTK programs, QtKeychain,
KWallet's API) find a provider only while KeePassXC is running with its Secret Service integration
turned on in its own settings. The KeePassXC recipe enables that integration, and nothing starts
KeePassXC or turns it on. Without it, such a program has nowhere to store its secret: Nheko, for
one, stores its login through QtKeychain.
### Chromium checks no spelling and reaches no Google service
Chromium reads only its own `.bdic` dictionaries, which it downloads, so it cannot use the
Hunspell dictionaries on the host, and its spelling service is off by policy. It is configured with
no Google API keys, so sync, sign-in, Safe Browsing, translation and location services do nothing.
### Quassel shows no link previews
The previews need Qt 5's WebEngine, which is not a port, so `quassel` is configured with
`WITH_WEBENGINE=OFF`.
### A Quassel core cannot sign users in through LDAP
`quasselcore` keeps its accounts in its own database only. Quassel is a Qt 5 program, so it links
OpenSSL 3 through QtNetwork, and `libldap` links OpenSSL 4; one process cannot load both, so
`quassel` is configured with `WITH_LDAP=OFF`. It returns when a Quassel release builds with Qt 6.
### An Android screen cannot be mirrored
`scrcpy` is not a port: its device-side server is a jar that cannot be built here, and shipping
upstream's prebuilt one was declined. `adb` and `fastboot` from `android-tools` are on the host.
### A phone cannot drive the pointer or keyboard through KDE Connect
KDE Connect's remote input, the phone as a touchpad and keyboard, asks the RemoteDesktop portal for
an EIS connection (`ConnectToEIS`). No backend on KDOS answers RemoteDesktop:
`xdg-desktop-portal-wlr` does not implement it, `xdg-desktop-portal-kdos` does not either, and
`kdos-portals.conf` routes it nowhere, so the request is refused. Pairing, notifications, the
clipboard, file transfer and the other plugins do not use the portal.
### The local model and translation programs ship without models or pages
`llama-server` serves its OpenAI-compatible API and no web page: the page is a Svelte application
that is either built with npm or downloaded, and the offline build does neither. A page placed in a
directory is served with `--path`. Translate Locally ships no Bergamot language model; its model
list is fetched from the network only when asked, and a model downloaded elsewhere is imported from
the disk.
### Hatari ships no TOS
The Atari ST emulator needs a TOS or EmuTOS image, and building EmuTOS needs an m68k cross
toolchain that is not a port, so the user supplies the image.
### SolveSpace takes no 3D mouse
`spacenavd` serves a 3D mouse to every `libspnav` client, FreeCAD and OpenSCAD among them, but
`solvespace-qt` has no 3D-mouse support at all; upstream has it only in its GTK and Windows
interfaces.
### Every program speaks English
There is no non-English interface anywhere on the system. Every package is made without its
translations: message catalogs, Qt translations, translated KDE handbooks and translated manual
pages are removed as the package is built, so setting `LANG` or `LC_MESSAGES` to another language
changes no program's text, because there is nothing for it to load. Text in any language can still
be typed, shown and edited: fonts, keyboard layouts and the input methods for Chinese, Japanese and
Korean ship. The rule is in
[Writing ports](/docs/kdos/05-developer/writing-ports.html#size-and-language-policy).
### `texdoc` finds no manuals, and HTML and PDF manuals are not installed
The manuals of the TeX packages are the `texlive-doc` port, which no phase builds, so `texdoc` has
nothing local to open; read them on CTAN. `kpkg install texlive-doc` does not change that as the
tree stands: the package-time prune removes its PDF manuals. Every other port's HTML and PDF manuals are removed as its package is made, and its
manual pages and info pages ship instead. HTML a program opens itself stays: mednafen's manual,
which upstream writes only in HTML, R's help index, the manuals behind the Help menus of geany,
gimagereader, texstudio, WSJT-X, Wireshark and hatari, the pages FreeCAD's and SMPlayer's About
dialogs show, and this book under `/usr/share/doc/kdos`.
## Hardware and platform
### x86-64 only
There is no other build target: the cross toolchain targets `x86_64-kdos-linux-musl`, and every
later phase builds with it.
### Secure Boot is not supported
Limine's EFI binary is unsigned and KDOS enrols no keys, so a machine with Secure Boot enabled
refuses to load it. The installer reports the firmware state on its first page; turning Secure Boot
off in firmware setup is the only way.
### 32-bit UEFI is built and has never been booted
`BOOTIA32.EFI` is on the ISO's EFI system partition tree, on an installed machine's, and in the El
Torito UEFI record, and the installer writes a firmware boot entry naming it where
`/sys/firmware/efi/fw_platform_size` says 32, but the machine that needs it is an early Atom tablet,
and nothing here has one. What is verified is that the binary is built and placed. BIOS and 64-bit
UEFI are the two that have been booted.
### Broad hardware support is not a goal
The firmware tree ships everything an x86 driver can load, which covers a great deal, but nothing
here is tested against a wide range of devices.
### `linux-firmware` leaves out what an x86 kernel cannot load
About 370 MiB of upstream's tree is not installed, by an explicit list in the recipe: the
Qualcomm SoC firmware under `qcom/` (Adreno GPU, Venus and Iris video, and the DSP images of
the arm64 laptop and phone SoCs), every `mlxsw_spectrum*.mfa2` except the three revisions the
`mlxsw` driver names, and Marvell Prestera v2.0 and v3.0. What stays under `qcom/` is what x86
drivers request: `aic100` and `aic200` (`qaic`), and `qdu100`, the `sdx*` modems and the
`prog_firehose_*` loaders (`mhi_pci_generic`). A kernel whose `mlxsw` asks for a newer
Spectrum revision than the recipe keeps finds no file and leaves the switch on the firmware in its
flash.
### `btop`'s GPU panel is empty on Intel graphics unless btop runs as root
It reads the i915 performance counters with `perf_event_open`, a system-wide event that the
kernel's default `perf_event_paranoid` of 2 refuses to a process without `CAP_PERFMON`, and nothing
grants that capability to the binary or lowers the setting. `sudo btop` shows the panel.
### LVM volume groups are activated only at boot
The initramfs activates them on a disk boot, then the `03_lvm` init script does. A disk carrying LVM
that is plugged in later shows no logical volumes until you run `sudo vgchange -aay`: lvm2's own
hotplug activation runs through `systemd-run`, so it is built off and its udev rule is not
installed.
### A root filesystem on LVM has not been booted
The installer's erase plan creates the volume group and slot A's volume, its reuse plan lists
existing volumes, and the initramfs carries `thin_check`, `cache_check` and the thin, cache and
snapshot targets. The commands were run against a loop device in a container and the installer's
probe and dry run were read back there, but no install onto LVM (plain, encrypted, thin or cached)
has been booted. The installer lays out only one shape, a volume group of one physical volume on the
target disk, and makes no `root_b`: slot B's space is left free, and its volume is made by hand like
the rest of slot B; see
[Activating volume groups](/docs/kdos/03-architecture/boot-and-init.html#activating-volume-groups).
### `lsblk` shows a filesystem's type, label and UUID to root only
util-linux is built without libudev, because eudev needs util-linux's libblkid first, so lsblk can
learn them only by probing the device, which it does only as root. `sudo lsblk -f`, or `blkid` as
root, answers.
### The power button and the sleep key work only inside a graphical session
They arrive as keys, which the compositor's `rc.xml` binds. There is no acpid, and nothing below the
session listens for them, so at a text login or on the console desktop the power button does
nothing. Neither binding has been pressed on real hardware.
### A USB modem that first appears as a storage device is not switched into a modem
`usb_modeswitch` is not a port, so such a stick shows up as a small read-only disk and ModemManager
never sees it. A built-in WWAN card, and a stick that appears as a modem straight away, connect
through NetworkManager. Mobile broadband, PPPoE and Bluetooth tethering are built and have not been
connected on hardware.
### A UEFI firmware (capsule) update has not been applied
What is verified is that `fwupd-efi` builds its loader with the NX flag and a KDOS SBAT line, and
that the EFI-partition probe the `fwupd` recipe patches in reads the right partition number, offset,
UUID and type from a mounted EFI partition. No capsule has been staged and booted: the rig's
firmware publishes no ESRT, so it has no device to update.
### A phone is mounted by hand
`kdos-mountd` offers block devices only, so an MTP phone never appears in its list. The Android
File Transfer window and `aft-mtp-mount ~/Phone` are the ways in, and no phone has been reached
through either on this system.
### Smart cards, drawing tablets and software radios have not met hardware
`opensc` has not been used with a card in a reader, `libwacom`'s pairing with a tablet, or the
SoapySDR modules with a radio; each is built and never tried against the hardware. The SDR
applications (GNU Radio, SDR++, SDRangel, Gqrx, URH) have not been through a build. SDRplay receivers have a udev permission rule
and no driver, because SDRplay's API is published only as a closed library, so SoapySDRPlay3,
SDRangel's SDRplay input and SDR++'s SDRplay source are all off. XTRX is not supported at all: it
needs the out-of-tree `xtrx_linux_pcie_drv` kernel module, and its libraries are unmaintained.
SDRangel's four remote plugins (remote input, output, sink and source) are not built on x86-64:
they need SSE3 at compile time, which the x86-64 baseline the tree compiles for does not define,
and `cm256cc`, the library they use, needs a processor with SSSE3 there. An aarch64 build, where
NEON stands in, builds all four against the `cm256cc` port.
### Packet radio has no kernel network interface
Linux 7.2 carries no AX.25, NET/ROM or ROSE stack and none of the hamradio device drivers, so there
is no `ax0` interface, no `kissattach` and no connected-mode AX.25 socket. Packet radio runs in
userspace instead: `direwolf` is the modem, Pat reaches it through its AGW port with the
`ax25+agwpe` transport, and Xastir through a KISS serial or network interface. A program that needs
the kernel's AX.25 sockets, such as the `ax25-tools` and `ax25-apps` suites, a NET/ROM node or
LinFBB, has nothing to talk to.
### Intel Quick Sync through oneVPL has no runtime
`libvpl` and `vpl-gpu-rt` are not ports, so ffmpeg's and GStreamer's `qsv` paths find nothing.
VA-API reaches the same decode and encode hardware through `intel-media-driver` and
`libva-intel-driver`.
### Encrypted Blu-ray discs do not play
An AACS-encrypted Blu-ray needs `libaacs`, which is not a port, so `mpv`, `ffmpeg` and GStreamer
open only an unencrypted Blu-ray or a backup. A Blu-ray's BD-J menus do not run either: they are
Java, and `libbluray` is built without its jar (`-Dbdj_jar=disabled`), because the jar is built
with Apache Ant, which is not a port, so a disc plays its titles without them. A CSS-encrypted DVD is opened through `libdvdcss`, which
`libdvdread` is configured to link. An audio CD lists as numbered tracks, because the CDDB lookup
`cmus` and `libcdio` can make needs `libcddb`, which is left out: its one job is a lookup over the
network. None of the optical paths has read a disc here, because the rig has no drive.
### Burning a disc and writing an image are unproved on hardware
`kdos-burn` has not burnt a disc: the rig has no optical drive, so what is verified is its frame
and the `--compare` it runs afterwards, not `xorriso`'s write or its `-compare_r` against a real
medium. The `write` verb of `kdos-mountd` is proved under `--fixture-serve`, where the copy and the
read-back run against a scratch file; the `O_EXCL` claim, the cache drop before the verify and the
partition re-read after it act only on a real block device and have not met one. `write` offers
only a disk the daemon lists, which means a disk carrying a filesystem it recognises: a blank stick,
or one holding only a partition type it does not probe, cannot be written through it, and in a live
session any disk with an ISO 9660 partition is refused as the boot disk.
`kdos-verify` checks a BLAKE3 list with `b3sum`, which is not a port, so such a list answers that
`b3sum` is not on this machine. SHA-256, SHA-512 and par2 are checked.
## Installation
### An interactive install stays on the Summary page
The wizard's pages are counted from zero, and Summary, Install and Done are pages 8, 9 and 10.
*BEGIN INSTALL* starts the install and moves to page 8, which is Summary itself, so the progress,
the log and the *Retry step* button on the Install page are never shown, and neither is the Done
page. *BEGIN INSTALL* stays live while the install runs, and pressing it again starts a second
install child beside the first. The Install page's *Continue*, when it is reached, moves to page 9,
which is Install again. The install itself runs to the end and writes its log to
`/var/log/kinstall.log` on the live system. An unattended install is not affected: it finds the
Install page by its id. See [The pages](/docs/kdos/04-programs/kinstall.html#the-pages).
### Applications imported or built during an install stay in the live session
Of the three routes the Applications step can take, only *pending* reaches the installed machine:
it records the selection in the target's `/var/lib/kdos/apps-pending`, and the first session
offers to build it. The *import* route runs `kdos-appbox import ` and the *network* route
runs `kdos-appbox install …`, both in the live session with no target root, so what they
install lands in the live system's store and ends with it. The target gets the empty store
directories and nothing in them. See
[The applications step](/docs/kdos/04-programs/kinstall.html#the-applications-step) and
[Applications](/docs/kdos/02-user-guide/installation.html#8-applications).
### An unattended install skips every check the pages make
`kinstall --config --unattended` goes straight to the install, and the checks each page
makes before it lets you continue are never run: that the target is not the running boot medium
and not read-only, that it is large enough, that the two passphrases and the two passwords match,
that the hostname and user name are well formed, that root is not locked while the user is not an
administrator, and that no other disk already holds a volume group named `kdos`. An answer file
that the wizard would refuse goes to the install as it is. Loading the same file into the wizard
(`kinstall --config `) and stepping through the pages runs the checks. See
[Installing unattended](/docs/kdos/02-user-guide/installation.html#installing-unattended).
### The installer's warnings are shown nowhere
The install child reports its progress to the wizard as one-letter lines, and the wizard drops every
warning (`W`) line: it is neither drawn nor written to `/var/log/kinstall.log`. What goes unreported
is a Limine with no `BOOTIA32.EFI`, a failed `limine bios-install` or no `limine` on the path, no
partition index for the EFI partition and so no firmware boot entry, an EFI partition too small for
a second slot's kernel, and an application route that fell back to *pending*. The install finishes
as if none of them happened. See [The install runs in a child
process](../04-programs/kinstall.md#the-install-runs-in-a-child-process).
## Boot and updates
### A disk-encryption key is typed, not sealed in the TPM
`tpm2-tss` and the `tpm2_*` tools ship, so a key *can* be sealed to the chip by hand, but nothing in
the boot path unseals one: `unlock_root` reads a passphrase from `tty1` and has no other route.
Adding one means a sealed blob on the EFI partition, a PCR policy, and an answer for what happens
when a firmware update changes the measurements, none of which is decided.
### Nothing creates or first fills the second root slot
The installer lays down slot A only and writes a state with `slot_b` empty. A second slot's
filesystem has to be made, filled with a copy of the system and recorded with
`kdos-bootctl set-slot b []`, all by hand; the steps are in
[Installation](/docs/kdos/02-user-guide/installation.html#ab-root-slots). From there `kdos update apply`
installs into the mounted inactive slot, deploys its kernel and marks it to try; the initramfs
selects a slot, unlocks that slot's own encrypted container and counts attempts; and a boot that
reaches the end of initialisation confirms the slot. A second *encrypted* slot has never been
booted. What is measured is on the build host: rolling back from slot B to A hands back A's
container and not B's, which is the failure the mechanism exists to prevent.
### The update path has not been run against a published tree
`kdos update fetch` takes `kdos-ports.tar.xz` from the latest release, and only a release made by
`ports/publish --release` with a release key carries one; until then it reports `fetch-failed`. Its
signature check, the refusal of an older tree, the exchange with `/ports`, `kpkg fetch`'s archive
and upstream order, and the recorded problems have been exercised against local directories in a
container with no network, and `kpkg fetch` is asserted by the self-test, but none of it against a
real release over the internet. No `kdos update apply` has built a
large set on an installed machine, so how long one takes, and how much of `/var/cache/kpkg` it
needs, is not measured.
### Per-slot kernels have not been booted
`deploy`, the regenerated boot menu, the hand-picked entry and the rollback onto the confirmed
slot's kernel are asserted on the host against a fixture EFI partition, and the `linux`
postinstall's appended initramfs was assembled and inspected, not started. The UEFI `BootNext` trial
has not met a real firmware: the load option is compared byte for byte with the specification's
layout, and the trial menu, rollback and clean-up are asserted against a fixture EFI partition, a
fixture GPT image and a directory standing in for `efivarfs`. A firmware that ignores `BootNext`, or
deletes a `Boot####` entry that is not in `BootOrder`, rolls every candidate back unbooted rather
than looping. On BIOS, a candidate kernel that dies before its initramfs runs spends no attempt,
because Limine counts nothing: the menu keeps leading with it until you pick the confirmed slot's
`/KDOS (slot )` entry by hand; see
[One boot through BootNext](/docs/kdos/03-architecture/boot-and-init.html#one-boot-through-bootnext).
A root that has no `/boot/initramfs.modules` builds a new kernel's initramfs from the module set its
own initramfs carries, rather than from a list; that path has been exercised on test archives only.
See [A new kernel](/docs/kdos/03-architecture/boot-and-init.html#a-new-kernel).
### A slot keeps the init it was installed with until that slot is updated
This affects a slot whose initramfs `init` does not read `kdos_slot=`, the word on each boot entry
naming the slot its kernel came from (see [Command-line parameters KDOS
reads](../03-architecture/boot-and-init.md#command-line-parameters-kdos-reads)). An update appends
modules to an initramfs and never replaces its `init`, and the confirmed slot's `init` is the one
that carries out a rollback. While an update is on trial on a machine whose confirmed slot has such
an `init`:
- in a trial led by the boot menu, a rollback returns to the confirmed slot's root but still on the
candidate's kernel, until `kdos-bootctl mark-good` corrects the menu at the end of that boot;
- after a UEFI `BootNext` trial's one boot, the next boot starts the candidate's root on the
confirmed slot's kernel once, and `mark-good` then sees the confirmed slot's `kdos_slot=` and rolls
the candidate back.
Both stop once the confirmed slot is itself updated, which gives it an `init` that reads
`kdos_slot=`. See [One kernel per slot](/docs/kdos/03-architecture/boot-and-init.html#one-kernel-per-slot).
## Security
The full statement is
[What is not protected](/docs/kdos/03-architecture/security-model.html#what-is-not-protected). In brief:
- there is no mandatory access control, no verified boot and no measured boot;
- kernel modules are signed but the signature is not enforced: root loads an unsigned module and
the kernel only marks itself tainted;
- the live image's serial console is a root shell with no password (an installed system's asks
for a login);
- on the live image, `root` and `kdos` both have the password `kdos`, and `sshd` starts at boot
behind the firewall's drop policy;
- the live image logs in as `kdos` automatically; an installed system does so only when its
answer file set `autologin = yes` or `kdos-power autologin` set it later;
- disk encryption protects data at rest only;
- a box shares your home directory by default, and can therefore edit its own profile and widen
its own compositor grant;
- a box granted `input-method` receives every keystroke on the seat;
- membership of `wheel` is effectively root;
- an OCI base image pulled from a registry is unsigned content;
- an unsigned pack mounts unless `KDOS_REQUIRE_SIG` is set, while a pack whose signature fails
does not;
- nothing installs updates automatically: a daily timer (`/etc/kdos/timers.d/10-update-check.timer`)
fetches the signed ports tree and runs `kdos update check`, and `kdos update apply` runs only when
you run it;
- `kdos-oomd`'s choice between several large processes is tested only against recorded process
tables.
## Ports built without a feature
Each port, its shelf and the phase that builds it, and the recipes that are not installed at all
are in [The ports catalogue](/docs/kdos/06-reference/ports-catalogue.html).
### Go has no race detector and no BoringCrypto
Both are objects upstream compiles and ships inside the source tarball, and the `go` port does not
install them, so `go build -race`, `go test -race` and `GOEXPERIMENT=boringcrypto` fail to link.
The `testdata` directories of the standard library's source are not installed either (33 MB,
including foreign ELF fixtures), so `go test std` fails; a module's own tests are unaffected.
Every other Go build is unaffected.
### GHC has no profiling libraries
The `ghc` port builds Hadrian's `release` flavour without its profiled variants, so `ghc -prof` and
`cabal --enable-profiling` fail to find the profiled `base`. Of GHC's documentation only the
`ghc(1)` manual page is installed. The User's Guide and the Haddock pages of the shipped libraries
are not, so `cabal haddock` writes pages whose references into `base` and the other GHC libraries
are plain text rather than links.
### SpatiaLite cannot load a WFS layer from a URL
libxml2 2.15 has no HTTP client, and the `libxml2` port builds none of its stand-in stubs, so
SpatiaLite's WFS functions (`load_from_wfs`, the `ImportWFS()` SQL function and the GetCapabilities
helpers) read a local file and fail on an `http://` address. The `libspatialite` port compiles its
proxy reset only where libxml2 has one. Fetch the document first, for example with
`curl -o layer.xml ''`, and load the file.
### nmap has no `jdwp-exec` and no `jdwp-info` script
Both inject Java classes that upstream compiles and ships inside the source tarball, and the `nmap`
port installs neither the classes nor the two scripts, so `--script jdwp-info` names nothing and the
`default` category runs without it. `jdwp-inject`, which injects a class you supply, and
`jdwp-version` are unaffected.
### qemu carries firmware only for its three targets' default machines
That is the x86_64 PC machines, aarch64 and riscv64 `virt`, and microvm, each through its defaults
and its firmware descriptors. The Nuvoton and ASPEED BMC boards inside `qemu-system-aarch64` stop at
startup with *Could not find ROM image* unless `-bios` names one, and there is no 32-bit Arm UEFI,
no 32-bit x86 OVMF and no OVMF build for microvm. The riscv64 `virt` UEFI image is upstream's rather
than compiled here; see [what is not built from
source](../01-philosophy/why-kdos.md#what-is-not-built-from-source).
### A qemu guest cannot join a host bridge as an ordinary user
`-netdev bridge` runs `qemu-bridge-helper`, which is installed without its setuid bit and with no
`/etc/qemu/bridge.conf`, so it serves only root, and only once root writes an `allow ` line
there. Making it setuid would add a root program to the
[setuid list](/docs/kdos/03-architecture/security-model.html), and that is not decided. User-mode networking
through `passt` needs no privilege.
### PROJ has no transformation grids, and no port carries them
A transformation that needs a grid (NAD27 to NAD83, OSGB36, a national geoid) falls back to a
ballpark one or fails, naming the grid it wanted. proj is built with `ENABLE_CURL=OFF`, so grids are
never fetched on demand either; the transformations that need no grid are the ones the bundled
`proj.db` answers exactly.
### presenterm's seven stock syntax themes are not compiled here
`base16-ocean.dark`, `InspiredGitHub`, the Solarized pair and the rest come from the serialized
`default.themedump` inside the vendored `syntect` crate. Their `.tmTheme` sources are in syntect's
repository and not in the crate, and the only way to swap in a rebuilt dump is a patch to
presenterm's theme loading. Its grammars, and bat's themes, are compiled here by the `bat` port.
### Strawberry has no tag fetcher
The fetcher sends a song's fingerprint to AcoustID and MusicBrainz, so `strawberry` is configured with
`ENABLE_TAGFETCHER=OFF`. Its fingerprints are still taken, locally, so a moved or renamed file keeps
its play counts and ratings.
### LinuxCNC is the simulator only
The recipe removes the setuid bit upstream sets on `rtapi_app` and `linuxcnc_module_helper`, so
LinuxCNC runs its threads without realtime priority and cannot drive a machine. The latency
histogram draws with BLT, which has no Tcl 9 support and is not a port, so it has no menu entry.
### GTK 4 converts half-float pixels without F16C
GTK 4's F16C path is chosen at run time through a GNU indirect function (`ifunc`), and its
configure probe needs the compiler to accept one. musl's dynamic loader resolves no `ifunc`, so
the probe fails and `gtk4` is built without `HAVE_F16C`: every conversion between 16-bit float and
32-bit float pixels, in GDK's memory-format conversions and in the GL renderer, takes the portable
C loop. Rendering is the same; a high-bit-depth or HDR texture costs more CPU to convert. No port can
change this short of a C library with `ifunc` support.
### A SPICE viewer redirects only the USB devices you can already open
`spice-gtk` is configured without `spice-client-glib-usb-acl-helper`, the setuid helper that opens
a device node for an unprivileged client, so USB redirection from virt-manager reaches only the
devices whose nodes a udev rule already gives you. Folder sharing (phodav) and smart card
passthrough (libcacard) are enabled.
### Features whose library has no port
The ports below are built with a feature switched off because the library or program behind it is
not in the tree. A missing library becomes a port when it adds something a person on this desktop
would see; OpenImageDenoise with ispc, Embree, meshoptimizer, libsrt and librist are ports for that
reason. Each one below was weighed the same way and left out, for the reason in its row:
- **one feature**: it serves one optional feature of one or two programs, and the program is whole
without it;
- **hardware**: it drives devices or buses the image has no other support for;
- **vendor**: it is a closed SDK or runtime, which is not built from source (see
[what is not built from source](/docs/kdos/01-philosophy/why-kdos.html#what-is-not-built-from-source));
- **superseded**: upstream has stopped maintaining it, or a port in the tree does the same work;
- **service**: it talks only to a network service or an account this desktop does not run;
- **large**: it is a stack of its own, with a build system and dependencies larger than the
feature it adds;
- **X11**: it works only on an X11 session, and the session here is Wayland;
- **rule**: it belongs to something KDOS excludes, such as systemd or SELinux (see
[Principles](/docs/kdos/01-philosophy/principles.html)).
`python3 testing/optdeps.py --claims` lists every recipe line that says a dependency is not a port,
and `python3 testing/optdeps.py` lists every switch that turns off a feature a port does provide;
see [Testing](/docs/kdos/05-developer/testing.html).
| Port | What is off | Missing | Why |
|---|---|---|---|
| `aalib` | The console mouse | gpm | one feature |
| `abiword` | Grammar check, thesaurus, MathML, summaries, the database, Psion and WMF importers; calendar, address-book, RDF and map fields | link-grammar, aiksaurus, gtkmathview, ots, libgda, psiconv, libwmf, Evolution Data Server, Redland, libchamplain | one feature each |
| `aircrack-ng` | The ESSID regular-expression filter | PCRE 1 | superseded |
| `alsa-utils`, `pipewire` | FireWire audio interfaces | libffado | hardware |
| `anthy-unicode` | The Emacs front end | emacs | one feature |
| `ark` | RAR, ARJ and `unar` formats beyond what libarchive reads | unrar, arj, unar | vendor (unrar's licence), one feature |
| `aubio`, `openimageio` | Manual pages | txt2man | one feature |
| `avidemux` | AV1, FAAC, Aften, DCA, Xvid and AMR encoders, VapourSynth input | aom, faac, aften, dcaenc, libdca, xvidcore, opencore-amr, VapourSynth | one feature each; dav1d decodes AV1 in every player |
| `avogadrolibs` | Space groups, symmetry and spectra plots | Spglib, libmsym, JKQTPlotter | one feature each |
| `baresip` | AMR, G.722, G.722.1 and packet-loss concealment codecs; ZRTP | opencore-amr, libg722, spandsp, gzrtp | one feature each |
| `blender` | VR, USD, MaterialX and Hydra; OSL shaders and OpenPGL path guiding in Cycles | OpenXR, USD, MaterialX, OSL, OpenPGL | large; no OpenXR runtime exists on this image |
| `boost` | The `stacktrace_backtrace` variant | libbacktrace | one feature |
| `brltty` | The Libbraille driver | libbraille | hardware |
| `btrfs-progs` | Converting a ReiserFS volume | reiserfsprogs | superseded: the kernel has no ReiserFS |
| `cantor` | The Julia back end | julia | large |
| `ceres-solver` | METIS ordering for the sparse solvers | METIS | one feature |
| `clamav` | The mail milter | libmilter | service: no mail transfer agent runs here |
| `codec2` | The FreeDV 2020 mode | LPCNet | one feature |
| `coin` | VRML JavaScript and image textures through simage | SpiderMonkey, simage | one feature; no consumer here uses them |
| `crun` | Container checkpoint and restore | CRIU | one feature |
| `cura` | The MakerBot writer | pyDulcificum | one feature |
| `darktable` | The map view, display colour management, G'MIC and Unity launcher progress | osm-gps-map, colord, G'MIC, libunity | service (online tiles), one feature each |
| `dasher`, `gparted` | The GNOME help | yelp-tools | one feature |
| `deja-dup` | Restoring a Duplicity backup | duplicity | superseded: new backups use restic |
| `dnsmasq`, `iptables` | Connection-tracking marks and labels | libnetfilter_conntrack, libnfnetlink | one feature; nftables is the firewall |
| `elisa` | UPnP browsing | UPnPQt | superseded: marked broken upstream |
| `enchant` | The nuspell, Hspell and Voikko providers | nuspell, hspell, libvoikko | one feature each; Hunspell and Aspell are the providers |
| `falkon` | The GNOME keyring password plugin | libgnome-keyring | superseded: KWallet keeps the passwords |
| `fastfetch` | The VDPAU, EET, RPM, ImageMagick 6 and QuickJS probes | libvdpau, efl, rpm, ImageMagick 6, quickjs | one feature each |
| `fcitx5-chinese-addons` | The graphical configuration tool | fcitx5-configtool | one feature; the configuration is a text file |
| `ffmpeg` | VDPAU, sndio, CUDA, NVENC and AMF | libvdpau, sndio, the NVIDIA and AMD SDKs | X11, vendor |
| `fluidsynth` | The MidiShare driver | MidiShare | superseded |
| `foot` | A login record for each window | libutempter | one feature |
| `freecad` | Point clouds | PCL | large |
| `freedoom` | The PDF manuals | asciidoctor-pdf | one feature |
| `gcc-arm-none-eabi`, `gcc-avr`, `gcc-riscv64-unknown-elf` | Graphite loop optimisations | isl | one feature |
| `gdb` | CTF traces, source highlighting through GNU source-highlight, Intel Processor Trace, AMD GPU debugging, debuginfod | babeltrace, source-highlight, libipt, amd-dbgapi; elfutils is built without debuginfod | one feature each, vendor; Pygments colours the source |
| `gdk-pixbuf` | Sandboxed image loading through glycin | glycin | one feature; the built-in loaders read every format |
| `gimp` | MNG, WMF and ILBM files; JavaScript and Lua plug-ins; full dashboard backtraces | libmng, libwmf, libilbm, gjs, lua-lgi, libbacktrace | one feature each |
| `glabels` | GNU Barcode and IEC 16022 symbologies; the Evolution address book | GNU Barcode, libiec16022, Evolution Data Server | one feature each; QR comes from qrencode |
| `glib-networking`, `openconnect` | PAC proxy configuration | libproxy | one feature; `http_proxy` and friends are honoured |
| `gmsh` | CGNS, Mmg remeshing and PETSc solvers | CGNS, Mmg, PETSc | large |
| `gnucash` | The SQL back ends and online banking | libdbi, AqBanking | one feature each; XML books are built |
| `gnumeric` | Psion and Paradox import, the database plug-in | psiconv, pxlib, libgda | one feature each |
| `goldendict-ng` | EPWING dictionaries | libeb | one feature |
| `gthumb` | Display colour management | colord | one feature |
| `gvfs` | Approving a WebDAV server's untrusted certificate; Windows network discovery | gcr, wsdd | one feature each; `network://` lists what Avahi finds |
| `ifcopenshell` | COLLADA and USD output, the RocksDB cache | OpenCOLLADA, USD, RocksDB | large |
| `imagemagick` | Liquid rescale, Ultra HDR, MagickCache | liblqr, libultrahdr, MagickCache | one feature each |
| `iperf3` | SCTP tests | lksctp-tools | one feature |
| `k3b`, `scummvm`, `vlc` | Musepack audio | libmpcdec | one feature |
| `kate` | The telemetry settings page | KUserFeedback | one feature |
| `kdeconnect` | Remote input from the phone on X11 | libfakekey | X11 |
| `kfilemetadata` | AppImage metadata | libappimage | one feature |
| `knewstuff` | The RSS provider type | Syndication | one feature |
| `konsole` | The Kapsule container profiles | Kapsule | one feature |
| `ktexteditor` | `.editorconfig` files | EditorConfig | one feature |
| `ldns` | A default DNSSEC trust anchor: `drill -S` needs `-k` | `/etc/unbound/root.key` (unbound, dns-root-data) | one feature |
| `libbluray` | AACS-encrypted discs; BD-J menus | libaacs, Apache Ant | vendor (keys), large (a JDK under ffmpeg) |
| `libcap-ng` | `cap-audit` | libaudit | one feature; no audit daemon runs here |
| `libgpod` | The SCSI path for older iPods | sg3_utils | hardware |
| `libheif` | The rav1e, kvazaar, uvg266, VVC and OpenJPH codecs | rav1e, kvazaar, uvg266, vvdec, vvenc, OpenJPH | one feature each |
| `libiscsi` | iSER transport | rdma-core | hardware |
| `libisofs`, `libisoburn` | Jigdo templates | libjte | one feature |
| `libmysofa` | `mysofa2json` and the tests | CUnit | one feature |
| `libnice` | UPnP port mapping | gupnp-igd | one feature |
| `libsigrok` | VISA, GPIB and IEEE 1284 instruments | librevisa, libgpib, libieee1284 | hardware |
| `libtiff` | LERC compression | lerc | one feature |
| `libvips` | GIF save through cgif, Ultra HDR, NIfTI, OpenSlide and quantizr | cgif, libuhdr, niftilib, OpenSlide, quantizr | one feature each |
| `libvirt` | The `iscsiadm` storage back end | open-iscsi | one feature; `iscsi-direct` is built |
| `libwacom` | `libwacom-show-stylus` | pyudev, python-libevdev | one feature |
| `libxfce4ui` | Startup notification and the system information pane | startup-notification, libgtop | one feature each |
| `linuxcnc` | The latency histogram | BLT | one feature |
| `lmms` | Carla and sndio | Carla, sndio | one feature each |
| `ltrace`, `lvm2`, `gettext`, `nbdkit` | SELinux and Smack labels | libselinux, Smack | rule |
| `luanti` | The LevelDB and Redis map databases | LevelDB, Redis | one feature each; SQLite stores the worlds |
| `mbpoll` | GPIO RTS control | libpiduino | hardware |
| `mpv` | Colour ASCII output, VapourSynth, JavaScript scripts, CUDA | libcaca, VapourSynth, mujs, CUDA | one feature each, large, vendor; Lua scripts run |
| `mumble` | Remote control over Ice | ZeroC Ice | one feature |
| `nbdkit` | The libblkio, libguestfs and VDDK plug-ins; USDT probes | libblkio, libguestfs, VMware VDDK, systemtap | large, vendor |
| `net-snmp` | The process-table regular-expression match | PCRE 1 | superseded |
| `netgen` | Python type stubs | pybind11-stubgen | one feature |
| `ntfs-3g` | Boot geometry from `libhd` | hwinfo | one feature |
| `obs-studio` | The browser source and What's New panel, `obs-websocket`, WebRTC output, AJA, DeckLink, NVENC and Quick Sync, sndio | CEF, websocketpp, libdatachannel, the AJA, Blackmagic, NVIDIA and Intel SDKs, sndio | large, one feature each, vendor |
| `opencascade` | Image export through FreeImage | FreeImage | one feature |
| `openimageio` | Ptex, Ultra HDR, OpenJPH, RED R3D and Nuke | Ptex, libuhdr, OpenJPH, the R3D SDK, the Nuke SDK | one feature each, vendor |
| `opensc` | The German eID's PACE channel and `npa-tool` | OpenPACE | one feature |
| `opensubdiv` | The Ptex, CUDA and OpenCL back ends | Ptex, CUDA | one feature, vendor |
| `orca` | Mouse review | libwnck | X11 |
| `perf` | libpfm4 event names, CTF output from `perf data`, USDT probes | libpfm4, babeltrace2, systemtap | one feature each |
| `picard` | Installing plug-ins from git | pygit2 | service |
| `pipewire` | ROC streaming, LC3plus, LDAC decoding, spandsp | roc-toolkit, lc3plus, an LDAC decoder, spandsp | one feature each |
| `powerman` | Genders node lists and TCP wrappers | genders, tcp_wrappers | one feature, superseded |
| `printrun` | `pronterface` and `plater`, the wx front ends | pyglet, puremagic | one feature; `printcore` and `pronsole` run |
| `profanity` | OTR encryption | libotr | superseded: OMEMO is built |
| `purpose` | Account sign-in for the YouTube and Nextcloud targets | KAccounts | service |
| `python3-meshtastic` | `mesh-analysis`, the web dashboard over a node's log | dash, dash-bootstrap-components, plotly, pyarrow | large; the `meshtastic` command is whole without it |
| `python3-nbconvert` | The web-PDF exporter | Playwright | large; the LaTeX PDF exporter runs |
| `python3-pyqt5` | The QtBluetooth, QtNfc, QtLocation, QtPositioning, QtSensors, QtWebChannel, QtRemoteObjects, QtTextToSpeech, QtXmlPatterns, QtQuick3D and QtWebKit bindings | those Qt 5 modules | one feature each |
| `qemu` | Guest 3D (`virtio-vga-gl`), the manual pages | virglrenderer, sphinx_rtd_theme | one feature each; a guest renders in software |
| `qgis` | GRASS, Oracle and SAP HANA | GRASS GIS, the Oracle and SAP client libraries | large, vendor |
| `qt6-qtquick3d` | Timeline animations in `balsam` imports | Qt Quick Timeline | one feature |
| `qt6-qtspeech`, `webkitgtk`, `webkitgtk6` | The Flite engine and Spiel; gamepads in WebKit | Flite, Spiel, libmanette | one feature each; speech-dispatcher is the engine |
| `qutebrowser` | The Brave ad-block engine | python-adblock, tldextract | one feature; the host-list blocker works |
| `recoll` | CHM files | libchm | one feature |
| `rmpc` | The visualiser pane | cava | one feature |
| `samba` | Snapper snapshots, GlusterFS, CephFS, FAM, DMAPI, LTTng, `winexe` | snapper, GlusterFS, Ceph, FAM, DMAPI, LTTng, a mingw cross-compiler | large, service |
| `satdump`, `sdrangel`, `urh` | SDRplay, Aaronia and XTRX radios | the SDRplay API, the Aaronia RTSA SDK, libxtrx | vendor, hardware |
| `skopeo` | Sequoia signatures | podman-sequoia | one feature; GnuPG signing is built |
| `slang` | The PCRE module | PCRE 1 | superseded |
| `smplayer` | The MPlayer back end | MPlayer | superseded: mpv is the player |
| `texlive` | `xindy` | clisp | large |
| `texstudio` | The embedded terminal | QTermWidget | one feature |
| `thunderbird` | The RLBox WebAssembly sandbox | wasi-sdk | large |
| `timg` | OpenSlide images | OpenSlide | one feature |
| `viking` | Map rendering through Mapnik | Mapnik | large |
| `vlc` | RTSP through live555, FireWire capture, SMB shares, Icecast output, teletext, ARIB subtitles, Kate and Tiger subtitles, the visualisations, UPnP and mDNS discovery, CDDB, AV1 encoding, the shine, DCA, Tremor, Daala, OpenAPV, BPG, x262, oneVPL and FluidLite codecs | live555, libdc1394, libraw1394, linsys, libdsm, libsmb2, libshout, zvbi, aribb24, aribb25, libkate, libtiger, goom, projectM, vsxu, libupnp, microdns, libcddb, aom, shine, libdca, tremor, daala, openapv, libbpg, x262, oneVPL, FluidLite | one feature each, hardware |
| `vorbis-tools` | Kate streams | libkate | one feature |
| `w3m` | X-Face headers | compface | one feature |
| `wcslib` | PGPLOT plotting | PGPLOT | one feature |
| `weechat` | PHP and JavaScript scripts | PHP's embed library, V8 | large |
| `wireshark` | cpuinfo, and the AMR, G.729, iLBC and spandsp RTP decoders | cpuinfo, opencore-amr, bcg729, libilbc, spandsp | one feature each |
| `wl-mirror` | `wl-present` | pipectl | one feature |
| `wv` | Embedded Windows Metafile pictures | libwmf | one feature |
| `xastir` | Speech | festival | one feature |
| `yosys` | `show` without `-viewer` | xdot | one feature |
| `zint` | The GS1 Syntax Engine | libgs1encoders | one feature; zint checks GS1 data with its own rules |
## Upgrades
### A `tzdata` upgrade can reset the time zone to UTC, once
The `tzdata` port does not own `/etc/localtime`, so upgrading `tzdata` on a machine whose installed
`tzdata` manifest lists the link removes it as an orphan. `rcS` then links UTC on the next boot, and
`TZ=':/etc/localtime'` follows it. kpkg has no rule that keeps a file a package does not own, so run
`kdos-power timezone <Area/City>` to set the zone again. Later upgrades leave it alone.
## Building
### The phase lists have not been through a build
The thirteen phases under `script/phases/`, the five userland phases `40_lang` to `44_apps` and the
ports tree filed on shelves pass preflight, `testing/phaseclosure.py` and the self-test, and no
build has run through them. How long each phase takes and how large its snapshot is are not
measured; layered snapshots have been measured only on a synthetic ten-phase tree, where they came
to 23% of full ones. Every phase up to `50_desktop` takes a snapshot, the first of each path whole
and the rest as layers; `60_kernel` and `70_image` leave `KDOS_SNAPSHOT_PATHS` empty in their
`phase.env` and are re-run instead of restored.
### Some command-line programs build after Qt
A port builds in the phase its whole dependency closure allows, and some closures reach further
than the program does. Each of these builds in `43_toolkits`, after GTK and Qt, for its own reason:
- `podman`, and `distrobox` with it, because `podman` depends on `gpgme`, `gpgme` on `gnupg`,
`gnupg` on `pinentry`, and `pinentry` on `qt6-qtbase` for its dialog. A terminal-only
`pinentry` would cut that chain.
- `qemu`, and `libvirt` with it, because `qemu` depends on `gtk3` and `vte3` for its display
window. Only a `qemu` built without that display could build earlier.
- `sane-backends`, because it depends on `poppler`, which depends on `qt6-qtbase` and on `gpgmepp`.
Cutting that chain takes a `poppler` without its Qt binding and its signature support.
`kdos-tools` builds in `42_graphics` because `kbd` depends on `libxkbcommon`, which the graphics
stack provides. A build that stops before those phases has none of them.
### The image's installer is rebuilt only when its mark is gone
The `kinstall` on the image is compiled by `10_bootstrap`'s `130_kinstall.sh`, straight from
`src/system/kdos-installer` and `src/system/kdos-appbox/catalogue.c`. That step is skipped
whenever `build/mark/bootstrap/kinstall` exists, whatever changed in either directory, so an edit
to the installer or to `catalogue.c` reaches the image only when the step runs again: remove the
mark, or name the step explicitly with `--steps 10_bootstrap:130_kinstall.sh`, which sets
`KDOS_REPLAY=1` for it.
The `kdos-installer` port builds the same program from the same sources, and no phase list names
it. Its recipe hash covers its own directory and `src/libs` but not `catalogue.c`, so a `kpkg`
build of that port counts an edit to `catalogue.c` alone as nothing to do.
### The package store keys only what a port declares
With `KDOS_PKG_STORE=1` a port is installed from `build/pkgstore` when its key matches (see
[The package store](/docs/kdos/03-architecture/packaging.html#the-package-store)). The key covers the recipe,
the environment, the bootstrap phases and the exact bytes of every declared dependency and of the
base toolchain, and an `X:` line re-checks every library the package's ELF files link. It does not
cover:
- **A dependency the build detected by itself and did not link.** A configure script that switches
a feature on because it found a header, a `pkg-config` file or a tool, a plugin opened with
`dlopen`, or a static library leaves no `DT_NEEDED` entry, so a change to that port reuses a
package built against the old one.
- **Files under `fs/`.** The overlay reaches the tree through `10_bootstrap` and later syncs; only
`fs/etc/passwd`, `group` and `ld-musl-x86_64.path` are in the salt.
- **Side effects outside `$PKG`.** A `postinstall.sh` runs on a store hit as on a build, but
anything a `build.sh` writes into the live tree rather than the package is not in the stored
package and does not happen on a hit.
- **Caches under `$HOME`.** A build that reads `.cargo`, `.cache` or a similar directory under the
build's `HOME` (`/var/tmp/kdos-home`) depends on what an earlier build left there, which no key
names.
A release build uses `KDOS_PKG_STORE=0` or `check`; `check` rebuilds every hit and reports a
difference in `build/logs/pkgstore-check.log`.
### The kernel package differs between two builds of the same tree
Every other package is byte-identical when rebuilt (see
[Reproducible packages](/docs/kdos/03-architecture/packaging.html#reproducible-packages)). `linux` pins its
version string, its build user and host and its module-signing key, but signs each module with
ECDSA, which draws a fresh random number for every signature, so every module's appended signature
differs between two builds and `kpkg verify --repro linux` reports them. Whether anything else in
the package differs has not been measured.
## Sources and publishing
### There is no public binary host
The mechanism is complete: a signed index, three checks that a prebuilt package matches this
machine (architecture, build configuration and recipe hash), and deltas; see
[The binary host](/docs/kdos/03-architecture/packaging.html#the-binary-host). `make build KDOS_MAKE_BINHOST=1`
writes a signed one to `build/binhost/`, and nothing publishes it: it is one you run yourself, with
`kpkg binhost` by hand. `kdos update` never reads one; every update is built from source.
### The source archive has one public location
Upstream sources live only as release assets on `kunaldawn/kdos`. If it cannot be reached, `make
fetch` falls back to each recipe's upstream URL, which works only while upstream still serves the
exact file. `KDOS_SOURCES_BASE` can point `make fetch` at another copy laid out the same way, and
nothing publishes such a copy. See
[Developing](/docs/kdos/05-developer/developing.html#where-sources-come-from).
### Two emulator cores may not go on sold media
`libretro-snes9x` is under the Snes9x licence, which forbids commercial distribution, and
`libretro-genesis-plus-gx`'s licence forbids selling it or using it in a commercial product. An
image or a medium that is sold must leave both out.
### A clone does not check what it pushes unless you enable the hook
`script/hooks/pre-push` runs only after `git config core.hooksPath script/hooks`. It refuses a push
that breaks the ports layout (a recipe not exactly one listed shelf down, a name held by two ports,
a reserved or port-named shelf), and a push naming a source hash the archive does not hold. Without
it, a push can carry a layout no build resolves, or name a source nobody has published, and every
other clone's `make fetch` then depends on upstream still serving that file. Setting
`core.hooksPath` replaces `.git/hooks` as a whole, so git-lfs's hooks, or any other installed
there, stop running in that clone.
The layout check reads the tree of each pushed ref's commit, not of every commit between it and the
remote, so a commit in the middle of a push that breaks the layout passes when a later one repairs
it; preflight is what checks the working tree. With the hook on, a push that introduces a new
source hash is also refused when the archive cannot be reached or answers anything but 200 or 404,
because the missing source cannot then be ruled out; such a push made offline needs the bypass.
Every push is refused while `KDOS_SOURCES_BASE` is empty. `KDOS_SKIP_PUBLISH_CHECK=1 git push …`
skips the archive check for one push and leaves the layout check in force;
`KDOS_SKIP_LAYOUT_CHECK=1` skips the layout check.
### An offline `kdos rebuild` from the medium has not been run to the end
A stick built with `KDOS_ISO_SOURCES=1` carries, under `sources/`, the ports tree (`/ports`
without its dot-directories, so every fetched source beside its recipe), `src/`, `script/` and
`fs/`, and `sources/binhost` when the build wrote one.
`kdos rebuild` refuses a tree without `fs/etc`, copies the tree somewhere writable and runs the
orchestrator there with `KDOS_WORKSPACE` naming the copy, which `script/env/host.env`, the
environment of `00_cross` and `10_bootstrap`, uses in place of `/workspace`. No rebuild from a medium has been run through every
phase. See [kdos rebuild](/docs/kdos/04-programs/kdos-command.html#kdos-rebuild) and, for the build it runs,
[How KDOS is built](/docs/kdos/05-developer/how-kdos-is-built.html); the copy itself is described in
[Repository layout](/docs/kdos/06-reference/repository-layout.html).
## Testing
### The compositor and the shell are not compiled by the self-test on a bare host
Their Wayland, font, D-Bus and audio libraries are not there, so those blocks report as skipped on
most machines. `testing/devdeps-image.sh` builds a container where they run.
### No test builds the distribution
`testing/selftest.sh` runs the orchestrator end to end against a synthetic two-phase tree (forking
steps, writing logs, taking and restoring snapshots) and a three-phase one whose snapshots are
layers, each restored and compared entry by entry with the tree it came from, and `kdosbuild --selftest` asserts its view
geometry and log classifier. `testing/selftest.sh` also builds `kpkg` and drives it against
synthetic, source-less ports, covering reproducible packaging, shared indexes, file ownership,
recipe-hash skipping, binhost signing and package deltas. A package built twice to compare its
bytes is that synthetic port, not a real one, and no test reconstructs a pack from a pack delta
(`kdos-pack delta`; see [Deltas](/docs/kdos/03-architecture/packs-and-boxes.html#deltas)). The real recipes
can only be tested by building the whole distribution, which takes most of a day and a container;
see [What a build costs](/docs/kdos/05-developer/how-kdos-is-built.html#what-a-build-costs).
### No harness exercises the source archive end to end
Nothing publishes to an archive and fetches back from it under test. `ports/publish` accepts
`KDOS_GITHUB_API` and `KDOS_GITHUB_UPLOADS`, and `ports/fetch` accepts `KDOS_SOURCES_BASE`, so a
local stand-in could be used, but no test does so. What `testing/preflight.sh` checks is that the
scripts parse and are executable, that git tracks no recipe-hashed archive, that the ignore rules
cover every source suffix and `ports/.srccache/` and ignore no tracked fixture, and that
`ports/sources.idx` holds every format-2 rule of `src_index_problems` in `ports/srclib.sh`.
### `kdos doctor` cannot check hardware a machine does not have
Several of its hardware checks report *skip*, with a reason, when the device they check for is
absent, as it is in a virtual machine: the wireless regulatory database with no wireless device,
the reachability of serial, camera and instrument device nodes with none plugged in, and the Intel
SOF audio and NVIDIA GSP firmware checks on a machine with neither the device nor the firmware. A
skip says the check could not answer, not that it passed.
### The rig cannot show a live microphone level on its own
Its emulated sound card gives the guest no capture signal, so a recording level meter stays flat
even with the rig's `--audio` option on. Loading the `snd-aloop` kernel module in the guest, from a
root script, gives it a loopback capture device to record from. See
[Testing](/docs/kdos/05-developer/testing.html#a-real-capture-device-with-no-emulator-flag).
### The phosphor shader is not in any rig photograph
The rig's virtual display puts the compositor on software rendering, where the pass switches itself
off. What is photographed is the cell grid underneath it.
## Documentation
### Some measurements in this book are quoted rather than re-taken
Contrast ratios, launch times, freeze ratios and transport throughput figures were each measured
once, under the conditions stated beside them, and are repeated rather than measured again for every
revision. A timing or a ratio depends on the machine it was taken on, so a figure quoted here is a
record of those conditions and not a guarantee for yours.
## See also
- [Decisions](/docs/kdos/01-philosophy/decisions.html) — what is absent on purpose, and why
- [Status](/docs/kdos/06-reference/status.html) — maturity per subsystem, and the evidence behind each verdict
- [How KDOS differs](/docs/kdos/01-philosophy/how-kdos-differs.html) — what the design gives up next to other distributions
- [The ports catalogue](/docs/kdos/06-reference/ports-catalogue.html) — every port, so a missing one can be told from one built without a feature
- [The security model](/docs/kdos/03-architecture/security-model.html) — the full statement of what is not protected
---
*Part VI — Reference, chapter 43.* Previous: [42. Repository layout](/docs/kdos/06-reference/repository-layout.html) · [Contents](/docs/kdos/) · Next: [44. Status](/docs/kdos/06-reference/status.html)