<feed xmlns='http://www.w3.org/2005/Atom'>
<title>archsetup/docs/specs/2026-07-10-audio-doctor-input-side-spec.org, branch main</title>
<subtitle>Builds a full dev workstation from a bare Arch Linux install.
</subtitle>
<id>https://git.cjennings.net/archsetup/atom?h=main</id>
<link rel='self' href='https://git.cjennings.net/archsetup/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/'/>
<updated>2026-07-10T15:42:58+00:00</updated>
<entry>
<title>docs: spec the audio doctor's input side, one doctor per direction</title>
<updated>2026-07-10T15:42:58+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-10T15:42:58+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=e3a479ec73ca69aa020c4ec86b71ee88a19d6bec'/>
<id>urn:sha1:e3a479ec73ca69aa020c4ec86b71ee88a19d6bec</id>
<content type='text'>
The doctor never examines the microphone. diag collects default_source and default_source_present, the classifier reads neither, so a muted mic, a stale default source, and a mic the sound server can't see all classify as healthy. Chrome losing the mic this morning surfaced it: the stack was genuinely fine and the doctor had nothing useful to say.

The design grew past the gap in one conversation. An empty source list is normal on a mic-less desktop and a failure on a machine that should have one, and no probe can tell those apart. The missing fact comes from the user's finger: a doctor key on each of the OUTPUTS and INPUTS section headers, where pressing the input one asserts a mic should exist. That retires the DOCTOR header key I shipped hours earlier, and it dissolves the precedence question a single classifier would have faced.

A new probe tier sits below PipeWire. /proc/asound lists capture-capable cards, needs no package, spawns no process, and can't hang, so it separates "the software lost a microphone the kernel sees" from "nothing is plugged in".

Push-to-talk stays as it is. It mutes the source, the one state where the server guarantees nothing is captured. A link-based push-to-talk fails open, and a crash mid-hold is a hot mic reading as muted. The doctor reads ptt.read_state() instead of guessing.

Four decisions are open. Three are closed.
</content>
</entry>
</feed>
