<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>EdS</title><link>https://cdeever.github.io/eds/</link><description>Recent content on EdS</description><generator>Hugo</generator><language>en-us</language><atom:link href="https://cdeever.github.io/eds/index.xml" rel="self" type="application/rss+xml"/><item><title>A Music Inventory</title><link>https://cdeever.github.io/eds/docs/architecture/proposals/music-inventory/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/proposals/music-inventory/</guid><description>&lt;h1 id="proposal-a-music-inventory"&gt;Proposal: A Music Inventory&lt;a class="anchor" href="#proposal-a-music-inventory"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Proposal, not decided and not built&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-24&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Where&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;eds-inventory&lt;/strong&gt;, a project of its own: &lt;a href="https://github.com/cdeever/eds-inventory"&gt;repository&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds-inventory/"&gt;docs&lt;/a&gt;. It runs in EdS&amp;rsquo;s Deevnet IoTaaS tenant&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Would extend&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0022-the-owners-collection-names-the-record/"&gt;ADR-0022&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0038-the-turntable-names-the-original-album-by-what-is-on-it/"&gt;ADR-0038&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0041-an-artists-nth-album-is-counted-in-musicbrainz/"&gt;ADR-0041&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0045-an-nth-album-not-owned-is-the-next-one-that-is/"&gt;ADR-0045&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0046-requests-are-matched-against-the-owners-library/"&gt;ADR-0046&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;A local inventory of the owner&amp;rsquo;s music, in every format, that holds one&#10;answer for each album and that EdS asks first. EdS would be its customer,&#10;the way &lt;code&gt;lightd&lt;/code&gt; is a customer of &lt;code&gt;palette&lt;/code&gt;.&lt;/p&gt;&#10;&lt;h2 id="why"&gt;Why&lt;a class="anchor" href="#why"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;EdS answers &amp;ldquo;what album is this, what does it look like, what else is&#10;there&amp;rdquo; by asking a different place for each question:&lt;/p&gt;</description></item><item><title>ADR-0001: The Stand Renders Effects</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0001-device-renders-effects/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0001-device-renders-effects/</guid><description>&lt;h1 id="adr-0001-the-stand-renders-effects-locally-and-never-receives-frames"&gt;ADR-0001: The Stand Renders Effects Locally and Never Receives Frames&lt;a class="anchor" href="#adr-0001-the-stand-renders-effects-locally-and-never-receives-frames"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-green"&gt;Accepted&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-09-07&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;What travels from &lt;code&gt;lightd&lt;/code&gt; to a stand, and where animation happens.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Backfilled&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Decided with the first firmware and argued in &lt;code&gt;firmware/lp-stand/README.md&lt;/code&gt;; written up here on 2026-10-10.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0002-gamma-in-firmware/"&gt;ADR-0002&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/reference/scene-descriptor/"&gt;Scene Descriptor&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The stand is an ESP32 driving an addressable strip over WiFi from a broker it&#10;does not control. The light has to look deliberate at all times, including&#10;when the network is slow or gone, and the stand is meant to sit on a shelf&#10;unattended.&lt;/p&gt;</description></item><item><title>Background: Sound Around the House</title><link>https://cdeever.github.io/eds/docs/architecture/spdif/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/spdif/</guid><description>&lt;h1 id="background-sound-around-the-house"&gt;Background: Sound Around the House&lt;a class="anchor" href="#background-sound-around-the-house"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;EdS did not bring music to the rooms of the house. A whole-house digital&#10;audio system was already doing that, was built years before EdS, and carries&#10;on exactly as it did. EdS listens in on it. This page is the short version;&#10;the project&amp;rsquo;s own page has the whole of it:&#10;&lt;a href="https://chrisdeever.com/electronics/spdif-audio-distribution/"&gt;S/PDIF Audio Distribution&lt;/a&gt;.&lt;/p&gt;&#10;&lt;h2 id="whole-house-digital-sound-distribution"&gt;Whole-house digital sound distribution&lt;a class="anchor" href="#whole-house-digital-sound-distribution"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;One digital feed (S/PDIF) is sent from the basement to every room, and each&#10;room&amp;rsquo;s own stereo plays it.&lt;/p&gt;</description></item><item><title>Change Record Template (CHG)</title><link>https://cdeever.github.io/eds/docs/develop/records/change-record/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/develop/records/change-record/</guid><description>&lt;h1 id="change-record-template-chg"&gt;Change Record Template (CHG)&lt;a class="anchor" href="#change-record-template-chg"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;The shape every &lt;a href="https://cdeever.github.io/eds/docs/changes/"&gt;change record&lt;/a&gt; takes. Copy the skeleton into&#10;a new file, fill it in &lt;strong&gt;before&lt;/strong&gt; the change runs, and complete &lt;strong&gt;Outcome&lt;/strong&gt;&#10;after. &lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0001-lp-stand-joins-its-tenant/"&gt;CHG-0001&lt;/a&gt; is a&#10;worked example.&lt;/p&gt;&#10;&lt;p&gt;It follows Deevnet IoTaaS&amp;rsquo;s template, trimmed to what an application needs: no&#10;site or maintenance window, because EdS changes one tenant and its own&#10;devices.&lt;/p&gt;&#10;&lt;h2 id="where-it-goes"&gt;Where it goes&lt;a class="anchor" href="#where-it-goes"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Number&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The next unused &lt;code&gt;CHG-NNNN&lt;/code&gt;, in the order records are opened. Runs across years, never reused, and kept even if the change is abandoned.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;File&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;docs/content/docs/changes/&amp;lt;YYYY&amp;gt;/&amp;lt;NNNN&amp;gt;-&amp;lt;slug&amp;gt;.md&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Title&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;CHG-NNNN: &amp;lt;What changed&amp;gt;&lt;/code&gt;, from the point of view of what is running&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The day execution starts. While it is still planned, the planned date; with none yet, &lt;strong&gt;Unscheduled&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Weight&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;NNNN&lt;/code&gt;, so records sort by number&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Index&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Add a row to &lt;a href="https://cdeever.github.io/eds/docs/changes/"&gt;Change Records&lt;/a&gt; and to that year&amp;rsquo;s page&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="status"&gt;Status&lt;a class="anchor" href="#status"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;&lt;code&gt;Planned&lt;/code&gt; → &lt;code&gt;In progress&lt;/code&gt; → &lt;code&gt;Complete&lt;/code&gt;, or &lt;code&gt;Rolled back&lt;/code&gt; or &lt;code&gt;Abandoned&lt;/code&gt;. A&#10;record is never deleted: a change that was abandoned or rolled back is exactly&#10;the one worth keeping.&lt;/p&gt;</description></item><item><title>CHG-0001: The LP Stand Joins Its Tenant</title><link>https://cdeever.github.io/eds/docs/changes/2026/0001-lp-stand-joins-its-tenant/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0001-lp-stand-joins-its-tenant/</guid><description>&lt;h1 id="chg-0001-the-lp-stand-joins-its-tenant"&gt;CHG-0001: The LP Stand Joins Its Tenant&lt;a class="anchor" href="#chg-0001-the-lp-stand-joins-its-tenant"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-10&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Deployment&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-complete"&gt;Complete&lt;/span&gt;&#10; 2026-10-10&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;lp-stand-01&lt;/code&gt; (ESP32-D0WD-V3); the &lt;code&gt;eds&lt;/code&gt; tenant&amp;rsquo;s Grafana organization&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make build flash provision&lt;/code&gt; in &lt;code&gt;firmware/lp-stand&lt;/code&gt;; &lt;code&gt;terraform apply&lt;/code&gt; in &lt;code&gt;infra/deevnet-tenant-eds&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Nothing issued is replaced. Most likely to go wrong: a broker account missing a topic the firmware uses, which fails silently&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0004-firmware-secrets-nvs-only/"&gt;ADR-0004&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0005-device-events-over-mqtt/"&gt;ADR-0005&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;None&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Backfilled&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Written after the change ran, from the session that ran it.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The stand had been flashed once, on 2026-09-09, built for plaintext MQTT on&#10;port 1883 and never provisioned. Deevnet IoTaaS&amp;rsquo;s broker is TLS only, so it had&#10;never reached the real broker; it sat lit in its default warm white, retrying&#10;WiFi with no key.&lt;/p&gt;</description></item><item><title>Firmware: lp-stand</title><link>https://cdeever.github.io/eds/docs/develop/lp-stand/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/develop/lp-stand/</guid><description>&lt;h1 id="firmware-lp-stand"&gt;Firmware: lp-stand&lt;a class="anchor" href="#firmware-lp-stand"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;ESP-IDF in C, following the conventions of &lt;code&gt;esp32-ma-bell-gateway&lt;/code&gt;: &lt;code&gt;main/app/&lt;/code&gt;,&#10;&lt;code&gt;main/config/&lt;/code&gt;, &lt;code&gt;main/hardware/&lt;/code&gt;, &lt;code&gt;main/network/&lt;/code&gt;, with a Makefile wrapper over&#10;&lt;code&gt;idf.py&lt;/code&gt;.&lt;/p&gt;&#10;&lt;h2 id="the-split-that-matters"&gt;The split that matters&lt;a class="anchor" href="#the-split-that-matters"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Scene validation, effect rendering, gamma and event formatting are pure C with&#10;no ESP-IDF dependency, because that is where a bug is subtle: it shows up only&#10;as &lt;em&gt;the light looks wrong&lt;/em&gt;, or, for an event that is not valid JSON, as nothing&#10;at all. They are tested with a compiler and nothing else:&lt;/p&gt;</description></item><item><title>INC-0001: The Beatles Played for a Request Nobody Made</title><link>https://cdeever.github.io/eds/docs/incidents/2026/0001-the-beatles-played-for-a-request-nobody-made/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/incidents/2026/0001-the-beatles-played-for-a-request-nobody-made/</guid><description>&lt;h1 id="inc-0001-the-beatles-played-for-a-request-nobody-made"&gt;INC-0001: The Beatles Played for a Request Nobody Made&lt;a class="anchor" href="#inc-0001-the-beatles-played-for-a-request-nobody-made"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-24&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;respeaker-01&lt;/code&gt;, &lt;code&gt;eds-scribe&lt;/code&gt; and &lt;code&gt;eds-voiced&lt;/code&gt; on the services workload, nowplayd, the relay&amp;rsquo;s iTunes driver&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Severity&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;An album nobody asked for replaced what was asked for. Recovery needed no more than asking again&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Open · &lt;span class="status-badge inc-green"&gt;Hardening&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Times&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UTC&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The first request sent from the reSpeaker played &lt;em&gt;Abbey Road&lt;/em&gt;. Its owner had&#10;asked for Aerosmith&amp;rsquo;s first album. scribe, given five seconds it could not&#10;make out, wrote back the prompt it had been given to spell names by - &amp;ldquo;Play&#10;Abbey Road by the Beatles.&amp;rdquo; - and voiced, which acted on any words scribe&#10;returned, read that as a request and sent &lt;code&gt;play_album&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Now Playing</title><link>https://cdeever.github.io/eds/docs/architecture/subsystems/now-playing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/subsystems/now-playing/</guid><description>&lt;h1 id="now-playing"&gt;Now Playing&lt;a class="anchor" href="#now-playing"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;Knowing what is playing is the one thing every other subsystem needs, so it&#10;is a subsystem of its own and the others are built on it. It hears or asks&#10;each source of music, decides which one is current, completes what it was&#10;told, and publishes one answer for everyone else.&lt;/p&gt;&#10;&lt;p&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/subsystems/now-playing/now-playing.svg"&gt;&lt;img src="https://cdeever.github.io/eds/docs/architecture/subsystems/now-playing/now-playing.svg" alt="Now Playing: the turntable, iTunes and Spotify reported by drivers on the agent Pi, the power beacon, and nowplayd on the workload asking Discogs and the catalogs." /&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Running the Vertical</title><link>https://cdeever.github.io/eds/docs/guide/quickstart/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/guide/quickstart/</guid><description>&lt;h1 id="running-the-vertical"&gt;Running the Vertical&lt;a class="anchor" href="#running-the-vertical"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;The whole chain on one machine, with no deevnet infrastructure.&lt;/p&gt;&#10;&lt;h2 id="1-start-the-palette-extractor"&gt;1. Start the palette extractor&lt;a class="anchor" href="#1-start-the-palette-extractor"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd services/palette&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make venv&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make serve PORT&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8731&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="2-start-a-broker-and-lightd"&gt;2. Start a broker and lightd&lt;a class="anchor" href="#2-start-a-broker-and-lightd"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd services/lightd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make broker &lt;span style="color:#75715e"&gt;# mosquitto in podman on tcp://127.0.0.1:21883&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make run&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;make run&lt;/code&gt; builds &lt;code&gt;lightd&lt;/code&gt; and points it at the development broker. It expects&#10;&lt;code&gt;palette&lt;/code&gt; on &lt;code&gt;:8731&lt;/code&gt;.&lt;/p&gt;&#10;&lt;h2 id="3-watch-the-topic-tree"&gt;3. Watch the topic tree&lt;a class="anchor" href="#3-watch-the-topic-tree"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;In another terminal:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd services/lightd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make broker-watch &lt;span style="color:#75715e"&gt;# tail every eds/# topic&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="4-send-a-cover"&gt;4. Send a cover&lt;a class="anchor" href="#4-send-a-cover"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl -F image&lt;span style="color:#f92672"&gt;=&lt;/span&gt;@jacket.jpg http://localhost:8732/v1/cover&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A scene should appear on &lt;code&gt;eds/lightstand/lp-stand-01/scene&lt;/code&gt;. Because gamma is&#10;applied on the device rather than on the wire, the colors you see here are the&#10;colors actually intended.&lt;/p&gt;</description></item><item><title>Scene Descriptor</title><link>https://cdeever.github.io/eds/docs/reference/scene-descriptor/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/reference/scene-descriptor/</guid><description>&lt;h1 id="scene-descriptor"&gt;Scene Descriptor&lt;a class="anchor" href="#scene-descriptor"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;The payload &lt;code&gt;lightd&lt;/code&gt; publishes and the LP stand renders. It is a description of&#10;&lt;em&gt;what to render&lt;/em&gt;, never a frame.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;v&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;effect&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;breathe&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;speed&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0.4&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;brightness&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0.8&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;palette&amp;#34;&lt;/span&gt;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#f92672"&gt;&amp;#34;rgb&amp;#34;&lt;/span&gt;: [&lt;span style="color:#ae81ff"&gt;232&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;77&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;], &lt;span style="color:#f92672"&gt;&amp;#34;weight&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0.5594&lt;/span&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#f92672"&gt;&amp;#34;rgb&amp;#34;&lt;/span&gt;: [&lt;span style="color:#ae81ff"&gt;182&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;159&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;], &lt;span style="color:#f92672"&gt;&amp;#34;weight&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0.3661&lt;/span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Field&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Type&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Meaning&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;v&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;int&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Contract version. Currently &lt;code&gt;1&lt;/code&gt;.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;effect&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;string&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;solid&lt;/code&gt;, &lt;code&gt;breathe&lt;/code&gt;, &lt;code&gt;sweep&lt;/code&gt;, &lt;code&gt;morph&lt;/code&gt;, &lt;code&gt;chase&lt;/code&gt; or &lt;code&gt;scanner&lt;/code&gt;.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;speed&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;float&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;0..1&lt;/code&gt; dial, not a frequency.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;brightness&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;float&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;0..1&lt;/code&gt;, applied before gamma on the device.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;palette&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;array&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Colors already corrected for the strip, ranked by weight.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;palette[].rgb&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;[int, int, int]&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;sRGB, 0–255. Gamma is &lt;strong&gt;not&lt;/strong&gt; applied.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;palette[].weight&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;float&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Share of the scene. Renormalized after filtering.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="version-handling"&gt;Version handling&lt;a class="anchor" href="#version-handling"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;A scene carrying a different &lt;code&gt;v&lt;/code&gt; is &lt;strong&gt;refused, not guessed at&lt;/strong&gt;. A scene that is&#10;malformed or unparseable is &lt;strong&gt;ignored&lt;/strong&gt;, and the previously rendering scene&#10;keeps running — a stand that goes dark on a bad payload is worse than one that&#10;ignores it.&lt;/p&gt;</description></item><item><title>ADR-0002: Gamma Belongs to the Firmware</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0002-gamma-in-firmware/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0002-gamma-in-firmware/</guid><description>&lt;h1 id="adr-0002-gamma-belongs-to-the-firmware-not-the-wire"&gt;ADR-0002: Gamma Belongs to the Firmware, Not the Wire&lt;a class="anchor" href="#adr-0002-gamma-belongs-to-the-firmware-not-the-wire"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-green"&gt;Accepted&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-09-07&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Which layer makes which color decision between a cover image and the strip.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Backfilled&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Decided with the first vertical and argued in the project READMEs and &lt;a href="https://cdeever.github.io/eds/docs/architecture/boundaries/"&gt;Boundaries&lt;/a&gt;; written up here on 2026-10-10.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Corrected&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-13: the consequence about OKLab said the conversion is implemented three times, in Python, Go and C. It is in two, and never was in the firmware. The decision is unchanged.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0001-device-renders-effects/"&gt;ADR-0001&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;A color passes through three programs on its way from a sleeve to a strip:&#10;&lt;code&gt;palette&lt;/code&gt; extracts it, &lt;code&gt;lightd&lt;/code&gt; turns swatches into a scene, and the firmware&#10;drives the LEDs. Several corrections have to happen somewhere along the way —&#10;rejecting dull swatches, boosting chroma, mapping into the strip&amp;rsquo;s gamut, and&#10;gamma, because WS2812 output is linear in duty cycle and perception is not.&lt;/p&gt;</description></item><item><title>Capturing Vinyl</title><link>https://cdeever.github.io/eds/docs/architecture/proposals/capturing-vinyl/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/proposals/capturing-vinyl/</guid><description>&lt;h1 id="proposal-capturing-vinyl"&gt;Proposal: Capturing Vinyl&lt;a class="anchor" href="#proposal-capturing-vinyl"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Proposal, not decided and not built&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-25&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Where&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;EdS listens and captures; &lt;a href="https://cdeever.github.io/eds-inventory/"&gt;eds-inventory&lt;/a&gt; knows what is captured and what is missing&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Would extend&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0021-the-turntable-is-identified-by-listening/"&gt;ADR-0021&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0022-the-owners-collection-names-the-record/"&gt;ADR-0022&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0026-what-silence-means-on-the-turntable/"&gt;ADR-0026&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;Every record played is captured to FLAC, by itself: put a record on and it&#10;is kept, track by track, and a track already kept is skipped. Nobody&#10;presses record. Over time the digital collection comes to include what is&#10;held only on vinyl, and every capture teaches EdS to name that record&#10;itself.&lt;/p&gt;</description></item><item><title>CHG-0002: The Relay Pi, and Accounts for Now Playing</title><link>https://cdeever.github.io/eds/docs/changes/2026/0002-relay-pi-and-now-playing-accounts/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0002-relay-pi-and-now-playing-accounts/</guid><description>&lt;h1 id="chg-0002-the-relay-pi-and-accounts-for-now-playing"&gt;CHG-0002: The Relay Pi, and Accounts for Now Playing&lt;a class="anchor" href="#chg-0002-the-relay-pi-and-accounts-for-now-playing"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-10&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Deployment&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-complete"&gt;Complete&lt;/span&gt;&#10; 2026-10-10&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;the &lt;code&gt;eds&lt;/code&gt; tenant&amp;rsquo;s broker accounts; &lt;code&gt;dv02rpi002p01&lt;/code&gt; (a Pi lab host in the site inventory); iTunes on a PC on the home LAN&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;terraform apply&lt;/code&gt; in &lt;code&gt;infra/deevnet-tenant-eds&lt;/code&gt;; &lt;code&gt;make -C deploy/relay image fetch card status pair&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Medium. A host is put on two networks the site otherwise keeps apart. Most likely to go wrong: the Pi&amp;rsquo;s Wi-Fi leg picking up a default route or DNS, which would send site traffic through the house&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0006-now-playing-bus-of-drivers/"&gt;ADR-0006&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0010-home-lan-relay/"&gt;ADR-0010&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0011-itunes-by-remote-pairing/"&gt;ADR-0011&lt;/a&gt;, and, made during it, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0015-eds-builds-its-own-pi-images/"&gt;ADR-0015&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0001-lp-stand-joins-its-tenant/"&gt;CHG-0001&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;iTunes runs on a PC on the home LAN. The broker is inside the Deevnet Mobile&#10;site. Neither can reach the other, so nothing that happens in iTunes can reach&#10;the stand.&lt;/p&gt;</description></item><item><title>Firmware: cover-screen</title><link>https://cdeever.github.io/eds/docs/develop/cover-screen/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/develop/cover-screen/</guid><description>&lt;h1 id="firmware-cover-screen"&gt;Firmware: cover-screen&lt;a class="anchor" href="#firmware-cover-screen"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;The touch screen that shows the cover and has the five buttons&#10;(&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0020-a-touch-screen-that-can-change-what-plays/"&gt;ADR-0020&lt;/a&gt;).&#10;ESP-IDF in C, laid out as &lt;a href="../lp-stand/"&gt;lp-stand&lt;/a&gt; is, for an&#10;ESP32-2432S028R.&lt;/p&gt;&#10;&lt;h2 id="the-split-that-matters"&gt;The split that matters&lt;a class="anchor" href="#the-split-that-matters"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;What a touch means and what is painted over the cover are pure C, because&#10;that is where a bug shows up only as &lt;em&gt;it did the wrong thing when I touched&#10;it&lt;/em&gt;:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make test &lt;span style="color:#75715e"&gt;# needs gcc; no ESP-IDF, no hardware&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make pictures &lt;span style="color:#75715e"&gt;# draws each screen to a BMP, with a made-up cover&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;make pictures&lt;/code&gt; runs the board&amp;rsquo;s own drawing code. Change an icon, run it,&#10;and look.&lt;/p&gt;</description></item><item><title>INC-0002: Deploys Hung the Core Router</title><link>https://cdeever.github.io/eds/docs/incidents/2026/0002-deploys-hung-the-core-router/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/incidents/2026/0002-deploys-hung-the-core-router/</guid><description>&lt;h1 id="inc-0002-deploys-hung-the-core-router"&gt;INC-0002: Deploys Hung the Core Router&lt;a class="anchor" href="#inc-0002-deploys-hung-the-core-router"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-24&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The mobile site&amp;rsquo;s core router; &lt;code&gt;deploy/&lt;/code&gt; (&lt;code&gt;make ship&lt;/code&gt;, &lt;code&gt;make load&lt;/code&gt;), the Builder, the services workload&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Severity&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The mobile site&amp;rsquo;s routed traffic stopped, twice, until the owner rebooted the router; a deploy was left half done, with the services still on the version before&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Open · &lt;span class="status-badge inc-green"&gt;Hardening&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Times&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UTC&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Every deploy sent every image from the Builder to the services workload,&#10;whether it had changed or not, as fast as it would go: about a gigabyte,&#10;most of it scribe&amp;rsquo;s 767 MB and palette&amp;rsquo;s 256 MB, through the core router&#10;that joins the Builder&amp;rsquo;s segment to the workload&amp;rsquo;s. That evening it was done&#10;eight times. During the eighth, and again when it was retried, the router&#10;hung, and the site&amp;rsquo;s routed traffic with it.&lt;/p&gt;</description></item><item><title>Incident Record Template (INC)</title><link>https://cdeever.github.io/eds/docs/develop/records/incident-record/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/develop/records/incident-record/</guid><description>&lt;h1 id="incident-record-template-inc"&gt;Incident Record Template (INC)&lt;a class="anchor" href="#incident-record-template-inc"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;The shape every &lt;a href="https://cdeever.github.io/eds/docs/incidents/"&gt;incident record&lt;/a&gt; takes. Copy the skeleton&#10;into &lt;code&gt;docs/content/docs/incidents/&amp;lt;YYYY&amp;gt;/&amp;lt;NNNN&amp;gt;-&amp;lt;slug&amp;gt;.md&lt;/code&gt;, numbered with the&#10;next unused &lt;code&gt;INC-NNNN&lt;/code&gt;, and add a row to the index.&lt;/p&gt;&#10;&lt;p&gt;Start the record while the incident is fresh, even with most sections empty.&#10;The timeline and the wrong turns are the parts memory loses first.&lt;/p&gt;&#10;&lt;h2 id="status"&gt;Status&lt;a class="anchor" href="#status"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;An incident carries a &lt;strong&gt;status&lt;/strong&gt; and a &lt;strong&gt;substatus&lt;/strong&gt;. The status says whether&#10;anything is left to do; the substatus says how far along it is, and only moves&#10;forward.&lt;/p&gt;</description></item><item><title>LP Light Show</title><link>https://cdeever.github.io/eds/docs/architecture/subsystems/lp-light-show/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/subsystems/lp-light-show/</guid><description>&lt;h1 id="lp-light-show"&gt;LP Light Show&lt;a class="anchor" href="#lp-light-show"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;The first subsystem, and EdS&amp;rsquo;s first idea of many: a record&amp;rsquo;s cover becomes&#10;the light on its stand. Prop the jacket on the LP stand and it is illuminated in&#10;its own colors, set slowly moving, for as long as the record plays. It is&#10;the first of what may be several light shows, which is why it is named for&#10;the LP.&lt;/p&gt;&#10;&lt;p&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/subsystems/lp-light-show/lp-light-show.svg"&gt;&lt;img src="https://cdeever.github.io/eds/docs/architecture/subsystems/lp-light-show/lp-light-show.svg" alt="LP Light Show: the cover and its look from Now Playing, lightd and palette on the workload, and the LP stand in the vinyl listening room." /&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Palette API</title><link>https://cdeever.github.io/eds/docs/reference/palette-api/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/reference/palette-api/</guid><description>&lt;h1 id="palette-api"&gt;Palette API&lt;a class="anchor" href="#palette-api"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;&lt;code&gt;POST /v1/palette&lt;/code&gt; — image bytes in, ranked color swatches out.&lt;/p&gt;&#10;&lt;p&gt;Accepts either a multipart upload or a raw body. Both return the same result:&#10;multipart is what a person uses, the raw body is what &lt;code&gt;lightd&lt;/code&gt; uses.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl -F image&lt;span style="color:#f92672"&gt;=&lt;/span&gt;@jacket.jpg &lt;span style="color:#e6db74"&gt;&amp;#39;http://localhost:8731/v1/palette?n=5&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl --data-binary @jacket.jpg -H &lt;span style="color:#e6db74"&gt;&amp;#39;Content-Type: image/png&amp;#39;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;http://localhost:8731/v1/palette&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;GET /openapi.json&lt;/code&gt; publishes the schema, which is how the contract stays&#10;honest across the Python/Go boundary.&lt;/p&gt;&#10;&lt;h2 id="parameters"&gt;Parameters&lt;a class="anchor" href="#parameters"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Name&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Type&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Default&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;n&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;int, 1–16&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;6&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Swatches to return.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="response"&gt;Response&lt;a class="anchor" href="#response"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;v&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;swatches&amp;#34;&lt;/span&gt;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#f92672"&gt;&amp;#34;rgb&amp;#34;&lt;/span&gt;: [&lt;span style="color:#ae81ff"&gt;225&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;82&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;26&lt;/span&gt;], &lt;span style="color:#f92672"&gt;&amp;#34;hex&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;#e1521a&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;oklab&amp;#34;&lt;/span&gt;: [&lt;span style="color:#ae81ff"&gt;0.6264&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0.147&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0.1184&lt;/span&gt;],&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;weight&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0.3705&lt;/span&gt;, &lt;span style="color:#f92672"&gt;&amp;#34;chroma&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0.1888&lt;/span&gt;, &lt;span style="color:#f92672"&gt;&amp;#34;lightness&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0.6264&lt;/span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ],&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;background_dropped&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0.8855&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;fallback&amp;#34;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;source&amp;#34;&lt;/span&gt;: { &lt;span style="color:#f92672"&gt;&amp;#34;width&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;600&lt;/span&gt;, &lt;span style="color:#f92672"&gt;&amp;#34;height&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;600&lt;/span&gt;, &lt;span style="color:#f92672"&gt;&amp;#34;format&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;jpeg&amp;#34;&lt;/span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;dl&gt;&#10;&lt;dt&gt;&lt;code&gt;weight&lt;/code&gt;&lt;/dt&gt;&#10;&lt;dd&gt;Share of clustered pixels, so swatches are ranked by how much of the sleeve&#10;they actually cover.&lt;/dd&gt;&#10;&lt;dt&gt;&lt;code&gt;background_dropped&lt;/code&gt;&lt;/dt&gt;&#10;&lt;dd&gt;Share of pixels discarded before clustering.&lt;/dd&gt;&#10;&lt;dt&gt;&lt;code&gt;fallback&lt;/code&gt;&lt;/dt&gt;&#10;&lt;dd&gt;True when filtering removed so much that the unfiltered image was used&#10;instead. Genuinely monochrome art sets this rather than returning nothing.&lt;/dd&gt;&#10;&lt;dt&gt;&lt;code&gt;chroma&lt;/code&gt;&lt;/dt&gt;&#10;&lt;dd&gt;How far the color is from neutral. &lt;strong&gt;Consumers should treat a low-chroma&#10;swatch as unfit to drive a strip regardless of its weight&lt;/strong&gt; — see below.&lt;/dd&gt;&#10;&lt;/dl&gt;&#10;&lt;h2 id="known-characteristics"&gt;Known characteristics&lt;a class="anchor" href="#known-characteristics"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;&lt;strong&gt;Low &lt;code&gt;n&lt;/code&gt; on busy art returns low-chroma centroids.&lt;/strong&gt; Asking for 2 swatches&#10;from a four-color sleeve forces one cluster to merge three of them, and the&#10;merged centroid is close to their average. This is arithmetic, not a bug — but&#10;it is why &lt;code&gt;chroma&lt;/code&gt; is in the contract. The default &lt;code&gt;n=6&lt;/code&gt; avoids the situation&#10;for most art.&lt;/p&gt;</description></item><item><title>Provisioning a Stand</title><link>https://cdeever.github.io/eds/docs/guide/provisioning/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/guide/provisioning/</guid><description>&lt;h1 id="provisioning-a-stand"&gt;Provisioning a Stand&lt;a class="anchor" href="#provisioning-a-stand"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;Credentials live in a dedicated &lt;code&gt;creds&lt;/code&gt; NVS partition, not in the firmware&#10;image. The WiFi key and the broker password have no build-time option at all:&#10;NVS is the only place they can come from. A built binary therefore carries no&#10;secret and can be cached, copied and shared without care, and &lt;code&gt;sdkconfig&lt;/code&gt;&#10;cannot hold one.&lt;/p&gt;&#10;&lt;h2 id="from-the-tenant"&gt;From the tenant&lt;a class="anchor" href="#from-the-tenant"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;A stand on Deevnet IoTaaS is flashed with what the EdS tenant issued:&lt;/p&gt;</description></item><item><title>Services: palette and lightd</title><link>https://cdeever.github.io/eds/docs/develop/services/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/develop/services/</guid><description>&lt;h1 id="services"&gt;Services&lt;a class="anchor" href="#services"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;h2 id="palette"&gt;palette&lt;a class="anchor" href="#palette"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd services/palette&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make venv &lt;span style="color:#75715e"&gt;# .venv with editable install + dev extras&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make test &lt;span style="color:#75715e"&gt;# pytest, no network&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make serve PORT&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8731&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Run a single test:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.venv/bin/pytest tests/test_extract.py::test_name -q&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="tuning-by-eye"&gt;Tuning by eye&lt;a class="anchor" href="#tuning-by-eye"&gt;&lt;/a&gt;&lt;/h3&gt;&#10;&lt;p&gt;The thresholds are judgment calls that no test can settle — where a color&#10;stops being a color, how much black field to discard. The CLI exists for that&#10;loop:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make palette COVERS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;~/covers&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make sheet COVERS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;~/covers &lt;span style="color:#75715e"&gt;# PNG contact sheet&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.venv/bin/eds-palette ~/covers --min-chroma 0.05 --min-lightness 0.08&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It prints truecolor swatches in the terminal and can render a sheet of&#10;thumbnails beside their weighted palettes, so many sleeves can be compared at&#10;once.&lt;/p&gt;</description></item><item><title>ADR-0003: The Broker Is Deevnet IoTaaS's</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0003-broker-is-the-substrates/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0003-broker-is-the-substrates/</guid><description>&lt;h1 id="adr-0003-the-mqtt-broker-is-deevnet-iotaass-not-a-tenant-vm"&gt;ADR-0003: The MQTT Broker Is Deevnet IoTaaS&amp;rsquo;s, Not a Tenant VM&lt;a class="anchor" href="#adr-0003-the-mqtt-broker-is-deevnet-iotaass-not-a-tenant-vm"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-green"&gt;Accepted&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-09-07&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Where EdS&amp;rsquo;s MQTT broker runs, and so how devices and services meet.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Backfilled&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Decided when the tenant was first written and argued in &lt;code&gt;infra/deevnet-tenant-eds/README.md&lt;/code&gt;; written up here on 2026-10-10.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Deevnet ADR-0001, ADR-0003 and ADR-0012 (&lt;a href="https://deevnet.github.io/deevnet-docs/docs/architecture/decisions/"&gt;deevnet-docs&lt;/a&gt;)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;EdS&amp;rsquo;s services run on a workload in its own tenant on Deevnet IoTaaS.&#10;Its devices are ESP32s on Deevnet IoTaaS&amp;rsquo;s IoT network. Both need a broker.&lt;/p&gt;</description></item><item><title>CHG-0003: The Stand Follows What Is Playing</title><link>https://cdeever.github.io/eds/docs/changes/2026/0003-the-stand-follows-now-playing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0003-the-stand-follows-now-playing/</guid><description>&lt;h1 id="chg-0003-the-stand-follows-what-is-playing"&gt;CHG-0003: The Stand Follows What Is Playing&lt;a class="anchor" href="#chg-0003-the-stand-follows-what-is-playing"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Deployment&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-complete"&gt;Complete&lt;/span&gt;&#10; 2026-10-11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;the &lt;code&gt;services&lt;/code&gt; workload of the &lt;code&gt;eds&lt;/code&gt; tenant: &lt;code&gt;eds-lightd&lt;/code&gt;, and a new &lt;code&gt;eds-nowplayd&lt;/code&gt;; by consequence, &lt;code&gt;lp-stand-01&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make -C deploy deploy WHERE=builder&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. &lt;code&gt;lightd&lt;/code&gt; gains an input and loses none. Most likely to go wrong: a settings file that leaves &lt;code&gt;nowplayd&lt;/code&gt; unable to log in to the broker, which shows as a unit restarting&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0006-now-playing-bus-of-drivers/"&gt;ADR-0006&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0008-nowplayd-arbitrates-and-enriches/"&gt;ADR-0008&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0009-lightd-takes-covers-from-a-topic/"&gt;ADR-0009&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0002-relay-pi-and-now-playing-accounts/"&gt;CHG-0002&lt;/a&gt;, whose follow-up this is&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Since &lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0002-relay-pi-and-now-playing-accounts/"&gt;CHG-0002&lt;/a&gt;&#10;the agent Pi has reported what iTunes is playing to the broker, and nothing&#10;has acted on it. The stand shows whatever cover was last sent to it by hand.&lt;/p&gt;</description></item><item><title>INC-0003: The Library Index Was Unreadable to voiced</title><link>https://cdeever.github.io/eds/docs/incidents/2026/0003-the-library-index-was-unreadable-to-voiced/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/incidents/2026/0003-the-library-index-was-unreadable-to-voiced/</guid><description>&lt;h1 id="inc-0003-the-library-index-was-unreadable-to-voiced-and-nothing-said-so"&gt;INC-0003: The Library Index Was Unreadable to voiced, and Nothing Said So&lt;a class="anchor" href="#inc-0003-the-library-index-was-unreadable-to-voiced-and-nothing-said-so"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-24&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;eds-voiced&lt;/code&gt; on the services workload; &lt;code&gt;make -C deploy library&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Severity&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Requests were answered as before the index (ADR-0045) rather than from it; some that it would have answered were not. Nothing wrong played&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Open · &lt;span class="status-badge inc-green"&gt;Hardening&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Times&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UTC&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;CHG-0040 copied the owner&amp;rsquo;s library index to &lt;code&gt;/var/lib/eds-voiced&lt;/code&gt; with&#10;&lt;code&gt;install&lt;/code&gt;, which labelled it &lt;code&gt;var_lib_t&lt;/code&gt;. voiced&amp;rsquo;s container, which podman&amp;rsquo;s&#10;&lt;code&gt;:Z&lt;/code&gt; gives &lt;code&gt;container_file_t&lt;/code&gt; and its own categories, could not read it.&#10;voiced took an unreadable index for none, as it was written to, and said&#10;nothing: requests went on being guessed at.&lt;/p&gt;</description></item><item><title>MQTT Topics</title><link>https://cdeever.github.io/eds/docs/reference/mqtt-topics/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/reference/mqtt-topics/</guid><description>&lt;h1 id="mqtt-topics"&gt;MQTT Topics&lt;a class="anchor" href="#mqtt-topics"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;The topic prefix defaults to &lt;code&gt;eds&lt;/code&gt; and must match on both sides — &lt;code&gt;lightd&lt;/code&gt;&amp;rsquo;s&#10;&lt;code&gt;LIGHTD_TOPIC_PREFIX&lt;/code&gt; and the firmware&amp;rsquo;s &lt;code&gt;LP_TOPIC_PREFIX&lt;/code&gt;.&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Topic&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Direction&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Retained&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;eds/lightstand/&amp;lt;id&amp;gt;/scene&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;lightd → device&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;yes&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;what to render&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;eds/lightstand/&amp;lt;id&amp;gt;/status&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;device → broker&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes (LWT)&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;online&lt;/code&gt; / &lt;code&gt;offline&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;eds/lightstand/&amp;lt;id&amp;gt;/state&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;device → broker&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;what it is rendering now&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;eds/lightd/status&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;lightd → broker&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes (LWT)&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;the publisher&amp;rsquo;s presence&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;eds/console/status&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;console → broker&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes (LWT)&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;the console&amp;rsquo;s presence; the only thing it publishes&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;eds/log/&amp;lt;id&amp;gt;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;device or agent Pi → broker&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;no&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;key events, for the log store: the stand&amp;rsquo;s, the cover screen&amp;rsquo;s, the power beacon&amp;rsquo;s, and the now-playing agent&amp;rsquo;s (&lt;code&gt;np-relay&lt;/code&gt;)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;eds/nowplaying/source/&amp;lt;id&amp;gt;/…&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;a driver → nowplayd&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;what one player is doing; see &lt;a href="../now-playing/"&gt;Now Playing&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;eds/nowplaying/current&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;nowplayd → subscribers&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;the one current track&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;eds/nowplaying/current/art&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;nowplayd → subscribers&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;its cover, as image bytes; lightd lights the stand from it&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;eds/nowplaying/current/art/small&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;nowplayd → subscribers&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;the same cover at 240 pixels, as a baseline JPEG; the cover screen shows it&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;eds/nowplaying/command&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;a controller → nowplayd&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;never&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;a button press, for whatever is current; see &lt;a href="../now-playing/#commands#commands"&gt;Now Playing&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;eds/nowplaying/source/&amp;lt;id&amp;gt;/command&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;nowplayd → a driver&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;never&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;the same press, passed to the current source; &lt;code&gt;play_album&lt;/code&gt; to &lt;code&gt;NP_ALBUM_SOURCE&lt;/code&gt; whatever is current (ADR-0040)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;eds/voice/&amp;lt;device&amp;gt;/utterance&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;device → voiced&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;never&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;what followed the wake word: a WAV, 16 kHz 16-bit mono, at most 15 s (ADR-0042)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;eds/voice/&amp;lt;device&amp;gt;/woken&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;device → voiced&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;never&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;{&amp;quot;v&amp;quot;:1}&lt;/code&gt;: the wake word was just heard, so the music is turned down (ADR-0044)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;eds/voice/&amp;lt;device&amp;gt;/heard&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;voiced → device, console&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;never&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;{&amp;quot;v&amp;quot;:1,&amp;quot;text&amp;quot;,&amp;quot;understood&amp;quot;,&amp;quot;artist&amp;quot;,&amp;quot;album&amp;quot;,&amp;quot;reason&amp;quot;}&lt;/code&gt;: what was made of the request&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;eds/voiced/status&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;voiced → broker&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes (LWT)&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;its presence&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;eds/screen/&amp;lt;id&amp;gt;/status&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;device → broker&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes (LWT)&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;the cover screen&amp;rsquo;s presence&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;eds/beacon/&amp;lt;id&amp;gt;/status&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;device → broker&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes (LWT)&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;whether the switch a beacon is on has power: &lt;code&gt;online&lt;/code&gt; while it does, the will&amp;rsquo;s &lt;code&gt;offline&lt;/code&gt; when it has not. nowplayd reads the one that speaks for the turntable (&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0023-a-source-that-is-switched-on-holds-the-stand/"&gt;ADR-0023&lt;/a&gt;)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;eds/nowplaying/current/look&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;nowplayd → lightd&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;whether that cover&amp;rsquo;s album has a look of its own, by name; see &lt;a href="../now-playing/#looks#looks"&gt;Now Playing&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;eds/nowplaying/stand&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;console → nowplayd&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes, as a setting&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;which sources the stand is lit for: &lt;code&gt;{&amp;quot;v&amp;quot;:1,&amp;quot;sources&amp;quot;:&amp;quot;records&amp;quot;}&lt;/code&gt;, the default, or &lt;code&gt;&amp;quot;all&amp;quot;&lt;/code&gt; (&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0039-the-console-can-light-the-stand-for-every-source/"&gt;ADR-0039&lt;/a&gt;)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="the-log-topic"&gt;The log topic&lt;a class="anchor" href="#the-log-topic"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;&lt;code&gt;eds/log/&amp;lt;id&amp;gt;&lt;/code&gt; is not EdS&amp;rsquo;s own layout. &lt;code&gt;&amp;lt;tenant&amp;gt;/log/&amp;lt;device&amp;gt;&lt;/code&gt; is the one&#10;topic under &lt;code&gt;log/&lt;/code&gt; Deevnet IoTaaS lets a device account publish, and its log&#10;bridge carries what arrives there into the tenant&amp;rsquo;s device log partition. The&#10;stand sends one JSON object per event — boot, network, scenes, health — at&#10;QoS 1 and &lt;strong&gt;not retained&lt;/strong&gt;: a log line replayed to every new subscriber would&#10;be an event that never happened again.&lt;/p&gt;</description></item><item><title>Powering the Strip</title><link>https://cdeever.github.io/eds/docs/guide/power/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/guide/power/</guid><description>&lt;h1 id="powering-the-strip"&gt;Powering the Strip&lt;a class="anchor" href="#powering-the-strip"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;WS2812-class LEDs draw about &lt;strong&gt;60 mA each at full white&lt;/strong&gt;, so a long strip at&#10;full brightness is an amp-scale load. The ESP32 devkit adds roughly 250 mA with&#10;WiFi up and peaks near 500 mA on transmit.&lt;/p&gt;&#10;&lt;h2 id="what-eds-actually-draws"&gt;What EdS actually draws&lt;a class="anchor" href="#what-eds-actually-draws"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Brightness is applied &lt;strong&gt;before&lt;/strong&gt; the gamma 2.6 table, which means current falls&#10;away far faster than the brightness figure suggests. Measured against the&#10;firmware&amp;rsquo;s own lookup table:&lt;/p&gt;</description></item><item><title>Remote Display</title><link>https://cdeever.github.io/eds/docs/architecture/subsystems/remote-display/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/subsystems/remote-display/</guid><description>&lt;h1 id="remote-display"&gt;Remote Display&lt;a class="anchor" href="#remote-display"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;A small touch screen that shows the cover of whatever is playing, and can&#10;change it&#10;(&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0020-a-touch-screen-that-can-change-what-plays/"&gt;ADR-0020&lt;/a&gt;).&#10;It is a stand-alone display and remote: for simple things, play or pause,&#10;back and next, it is handier than the phone app, and it is a way to enjoy&#10;the cover art in another room.&lt;/p&gt;&#10;&lt;p&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/subsystems/remote-display/remote-display.svg"&gt;&lt;img src="https://cdeever.github.io/eds/docs/architecture/subsystems/remote-display/remote-display.svg" alt="Remote Display: the cover screen reads the current track and its small cover from the broker, and sends a press to nowplayd, which passes it to the current source&amp;rsquo;s driver and its player." /&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Tenant: deevnet-tenant-eds</title><link>https://cdeever.github.io/eds/docs/develop/tenant/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/develop/tenant/</guid><description>&lt;h1 id="tenant-deevnet-tenant-eds"&gt;Tenant: deevnet-tenant-eds&lt;a class="anchor" href="#tenant-deevnet-tenant-eds"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;The EdS tenant as code: its overlay network, its workload and its DNS records,&#10;rebuildable from scratch against Deevnet IoTaaS without a Deevnet IoTaaS commit&#10;(Deevnet ADR-0006).&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Index&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1 (to be allocated in the factory&amp;rsquo;s &lt;code&gt;TENANTS.md&lt;/code&gt;)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Subnet&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;10.20.129.0/24&lt;/code&gt;, gateway &lt;code&gt;10.20.129.1&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Zone&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;eds.mobile.deevnet.net&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Service host&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;10.20.129.10&lt;/code&gt; — &lt;code&gt;palette&lt;/code&gt; and &lt;code&gt;lightd&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Module&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;tenant-module-v1.1.0&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="status-written-never-applied"&gt;Status: written, never applied&lt;a class="anchor" href="#status-written-never-applied"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;&lt;code&gt;terraform validate&lt;/code&gt;d against the real module, with derived addressing checked&#10;against Deevnet ADR-0002. It has &lt;strong&gt;not&lt;/strong&gt; been planned or applied, and three things must&#10;happen first:&lt;/p&gt;</description></item><item><title>ADR-0004: Firmware Secrets Are NVS-Only</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0004-firmware-secrets-nvs-only/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0004-firmware-secrets-nvs-only/</guid><description>&lt;h1 id="adr-0004-firmware-secrets-are-nvs-only-and-the-brokers-ca-is-provisioned"&gt;ADR-0004: Firmware Secrets Are NVS-Only, and the Broker&amp;rsquo;s CA Is Provisioned&lt;a class="anchor" href="#adr-0004-firmware-secrets-are-nvs-only-and-the-brokers-ca-is-provisioned"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-green"&gt;Accepted&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-10&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Where a device&amp;rsquo;s WiFi key, broker password and broker CA come from.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0001-lp-stand-joins-its-tenant/"&gt;CHG-0001&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/guide/provisioning/"&gt;Provisioning a Stand&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The stand needs a WiFi key and a broker password, both issued by the EdS&#10;tenant, and the CA that the broker&amp;rsquo;s certificate is verified against. The&#10;repository is public, and the firmware image gets built, cached and copied.&lt;/p&gt;</description></item><item><title>CHG-0004: Spotify on the Agent Pi</title><link>https://cdeever.github.io/eds/docs/changes/2026/0004-spotify-on-the-agent-pi/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0004-spotify-on-the-agent-pi/</guid><description>&lt;h1 id="chg-0004-spotify-on-the-agent-pi"&gt;CHG-0004: Spotify on the Agent Pi&lt;a class="anchor" href="#chg-0004-spotify-on-the-agent-pi"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Deployment&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-complete"&gt;Complete&lt;/span&gt;&#10; 2026-10-11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;the agent Pi &lt;code&gt;dv02rpi002p01&lt;/code&gt;; the &lt;code&gt;np-relay&lt;/code&gt; broker account of the &lt;code&gt;eds&lt;/code&gt; tenant; &lt;code&gt;eds-nowplayd&lt;/code&gt; on the &lt;code&gt;services&lt;/code&gt; workload&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;terraform apply&lt;/code&gt;; &lt;code&gt;make -C deploy units&lt;/code&gt;; &lt;code&gt;make -C deploy/relay push spotify&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low to the stand, which this change is designed not to affect. Most likely to go wrong: the account change reissuing the relay&amp;rsquo;s password, which would silence iTunes too&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0012-spotify-by-web-api/"&gt;ADR-0012&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0016-a-source-can-be-reported-without-its-cover/"&gt;ADR-0016&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0002-relay-pi-and-now-playing-accounts/"&gt;CHG-0002&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0003-the-stand-follows-now-playing/"&gt;CHG-0003&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The agent Pi follows iTunes. After this change it also follows a Spotify&#10;account, and reports what that account plays on the devices named as being in&#10;the room.&lt;/p&gt;</description></item><item><title>Configuration</title><link>https://cdeever.github.io/eds/docs/reference/configuration/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/reference/configuration/</guid><description>&lt;h1 id="configuration"&gt;Configuration&lt;a class="anchor" href="#configuration"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;h2 id="lightd"&gt;lightd&lt;a class="anchor" href="#lightd"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;All environment, no config file: the broker credentials must never land on disk&#10;in a repository, and the same binary has to work under a systemd unit or a&#10;container without knowing which.&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Variable&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Default&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;LIGHTD_ADDR&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;:8732&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;listen address&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;LIGHTD_PALETTE_URL&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;http://127.0.0.1:8731&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;palette service&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;LIGHTD_STAND_ID&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;lp-stand-01&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;default stand&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;LIGHTD_COVER_TOPIC&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;unset&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;a topic of cover images to light the stand from, relative to the prefix, e.g. &lt;code&gt;nowplaying/current/art&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;LIGHTD_LOOK_TOPIC&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;unset&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;a topic that says which covers have a look of their own, e.g. &lt;code&gt;nowplaying/current/look&lt;/code&gt;. Needs &lt;code&gt;LIGHTD_COVER_TOPIC&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;LIGHTD_SPECTRUM_EFFECT&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;sweep&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;how the &lt;code&gt;spectrum&lt;/code&gt; look moves: &lt;code&gt;sweep&lt;/code&gt;, the rainbow around the strip, or &lt;code&gt;morph&lt;/code&gt;, each color in turn. Anything else stops the daemon&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;LIGHTD_TOPIC_PREFIX&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;eds&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;root of the topic tree&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;LIGHTD_MQTT_URL&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;tcp://127.0.0.1:1883&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;tls://mqtt01…:8883&lt;/code&gt; in production&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;LIGHTD_MQTT_USERNAME&lt;/code&gt; / &lt;code&gt;_PASSWORD&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;—&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;broker credentials&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;LIGHTD_MQTT_CA_FILE&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;—&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;CA for the broker&amp;rsquo;s certificate&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;LIGHTD_MQTT_INSECURE&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;bring-up only; never with a real cert&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;LIGHTD_EFFECT&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;breathe&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;default effect: &lt;code&gt;solid&lt;/code&gt;, &lt;code&gt;breathe&lt;/code&gt;, &lt;code&gt;sweep&lt;/code&gt;, &lt;code&gt;morph&lt;/code&gt;, &lt;code&gt;chase&lt;/code&gt; or &lt;code&gt;scanner&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;LIGHTD_SPEED&lt;/code&gt; / &lt;code&gt;LIGHTD_BRIGHTNESS&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;0.4&lt;/code&gt; / &lt;code&gt;0.8&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;LIGHTD_SWATCHES&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;6&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;swatches requested from palette&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;LIGHTD_MIN_CHROMA&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;0.05&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;below this a swatch is a gray&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;LIGHTD_SATURATION&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;1.25&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;chroma multiplier for the strip&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;LIGHTD_MAX_COLORS&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;4&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;palette entries per scene&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;&lt;strong&gt;Invalid values stop the daemon&lt;/strong&gt; rather than lighting the room wrong quietly.&lt;/p&gt;</description></item><item><title>EdS on One Pi</title><link>https://cdeever.github.io/eds/docs/guide/one-pi/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/guide/one-pi/</guid><description>&lt;h1 id="eds-on-one-pi"&gt;EdS on One Pi&lt;a class="anchor" href="#eds-on-one-pi"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;Everything EdS needs can be put on one Raspberry Pi on the home network: the&#10;broker, the log store, Grafana, the four services and the now-playing agent.&#10;Nothing of Deevnet IoTaaS is behind it.&lt;/p&gt;&#10;&lt;blockquote class=''&gt;&#10;&lt;p&gt;&lt;strong&gt;Not yet proven.&lt;/strong&gt; The image is defined and has not run on a Pi.&#10;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0033-the-whole-back-end-on-one-pi/"&gt;ADR-0033&lt;/a&gt;&#10;is &lt;code&gt;Proposed&lt;/code&gt; and lists what would settle it.&lt;/p&gt;&#10;&lt;/blockquote&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;stand, screen, beacon ──TLS 8883──▶ ┌ Pi ────────────────────────────────┐&#10;iTunes PC ◀── remote protocol ────▶ │ Mosquitto · log store · Grafana │&#10;a browser ──────── 443 ───────────▶ │ palette · lightd · nowplayd │&#10;turntable ── tape out, sound card ─▶│ console · npagent │&#10; └────────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It is beside the tenant on Deevnet IoTaaS, not in place of it. Building the&#10;image and running the Pi change nothing there, and the stand, the screen and&#10;the beacon stay with the tenant until each is provisioned again.&lt;/p&gt;</description></item><item><title>INC-0004: The Stand Went Dark on One Channel</title><link>https://cdeever.github.io/eds/docs/incidents/2026/0004-the-stand-went-dark-on-one-channel/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/incidents/2026/0004-the-stand-went-dark-on-one-channel/</guid><description>&lt;h1 id="inc-0004-the-stand-went-dark-mid-side-because-the-turntable-was-heard-on-one-channel-and-that-one-went-silent"&gt;INC-0004: The Stand Went Dark Mid-Side, Because the Turntable Was Heard on One Channel and That One Went Silent&lt;a class="anchor" href="#inc-0004-the-stand-went-dark-mid-side-because-the-turntable-was-heard-on-one-channel-and-that-one-went-silent"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-26&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;npagent&lt;/code&gt;&amp;rsquo;s turntable driver and &lt;code&gt;nowplayd&lt;/code&gt; on the backend Pi; the UFO202 sound card; the Tape 1 output of the amplifier, an Onkyo A-8170 integrated amplifier from the mid-1980s; &lt;code&gt;lp-stand-01&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Severity&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The stand dropped to standby for the rest of a side, and stayed there through a reboot. Nothing else was lost; every other source and device worked&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Open · &lt;span class="status-badge inc-orange"&gt;Mitigated&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Times&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UTC&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The turntable reaches the sound card through the Tape 1 output of an Onkyo&#10;A-8170, an integrated amplifier from the mid-1980s, whose aged tape selector&#10;contacts can drop a channel. Partway through a side, the&#10;left channel went silent. &lt;code&gt;npagent&lt;/code&gt; records one channel, and what it records&#10;is the left, so it heard twenty seconds of silence, decided the record had&#10;stopped, and the stand went to standby while the record played on.&lt;/p&gt;</description></item><item><title>Now Playing</title><link>https://cdeever.github.io/eds/docs/reference/now-playing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/reference/now-playing/</guid><description>&lt;h1 id="now-playing"&gt;Now Playing&lt;a class="anchor" href="#now-playing"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;The contract between the programs that know what is playing and the programs&#10;that react to it. It is version &lt;strong&gt;1&lt;/strong&gt;, stamped on every message as &lt;code&gt;&amp;quot;v&amp;quot;: 1&lt;/code&gt;,&#10;and a message with any other version is refused rather than guessed at.&lt;/p&gt;&#10;&lt;p&gt;Why it is shaped this way:&#10;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0006-now-playing-bus-of-drivers/"&gt;ADR-0006&lt;/a&gt; and&#10;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0008-nowplayd-arbitrates-and-enriches/"&gt;ADR-0008&lt;/a&gt;.&lt;/p&gt;&#10;&lt;h2 id="topics"&gt;Topics&lt;a class="anchor" href="#topics"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;All under the tenant&amp;rsquo;s prefix, &lt;code&gt;eds/&lt;/code&gt;.&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Topic&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;From&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Retained&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Payload&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;nowplaying/source/&amp;lt;id&amp;gt;/state&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;a driver&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;what that player is doing&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;nowplaying/source/&amp;lt;id&amp;gt;/status&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;a driver&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes (last will)&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;online&lt;/code&gt; / &lt;code&gt;offline&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;nowplaying/source/&amp;lt;id&amp;gt;/art&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;a driver&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;the cover, as image bytes&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;nowplaying/current&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;nowplayd&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;the one current track&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;nowplaying/current/art&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;nowplayd&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;its cover, as image bytes&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;nowplaying/current/art/small&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;nowplayd&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;the same cover, small: a baseline JPEG, 240 pixels on its longer side&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;nowplaying/current/look&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;nowplayd&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;whether that cover&amp;rsquo;s album has a look of its own; with no cover, whether the room is waiting for one&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;nowplaying/stand&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;the console&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;which sources the stand is lit for: &lt;code&gt;records&lt;/code&gt; or &lt;code&gt;all&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;nowplaying/command&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;a controller&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;never&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;a button press, for whatever is current&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;nowplaying/source/&amp;lt;id&amp;gt;/command&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;nowplayd&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;never&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;that press, passed to the current source&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;nowplaying/source/spotify/switch&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;the console&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;whether the Spotify driver runs: &lt;code&gt;on&lt;/code&gt; or &lt;code&gt;off&lt;/code&gt;, and nothing is &lt;code&gt;off&lt;/code&gt; (ADR-0051)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;nowplaying/status&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;nowplayd&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;yes (last will)&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;online&lt;/code&gt; / &lt;code&gt;offline&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;&lt;code&gt;&amp;lt;id&amp;gt;&lt;/code&gt; names one driver deployment, such as &lt;code&gt;itunes-den&lt;/code&gt;. It is lowercase&#10;letters, digits and hyphens, at most 63 characters, starting with a letter or&#10;digit.&lt;/p&gt;</description></item><item><title>This Site</title><link>https://cdeever.github.io/eds/docs/develop/docs-site/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/develop/docs-site/</guid><description>&lt;h1 id="this-site"&gt;This Site&lt;a class="anchor" href="#this-site"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;Hugo with the &lt;a href="https://github.com/alex-shpak/hugo-book"&gt;hugo-book&lt;/a&gt; theme,&#10;following the &lt;code&gt;deevnet-docs&lt;/code&gt; pattern. It lives at &lt;code&gt;docs/&lt;/code&gt; inside the monorepo&#10;so documentation and the thing it documents move in the same commit.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd docs&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make server &lt;span style="color:#75715e"&gt;# live reload on :1313&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make html &lt;span style="color:#75715e"&gt;# build to public/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The theme is a git submodule. After a fresh clone:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git submodule update --init --recursive&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="living-in-a-monorepo"&gt;Living in a monorepo&lt;a class="anchor" href="#living-in-a-monorepo"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Two consequences, both handled:&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;A repository serves exactly one Pages site.&lt;/strong&gt; The site is therefore published&#10;at &lt;code&gt;https://cdeever.github.io/eds/&lt;/code&gt; — the repository name, not the site name —&#10;and &lt;code&gt;baseURL&lt;/code&gt; reflects that. &lt;code&gt;BookEditPath&lt;/code&gt; carries the &lt;code&gt;docs/&lt;/code&gt; prefix so &amp;ldquo;edit&#10;this page&amp;rdquo; links resolve.&lt;/p&gt;</description></item><item><title>Voice Request</title><link>https://cdeever.github.io/eds/docs/architecture/subsystems/voice-request/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/subsystems/voice-request/</guid><description>&lt;h1 id="voice-request"&gt;Voice Request&lt;a class="anchor" href="#voice-request"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;An album played because someone asked for it out loud: &amp;ldquo;play Aerosmith&amp;rsquo;s&#10;first album&amp;rdquo;, and it plays&#10;(&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0042-a-request-is-heard-on-the-workload/"&gt;ADR-0042&lt;/a&gt;).&#10;It is in development: one device listens so far, and it sits wherever it is&#10;being worked on. Ears are meant to be on several devices throughout the&#10;house, or on one carried from room to room.&lt;/p&gt;&#10;&lt;p&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/subsystems/voice-request/voice-request.svg"&gt;&lt;img src="https://cdeever.github.io/eds/docs/architecture/subsystems/voice-request/voice-request.svg" alt="Voice Request: the ears send a request as a WAV to the broker; voiced on the workload has scribe write it down, counts albums in MusicBrainz, chooses from the library index, and sends play_album to Now Playing." /&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>ADR-0005: Device Events Over MQTT</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0005-device-events-over-mqtt/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0005-device-events-over-mqtt/</guid><description>&lt;h1 id="adr-0005-a-device-reports-key-events-over-mqtt-not-its-serial-log"&gt;ADR-0005: A Device Reports Key Events Over MQTT, Not Its Serial Log&lt;a class="anchor" href="#adr-0005-a-device-reports-key-events-over-mqtt-not-its-serial-log"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-green"&gt;Accepted&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-10&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;How an EdS device says what it is doing once the USB cable is gone, and how that is read.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extended by&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0017-an-agent-pi-is-a-registered-device/"&gt;ADR-0017&lt;/a&gt;: an agent Pi is registered as a device and reports the same way&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0001-lp-stand-joins-its-tenant/"&gt;CHG-0001&lt;/a&gt;, Deevnet ADR-0027 and CHG-0021 (&lt;a href="https://deevnet.github.io/deevnet-docs/"&gt;deevnet-docs&lt;/a&gt;), &lt;a href="https://cdeever.github.io/eds/docs/reference/mqtt-topics/"&gt;MQTT Topics&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;A stand on a shelf has no console. It fails soft by design, which makes its&#10;failures quiet: one that keeps showing the last good scene looks, from the&#10;room, exactly like one that was sent nothing.&lt;/p&gt;</description></item><item><title>CHG-0005: The Agent Reports Its Events</title><link>https://cdeever.github.io/eds/docs/changes/2026/0005-the-agent-reports-its-events/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0005-the-agent-reports-its-events/</guid><description>&lt;h1 id="chg-0005-the-agent-reports-its-events"&gt;CHG-0005: The Agent Reports Its Events&lt;a class="anchor" href="#chg-0005-the-agent-reports-its-events"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Deployment&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-complete"&gt;Complete&lt;/span&gt;&#10; 2026-10-11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;the &lt;code&gt;eds&lt;/code&gt; tenant&amp;rsquo;s device registry and the &lt;code&gt;np-relay&lt;/code&gt; broker account; the agent Pi &lt;code&gt;dv02rpi002p01&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;terraform apply -target&lt;/code&gt;; &lt;code&gt;make -C deploy/relay push&lt;/code&gt;; one line added to the Pi&amp;rsquo;s settings&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: giving the account a device replaces it and reissues its password, which would silence both drivers&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0017-an-agent-pi-is-a-registered-device/"&gt;ADR-0017&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0004-spotify-on-the-agent-pi/"&gt;CHG-0004&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The agent Pi follows iTunes and Spotify and says so only in its own journal.&#10;After this change it is a registered device of the tenant and reports its key&#10;events to the log store: each track that plays, and each time a driver comes&#10;or goes.&lt;/p&gt;</description></item><item><title>Layer Boundaries</title><link>https://cdeever.github.io/eds/docs/architecture/boundaries/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/boundaries/</guid><description>&lt;h1 id="layer-boundaries"&gt;Layer Boundaries&lt;a class="anchor" href="#layer-boundaries"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;Each component of EdS is built to do one well-defined job, and to do it&#10;without knowing how its neighbors do theirs. It takes a plain input, returns&#10;a plain output, and keeps everything in between to itself: much as&#10;abstraction and encapsulation work in object-oriented programming, applied to&#10;services and devices in place of classes.&lt;/p&gt;&#10;&lt;p&gt;That is what lets each part be built, tested and tuned alone, and replaced&#10;without the others noticing. &lt;code&gt;palette&lt;/code&gt; can be tuned against a folder of&#10;JPEGs with nothing else running. A different diffuser wants a different&#10;gamma curve, and that changes the firmware and nothing upstream of it.&lt;/p&gt;</description></item><item><title>ADR-0006: Now Playing Is a Bus of Small Drivers</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0006-now-playing-bus-of-drivers/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0006-now-playing-bus-of-drivers/</guid><description>&lt;h1 id="adr-0006-now-playing-is-a-bus-of-small-drivers-behind-one-contract"&gt;ADR-0006: Now Playing Is a Bus of Small Drivers Behind One Contract&lt;a class="anchor" href="#adr-0006-now-playing-is-a-bus-of-small-drivers-behind-one-contract"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-green"&gt;Accepted&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-10&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;How EdS learns what is playing across several players, and how that knowledge reaches whatever reacts to it.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extended by&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0020-a-touch-screen-that-can-change-what-plays/"&gt;ADR-0020&lt;/a&gt;: a controller may send a command for the current track, and a driver that can carry one out reads its own command topic&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0003-broker-is-the-substrates/"&gt;ADR-0003&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0007-drivers-are-portable-go/"&gt;ADR-0007&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0008-nowplayd-arbitrates-and-enriches/"&gt;ADR-0008&lt;/a&gt;, and one record per player: &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0011-itunes-by-remote-pairing/"&gt;0011&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0012-spotify-by-web-api/"&gt;0012&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0013-musicbee-by-remote-protocol/"&gt;0013&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0014-tidal-by-lastfm/"&gt;0014&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The stand lights from a cover image, but nothing tells EdS what is playing.&#10;&lt;code&gt;lightd&lt;/code&gt; has carried &lt;code&gt;POST /v1/cover&lt;/code&gt; since the first vertical as &amp;ldquo;the&#10;interface the future album-cover resolver will call&amp;rdquo;; this is what sits&#10;upstream of it.&lt;/p&gt;</description></item><item><title>CHG-0006: The Console</title><link>https://cdeever.github.io/eds/docs/changes/2026/0006-the-console/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0006-the-console/</guid><description>&lt;h1 id="chg-0006-the-console"&gt;CHG-0006: The Console&lt;a class="anchor" href="#chg-0006-the-console"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Deployment&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-complete"&gt;Complete&lt;/span&gt;&#10; 2026-10-11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;the &lt;code&gt;eds&lt;/code&gt; tenant: a new broker account and a DNS name; the &lt;code&gt;services&lt;/code&gt; workload: a new &lt;code&gt;eds-console&lt;/code&gt;, and its firewall&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;terraform apply&lt;/code&gt;; &lt;code&gt;make -C deploy deploy WHERE=builder&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Nothing existing is changed except by being restarted. Most likely to go wrong: the console unable to bind port 80 as a user who is not root&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0018-a-console-of-eds-own/"&gt;ADR-0018&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0003-the-stand-follows-now-playing/"&gt;CHG-0003&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;EdS gains a page of its own: what is playing and on which player, its cover,&#10;each stand drawn in the colors and motion it was sent, and whether each part&#10;is up. It is served from the workload at &lt;code&gt;http://console.eds.mobile.deevnet.net/&lt;/code&gt;&#10;and only looks.&lt;/p&gt;</description></item><item><title>ADR-0007: Drivers Are Portable Go</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0007-drivers-are-portable-go/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0007-drivers-are-portable-go/</guid><description>&lt;h1 id="adr-0007-drivers-are-portable-go-in-one-agent-binary"&gt;ADR-0007: Drivers Are Portable Go, in One Agent Binary&lt;a class="anchor" href="#adr-0007-drivers-are-portable-go-in-one-agent-binary"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-green"&gt;Accepted&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-10&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The language and packaging of the now-playing drivers and backend.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0006-now-playing-bus-of-drivers/"&gt;ADR-0006&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The players run on Windows 11, which pulls toward Windows tooling. But&#10;development happens on a Mac against the Deevnet Mobile site, some drivers&#10;will run on a Raspberry Pi and some on the tenant workload, and &lt;code&gt;lightd&lt;/code&gt; is&#10;already Go.&lt;/p&gt;</description></item><item><title>CHG-0007: The Console Over TLS</title><link>https://cdeever.github.io/eds/docs/changes/2026/0007-the-console-over-tls/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0007-the-console-over-tls/</guid><description>&lt;h1 id="chg-0007-the-console-over-tls"&gt;CHG-0007: The Console Over TLS&lt;a class="anchor" href="#chg-0007-the-console-over-tls"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Deployment&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-complete"&gt;Complete&lt;/span&gt;&#10; 2026-10-11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;the &lt;code&gt;eds&lt;/code&gt; tenant: a certificate, held in its state; the &lt;code&gt;services&lt;/code&gt; workload: &lt;code&gt;eds-console&lt;/code&gt;, and its firewall&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;terraform init -upgrade&lt;/code&gt;, &lt;code&gt;terraform apply&lt;/code&gt;; &lt;code&gt;make -C deploy deploy WHERE=builder&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: the console unable to read its key as the user it runs as, which stops it at start with the reason in its log&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0018-a-console-of-eds-own/"&gt;ADR-0018&lt;/a&gt;; Deevnet ADR-0037, which gave tenants a CA to ask&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0006-the-console/"&gt;CHG-0006&lt;/a&gt;; Deevnet CHG-0047, which built the Tenant Service CA this is the first use of&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The console is served in the clear, because when it was built nothing on the&#10;site would certify a name a tenant serves. Deevnet IoTaaS now has a Tenant&#10;Service CA (Deevnet ADR-0037), and a tenant can ask it for a server&#10;certificate for a name in its own zone.&lt;/p&gt;</description></item><item><title>ADR-0008: nowplayd Picks the Track and Guarantees the Fields</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0008-nowplayd-arbitrates-and-enriches/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0008-nowplayd-arbitrates-and-enriches/</guid><description>&lt;h1 id="adr-0008-nowplayd-picks-the-current-track-and-guarantees-title-album-and-art"&gt;ADR-0008: nowplayd Picks the Current Track and Guarantees Title, Album and Art&lt;a class="anchor" href="#adr-0008-nowplayd-picks-the-current-track-and-guarantees-title-album-and-art"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-green"&gt;Accepted&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-10&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;What turns several sources&amp;rsquo; states into one current track, and who is responsible for the fields subscribers rely on.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extended by&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0016-a-source-can-be-reported-without-its-cover/"&gt;ADR-0016&lt;/a&gt;: a source can be named as reported without its cover, and then the promise of art does not apply to it&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0006-now-playing-bus-of-drivers/"&gt;ADR-0006&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0009-lightd-takes-covers-from-a-topic/"&gt;ADR-0009&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Several drivers may report at once: a paused iTunes, a Spotify playing on a&#10;phone. Subscribers want one answer. They also need a title, an album and a&#10;cover, and the drivers cannot all supply those: TIDAL through Last.fm arrives&#10;with no art, and a locally read TIDAL has no album.&lt;/p&gt;</description></item><item><title>CHG-0008: The Stand Reports Its Colors</title><link>https://cdeever.github.io/eds/docs/changes/2026/0008-the-stand-reports-its-colours/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0008-the-stand-reports-its-colours/</guid><description>&lt;h1 id="chg-0008-the-stand-reports-its-colors"&gt;CHG-0008: The Stand Reports Its Colors&lt;a class="anchor" href="#chg-0008-the-stand-reports-its-colors"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Upgrade&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-complete"&gt;Complete&lt;/span&gt;&#10; 2026-10-11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;lp-stand-01&lt;/code&gt;, over USB from the development Mac&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make -C firmware/lp-stand build flash PORT=/dev/cu.usbserial-0001&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: a flash that also erased the stand&amp;rsquo;s credentials, which would leave it off the network until provisioned again&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0005-device-events-over-mqtt/"&gt;ADR-0005&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0001-lp-stand-joins-its-tenant/"&gt;CHG-0001&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;When the stand applies a scene it reports the effect, how many colors and the&#10;brightness. It does not say which colors. The firmware that does has been on&#10;&lt;code&gt;main&lt;/code&gt; since it was written for a dashboard panel that was not kept, and has&#10;never been on the stand.&lt;/p&gt;</description></item><item><title>ADR-0009: lightd Takes Covers From a Topic</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0009-lightd-takes-covers-from-a-topic/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0009-lightd-takes-covers-from-a-topic/</guid><description>&lt;h1 id="adr-0009-lightd-takes-covers-from-a-topic-as-a-second-input"&gt;ADR-0009: lightd Takes Covers From a Topic as a Second Input&lt;a class="anchor" href="#adr-0009-lightd-takes-covers-from-a-topic-as-a-second-input"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-green"&gt;Accepted&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-10&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;How the current track&amp;rsquo;s cover reaches &lt;code&gt;lightd&lt;/code&gt;.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extended by&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0019-an-album-can-have-a-look-of-its-own/"&gt;ADR-0019&lt;/a&gt;: a cover may arrive with the name of a look, which &lt;code&gt;lightd&lt;/code&gt; draws in place of the cover&amp;rsquo;s own colors&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0002-gamma-in-firmware/"&gt;ADR-0002&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0008-nowplayd-arbitrates-and-enriches/"&gt;ADR-0008&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;&lt;code&gt;nowplayd&lt;/code&gt; publishes the current cover as image bytes on&#10;&lt;code&gt;eds/nowplaying/current/art&lt;/code&gt;. &lt;code&gt;lightd&lt;/code&gt; turns image bytes into a scene, and&#10;today takes them only over HTTP, at &lt;code&gt;POST /v1/cover&lt;/code&gt;. Something has to carry&#10;the bytes from the topic to &lt;code&gt;lightd&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>CHG-0009: Two Effects for the Accents</title><link>https://cdeever.github.io/eds/docs/changes/2026/0009-two-effects-for-the-accents/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0009-two-effects-for-the-accents/</guid><description>&lt;h1 id="chg-0009-two-effects-for-the-accents"&gt;CHG-0009: Two Effects for the Accents&lt;a class="anchor" href="#chg-0009-two-effects-for-the-accents"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Upgrade&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-complete"&gt;Complete&lt;/span&gt;&#10; 2026-10-11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;lp-stand-01&lt;/code&gt;, over USB; &lt;code&gt;eds-lightd&lt;/code&gt; and &lt;code&gt;eds-console&lt;/code&gt; on the &lt;code&gt;services&lt;/code&gt; workload&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make -C firmware/lp-stand build flash&lt;/code&gt;; &lt;code&gt;make -C deploy deploy WHERE=builder&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: &lt;code&gt;lightd&lt;/code&gt; asking for an effect the stand does not know, which the stand shows as a steady color&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0001-device-renders-effects/"&gt;ADR-0001&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0008-the-stand-reports-its-colours/"&gt;CHG-0008&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The stand&amp;rsquo;s default effect, &lt;code&gt;breathe&lt;/code&gt;, lights a cover&amp;rsquo;s dominant color and&#10;nothing else. The other colors &lt;code&gt;lightd&lt;/code&gt; picks, the accents, reach the stand&#10;in every scene and are used only by &lt;code&gt;sweep&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>ADR-0010: A Dual-Homed Pi Relays the Home LAN</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0010-home-lan-relay/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0010-home-lan-relay/</guid><description>&lt;h1 id="adr-0010-home-lan-drivers-reach-the-broker-through-a-dual-homed-mobile-pi"&gt;ADR-0010: Home-LAN Drivers Reach the Broker Through a Dual-Homed Mobile Pi&lt;a class="anchor" href="#adr-0010-home-lan-drivers-reach-the-broker-through-a-dual-homed-mobile-pi"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-green"&gt;Accepted&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-10&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;How a driver that must be near a player on the home LAN reaches the broker at the Deevnet Mobile site.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extended by&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0015-eds-builds-its-own-pi-images/"&gt;ADR-0015&lt;/a&gt;: the image is EdS&amp;rsquo;s own, and a relay is a way of configuring it&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0003-broker-is-the-substrates/"&gt;ADR-0003&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0006-now-playing-bus-of-drivers/"&gt;ADR-0006&lt;/a&gt;, the Deevnet network segmentation standard (&lt;a href="https://deevnet.github.io/deevnet-docs/"&gt;deevnet-docs&lt;/a&gt;)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The Windows PCs that run iTunes and MusicBee sit on a home LAN. The broker&#10;is inside the Deevnet Mobile site. There is no path from the home LAN into&#10;the site, and the site&amp;rsquo;s workloads cannot reach private addresses outside&#10;it. The iTunes and MusicBee drivers speak network protocols to their&#10;players, and pairing with iTunes needs multicast, so they have to be on the&#10;players&amp;rsquo; LAN.&lt;/p&gt;</description></item><item><title>CHG-0010: A Look for One Album, and a Strip of Eighteen</title><link>https://cdeever.github.io/eds/docs/changes/2026/0010-a-look-for-one-album-and-a-strip-of-eighteen/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0010-a-look-for-one-album-and-a-strip-of-eighteen/</guid><description>&lt;h1 id="chg-0010-a-look-for-one-album-and-a-strip-of-eighteen"&gt;CHG-0010: A Look for One Album, and a Strip of Eighteen&lt;a class="anchor" href="#chg-0010-a-look-for-one-album-and-a-strip-of-eighteen"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Upgrade&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-complete"&gt;Complete&lt;/span&gt;&#10; 2026-10-11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;the &lt;code&gt;eds&lt;/code&gt; tenant: two broker accounts gain a topic; &lt;code&gt;eds-nowplayd&lt;/code&gt;, &lt;code&gt;eds-lightd&lt;/code&gt; and &lt;code&gt;eds-console&lt;/code&gt; on the &lt;code&gt;services&lt;/code&gt; workload; &lt;code&gt;lp-stand-01&lt;/code&gt;, over USB&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;terraform apply&lt;/code&gt;; &lt;code&gt;make -C firmware/lp-stand build flash&lt;/code&gt;; &lt;code&gt;make -C deploy deploy WHERE=builder&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: a grant that does not match the topic, which the broker refuses without saying so and which leaves every album lit from its cover as before&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0019-an-album-can-have-a-look-of-its-own/"&gt;ADR-0019&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0009-two-effects-for-the-accents/"&gt;CHG-0009&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Two things, deployed together because they touch the same three programs.&lt;/p&gt;</description></item><item><title>ADR-0011: iTunes by Remote Pairing</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0011-itunes-by-remote-pairing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0011-itunes-by-remote-pairing/</guid><description>&lt;h1 id="adr-0011-itunes-is-read-by-remote-pairing-the-way-the-phone-remote-does-it"&gt;ADR-0011: iTunes Is Read by Remote Pairing, the Way the Phone Remote Does It&lt;a class="anchor" href="#adr-0011-itunes-is-read-by-remote-pairing-the-way-the-phone-remote-does-it"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-green"&gt;Accepted&lt;/span&gt;&#10; 2026-10-10, after pairing with the real iTunes; see &lt;a href="#evidence"&gt;Evidence&lt;/a&gt;. Opened the same day as &lt;code&gt;Proposed&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-10&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;How the iTunes driver learns of track changes and gets artwork.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extended by&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0020-a-touch-screen-that-can-change-what-plays/"&gt;ADR-0020&lt;/a&gt;: the pairing is also used to play, pause, skip and set the volume&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0006-now-playing-bus-of-drivers/"&gt;ADR-0006&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0007-drivers-are-portable-go/"&gt;ADR-0007&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0010-home-lan-relay/"&gt;ADR-0010&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The PCs run &lt;strong&gt;classic iTunes for Windows&lt;/strong&gt;, not the Microsoft Store build and&#10;not the newer Apple Music app. A phone remote app already sees and controls&#10;it, after a one-time pairing and with no Apple ID sign-in. That pairing has to&#10;keep working for as long as Apple supports it.&lt;/p&gt;</description></item><item><title>CHG-0011: Spotify Turned Off</title><link>https://cdeever.github.io/eds/docs/changes/2026/0011-spotify-turned-off/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0011-spotify-turned-off/</guid><description>&lt;h1 id="chg-0011-spotify-turned-off"&gt;CHG-0011: Spotify Turned Off&lt;a class="anchor" href="#chg-0011-spotify-turned-off"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Configuration&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-complete"&gt;Complete&lt;/span&gt;&#10; 2026-10-11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;the agent Pi: one line of its settings, and its agent restarted&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make -C deploy/relay drivers DRIVERS=itunes&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: the agent not coming back, which would stop iTunes being followed too&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0012-spotify-by-web-api/"&gt;ADR-0012&lt;/a&gt;, unchanged&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0004-spotify-on-the-agent-pi/"&gt;CHG-0004&lt;/a&gt;, which turned it on&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The Spotify driver works, and nothing uses what it reports: the stand does&#10;not follow Spotify, by decision. Meanwhile it asks Spotify what is playing&#10;every ten seconds, all day. Its owner is not using it for now and will come&#10;back to it.&lt;/p&gt;</description></item><item><title>ADR-0012: Spotify by the Web API</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0012-spotify-by-web-api/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0012-spotify-by-web-api/</guid><description>&lt;h1 id="adr-0012-spotify-is-read-from-the-account-through-the-web-api"&gt;ADR-0012: Spotify Is Read From the Account, Through the Web API&lt;a class="anchor" href="#adr-0012-spotify-is-read-from-the-account-through-the-web-api"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-green"&gt;Accepted&lt;/span&gt;&#10; 2026-10-11, once the driver had run against the account; two observations are still wanted, under &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-10&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;How the Spotify driver learns what is playing.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Amended&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-11, before it was accepted: where the driver runs, how it is authorized, which devices count, and that it takes no artwork. The text below is the amended decision; &lt;a href="#what-changed-on-2026-10-11"&gt;What changed&lt;/a&gt; lists the differences&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extended by&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0031-spotify-is-shown-like-itunes/"&gt;ADR-0031&lt;/a&gt;: the driver takes the album&amp;rsquo;s picture after all, from the answer it already asks for. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0032-spotify-takes-commands/"&gt;ADR-0032&lt;/a&gt;: the authorization also allows changing playback, and the driver carries out commands&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0006-now-playing-bus-of-drivers/"&gt;ADR-0006&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0007-drivers-are-portable-go/"&gt;ADR-0007&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0016-a-source-can-be-reported-without-its-cover/"&gt;ADR-0016&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Spotify knows what an account is playing wherever it plays: start a track on&#10;the desktop and the phone shows it. Spotify must also work when the rack is&#10;away from the house, which rules out anything that depends on the home LAN.&lt;/p&gt;</description></item><item><title>CHG-0012: The Cover Screen</title><link>https://cdeever.github.io/eds/docs/changes/2026/0012-the-cover-screen/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0012-the-cover-screen/</guid><description>&lt;h1 id="chg-0012-the-cover-screen"&gt;CHG-0012: The Cover Screen&lt;a class="anchor" href="#chg-0012-the-cover-screen"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Deployment&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-in-progress"&gt;In progress&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;a new device, &lt;code&gt;cover-screen-01&lt;/code&gt;; the tenant&amp;rsquo;s Terraform (one device, one broker account, grants on two others); &lt;code&gt;nowplayd&lt;/code&gt; on the workload; the agent on the Pi&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make flash&lt;/code&gt; and &lt;code&gt;make provision&lt;/code&gt; in &lt;code&gt;firmware/cover-screen&lt;/code&gt;; &lt;code&gt;make plan apply&lt;/code&gt; in &lt;code&gt;infra/deevnet-tenant-eds&lt;/code&gt;; &lt;code&gt;make -C deploy deploy WHERE=builder&lt;/code&gt;; &lt;code&gt;make -C deploy/relay push&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Medium. It is the first change that lets anything alter what plays. Most likely to go wrong: the agent or &lt;code&gt;nowplayd&lt;/code&gt; not coming back, which would stop the stand following the music&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0020-a-touch-screen-that-can-change-what-plays/"&gt;ADR-0020&lt;/a&gt;, which this is the evidence for&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0002-relay-pi-and-now-playing-accounts/"&gt;CHG-0002&lt;/a&gt;, which made the accounts this adds to&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;A touch screen is added beside the stand. It shows the cover of what is&#10;playing and, when touched, five buttons: play or pause, previous, next,&#10;volume up, volume down.&lt;/p&gt;</description></item><item><title>ADR-0013: MusicBee by the Remote Plugin's Protocol</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0013-musicbee-by-remote-protocol/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0013-musicbee-by-remote-protocol/</guid><description>&lt;h1 id="adr-0013-musicbee-is-read-through-the-musicbee-remote-plugins-protocol"&gt;ADR-0013: MusicBee Is Read Through the MusicBee Remote Plugin&amp;rsquo;s Protocol&lt;a class="anchor" href="#adr-0013-musicbee-is-read-through-the-musicbee-remote-plugins-protocol"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10; — the protocol has been read and does what is needed; it has not been tried against a real MusicBee. See &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-10&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;How the MusicBee driver learns of track changes and gets artwork.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0006-now-playing-bus-of-drivers/"&gt;ADR-0006&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0007-drivers-are-portable-go/"&gt;ADR-0007&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0010-home-lan-relay/"&gt;ADR-0010&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0011-itunes-by-remote-pairing/"&gt;ADR-0011&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;MusicBee plays local files and has no cloud. Anything that reads it runs on&#10;or near the PC. Its extension point is a plugin: a .NET DLL loaded into&#10;MusicBee, with a notification when the track changes.&lt;/p&gt;</description></item><item><title>CHG-0013: The Turntable Driver</title><link>https://cdeever.github.io/eds/docs/changes/2026/0013-the-turntable-driver/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0013-the-turntable-driver/</guid><description>&lt;h1 id="chg-0013-the-turntable-driver"&gt;CHG-0013: The Turntable Driver&lt;a class="anchor" href="#chg-0013-the-turntable-driver"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-11, run on 2026-10-12 UTC&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Deployment&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-complete"&gt;Complete&lt;/span&gt;&#10; 2026-10-12&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;the tenant (one broker account), the agent Pi (its agent, its unit, a recognizer installed, two lines of its settings)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make apply&lt;/code&gt; in the tenant; &lt;code&gt;make -C deploy/relay push&lt;/code&gt;, &lt;code&gt;turntable&lt;/code&gt;, &lt;code&gt;drivers&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Medium. Most likely to go wrong: the agent&amp;rsquo;s unit, which changes how it is confined, not starting, which would stop iTunes being followed too&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0021-the-turntable-is-identified-by-listening/"&gt;ADR-0021&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0002-relay-pi-and-now-playing-accounts/"&gt;CHG-0002&lt;/a&gt;, which made the account; &lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0012-the-cover-screen/"&gt;CHG-0012&lt;/a&gt;, in progress on the same Pi&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The agent Pi gains a third driver, which listens to the amplifier&amp;rsquo;s tape&#10;output through a USB audio interface and reports the record that is playing.&lt;/p&gt;</description></item><item><title>ADR-0014: TIDAL by Last.fm</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0014-tidal-by-lastfm/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0014-tidal-by-lastfm/</guid><description>&lt;h1 id="adr-0014-tidal-is-read-through-lastfm-because-nothing-better-is-offered"&gt;ADR-0014: TIDAL Is Read Through Last.fm, Because Nothing Better Is Offered&lt;a class="anchor" href="#adr-0014-tidal-is-read-through-lastfm-because-nothing-better-is-offered"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10; — until it has been tried against the account; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-10&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;How the TIDAL driver learns what is playing.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Priority&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The lowest of the four players, by the owner&amp;rsquo;s choice. Built last.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0006-now-playing-bus-of-drivers/"&gt;ADR-0006&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0007-drivers-are-portable-go/"&gt;ADR-0007&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0012-spotify-by-web-api/"&gt;ADR-0012&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The wish was for TIDAL to work like Spotify: ask the account, from the cloud,&#10;with nothing on the PC, so that it also works away from home.&lt;/p&gt;</description></item><item><title>CHG-0014: The Owner's Collection</title><link>https://cdeever.github.io/eds/docs/changes/2026/0014-the-owners-collection/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0014-the-owners-collection/</guid><description>&lt;h1 id="chg-0014-the-owners-collection"&gt;CHG-0014: The Owner&amp;rsquo;s Collection&lt;a class="anchor" href="#chg-0014-the-owners-collection"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-12&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Deployment&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-in-progress"&gt;In progress&lt;/span&gt;&#10; — a record from the collection is shown with its own sleeve; one that is not in it has not been tried&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;the services workload: nowplayd&amp;rsquo;s image, its unit, one settings file changed and one added. The console&amp;rsquo;s image, for one line of its page&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make -C deploy deploy WHERE=builder&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Medium. Most likely to go wrong: nowplayd&amp;rsquo;s unit, which names a new settings file, not starting; nothing would then be current and the stand would hold its last scene&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0022-the-owners-collection-names-the-record/"&gt;ADR-0022&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0013-the-turntable-driver/"&gt;CHG-0013&lt;/a&gt;, which put the turntable on the bus&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;nowplayd learns to ask its owner&amp;rsquo;s Discogs collection which record a track&#10;from the turntable is on.&lt;/p&gt;</description></item><item><title>ADR-0015: EdS Builds Its Own Pi Images</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0015-eds-builds-its-own-pi-images/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0015-eds-builds-its-own-pi-images/</guid><description>&lt;h1 id="adr-0015-eds-builds-its-own-pi-images-on-deevnet-iotaass-base"&gt;ADR-0015: EdS Builds Its Own Pi Images, on Deevnet IoTaaS&amp;rsquo;s Base&lt;a class="anchor" href="#adr-0015-eds-builds-its-own-pi-images-on-deevnet-iotaass-base"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-green"&gt;Accepted&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-10&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Where the definition of an EdS Raspberry Pi image lives, what it is built from, and what &amp;ldquo;the relay&amp;rdquo; is.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0010-home-lan-relay/"&gt;ADR-0010&lt;/a&gt;, which decided there would be a dual-homed Pi and did not say whose image it would run&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0004-firmware-secrets-nvs-only/"&gt;ADR-0004&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0002-relay-pi-and-now-playing-accounts/"&gt;CHG-0002&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The Pi that carries now-playing reports from the home LAN to the broker needed&#10;an image. Deevnet IoTaaS has an image factory that builds Raspberry Pi images,&#10;and the first relay image was built there, as a new variant beside&#10;Deevnet IoTaaS&amp;rsquo;s own.&lt;/p&gt;</description></item><item><title>CHG-0015: The Turntable's Power Beacon</title><link>https://cdeever.github.io/eds/docs/changes/2026/0015-the-turntables-power-beacon/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0015-the-turntables-power-beacon/</guid><description>&lt;h1 id="chg-0015-the-turntables-power-beacon"&gt;CHG-0015: The Turntable&amp;rsquo;s Power Beacon&lt;a class="anchor" href="#chg-0015-the-turntables-power-beacon"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-12&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Deployment&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-in-progress"&gt;In progress&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;a new device, &lt;code&gt;turntable-power-01&lt;/code&gt;; the tenant&amp;rsquo;s Terraform (one device, one broker account, a grant on two others); &lt;code&gt;nowplayd&lt;/code&gt; and the console on the workload&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make flash&lt;/code&gt; and &lt;code&gt;make provision&lt;/code&gt; in &lt;code&gt;firmware/power-beacon&lt;/code&gt;; &lt;code&gt;make plan apply&lt;/code&gt; in &lt;code&gt;infra/deevnet-tenant-eds&lt;/code&gt;; &lt;code&gt;make -C deploy deploy WHERE=builder&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low to medium. &lt;code&gt;nowplayd&lt;/code&gt;&amp;rsquo;s rule for what is current changes, for the turntable only and only once its beacon has been heard. Most likely to go wrong: &lt;code&gt;nowplayd&lt;/code&gt; or the console not coming back, which would stop the stand following the music or blank the page&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0023-a-source-that-is-switched-on-holds-the-stand/"&gt;ADR-0023&lt;/a&gt;, which this is the evidence for&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0013-the-turntable-driver/"&gt;CHG-0013&lt;/a&gt;, whose follow-up about a lifted needle this answers; &lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0012-the-cover-screen/"&gt;CHG-0012&lt;/a&gt;, the last device added, and the shape this follows&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;A bare ESP32-S2 goes on the outlet that is switched with the turntable. It&#10;is connected to the broker while the turntable is on and says nothing else.&lt;/p&gt;</description></item><item><title>ADR-0016: A Source Can Be Reported Without Its Cover</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0016-a-source-can-be-reported-without-its-cover/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0016-a-source-can-be-reported-without-its-cover/</guid><description>&lt;h1 id="adr-0016-a-source-can-be-reported-without-its-cover-and-spotify-is"&gt;ADR-0016: A Source Can Be Reported Without Its Cover, and Spotify Is&lt;a class="anchor" href="#adr-0016-a-source-can-be-reported-without-its-cover-and-spotify-is"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-green"&gt;Accepted&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Whether everything that is reported as playing also lights the stand.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0008-nowplayd-arbitrates-and-enriches/"&gt;ADR-0008&lt;/a&gt;, which promised that &lt;code&gt;current&lt;/code&gt; carries a cover whenever something is playing&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extended by&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0028-the-stand-is-for-records/"&gt;ADR-0028&lt;/a&gt;: a source can also be reported with its cover and still not lit, by a look that says so. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0031-spotify-is-shown-like-itunes/"&gt;ADR-0031&lt;/a&gt;: Spotify is no longer reported this way. It has its cover, and is kept off the stand as iTunes is; the setting remains, with no source in it&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0009-lightd-takes-covers-from-a-topic/"&gt;ADR-0009&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0012-spotify-by-web-api/"&gt;ADR-0012&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The stand was built to stand beside a record that is playing. iTunes plays a&#10;library of albums the owner chose, and the stand follows it.&lt;/p&gt;</description></item><item><title>CHG-0016: Idle, the Screen on the Console, and No Buttons for a Record</title><link>https://cdeever.github.io/eds/docs/changes/2026/0016-idle-the-screen-on-the-console-and-no-buttons-for-a-record/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0016-idle-the-screen-on-the-console-and-no-buttons-for-a-record/</guid><description>&lt;h1 id="chg-0016-idle-the-screen-on-the-console-and-no-buttons-for-a-record"&gt;CHG-0016: Idle, the Screen on the Console, and No Buttons for a Record&lt;a class="anchor" href="#chg-0016-idle-the-screen-on-the-console-and-no-buttons-for-a-record"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-12&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Upgrade&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-in-progress"&gt;In progress&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;nowplayd&lt;/code&gt;, &lt;code&gt;lightd&lt;/code&gt; and the console on the workload; the cover screen&amp;rsquo;s firmware; the tenant&amp;rsquo;s Terraform (one grant on the console&amp;rsquo;s account)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make plan apply&lt;/code&gt; in &lt;code&gt;infra/deevnet-tenant-eds&lt;/code&gt;; &lt;code&gt;make -C deploy deploy WHERE=builder&lt;/code&gt;; &lt;code&gt;make flash&lt;/code&gt; in &lt;code&gt;firmware/cover-screen&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Medium. What lights the room changes: the stand dims by itself for the first time. Most likely to go wrong: the stand dim when something is playing, or lit when nothing is&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0024-paused-long-enough-is-not-playing/"&gt;ADR-0024&lt;/a&gt; and &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0025-current-says-when-there-are-no-controls/"&gt;ADR-0025&lt;/a&gt;, which this is the evidence for&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0015-the-turntables-power-beacon/"&gt;CHG-0015&lt;/a&gt;, on whose branch this is built and whose console change this adds to&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Three things, asked for together.&lt;/p&gt;</description></item><item><title>ADR-0017: An Agent Pi Is a Registered Device</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0017-an-agent-pi-is-a-registered-device/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0017-an-agent-pi-is-a-registered-device/</guid><description>&lt;h1 id="adr-0017-an-agent-pi-is-a-registered-device-and-reports-its-events-like-one"&gt;ADR-0017: An Agent Pi Is a Registered Device, and Reports Its Events Like One&lt;a class="anchor" href="#adr-0017-an-agent-pi-is-a-registered-device-and-reports-its-events-like-one"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-green"&gt;Accepted&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;How the now-playing agent&amp;rsquo;s key events reach the tenant&amp;rsquo;s log store, and what the Pi it runs on is to the tenant.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0005-device-events-over-mqtt/"&gt;ADR-0005&lt;/a&gt;, which gave devices a way to report and said a program that is not a device &amp;ldquo;needs another route&amp;rdquo;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0015-eds-builds-its-own-pi-images/"&gt;ADR-0015&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0010-home-lan-relay/"&gt;ADR-0010&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The stand reports its key events to the tenant&amp;rsquo;s log store, and they are read&#10;on a dashboard. The agent Pi reported nothing: what it saw playing, and&#10;whether its drivers were working, was in its own journal, reached by SSH&#10;through the Builder.&lt;/p&gt;</description></item><item><title>CHG-0017: The Gap Between Tracks, and a Silent Turntable</title><link>https://cdeever.github.io/eds/docs/changes/2026/0017-the-gap-between-tracks-and-a-silent-turntable/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0017-the-gap-between-tracks-and-a-silent-turntable/</guid><description>&lt;h1 id="chg-0017-the-gap-between-tracks-and-a-silent-turntable"&gt;CHG-0017: The Gap Between Tracks, and a Silent Turntable&lt;a class="anchor" href="#chg-0017-the-gap-between-tracks-and-a-silent-turntable"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-12&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Upgrade&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-in-progress"&gt;In progress&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;npagent&lt;/code&gt; on the agent Pi (&lt;code&gt;np-relay&lt;/code&gt;); &lt;code&gt;nowplayd&lt;/code&gt; and the console on the workload&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make -C deploy/relay push&lt;/code&gt;; &lt;code&gt;make -C deploy deploy WHERE=builder&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: a wrong title for a few seconds after a quiet passage, or a room that dims while a record is being turned over and surprises someone&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0026-what-silence-means-on-the-turntable/"&gt;ADR-0026&lt;/a&gt;, which this is the evidence for&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0013-the-turntable-driver/"&gt;CHG-0013&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0016-idle-the-screen-on-the-console-and-no-buttons-for-a-record/"&gt;CHG-0016&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Three things about silence, asked for together.&lt;/p&gt;</description></item><item><title>ADR-0018: A Console of EdS's Own</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0018-a-console-of-eds-own/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0018-a-console-of-eds-own/</guid><description>&lt;h1 id="adr-0018-eds-has-a-console-of-its-own-fed-from-the-bus-and-it-only-looks"&gt;ADR-0018: EdS Has a Console of Its Own, Fed From the Bus, and It Only Looks&lt;a class="anchor" href="#adr-0018-eds-has-a-console-of-its-own-fed-from-the-bus-and-it-only-looks"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-green"&gt;Accepted&lt;/span&gt;&#10; 2026-10-11, once it had been watched in a browser on the site with tracks changing&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Amended&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-11, before it was accepted: served over TLS, not in the clear. When this was written nothing on the site would certify a name a tenant serves; Deevnet ADR-0037 has since given tenants a CA to ask. &lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0007-the-console-over-tls/"&gt;CHG-0007&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Where a person looks to see what EdS is doing: what is playing, what the stand is showing, and whether the parts are up.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extended by&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0039-the-console-can-light-the-stand-for-every-source/"&gt;ADR-0039&lt;/a&gt;: its first control, which switches the stand between records and every source&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0005-device-events-over-mqtt/"&gt;ADR-0005&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0006-now-playing-bus-of-drivers/"&gt;ADR-0006&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0009-lightd-takes-covers-from-a-topic/"&gt;ADR-0009&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0016-a-source-can-be-reported-without-its-cover/"&gt;ADR-0016&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;What EdS is doing was visible in three places, none of them a picture: the&#10;tenant&amp;rsquo;s Grafana dashboard, which lists events; &lt;code&gt;mosquitto_sub&lt;/code&gt;; and the&#10;services&amp;rsquo; journals. The stand has no LEDs attached yet, so nothing at all&#10;showed its colors.&lt;/p&gt;</description></item><item><title>CHG-0018: Counting What Is Asked of Outside Services</title><link>https://cdeever.github.io/eds/docs/changes/2026/0018-counting-what-is-asked-of-outside-services/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0018-counting-what-is-asked-of-outside-services/</guid><description>&lt;h1 id="chg-0018-counting-what-is-asked-of-outside-services"&gt;CHG-0018: Counting What Is Asked of Outside Services&lt;a class="anchor" href="#chg-0018-counting-what-is-asked-of-outside-services"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-12&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Upgrade&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-in-progress"&gt;In progress&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;npagent&lt;/code&gt; and its recognizer on the agent Pi (&lt;code&gt;np-relay&lt;/code&gt;); &lt;code&gt;nowplayd&lt;/code&gt; on the workload; the tenant&amp;rsquo;s Terraform (one dashboard added)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make plan apply&lt;/code&gt; in &lt;code&gt;infra/deevnet-tenant-eds&lt;/code&gt;; &lt;code&gt;make -C deploy/relay push&lt;/code&gt;; &lt;code&gt;make -C deploy deploy WHERE=builder&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Nothing that lights the room changes. Most likely to go wrong: the log store refuses &lt;code&gt;nowplayd&lt;/code&gt;, and its counts stay in the journal&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0027-what-is-asked-of-outside-services-is-counted/"&gt;ADR-0027&lt;/a&gt;, which this is the evidence for&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0017-the-gap-between-tracks-and-a-silent-turntable/"&gt;CHG-0017&lt;/a&gt;, which is on the Pi and the workload from a branch of its own and is not in this one: see the procedure&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;&lt;code&gt;npagent&lt;/code&gt; and &lt;code&gt;nowplayd&lt;/code&gt; count what they ask of services that are not&#10;EdS&amp;rsquo;s, and say so once a minute. The agent&amp;rsquo;s counts arrive as events.&#10;&lt;code&gt;nowplayd&lt;/code&gt; writes its own to the tenant&amp;rsquo;s log store, which no EdS workload&#10;has done before. A dashboard, &lt;strong&gt;Outside Services&lt;/strong&gt;, shows both.&lt;/p&gt;</description></item><item><title>ADR-0019: An Album Can Have a Look of Its Own</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0019-an-album-can-have-a-look-of-its-own/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0019-an-album-can-have-a-look-of-its-own/</guid><description>&lt;h1 id="adr-0019-an-album-can-have-a-look-of-its-own-named-on-the-music-side-and-drawn-on-the-light-side"&gt;ADR-0019: An Album Can Have a Look of Its Own, Named on the Music Side and Drawn on the Light Side&lt;a class="anchor" href="#adr-0019-an-album-can-have-a-look-of-its-own-named-on-the-music-side-and-drawn-on-the-light-side"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10; — until the first one has been seen on the stand&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;How one particular album gets a scene that is not derived from its cover, without the part that makes scenes learning what an album is.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0009-lightd-takes-covers-from-a-topic/"&gt;ADR-0009&lt;/a&gt;, which gave &lt;code&gt;lightd&lt;/code&gt; covers and kept tracks and albums on the other side of the topic&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extended by&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0028-the-stand-is-for-records/"&gt;ADR-0028&lt;/a&gt;: a look can name no cover, and is then the look of there being none. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0030-a-piece-of-music-can-have-a-look-from-any-source/"&gt;ADR-0030&lt;/a&gt;: a single piece of music can have one too, by its title&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0008-nowplayd-arbitrates-and-enriches/"&gt;ADR-0008&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0001-device-renders-effects/"&gt;ADR-0001&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Every scene so far is made the same way: the cover&amp;rsquo;s colors, picked by&#10;&lt;code&gt;palette&lt;/code&gt;, turned into a scene by &lt;code&gt;lightd&lt;/code&gt;. That is right for almost every&#10;record and wrong for a few. &lt;em&gt;The Dark Side of the Moon&lt;/em&gt; is a black sleeve with&#10;a thin spectrum across it. The colors a fair extraction finds on it are not&#10;what anyone would light a room with for that album, and what they would light&#10;it with is obvious: the spectrum.&lt;/p&gt;</description></item><item><title>CHG-0019: The Stand Is for Records</title><link>https://cdeever.github.io/eds/docs/changes/2026/0019-the-stand-is-for-records/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0019-the-stand-is-for-records/</guid><description>&lt;h1 id="chg-0019-the-stand-is-for-records"&gt;CHG-0019: The Stand Is for Records&lt;a class="anchor" href="#chg-0019-the-stand-is-for-records"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-13&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Upgrade&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-in-progress"&gt;In progress&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;nowplayd&lt;/code&gt; and &lt;code&gt;lightd&lt;/code&gt; on the workload&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make -C deploy deploy WHERE=builder&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: a stand that is dark when someone expects it lit, and is taken for dead&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0028-the-stand-is-for-records/"&gt;ADR-0028&lt;/a&gt;, which this is the evidence for&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0016-idle-the-screen-on-the-console-and-no-buttons-for-a-record/"&gt;CHG-0016&lt;/a&gt;, which gave the stand its idle scene; &lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0015-the-turntables-power-beacon/"&gt;CHG-0015&lt;/a&gt;, whose beacon now decides between dim and dark&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The stand was lit all day: dim whenever nothing played, and from iTunes'&#10;cover whenever iTunes did. It is an LP stand, and from this change it is lit&#10;by records only.&lt;/p&gt;</description></item><item><title>ADR-0020: A Touch Screen That Can Change What Plays</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0020-a-touch-screen-that-can-change-what-plays/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0020-a-touch-screen-that-can-change-what-plays/</guid><description>&lt;h1 id="adr-0020-a-touch-screen-shows-the-cover-and-can-change-what-plays-by-asking-nowplayd"&gt;ADR-0020: A Touch Screen Shows the Cover and Can Change What Plays, by Asking nowplayd&lt;a class="anchor" href="#adr-0020-a-touch-screen-shows-the-cover-and-can-change-what-plays-by-asking-nowplayd"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10; — until a button on the screen has paused the real iTunes; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;A second device, a small touch screen, that shows the cover of what is playing and has five buttons: play or pause, previous, next, volume up, volume down. This is the first thing in EdS that changes anything outside itself.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0006-now-playing-bus-of-drivers/"&gt;ADR-0006&lt;/a&gt;, in which a driver reports and reads nothing, and &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0011-itunes-by-remote-pairing/"&gt;ADR-0011&lt;/a&gt;, which paired with iTunes as a remote and used the pairing only to read&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extended by&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0032-spotify-takes-commands/"&gt;ADR-0032&lt;/a&gt;: Spotify&amp;rsquo;s driver carries the commands out too; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0040-a-request-can-name-an-album-to-play/"&gt;ADR-0040&lt;/a&gt;: a sixth command names an album, and goes to iTunes whatever plays&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0008-nowplayd-arbitrates-and-enriches/"&gt;ADR-0008&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0010-home-lan-relay/"&gt;ADR-0010&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0016-a-source-can-be-reported-without-its-cover/"&gt;ADR-0016&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0018-a-console-of-eds-own/"&gt;ADR-0018&lt;/a&gt;, which said controls would be a decision of their own&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The stand shows a record&amp;rsquo;s colors. A screen beside it can show the cover&#10;itself, and a screen that can be touched is the obvious place for the few&#10;controls a listener reaches for.&lt;/p&gt;</description></item><item><title>CHG-0020: The Stand Starts Dark, Blinks, Opens and Scans</title><link>https://cdeever.github.io/eds/docs/changes/2026/0020-the-stand-starts-dark-blinks-opens-and-scans/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0020-the-stand-starts-dark-blinks-opens-and-scans/</guid><description>&lt;h1 id="chg-0020-the-stand-starts-dark-blinks-opens-and-scans"&gt;CHG-0020: The Stand Starts Dark, Blinks, Opens and Scans&lt;a class="anchor" href="#chg-0020-the-stand-starts-dark-blinks-opens-and-scans"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-13&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Upgrade&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-in-progress"&gt;In progress&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The LP stand (&lt;code&gt;lp-stand-01&lt;/code&gt;), flashed; &lt;code&gt;nowplayd&lt;/code&gt;, &lt;code&gt;lightd&lt;/code&gt; and the console on the workload&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make build flash&lt;/code&gt; in &lt;code&gt;firmware/lp-stand&lt;/code&gt;; &lt;code&gt;make -C deploy ship WHERE=builder&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: a stand flashed with something that does not start, which is put right by flashing the build before it; or an opening that is too much for a living room&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0029-the-stand-starts-dark-and-blinks-what-is-wrong/"&gt;ADR-0029&lt;/a&gt; and &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0030-a-piece-of-music-can-have-a-look-from-any-source/"&gt;ADR-0030&lt;/a&gt;, which this is the evidence for&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0019-the-stand-is-for-records/"&gt;CHG-0019&lt;/a&gt;, which made the room dark and left the stand&amp;rsquo;s own start dim&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Three things asked for in one afternoon, and one flash.&lt;/p&gt;</description></item><item><title>ADR-0021: The Turntable Is Identified by Listening</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0021-the-turntable-is-identified-by-listening/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0021-the-turntable-is-identified-by-listening/</guid><description>&lt;h1 id="adr-0021-the-turntable-is-identified-by-listening-with-a-recognizer-that-can-be-replaced"&gt;ADR-0021: The Turntable Is Identified by Listening, With a Recognizer That Can Be Replaced&lt;a class="anchor" href="#adr-0021-the-turntable-is-identified-by-listening-with-a-recognizer-that-can-be-replaced"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10; — until a record on the platter has lit the stand; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;A third driver in &lt;code&gt;npagent&lt;/code&gt;, &lt;code&gt;turntable&lt;/code&gt;: it listens to the amplifier&amp;rsquo;s line-level output on the agent Pi, has a recognizer name what it hears, and reports that as a source on the now-playing bus.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0006-now-playing-bus-of-drivers/"&gt;ADR-0006&lt;/a&gt;, which said a turntable that identifies its record would be one more driver, and &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0007-drivers-are-portable-go/"&gt;ADR-0007&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0008-nowplayd-arbitrates-and-enriches/"&gt;ADR-0008&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0012-spotify-by-web-api/"&gt;ADR-0012&lt;/a&gt; and &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0014-tidal-by-lastfm/"&gt;ADR-0014&lt;/a&gt;, which each declined an unpublished interface; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0015-eds-builds-its-own-pi-images/"&gt;ADR-0015&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0017-an-agent-pi-is-a-registered-device/"&gt;ADR-0017&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The stand was built to stand beside a record that is playing. So far it&#10;follows iTunes, because iTunes can be asked what it is playing and a turntable&#10;cannot.&lt;/p&gt;</description></item><item><title>CHG-0021: A New Sound Card for the Turntable</title><link>https://cdeever.github.io/eds/docs/changes/2026/0021-a-new-sound-card-for-the-turntable/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0021-a-new-sound-card-for-the-turntable/</guid><description>&lt;h1 id="chg-0021-a-new-sound-card-for-the-turntable"&gt;CHG-0021: A New Sound Card for the Turntable&lt;a class="anchor" href="#chg-0021-a-new-sound-card-for-the-turntable"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-13&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Configuration&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-complete"&gt;Complete&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;npagent&lt;/code&gt; on the agent Pi (&lt;code&gt;np-relay&lt;/code&gt;)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make -C deploy/relay turntable DEVICE=plughw:CODEC&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. One line of the agent&amp;rsquo;s settings, and a restart of the agent&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0021-the-turntable-is-identified-by-listening/"&gt;ADR-0021&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0013-the-turntable-driver/"&gt;CHG-0013&lt;/a&gt;, which named the first input; &lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0019-the-stand-is-for-records/"&gt;CHG-0019&lt;/a&gt;, since which only a record lights the stand&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The sound card the turntable is heard through was replaced with another USB&#10;adapter. The agent was still told to listen to the old one by name,&#10;&lt;code&gt;plughw:UA4FX&lt;/code&gt;, which was no longer there, so the turntable&amp;rsquo;s driver heard&#10;nothing and reported nothing. With the stand lit for records only, that was&#10;a stand that did nothing for a record.&lt;/p&gt;</description></item><item><title>ADR-0022: The Owner's Collection Names the Record</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0022-the-owners-collection-names-the-record/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0022-the-owners-collection-names-the-record/</guid><description>&lt;h1 id="adr-0022-for-a-source-that-plays-the-owners-records-the-owners-collection-names-the-record"&gt;ADR-0022: For a Source That Plays the Owner&amp;rsquo;s Records, the Owner&amp;rsquo;s Collection Names the Record&lt;a class="anchor" href="#adr-0022-for-a-source-that-plays-the-owners-records-the-owners-collection-names-the-record"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10; — until a record on the platter has been shown with its own sleeve; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-12&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;How nowplayd completes a track from a source that plays physical records: it asks the owner&amp;rsquo;s collection at Discogs before any catalog, and the collection&amp;rsquo;s answer replaces the album the source named.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0008-nowplayd-arbitrates-and-enriches/"&gt;ADR-0008&lt;/a&gt;, in which a known album is never renamed. For the sources named here, it is.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0021-the-turntable-is-identified-by-listening/"&gt;ADR-0021&lt;/a&gt;, which left this open; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0016-a-source-can-be-reported-without-its-cover/"&gt;ADR-0016&lt;/a&gt;, the other setting that treats named sources differently&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The turntable driver names a track by what it sounds like. A recording is&#10;pressed on many records - the album, its reissues, compilations, box sets -&#10;and nothing in the sound says which. The recognizer names an album anyway.&#10;On the bench it called one track of &lt;em&gt;Chicago Transit Authority&lt;/em&gt; a box set,&#10;and a track of &lt;em&gt;No Jacket Required&lt;/em&gt; a singles collection.&lt;/p&gt;</description></item><item><title>CHG-0022: Spotify Shown, and On Again</title><link>https://cdeever.github.io/eds/docs/changes/2026/0022-spotify-shown-and-on-again/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0022-spotify-shown-and-on-again/</guid><description>&lt;h1 id="chg-0022-spotify-shown-and-on-again"&gt;CHG-0022: Spotify Shown, and On Again&lt;a class="anchor" href="#chg-0022-spotify-shown-and-on-again"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-13&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Upgrade&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-in-progress"&gt;In progress&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;npagent&lt;/code&gt; on the agent Pi (&lt;code&gt;np-relay&lt;/code&gt;); &lt;code&gt;nowplayd&lt;/code&gt; on the workload&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make -C deploy/relay push&lt;/code&gt;; &lt;code&gt;make -C deploy/relay drivers DRIVERS=itunes,spotify,turntable&lt;/code&gt;; &lt;code&gt;make -C deploy units&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: the Spotify authorization given on 2026-10-11 no longer stands, and the driver stops and says so; or the agent does not come back after the push&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0031-spotify-is-shown-like-itunes/"&gt;ADR-0031&lt;/a&gt;, which this is the evidence for&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0011-spotify-turned-off/"&gt;CHG-0011&lt;/a&gt;, which this undoes; &lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0004-spotify-on-the-agent-pi/"&gt;CHG-0004&lt;/a&gt;; &lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0020-the-stand-starts-dark-blinks-opens-and-scans/"&gt;CHG-0020&lt;/a&gt;, whose scanner is what was missed from Spotify&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Spotify was reported with no cover, and its driver was off. The driver now&#10;takes the album&amp;rsquo;s picture, Spotify is kept off the stand the way iTunes is,&#10;and the driver is on again.&lt;/p&gt;</description></item><item><title>ADR-0023: A Source That Is Switched On Holds the Stand</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0023-a-source-that-is-switched-on-holds-the-stand/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0023-a-source-that-is-switched-on-holds-the-stand/</guid><description>&lt;h1 id="adr-0023-a-sources-equipment-can-say-it-is-on-and-a-source-that-is-on-holds-the-stand"&gt;ADR-0023: A Source&amp;rsquo;s Equipment Can Say It Is On, and a Source That Is On Holds the Stand&lt;a class="anchor" href="#adr-0023-a-sources-equipment-can-say-it-is-on-and-a-source-that-is-on-holds-the-stand"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10; — until the beacon has been timed on the switch it shares and a record has been held through its silences; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-12&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;How EdS knows the turntable is switched on: a small device on the same switched outlet, whose connection to the broker is the whole of what it says. And what nowplayd does knowing it.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0008-nowplayd-arbitrates-and-enriches/"&gt;ADR-0008&lt;/a&gt;, whose rule now has one thing before it. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0018-a-console-of-eds-own/"&gt;ADR-0018&lt;/a&gt;: the console reads one more topic, and still only looks.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0021-the-turntable-is-identified-by-listening/"&gt;ADR-0021&lt;/a&gt;, whose driver this is for and whose account of the wiring this corrects; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0016-a-source-can-be-reported-without-its-cover/"&gt;ADR-0016&lt;/a&gt; and &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0022-the-owners-collection-names-the-record/"&gt;ADR-0022&lt;/a&gt;, the other settings that treat named sources differently&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The turntable driver (&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0021-the-turntable-is-identified-by-listening/"&gt;ADR-0021&lt;/a&gt;)&#10;reports what it hears, and three things it cannot hear are in the way.&lt;/p&gt;</description></item><item><title>CHG-0023: Spotify Takes Commands</title><link>https://cdeever.github.io/eds/docs/changes/2026/0023-spotify-takes-commands/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0023-spotify-takes-commands/</guid><description>&lt;h1 id="chg-0023-spotify-takes-commands"&gt;CHG-0023: Spotify Takes Commands&lt;a class="anchor" href="#chg-0023-spotify-takes-commands"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-13&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Upgrade&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-in-progress"&gt;In progress&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;npagent&lt;/code&gt; on the agent Pi (&lt;code&gt;np-relay&lt;/code&gt;); the agent&amp;rsquo;s broker account, in the tenant; the Spotify authorization&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make -C deploy/relay push&lt;/code&gt;; &lt;code&gt;make apply&lt;/code&gt; in &lt;code&gt;infra/deevnet-tenant-eds&lt;/code&gt;; &lt;code&gt;make -C deploy/relay spotify AGAIN=1&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: the authorization is given again and something about it fails, leaving Spotify unreported until it is done once more&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0032-spotify-takes-commands/"&gt;ADR-0032&lt;/a&gt;, which this is the evidence for&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0022-spotify-shown-and-on-again/"&gt;CHG-0022&lt;/a&gt;, which put Spotify on the cover screen; &lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0012-the-cover-screen/"&gt;CHG-0012&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The cover screen&amp;rsquo;s buttons did nothing while Spotify was current. The&#10;Spotify driver now carries out play or pause, next, previous and volume&#10;through Spotify&amp;rsquo;s Web API. Three things have to change for a press to&#10;arrive: the agent, the broker account that lets it hear the command, and&#10;what Spotify has authorized it to do.&lt;/p&gt;</description></item><item><title>ADR-0024: Paused Long Enough Is Not Playing</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0024-paused-long-enough-is-not-playing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0024-paused-long-enough-is-not-playing/</guid><description>&lt;h1 id="adr-0024-a-track-left-paused-is-not-playing-for-ever-and-a-room-with-nothing-playing-is-dim"&gt;ADR-0024: A Track Left Paused Is Not Playing for Ever, and a Room With Nothing Playing Is Dim&lt;a class="anchor" href="#adr-0024-a-track-left-paused-is-not-playing-for-ever-and-a-room-with-nothing-playing-is-dim"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10; — until it has been seen in the room; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-12&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;What nowplayd says when the current track has sat paused, or nobody is reporting; how that reaches the stand; what the stand shows then.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0008-nowplayd-arbitrates-and-enriches/"&gt;ADR-0008&lt;/a&gt;, which left &amp;ldquo;what a subscriber does with stopped&amp;rdquo; to the subscriber and &amp;ldquo;paused on B is more use than silence&amp;rdquo; without an end. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0009-lightd-takes-covers-from-a-topic/"&gt;ADR-0009&lt;/a&gt;: an emptied cover topic now means something to lightd.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extended by&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0028-the-stand-is-for-records/"&gt;ADR-0028&lt;/a&gt;: the idle scene is for a room where something is switched on; with nothing switched on, a room with nothing playing is dark&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0016-a-source-can-be-reported-without-its-cover/"&gt;ADR-0016&lt;/a&gt;, whose &amp;ldquo;no cover sent&amp;rdquo; this must not be mistaken for; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0023-a-source-that-is-switched-on-holds-the-stand/"&gt;ADR-0023&lt;/a&gt;, whose held source is left alone; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0020-a-touch-screen-that-can-change-what-plays/"&gt;ADR-0020&lt;/a&gt;, whose play button must go on working&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Pause iTunes and walk away, and the stand goes on showing the album for as&#10;long as nothing else plays: hours, overnight. The console says &amp;ldquo;Paused on&#10;iTunes&amp;rdquo; over the same sleeve. Neither is false, and neither is what the room&#10;is doing, which is nothing.&lt;/p&gt;</description></item><item><title>CHG-0024: Spotify Turned Off Again</title><link>https://cdeever.github.io/eds/docs/changes/2026/0024-spotify-turned-off-again/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0024-spotify-turned-off-again/</guid><description>&lt;h1 id="chg-0024-spotify-turned-off-again"&gt;CHG-0024: Spotify Turned Off Again&lt;a class="anchor" href="#chg-0024-spotify-turned-off-again"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-16&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Configuration&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-complete"&gt;Complete&lt;/span&gt;&#10; 2026-10-16&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;the agent Pi: one line of its settings, and its agent restarted&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make -C deploy/relay drivers DRIVERS=itunes,turntable&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: the agent not coming back, which would stop iTunes and the turntable being followed too&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0031-spotify-is-shown-like-itunes/"&gt;ADR-0031&lt;/a&gt; and &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0032-spotify-takes-commands/"&gt;ADR-0032&lt;/a&gt;, unchanged&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0022-spotify-shown-and-on-again/"&gt;CHG-0022&lt;/a&gt;, which turned it on; &lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0011-spotify-turned-off/"&gt;CHG-0011&lt;/a&gt;, the same change once before&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The Spotify driver was asking Spotify what is playing six times a minute,&#10;all day, as the &lt;strong&gt;Outside Services&lt;/strong&gt; count showed. Its owner does not want&#10;that for now and will come back to it. The agent Pi now runs the iTunes and&#10;turntable drivers only. Nothing is removed: the driver, its authorization on&#10;the Pi, the broker grants and the app at Spotify all stay, and one command&#10;turns it back on.&lt;/p&gt;</description></item><item><title>ADR-0025: Current Says When There Are No Controls</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0025-current-says-when-there-are-no-controls/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0025-current-says-when-there-are-no-controls/</guid><description>&lt;h1 id="adr-0025-the-current-track-says-when-there-is-nothing-a-controller-could-do"&gt;ADR-0025: The Current Track Says When There Is Nothing a Controller Could Do&lt;a class="anchor" href="#adr-0025-the-current-track-says-when-there-is-nothing-a-controller-could-do"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10; — until the screen has been touched with a record playing; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-12&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;One optional field in &lt;code&gt;current&lt;/code&gt;, said by nowplayd, and what the cover screen does with it.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0020-a-touch-screen-that-can-change-what-plays/"&gt;ADR-0020&lt;/a&gt;, which noted that &amp;ldquo;a source that takes commands does not say so anywhere&amp;rdquo;. Now the current one does.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0023-a-source-that-is-switched-on-holds-the-stand/"&gt;ADR-0023&lt;/a&gt;, which made the turntable current for as long as it is on, and so made the screen&amp;rsquo;s buttons idle for as long&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Touch the cover screen and five buttons come up. With a record on the&#10;turntable every one of them does nothing: a command goes to the source that&#10;is current, and nothing can skip a record. Since&#10;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0023-a-source-that-is-switched-on-holds-the-stand/"&gt;ADR-0023&lt;/a&gt;&#10;the turntable is current the whole time it is switched on, so that is the&#10;whole evening. The sleeve is what the screen is for then, and buttons over it&#10;are wrong twice: they hide it, and they lie.&lt;/p&gt;</description></item><item><title>CHG-0025: Presence Repeated, and Updates Through the Broker</title><link>https://cdeever.github.io/eds/docs/changes/2026/0025-presence-repeated-and-updates-through-the-broker/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0025-presence-repeated-and-updates-through-the-broker/</guid><description>&lt;h1 id="chg-0025-presence-repeated-and-updates-through-the-broker"&gt;CHG-0025: Presence Repeated, and Updates Through the Broker&lt;a class="anchor" href="#chg-0025-presence-repeated-and-updates-through-the-broker"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-16 (planned)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Upgrade&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-complete"&gt;Complete&lt;/span&gt;&#10; 2026-10-17&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The tenant&amp;rsquo;s broker accounts; &lt;code&gt;cover-screen-01&lt;/code&gt;, &lt;code&gt;turntable-power-01&lt;/code&gt; and &lt;code&gt;lp-stand-01&lt;/code&gt;, by cable; lightd, nowplayd and the console on the services workload; &lt;code&gt;npagent&lt;/code&gt; on the agent Pi&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make plan apply&lt;/code&gt; in &lt;code&gt;infra/deevnet-tenant-eds&lt;/code&gt;; &lt;code&gt;make build flash&lt;/code&gt; in each firmware; &lt;code&gt;make -C deploy deploy WHERE=builder&lt;/code&gt;; &lt;code&gt;make -C deploy/relay push&lt;/code&gt;; &lt;code&gt;make ota&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Medium. Most likely to go wrong: the plan replacing a device&amp;rsquo;s broker account instead of changing it, which issues a new password and strands that device until it is reprovisioned&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0034-presence-is-heard-not-remembered/"&gt;ADR-0034&lt;/a&gt; and &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0035-firmware-is-updated-through-the-broker/"&gt;ADR-0035&lt;/a&gt;, which this is the evidence for&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0024-spotify-turned-off-again/"&gt;CHG-0024&lt;/a&gt;, the day&amp;rsquo;s other change&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Two decisions go out together, because the firmware for both goes on by the&#10;same cable.&lt;/p&gt;</description></item><item><title>ADR-0026: What Silence Means on the Turntable</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0026-what-silence-means-on-the-turntable/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0026-what-silence-means-on-the-turntable/</guid><description>&lt;h1 id="adr-0026-a-gap-between-tracks-is-listened-for-and-a-silent-turntable-is-idle-in-twenty-seconds"&gt;ADR-0026: A Gap Between Tracks Is Listened For, and a Silent Turntable Is Idle in Twenty Seconds&lt;a class="anchor" href="#adr-0026-a-gap-between-tracks-is-listened-for-and-a-silent-turntable-is-idle-in-twenty-seconds"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10; — until a side has been played to it; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-12&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;What the turntable driver does with a short silence, and how long nowplayd keeps the cover of a source that is stopped and held.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0021-the-turntable-is-identified-by-listening/"&gt;ADR-0021&lt;/a&gt;, whose &amp;ldquo;no single answer after that&amp;rdquo; now has one exception, and &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0024-paused-long-enough-is-not-playing/"&gt;ADR-0024&lt;/a&gt;, whose five minutes for a stopped, held source is taken back&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0023-a-source-that-is-switched-on-holds-the-stand/"&gt;ADR-0023&lt;/a&gt;, which is why a stopped turntable is still current; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0022-the-owners-collection-names-the-record/"&gt;ADR-0022&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Two things were seen with records playing, on the day the driver went into&#10;service.&lt;/p&gt;</description></item><item><title>CHG-0026: The Cover Screen Sleeps</title><link>https://cdeever.github.io/eds/docs/changes/2026/0026-the-cover-screen-sleeps/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0026-the-cover-screen-sleeps/</guid><description>&lt;h1 id="chg-0026-the-cover-screen-sleeps"&gt;CHG-0026: The Cover Screen Sleeps&lt;a class="anchor" href="#chg-0026-the-cover-screen-sleeps"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-17&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Upgrade&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-complete"&gt;Complete&lt;/span&gt;&#10; 2026-10-17&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;cover-screen-01&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make build ota&lt;/code&gt; in &lt;code&gt;firmware/cover-screen&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: the screen sleeping when someone is there, because a source that should count does not name itself in &lt;code&gt;current&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0036-the-screen-sleeps-when-nothing-plays/"&gt;ADR-0036&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0025-presence-repeated-and-updates-through-the-broker/"&gt;CHG-0025&lt;/a&gt;, which made updates over the air possible&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The cover screen is lit all the time, showing a drawn record to nobody when&#10;nothing plays. After this, it goes dark five minutes after &lt;code&gt;current&lt;/code&gt; last&#10;said something was playing, and lights again for music, a touch, or a lost&#10;broker.&lt;/p&gt;</description></item><item><title>ADR-0027: What Is Asked of Outside Services Is Counted</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0027-what-is-asked-of-outside-services-is-counted/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0027-what-is-asked-of-outside-services-is-counted/</guid><description>&lt;h1 id="adr-0027-what-eds-asks-of-other-peoples-services-is-counted-a-minute-at-a-time-and-nowplayd-writes-its-counts-to-the-log-store-itself"&gt;ADR-0027: What EdS Asks of Other People&amp;rsquo;s Services Is Counted, a Minute at a Time, and nowplayd Writes Its Counts to the Log Store Itself&lt;a class="anchor" href="#adr-0027-what-eds-asks-of-other-peoples-services-is-counted-a-minute-at-a-time-and-nowplayd-writes-its-counts-to-the-log-store-itself"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10; — until the counts have been seen on the dashboard; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-12&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Counting the calls &lt;code&gt;npagent&lt;/code&gt; and &lt;code&gt;nowplayd&lt;/code&gt; make to services that are not EdS&amp;rsquo;s; how those counts reach the tenant&amp;rsquo;s log store from each; the dashboard that reads them.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0005-device-events-over-mqtt/"&gt;ADR-0005&lt;/a&gt; and &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0017-an-agent-pi-is-a-registered-device/"&gt;ADR-0017&lt;/a&gt;: the agent&amp;rsquo;s counts are one more event. A workload gets a route of its own, which neither gave it.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0021-the-turntable-is-identified-by-listening/"&gt;ADR-0021&lt;/a&gt;, whose recognizer is the service least entitled to be leaned on; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0022-the-owners-collection-names-the-record/"&gt;ADR-0022&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0012-spotify-by-web-api/"&gt;ADR-0012&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0008-nowplayd-arbitrates-and-enriches/"&gt;ADR-0008&lt;/a&gt;; Deevnet ADR-0027 (the tenant log store) and Deevnet ADR-0024 (dashboards)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;EdS asks things of services that are not its own. The turntable&amp;rsquo;s recognizer&#10;is Shazam&amp;rsquo;s, through an endpoint nobody offered. The owner&amp;rsquo;s collection is&#10;read from Discogs. Spotify&amp;rsquo;s Web API is polled. Covers are looked up at&#10;Deezer, the iTunes Search API, MusicBrainz and the Cover Art Archive.&lt;/p&gt;</description></item><item><title>CHG-0027: The Beacon on an ESP32</title><link>https://cdeever.github.io/eds/docs/changes/2026/0027-the-beacon-on-an-esp32/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0027-the-beacon-on-an-esp32/</guid><description>&lt;h1 id="chg-0027-the-beacon-on-an-esp32"&gt;CHG-0027: The Beacon on an ESP32&lt;a class="anchor" href="#chg-0027-the-beacon-on-an-esp32"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-18&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Upgrade&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-complete"&gt;Complete&lt;/span&gt;&#10; 2026-10-18&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;turntable-power-01&lt;/code&gt;: a new board, a plain ESP32, in place of the ESP32-S2&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make build flash provision&lt;/code&gt; in &lt;code&gt;firmware/power-beacon&lt;/code&gt;, by cable&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: the old S2 powered at the same time as the new board. Both log in as &lt;code&gt;turntable-power-01&lt;/code&gt;, the broker takes the account from one for the other, and each time says &lt;code&gt;offline&lt;/code&gt; for the turntable&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0023-a-source-that-is-switched-on-holds-the-stand/"&gt;ADR-0023&lt;/a&gt;, unchanged: any ESP32 with WiFi and 4 MB will do&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0015-the-turntables-power-beacon/"&gt;CHG-0015&lt;/a&gt;, the first beacon; &lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0025-presence-repeated-and-updates-through-the-broker/"&gt;CHG-0025&lt;/a&gt;, where the S2 needed an external antenna to join from the turntable&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The beacon moves from an ESP32-S2 to a plain ESP32 that fits the case its&#10;owner bought. The case has no opening for an external antenna, and the S2&#10;could not join from the turntable without one. The new board&amp;rsquo;s antenna is&#10;on the board.&lt;/p&gt;</description></item><item><title>ADR-0028: The Stand Is for Records</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0028-the-stand-is-for-records/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0028-the-stand-is-for-records/</guid><description>&lt;h1 id="adr-0028-the-stand-is-lit-for-records-only-and-is-dim-only-while-the-turntable-is-on"&gt;ADR-0028: The Stand Is Lit for Records Only, and Is Dim Only While the Turntable Is On&lt;a class="anchor" href="#adr-0028-the-stand-is-lit-for-records-only-and-is-dim-only-while-the-turntable-is-on"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10; — until it has been seen in the room; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-13&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Which sources light the stand; what it shows when nothing is playing; and how lightd is told, without learning what a source is.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0024-paused-long-enough-is-not-playing/"&gt;ADR-0024&lt;/a&gt;, whose idle scene is now for one case of two, and whose &amp;ldquo;it is not dark&amp;rdquo; no longer holds for the other. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0019-an-album-can-have-a-look-of-its-own/"&gt;ADR-0019&lt;/a&gt;: a look can be named for there being no cover, and a look can be &amp;ldquo;light nothing&amp;rdquo;. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0016-a-source-can-be-reported-without-its-cover/"&gt;ADR-0016&lt;/a&gt;: a second way for a source to be reported and not lit, which keeps its cover. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0023-a-source-that-is-switched-on-holds-the-stand/"&gt;ADR-0023&lt;/a&gt;: the switch says one thing more.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extended by&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0029-the-stand-starts-dark-and-blinks-what-is-wrong/"&gt;ADR-0029&lt;/a&gt;: the stand is dark from power on too, and blinks when it cannot reach the broker. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0030-a-piece-of-music-can-have-a-look-from-any-source/"&gt;ADR-0030&lt;/a&gt;: one look is shown from a dark source too. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0039-the-console-can-light-the-stand-for-every-source/"&gt;ADR-0039&lt;/a&gt;: records-only is the default, and the console can switch the stand to every source&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0009-lightd-takes-covers-from-a-topic/"&gt;ADR-0009&lt;/a&gt;, whose boundary this keeps; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0026-what-silence-means-on-the-turntable/"&gt;ADR-0026&lt;/a&gt;, whose dimmed room between two sides is the case that stays dim&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0024-paused-long-enough-is-not-playing/"&gt;ADR-0024&lt;/a&gt;&#10;gave a room with nothing playing a scene of its own: steady, warm, at 0.15.&#10;It chose that over dark because &amp;ldquo;a dark stand cannot be told from a dead&#10;one&amp;rdquo;.&lt;/p&gt;</description></item><item><title>CHG-0028: The Back End on One Pi, Tried on DVNTM</title><link>https://cdeever.github.io/eds/docs/changes/2026/0028-the-back-end-on-one-pi-on-dvntm/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0028-the-back-end-on-one-pi-on-dvntm/</guid><description>&lt;h1 id="chg-0028-the-back-end-on-one-pi-tried-on-dvntm"&gt;CHG-0028: The Back End on One Pi, Tried on DVNTM&lt;a class="anchor" href="#chg-0028-the-back-end-on-one-pi-tried-on-dvntm"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-18&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Deployment&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-in-progress"&gt;In progress&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;dv02rpi003p01&lt;/code&gt; (a Pi 4, wired to DVNTM&amp;rsquo;s IoT segment on &lt;code&gt;Gi1/0/11&lt;/code&gt;, &lt;code&gt;10.20.30.13&lt;/code&gt;, and on DVNT-CORE by Wi-Fi), with a new card. Nothing of the tenant&amp;rsquo;s, the workload&amp;rsquo;s, the relay Pi&amp;rsquo;s or the devices'&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make -C deploy/backend image fetch&lt;/code&gt;; the card flashed by its owner; &lt;code&gt;make card&lt;/code&gt;; first boot; &lt;code&gt;make status&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: the card&amp;rsquo;s first boot not finishing (&lt;code&gt;deevnet-kit&lt;/code&gt; or &lt;code&gt;eds-backend-setup&lt;/code&gt;), which leaves a Pi to reflash and nothing else touched&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0033-the-whole-back-end-on-one-pi/"&gt;ADR-0033&lt;/a&gt;, whose evidence this is&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Deevnet CHG-0048, which gave &lt;code&gt;dv02rpi003p01&lt;/code&gt; its switch port; Deevnet CHG-0049, which rebuilt the take-home image this is built on&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The whole of EdS on one Pi, beside the tenant: its own broker, log store,&#10;Grafana, the four services and the agent. It is tried on the kit&amp;rsquo;s network&#10;first, where the devices are, and goes to the home network only once it&#10;works.&lt;/p&gt;</description></item><item><title>ADR-0029: The Stand Starts Dark, and Blinks What Is Wrong</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0029-the-stand-starts-dark-and-blinks-what-is-wrong/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0029-the-stand-starts-dark-and-blinks-what-is-wrong/</guid><description>&lt;h1 id="adr-0029-the-stand-starts-dark-and-says-in-red-blinks-how-far-it-got"&gt;ADR-0029: The Stand Starts Dark, and Says in Red Blinks How Far It Got&lt;a class="anchor" href="#adr-0029-the-stand-starts-dark-and-says-in-red-blinks-how-far-it-got"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10; — until each blink has been seen on the stand; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-13&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;What the stand&amp;rsquo;s strip shows from power on until it is sent a scene; what it shows when it cannot get that far; and how it comes on and goes off.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0028-the-stand-is-for-records/"&gt;ADR-0028&lt;/a&gt;, which made a room with nothing playing dark and left the stand&amp;rsquo;s own first seconds dim. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0001-device-renders-effects/"&gt;ADR-0001&lt;/a&gt;: the stand now draws one thing nobody sent it.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0005-device-events-over-mqtt/"&gt;ADR-0005&lt;/a&gt;, the stand&amp;rsquo;s other way of saying what happened, which needs the broker this is for the lack of; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0004-firmware-secrets-nvs-only/"&gt;ADR-0004&lt;/a&gt;, whose unprovisioned stand gets a blink of its own&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The firmware has always lit the strip the moment it had power: a dim warm&#10;white, &amp;ldquo;so an unconfigured or unreachable stand looks deliberate rather than&#10;broken&amp;rdquo;. Since&#10;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0028-the-stand-is-for-records/"&gt;ADR-0028&lt;/a&gt; the&#10;stand is dark unless a record is on or the turntable is switched on. The&#10;warm white at power on is then the one time the stand is lit with nobody&#10;having asked: for a few seconds on every start, and for as long as the&#10;network is away.&lt;/p&gt;</description></item><item><title>CHG-0029: The Turntable's Album by What Is on It</title><link>https://cdeever.github.io/eds/docs/changes/2026/0029-the-turntables-album-by-what-is-on-it/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0029-the-turntables-album-by-what-is-on-it/</guid><description>&lt;h1 id="chg-0029-the-turntables-album-by-what-is-on-it"&gt;CHG-0029: The Turntable&amp;rsquo;s Album by What Is on It&lt;a class="anchor" href="#chg-0029-the-turntables-album-by-what-is-on-it"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-19&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Upgrade&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-in-progress"&gt;In progress&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The home backend Pi, &lt;code&gt;dv01rpi001p01&lt;/code&gt; (&lt;code&gt;192.168.2.40&lt;/code&gt;): nowplayd and npagent, with the other services restarted&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make -C deploy/backend push PI=192.168.2.40&lt;/code&gt; from &lt;code&gt;main&lt;/code&gt; at &lt;code&gt;44828a9&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: a lookup that names the wrong album for a record not in the collection; the stand is lit from the wrong sleeve until the next track&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0038-the-turntable-names-the-original-album-by-what-is-on-it/"&gt;ADR-0038&lt;/a&gt;, whose evidence this is&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0028-the-back-end-on-one-pi-on-dvntm/"&gt;CHG-0028&lt;/a&gt;, the Pi this goes to&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;On the first evening at home, &lt;em&gt;Animals&lt;/em&gt; put on a minute after &lt;em&gt;The Dark Side&#10;of the Moon&lt;/em&gt; kept &lt;em&gt;Dark Side&lt;/em&gt;&amp;rsquo;s rainbow: the driver held a side&amp;rsquo;s first&#10;album for ten minutes of silence. ADR-0038 names the album by what is on the&#10;record instead, and prefers the original album. This puts it on the Pi.&lt;/p&gt;</description></item><item><title>ADR-0030: A Piece of Music Can Have a Look, From Any Source</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0030-a-piece-of-music-can-have-a-look-from-any-source/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0030-a-piece-of-music-can-have-a-look-from-any-source/</guid><description>&lt;h1 id="adr-0030-one-piece-of-music-can-have-a-look-of-its-own-shown-whatever-plays-it-and-the-stand-learns-to-scan"&gt;ADR-0030: One Piece of Music Can Have a Look of Its Own, Shown Whatever Plays It, and the Stand Learns to Scan&lt;a class="anchor" href="#adr-0030-one-piece-of-music-can-have-a-look-of-its-own-shown-whatever-plays-it-and-the-stand-learns-to-scan"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10; — until it has been seen on the stand with the theme playing; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-13&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;A look for a single track, known by its title; the one exception to the stand being lit for records only; and a sixth effect in the firmware to draw it with.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0019-an-album-can-have-a-look-of-its-own/"&gt;ADR-0019&lt;/a&gt;, whose looks were albums&amp;rsquo;. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0028-the-stand-is-for-records/"&gt;ADR-0028&lt;/a&gt;, whose dark sources now have one thing that lights them. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0001-device-renders-effects/"&gt;ADR-0001&lt;/a&gt;: the stand has one more effect.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0029-the-stand-starts-dark-and-blinks-what-is-wrong/"&gt;ADR-0029&lt;/a&gt;, whose opening and closing are how this comes on and goes off in a dark room&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Its owner wants the stand to do what the front of KITT does while the theme&#10;from &lt;em&gt;Knight Rider&lt;/em&gt; is playing: one red light, going from side to side.&lt;/p&gt;</description></item><item><title>CHG-0030: The Console Switches the Stand</title><link>https://cdeever.github.io/eds/docs/changes/2026/0030-the-console-switches-the-stand/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0030-the-console-switches-the-stand/</guid><description>&lt;h1 id="chg-0030-the-console-switches-the-stand"&gt;CHG-0030: The Console Switches the Stand&lt;a class="anchor" href="#chg-0030-the-console-switches-the-stand"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-19&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Upgrade&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-in-progress"&gt;In progress&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The home backend Pi, &lt;code&gt;dv01rpi001p01&lt;/code&gt; (&lt;code&gt;192.168.2.40&lt;/code&gt;): nowplayd, the console, the &lt;code&gt;nowplayd&lt;/code&gt; and &lt;code&gt;console&lt;/code&gt; broker accounts; the other services restarted&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make -C deploy/backend push PI=192.168.2.40&lt;/code&gt; from branch &lt;code&gt;adr-0039-stand-for-every-source&lt;/code&gt; (PR #60), before it is merged&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: the two accounts made again with grants the broker refuses, and nowplayd or the console unable to log in until they are put back&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0039-the-console-can-light-the-stand-for-every-source/"&gt;ADR-0039&lt;/a&gt;, whose evidence this is&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0029-the-turntables-album-by-what-is-on-it/"&gt;CHG-0029&lt;/a&gt;, the push before this one&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The console gets a switch that lights the stand for every source, for working&#10;on the stand&amp;rsquo;s looks with iTunes and Spotify. Pushed from the PR&amp;rsquo;s branch so&#10;it can be tried before it is merged.&lt;/p&gt;</description></item><item><title>ADR-0031: Spotify Is Shown, Like iTunes</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0031-spotify-is-shown-like-itunes/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0031-spotify-is-shown-like-itunes/</guid><description>&lt;h1 id="adr-0031-spotify-is-reported-with-its-cover-and-treated-as-itunes-is"&gt;ADR-0031: Spotify Is Reported With Its Cover, and Treated as iTunes Is&lt;a class="anchor" href="#adr-0031-spotify-is-reported-with-its-cover-and-treated-as-itunes-is"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10; — until the driver has fetched a cover from the real account and the screen has shown it; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-13&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Whether Spotify&amp;rsquo;s track comes with a cover, where the cover is from, and what the stand does for it.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0012-spotify-by-web-api/"&gt;ADR-0012&lt;/a&gt;, whose driver took no artwork and now takes the album&amp;rsquo;s. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0016-a-source-can-be-reported-without-its-cover/"&gt;ADR-0016&lt;/a&gt;: a source can still be reported without its cover, and Spotify no longer is. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0028-the-stand-is-for-records/"&gt;ADR-0028&lt;/a&gt;: Spotify becomes a dark source, as iTunes is.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0030-a-piece-of-music-can-have-a-look-from-any-source/"&gt;ADR-0030&lt;/a&gt;, whose &amp;ldquo;any source&amp;rdquo; this makes true of Spotify; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0027-what-is-asked-of-outside-services-is-counted/"&gt;ADR-0027&lt;/a&gt;, which counts the new requests; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0018-a-console-of-eds-own/"&gt;ADR-0018&lt;/a&gt;, whose page shows the cover&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0016-a-source-can-be-reported-without-its-cover/"&gt;ADR-0016&lt;/a&gt;&#10;reported Spotify without a cover for two reasons. The owner did not want&#10;the lights to follow it. And Spotify&amp;rsquo;s developer pages have a line about&#10;not synchronizing its recordings with visual media, which&#10;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0012-spotify-by-web-api/"&gt;ADR-0012&lt;/a&gt; left to&#10;the owner&amp;rsquo;s judgment; fetching no artwork and lighting nothing stepped&#10;around it.&lt;/p&gt;</description></item><item><title>CHG-0031: The Turntable Heard Through a UFO202</title><link>https://cdeever.github.io/eds/docs/changes/2026/0031-the-turntable-heard-through-a-ufo202/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0031-the-turntable-heard-through-a-ufo202/</guid><description>&lt;h1 id="chg-0031-the-turntable-heard-through-a-ufo202"&gt;CHG-0031: The Turntable Heard Through a UFO202&lt;a class="anchor" href="#chg-0031-the-turntable-heard-through-a-ufo202"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-21&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Configuration&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-complete"&gt;Complete&lt;/span&gt;&#10; 2026-10-21&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;dv02rpi003p01&lt;/code&gt;, the back-end Pi: one line of its agent&amp;rsquo;s settings, and its agent restarted&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make -C deploy/backend turntable DEVICE=plughw:CODEC PI=192.168.2.40&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: the agent not coming back, which would stop iTunes being followed too&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0021-the-turntable-is-identified-by-listening/"&gt;ADR-0021&lt;/a&gt;, unchanged&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0028-the-back-end-on-one-pi-on-dvntm/"&gt;CHG-0028&lt;/a&gt;, which named &lt;code&gt;plughw:UA4FX&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The turntable was heard through a Roland UA-4FX, and the Pi&amp;rsquo;s agent listened&#10;to &lt;code&gt;plughw:UA4FX&lt;/code&gt;. Its owner found a Behringer UFO202 and plugged it into the&#10;Pi in the UA-4FX&amp;rsquo;s place. ALSA names it&#10;&lt;code&gt;CODEC&lt;/code&gt; (card 3, &lt;em&gt;USB Audio CODEC&lt;/em&gt;), and the UA-4FX is no longer there, so the&#10;agent is told the new name. Nothing else changes: the same line-level feed&#10;from the selector, the same driver, the same recognizer.&lt;/p&gt;</description></item><item><title>ADR-0032: Spotify Takes Commands</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0032-spotify-takes-commands/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0032-spotify-takes-commands/</guid><description>&lt;h1 id="adr-0032-the-spotify-driver-carries-out-commands-with-a-wider-authorization-for-what-is-playing-here"&gt;ADR-0032: The Spotify Driver Carries Out Commands, With a Wider Authorization, for What Is Playing Here&lt;a class="anchor" href="#adr-0032-the-spotify-driver-carries-out-commands-with-a-wider-authorization-for-what-is-playing-here"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10; — until a press on the cover screen has paused Spotify; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-13&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Whether a controller&amp;rsquo;s command reaches Spotify, what the agent must be authorized for to carry it out, and which playback a command may touch.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0020-a-touch-screen-that-can-change-what-plays/"&gt;ADR-0020&lt;/a&gt;, whose commands only iTunes carried out. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0012-spotify-by-web-api/"&gt;ADR-0012&lt;/a&gt;, whose authorization only read.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0031-spotify-is-shown-like-itunes/"&gt;ADR-0031&lt;/a&gt;, which put Spotify&amp;rsquo;s sleeve on the cover screen above buttons that did nothing; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0025-current-says-when-there-are-no-controls/"&gt;ADR-0025&lt;/a&gt;, the other answer to that; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0027-what-is-asked-of-outside-services-is-counted/"&gt;ADR-0027&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Since &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0031-spotify-is-shown-like-itunes/"&gt;ADR-0031&lt;/a&gt;&#10;the cover screen shows what Spotify is playing, with the same five buttons&#10;it shows for iTunes. Pressed, they do nothing: &lt;code&gt;nowplayd&lt;/code&gt; passes the command&#10;to the current source&#10;(&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0020-a-touch-screen-that-can-change-what-plays/"&gt;ADR-0020&lt;/a&gt;),&#10;and Spotify&amp;rsquo;s driver reads no command topic. It was built to read, with an&#10;authorization that only reads, and both the code and the broker account say&#10;that changing it is a decision. This is that decision.&lt;/p&gt;</description></item><item><title>CHG-0032: American Idiot Has a Look</title><link>https://cdeever.github.io/eds/docs/changes/2026/0032-american-idiot-has-a-look/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0032-american-idiot-has-a-look/</guid><description>&lt;h1 id="chg-0032-american-idiot-has-a-look"&gt;CHG-0032: American Idiot Has a Look&lt;a class="anchor" href="#chg-0032-american-idiot-has-a-look"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-23&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Upgrade&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-complete"&gt;Complete&lt;/span&gt;&#10; 2026-10-23&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;dv02rpi003p01&lt;/code&gt;, the back-end Pi: nowplayd and lightd replaced, and the four services restarted&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make -C deploy/backend push PI=192.168.2.40&lt;/code&gt;, from #60&amp;rsquo;s branch with this change on it&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: a service not coming back after the push, which leaves the stand dark until it is pushed again&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0019-an-album-can-have-a-look-of-its-own/"&gt;ADR-0019&lt;/a&gt;, a second album on its list&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0030-the-console-switches-the-stand/"&gt;CHG-0030&lt;/a&gt;, whose branch is what runs on the Pi and is pushed again here&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Green Day&amp;rsquo;s &lt;em&gt;American Idiot&lt;/em&gt; was lit from the owner&amp;rsquo;s own pressing once the&#10;record was added to the Discogs collection. That sleeve&amp;rsquo;s picture is a&#10;photograph, and lightd read it as one red in four shades&#10;(&lt;code&gt;#df0040 56%, #b90237 16%, #92122f 14%, #671c2b 14%&lt;/code&gt;), which a strip of LEDs&#10;shows as one red going nowhere. Deezer&amp;rsquo;s clean scan of the same sleeve, a few&#10;minutes earlier, had read as two reds with the pale pink of the hand and a&#10;salmon among them (&lt;code&gt;#d90018 45%, #e22f28 31%, #efb6b0 13%, #e35f55 12%&lt;/code&gt;), and&#10;its owner liked that better.&lt;/p&gt;</description></item><item><title>ADR-0033: The Whole Back End on One Pi</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0033-the-whole-back-end-on-one-pi/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0033-the-whole-back-end-on-one-pi/</guid><description>&lt;h1 id="adr-0033-the-whole-back-end-can-run-on-one-pi-as-an-image-built-on-deevnets-take-home-one"&gt;ADR-0033: The Whole Back End Can Run on One Pi, as an Image Built on Deevnet&amp;rsquo;s Take-Home One&lt;a class="anchor" href="#adr-0033-the-whole-back-end-can-run-on-one-pi-as-an-image-built-on-deevnets-take-home-one"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10; — until a card has been built, booted and run; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-13&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Whether EdS can run with nothing of Deevnet IoTaaS behind it, on one Raspberry Pi; what that Pi&amp;rsquo;s image is built from; how its services run, where its secrets come from, and what its console presents.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0015-eds-builds-its-own-pi-images/"&gt;ADR-0015&lt;/a&gt;: a second image, on a second base. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0003-broker-is-the-substrates/"&gt;ADR-0003&lt;/a&gt;: on Deevnet the broker is still Deevnet&amp;rsquo;s; on this Pi it is the Pi&amp;rsquo;s. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0010-home-lan-relay/"&gt;ADR-0010&lt;/a&gt;: this Pi has one leg and is no relay. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0018-a-console-of-eds-own/"&gt;ADR-0018&lt;/a&gt;: the console&amp;rsquo;s certificate, where there is no Tenant Service CA.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0017-an-agent-pi-is-a-registered-device/"&gt;ADR-0017&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0027-what-is-asked-of-outside-services-is-counted/"&gt;ADR-0027&lt;/a&gt;, Deevnet&amp;rsquo;s runbook &amp;ldquo;Convert a Tenant to a Pi Image&amp;rdquo;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;EdS runs in two places. Four services (&lt;code&gt;palette&lt;/code&gt;, &lt;code&gt;lightd&lt;/code&gt;, &lt;code&gt;nowplayd&lt;/code&gt;, the&#10;console) are containers on a workload in the EdS tenant. The agent, &lt;code&gt;npagent&lt;/code&gt;,&#10;is on a Pi with a leg on the home network&#10;(&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0010-home-lan-relay/"&gt;ADR-0010&lt;/a&gt;). The broker,&#10;the log store and Grafana are Deevnet IoTaaS&amp;rsquo;s.&lt;/p&gt;</description></item><item><title>CHG-0033: An Album Asked For on the Bus</title><link>https://cdeever.github.io/eds/docs/changes/2026/0033-an-album-asked-for-on-the-bus/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0033-an-album-asked-for-on-the-bus/</guid><description>&lt;h1 id="chg-0033-an-album-asked-for-on-the-bus"&gt;CHG-0033: An Album Asked For on the Bus&lt;a class="anchor" href="#chg-0033-an-album-asked-for-on-the-bus"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-23&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Upgrade&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-in-progress"&gt;In progress&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The tenant&amp;rsquo;s services workload (&lt;code&gt;services.eds.mobile.deevnet.net&lt;/code&gt;): the four services rebuilt and restarted. &lt;code&gt;dv02rpi002p01&lt;/code&gt;, the relay: &lt;code&gt;npagent&lt;/code&gt; replaced&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make -C deploy ship WHERE=builder&lt;/code&gt; and &lt;code&gt;make -C deploy/relay push&lt;/code&gt;, from the branch &lt;code&gt;voice-play-album&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: a service not coming back, which leaves the mobile site&amp;rsquo;s stand and screen without a current track until shipped again. The home back-end Pi is not touched&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0040-a-request-can-name-an-album-to-play/"&gt;ADR-0040&lt;/a&gt;, whose command this puts on the bus&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0032-american-idiot-has-a-look/"&gt;CHG-0032&lt;/a&gt;, the last change, made on the back-end Pi&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;&lt;code&gt;play_album&lt;/code&gt; is the first command that chooses what plays&#10;(&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0040-a-request-can-name-an-album-to-play/"&gt;ADR-0040&lt;/a&gt;).&#10;&lt;code&gt;npagent play-album&lt;/code&gt; has already played Van Halen&amp;rsquo;s first album from the&#10;relay by hand; this puts the same request behind the bus. nowplayd passes&#10;&lt;code&gt;play_album&lt;/code&gt; to &lt;code&gt;itunes&lt;/code&gt; whatever is current, and the iTunes driver asks&#10;for the album and then asks what plays.&lt;/p&gt;</description></item><item><title>ADR-0034: Presence Is Heard, Not Remembered</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0034-presence-is-heard-not-remembered/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0034-presence-is-heard-not-remembered/</guid><description>&lt;h1 id="adr-0034-presence-is-heard-not-remembered-everything-says-it-is-there-every-thirty-seconds"&gt;ADR-0034: Presence Is Heard, Not Remembered: Everything Says It Is There Every Thirty Seconds&lt;a class="anchor" href="#adr-0034-presence-is-heard-not-remembered-everything-says-it-is-there-every-thirty-seconds"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10; — until a stand unplugged across a broker restart is seen gray; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-16&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;What &lt;code&gt;online&lt;/code&gt; on a &lt;code&gt;…/status&lt;/code&gt; topic means to whoever reads it: the console, and nowplayd for sources and beacons.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0023-a-source-that-is-switched-on-holds-the-stand/"&gt;ADR-0023&lt;/a&gt;, whose consequence &amp;ldquo;a will needs a broker to send it&amp;rdquo; this removes. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0018-a-console-of-eds-own/"&gt;ADR-0018&lt;/a&gt;: the console now shows a part as up only if it has heard from it lately.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0003-broker-is-the-substrates/"&gt;ADR-0003&lt;/a&gt;, the broker that keeps retained messages across restarts&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Every part of EdS says it is there the same way: on connecting, it publishes&#10;&lt;code&gt;online&lt;/code&gt;, retained, to its status topic, and leaves the broker a last will&#10;of &lt;code&gt;offline&lt;/code&gt;, retained. The broker sends the will when it sees the&#10;connection die.&lt;/p&gt;</description></item><item><title>CHG-0034: voiced and scribe on the Workload</title><link>https://cdeever.github.io/eds/docs/changes/2026/0034-voiced-and-scribe-on-the-workload/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0034-voiced-and-scribe-on-the-workload/</guid><description>&lt;h1 id="chg-0034-voiced-and-scribe-on-the-workload"&gt;CHG-0034: voiced and scribe on the Workload&lt;a class="anchor" href="#chg-0034-voiced-and-scribe-on-the-workload"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-24&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Deployment&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-in-progress"&gt;In progress&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The tenant&amp;rsquo;s Terraform on the mobile site&amp;rsquo;s API: broker accounts for &lt;code&gt;voiced&lt;/code&gt; and &lt;code&gt;respeaker-01&lt;/code&gt; and the device &lt;code&gt;respeaker-01&lt;/code&gt; created; &lt;code&gt;console&lt;/code&gt; and &lt;code&gt;nowplayd&lt;/code&gt; given &lt;code&gt;nowplaying/stand&lt;/code&gt;. The services workload: &lt;code&gt;eds-scribe&lt;/code&gt; and &lt;code&gt;eds-voiced&lt;/code&gt; added, the other four rebuilt and restarted&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make -C infra/deevnet-tenant-eds apply&lt;/code&gt;, then &lt;code&gt;make -C deploy kit-env deploy WHERE=builder&lt;/code&gt;, from the branch &lt;code&gt;voice-play-album&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Medium. The workload has two cores and two gigabytes, and scribe&amp;rsquo;s model takes a few hundred megabytes of it: most likely to go wrong is memory, which would stop a service. &lt;code&gt;eds-scribe&lt;/code&gt; is held to 900 MB for that reason. Updating &lt;code&gt;console&lt;/code&gt; and &lt;code&gt;nowplayd&lt;/code&gt; in place keeps their passwords&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0042-a-request-is-heard-on-the-workload/"&gt;ADR-0042&lt;/a&gt;; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0039-the-console-can-light-the-stand-for-every-source/"&gt;ADR-0039&lt;/a&gt;, whose grant this applies to the tenant at last&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0033-an-album-asked-for-on-the-bus/"&gt;CHG-0033&lt;/a&gt;, which put &lt;code&gt;play_album&lt;/code&gt; on the bus; &lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0030-the-console-switches-the-stand/"&gt;CHG-0030&lt;/a&gt;, which switched the stand on the back-end Pi only&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;A spoken request is written down by &lt;code&gt;scribe&lt;/code&gt; and made a command by &lt;code&gt;voiced&lt;/code&gt;&#10;(&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0042-a-request-is-heard-on-the-workload/"&gt;ADR-0042&lt;/a&gt;).&#10;Both have run on a Mac against the development broker. This puts them on the&#10;workload, with &lt;code&gt;voiced&lt;/code&gt;&amp;rsquo;s own broker account, and registers the reSpeaker,&#10;whose account is the one that may publish a request.&lt;/p&gt;</description></item><item><title>ADR-0035: Firmware Is Updated Through the Broker</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0035-firmware-is-updated-through-the-broker/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0035-firmware-is-updated-through-the-broker/</guid><description>&lt;h1 id="adr-0035-firmware-is-updated-through-the-broker-and-a-build-that-cannot-reach-it-is-undone"&gt;ADR-0035: Firmware Is Updated Through the Broker, and a Build That Cannot Reach It Is Undone&lt;a class="anchor" href="#adr-0035-firmware-is-updated-through-the-broker-and-a-build-that-cannot-reach-it-is-undone"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-green"&gt;Accepted&lt;/span&gt;&#10; 2026-10-17, after each device was updated over the air, one rolled back by itself, and one refused a build not its own; see &lt;a href="#evidence"&gt;Evidence&lt;/a&gt;. Opened 2026-10-16 as &lt;code&gt;Proposed&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-16&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;How a new build reaches the stand, the cover screen and the beacon once each is in place; what a device does with one; and how a bad one is undone.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0029-the-stand-starts-dark-and-blinks-what-is-wrong/"&gt;ADR-0029&lt;/a&gt;: the stand that cannot reach the broker still blinks, and now also gives up a new build that caused it.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0003-broker-is-the-substrates/"&gt;ADR-0003&lt;/a&gt;, why the broker sits where devices can reach it and nothing else of EdS can; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0023-a-source-that-is-switched-on-holds-the-stand/"&gt;ADR-0023&lt;/a&gt;, the beacon whose connection is its message; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0034-presence-is-heard-not-remembered/"&gt;ADR-0034&lt;/a&gt;, the change that showed why this is wanted&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Every change to a device&amp;rsquo;s firmware has meant a USB cable: the stand&#10;unscrewed from its shelf, the beacon taken off its outlet, and the cover&#10;screen and the beacon taking turns on the Mac&amp;rsquo;s one serial port.&#10;ADR-0034 is the case in point: three devices to flash before three&#10;services could be deployed.&lt;/p&gt;</description></item><item><title>CHG-0035: Only Words scribe Is Sure Of</title><link>https://cdeever.github.io/eds/docs/changes/2026/0035-only-words-scribe-is-sure-of/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0035-only-words-scribe-is-sure-of/</guid><description>&lt;h1 id="chg-0035-only-words-scribe-is-sure-of-and-the-respeaker-asked-from-its-console"&gt;CHG-0035: Only Words scribe Is Sure Of, and the reSpeaker Asked From Its Console&lt;a class="anchor" href="#chg-0035-only-words-scribe-is-sure-of-and-the-respeaker-asked-from-its-console"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-24&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Upgrade&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-complete"&gt;Complete&lt;/span&gt;&#10; 2026-10-24&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The services workload: the six services rebuilt, &lt;code&gt;eds-scribe&lt;/code&gt; and &lt;code&gt;eds-voiced&lt;/code&gt; changed, all restarted. &lt;code&gt;respeaker-01&lt;/code&gt;: firmware flashed by cable&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make -C deploy ship WHERE=builder&lt;/code&gt;; &lt;code&gt;make -C firmware/ears build flash&lt;/code&gt;, from &lt;code&gt;e9ed753&lt;/code&gt; on &lt;code&gt;voice-play-album&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: scribe&amp;rsquo;s thresholds refusing speech it should take, which is a request said again, not a record played wrongly&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0042-a-request-is-heard-on-the-workload/"&gt;ADR-0042&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0043-the-respeaker-runs-firmware-of-edss-own/"&gt;ADR-0043&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/incidents/2026/0001-the-beatles-played-for-a-request-nobody-made/"&gt;INC-0001&lt;/a&gt;, which this corrects&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The reSpeaker&amp;rsquo;s first request played &lt;em&gt;Abbey Road&lt;/em&gt;, which nobody asked for&#10;(&lt;a href="https://cdeever.github.io/eds/docs/incidents/2026/0001-the-beatles-played-for-a-request-nobody-made/"&gt;INC-0001&lt;/a&gt;):&#10;scribe&amp;rsquo;s model wrote its own prompt back, a request in words, and voiced&#10;acted on it. scribe&amp;rsquo;s prompt is now a list of names, and scribe says whether&#10;the words are worth acting on, by Whisper&amp;rsquo;s own thresholds; voiced acts on&#10;nothing else.&lt;/p&gt;</description></item><item><title>ADR-0036: The Screen Sleeps When Nothing Plays</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0036-the-screen-sleeps-when-nothing-plays/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0036-the-screen-sleeps-when-nothing-plays/</guid><description>&lt;h1 id="adr-0036-the-cover-screen-sleeps-when-nothing-has-played-for-five-minutes-and-wakes-for-music"&gt;ADR-0036: The Cover Screen Sleeps When Nothing Has Played for Five Minutes, and Wakes for Music&lt;a class="anchor" href="#adr-0036-the-cover-screen-sleeps-when-nothing-has-played-for-five-minutes-and-wakes-for-music"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-green"&gt;Accepted&lt;/span&gt;&#10; 2026-10-17 — slept and woken on the board (&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0026-the-cover-screen-sleeps/"&gt;CHG-0026&lt;/a&gt;); see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-17&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The cover screen&amp;rsquo;s firmware: when it turns its panel off, and what wakes it. Nothing on the bus changes.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0020-a-touch-screen-that-can-change-what-plays/"&gt;ADR-0020&lt;/a&gt;, the screen itself&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0023-a-source-that-is-switched-on-holds-the-stand/"&gt;ADR-0023&lt;/a&gt;, which makes a turntable that is switched off not heard; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0024-paused-long-enough-is-not-playing/"&gt;ADR-0024&lt;/a&gt;, which turns a long pause into stopped; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0025-current-says-when-there-are-no-controls/"&gt;ADR-0025&lt;/a&gt;, the last time the screen had to be told something without knowing a source; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0029-the-stand-starts-dark-and-blinks-what-is-wrong/"&gt;ADR-0029&lt;/a&gt;, the stand&amp;rsquo;s dark that is not a fault&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The cover screen is lit all the time. With nothing playing it shows a drawn&#10;record all night, to nobody. Its owner asked first for it to sleep when the&#10;turntable&amp;rsquo;s power, iTunes and Spotify are all gone, and to come back when&#10;one of them is.&lt;/p&gt;</description></item><item><title>CHG-0036: The reSpeaker Wakes to "Hey Jarvis"</title><link>https://cdeever.github.io/eds/docs/changes/2026/0036-the-respeaker-wakes-to-hey-jarvis/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0036-the-respeaker-wakes-to-hey-jarvis/</guid><description>&lt;h1 id="chg-0036-the-respeaker-wakes-to-hey-jarvis-and-hears-a-request-until-it-ends"&gt;CHG-0036: The reSpeaker Wakes to &amp;ldquo;Hey Jarvis&amp;rdquo;, and Hears a Request Until It Ends&lt;a class="anchor" href="#chg-0036-the-respeaker-wakes-to-hey-jarvis-and-hears-a-request-until-it-ends"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-24&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Upgrade&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-complete"&gt;Complete&lt;/span&gt;&#10; 2026-10-24&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;respeaker-01&lt;/code&gt;: firmware flashed by cable. The services workload: &lt;code&gt;eds-voiced&lt;/code&gt; rebuilt with the others and all restarted&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make -C firmware/ears build flash&lt;/code&gt;; &lt;code&gt;make -C deploy ship WHERE=builder&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: the device waking for something that is not its name, which sends a few seconds of the room; voiced acts only on a request it is sure of (INC-0001)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0043-the-respeaker-runs-firmware-of-edss-own/"&gt;ADR-0043&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0035-only-words-scribe-is-sure-of/"&gt;CHG-0035&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The reSpeaker listens for a wake word: microWakeWord&amp;rsquo;s &amp;ldquo;Hey Jarvis&amp;rdquo;, ESPHome&amp;rsquo;s&#10;model, on TensorFlow Lite Micro with the audio frontend it was trained on.&#10;What follows it is heard until the speaker stops - 0.7 s quieter than the&#10;room by 10 dB, at most six seconds - and sent, with the 350 ms before the&#10;wake was decided on, so that a &amp;ldquo;play&amp;rdquo; said straight after keeps its P. voiced&#10;allows a word or two before &amp;ldquo;play&amp;rdquo;, for the end of the wake word that comes&#10;with it, but never a negation.&lt;/p&gt;</description></item><item><title>ADR-0037: Hand-Kept Secrets Are Encrypted in the Repository</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0037-hand-kept-secrets-are-encrypted-in-the-repository/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0037-hand-kept-secrets-are-encrypted-in-the-repository/</guid><description>&lt;h1 id="adr-0037-the-secrets-nothing-else-can-issue-are-kept-encrypted-in-the-repository-with-sops-and-age"&gt;ADR-0037: The Secrets Nothing Else Can Issue Are Kept Encrypted in the Repository, with sops and age&lt;a class="anchor" href="#adr-0037-the-secrets-nothing-else-can-issue-are-kept-encrypted-in-the-repository-with-sops-and-age"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10; — until the first secrets have moved and a second machine has read them; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-18&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Where EdS keeps the secrets it is the only holder of, and how its tools read them. Not the secrets Deevnet IoTaaS issues, and not those made on a device or a card.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0004-firmware-secrets-nvs-only/"&gt;ADR-0004&lt;/a&gt;, whose rule (no secret compiled in) stands; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0022-the-owners-collection-names-the-record/"&gt;ADR-0022&lt;/a&gt;, whose token &amp;ldquo;is never committed&amp;rdquo; in plain text, and now is committed encrypted&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0033-the-whole-back-end-on-one-pi/"&gt;ADR-0033&lt;/a&gt;, whose first card went out without the Discogs token&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;On 2026-10-18 the first backend card was written from a worktree, and went&#10;out with no Discogs settings. &lt;code&gt;make card&lt;/code&gt; looks for &lt;code&gt;deploy/discogs.env&lt;/code&gt; in&#10;the checkout it runs in; the file is gitignored, so a worktree never has it;&#10;and the script says &amp;ldquo;no Discogs settings&amp;rdquo; and carries on, as it should for an&#10;owner who has none. Nothing was wrong except where the secret lived.&lt;/p&gt;</description></item><item><title>CHG-0037: A Request Answered Sooner</title><link>https://cdeever.github.io/eds/docs/changes/2026/0037-a-request-answered-sooner/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0037-a-request-answered-sooner/</guid><description>&lt;h1 id="chg-0037-a-request-answered-sooner"&gt;CHG-0037: A Request Answered Sooner&lt;a class="anchor" href="#chg-0037-a-request-answered-sooner"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-24&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Upgrade&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-in-progress"&gt;In progress&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;respeaker-01&lt;/code&gt;: firmware flashed by cable. The services workload: all six rebuilt, &lt;code&gt;eds-voiced&lt;/code&gt;&amp;rsquo;s unit changed and &lt;code&gt;/var/lib/eds-voiced&lt;/code&gt; made&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make -C firmware/ears build flash&lt;/code&gt;; &lt;code&gt;make -C deploy deploy WHERE=builder&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: a request cut before its last word, which is a request said again&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0042-a-request-is-heard-on-the-workload/"&gt;ADR-0042&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0043-the-respeaker-runs-firmware-of-edss-own/"&gt;ADR-0043&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0036-the-respeaker-wakes-to-hey-jarvis/"&gt;CHG-0036&lt;/a&gt;, whose request took 21 s from the wake word to the music&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;From &amp;ldquo;Hey Jarvis&amp;rdquo; to the music took 21 s in CHG-0036: 6.4 s heard, because&#10;the room never got as quiet as the floor learned from its quietest moments;&#10;5.3 s to send 200 KB at -80 dBm; 4.6 s to write down; 5 s to count&#10;Aerosmith&amp;rsquo;s albums in MusicBrainz after a restart had forgotten them.&lt;/p&gt;</description></item><item><title>ADR-0038: The Turntable's Album Is the Original One the Track Is On</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0038-the-turntable-names-the-original-album-by-what-is-on-it/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0038-the-turntable-names-the-original-album-by-what-is-on-it/</guid><description>&lt;h1 id="adr-0038-the-turntables-album-is-the-one-the-track-is-on-and-the-original-one-not-a-time-since-the-last"&gt;ADR-0038: The Turntable&amp;rsquo;s Album Is the One the Track Is On, and the Original One, Not a Time Since the Last&lt;a class="anchor" href="#adr-0038-the-turntables-album-is-the-one-the-track-is-on-and-the-original-one-not-a-time-since-the-last"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10; — until a side of one record and then another by the same artist have been played; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-19&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Which album nowplayd names for a track heard on the turntable, and so which cover lights the room. The turntable driver, nowplayd&amp;rsquo;s resolution for the turntable, and the catalogs it asks.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Supersedes&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0026-what-silence-means-on-the-turntable/"&gt;ADR-0026&lt;/a&gt;&amp;rsquo;s &amp;ldquo;the driver remembers the album for ten minutes&amp;rdquo;; the rest of ADR-0026 stands&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0022-the-owners-collection-names-the-record/"&gt;ADR-0022&lt;/a&gt;, the owner&amp;rsquo;s collection first, which stands and still comes first&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0019-an-album-can-have-a-look-of-its-own/"&gt;ADR-0019&lt;/a&gt;, whose album looks follow the album named; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0027-what-is-asked-of-outside-services-is-counted/"&gt;ADR-0027&lt;/a&gt;, which counts every call this adds&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;On 2026-10-18, the first evening on the home Pi&#10;(&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0028-the-back-end-on-one-pi-on-dvntm/"&gt;CHG-0028&lt;/a&gt;), &lt;em&gt;The&#10;Dark Side of the Moon&lt;/em&gt; was played, lifted, and &lt;em&gt;Animals&lt;/em&gt; put on 52 seconds&#10;later. The recognizer named &amp;ldquo;Pigs On the Wing, Pt. 1&amp;rdquo; and then &amp;ldquo;Dogs&amp;rdquo;, which&#10;are right. The stand kept &lt;em&gt;Dark Side&lt;/em&gt;&amp;rsquo;s rainbow look for both, because both&#10;were reported as on &lt;em&gt;The Dark Side of the Moon&lt;/em&gt;.&lt;/p&gt;</description></item><item><title>CHG-0038: A Misheard "Play", and a Longer Pre-roll</title><link>https://cdeever.github.io/eds/docs/changes/2026/0038-a-misheard-play-and-a-longer-pre-roll/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0038-a-misheard-play-and-a-longer-pre-roll/</guid><description>&lt;h1 id="chg-0038-a-misheard-play-is-taken-for-one-where-the-rest-is-an-album-by-its-place-and-the-pre-roll-is-600-ms"&gt;CHG-0038: A Misheard &amp;ldquo;Play&amp;rdquo; Is Taken for One Where the Rest Is an Album by Its Place, and the Pre-roll Is 600 ms&lt;a class="anchor" href="#chg-0038-a-misheard-play-is-taken-for-one-where-the-rest-is-an-album-by-its-place-and-the-pre-roll-is-600-ms"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-24&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Upgrade&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-in-progress"&gt;In progress&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The services workload: nowplayd and voiced sent and all restarted. &lt;code&gt;respeaker-01&lt;/code&gt;: flashed by cable&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make -C deploy ship WHERE=builder&lt;/code&gt;, the first with &lt;code&gt;load.sh&lt;/code&gt; (&lt;a href="https://cdeever.github.io/eds/docs/incidents/2026/0002-deploys-hung-the-core-router/"&gt;INC-0002&lt;/a&gt;); &lt;code&gt;make -C firmware/ears build flash&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: a sentence that is not a request read as one; only &amp;ldquo;X&amp;rsquo;s Nth album&amp;rdquo; and &amp;ldquo;the Nth album by X&amp;rdquo; are read behind a misheard &amp;ldquo;play&amp;rdquo;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0042-a-request-is-heard-on-the-workload/"&gt;ADR-0042&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0043-the-respeaker-runs-firmware-of-edss-own/"&gt;ADR-0043&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0037-a-request-answered-sooner/"&gt;CHG-0037&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;After CHG-0037 and ADR-0044, &amp;ldquo;Hey Jarvis, play Aerosmith&amp;rsquo;s first album&amp;rdquo;&#10;played in 8 s from the wake word: 2 s heard, sent in 89 ms, 4 s to write&#10;down, 1.7 s to count. The music dipped while it listened. &amp;ldquo;Play Van Halen&amp;rsquo;s&#10;first album&amp;rdquo;, straight after, was written &amp;ldquo;Tae Van Halen&amp;rsquo;s first album.&amp;rdquo;&#10;and was not a request.&lt;/p&gt;</description></item><item><title>ADR-0039: The Console Can Light the Stand for Every Source</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0039-the-console-can-light-the-stand-for-every-source/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0039-the-console-can-light-the-stand-for-every-source/</guid><description>&lt;h1 id="adr-0039-the-console-can-light-the-stand-for-every-source-until-it-is-switched-back"&gt;ADR-0039: The Console Can Light the Stand for Every Source, Until It Is Switched Back&lt;a class="anchor" href="#adr-0039-the-console-can-light-the-stand-for-every-source-until-it-is-switched-back"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10; — until it has been switched both ways from the console in the room; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-19&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;A switch on the console that lights the stand from iTunes and Spotify as well as records; where its state is kept; who may change it.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0018-a-console-of-eds-own/"&gt;ADR-0018&lt;/a&gt;: the console gets its first control, and its account its second topic to publish. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0028-the-stand-is-for-records/"&gt;ADR-0028&lt;/a&gt;: records-only stays the default, and becomes a setting that can be changed while running.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0020-a-touch-screen-that-can-change-what-plays/"&gt;ADR-0020&lt;/a&gt;, whose commands are never retained; this is not one of them. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0030-a-piece-of-music-can-have-a-look-from-any-source/"&gt;ADR-0030&lt;/a&gt;, whose any-source look is unchanged. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0009-lightd-takes-covers-from-a-topic/"&gt;ADR-0009&lt;/a&gt;, whose boundary this keeps.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The stand is lit for records only&#10;(&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0028-the-stand-is-for-records/"&gt;ADR-0028&lt;/a&gt;):&#10;&lt;code&gt;NP_DARK_SOURCES=itunes,spotify&lt;/code&gt; makes nowplayd give those sources&amp;rsquo; covers&#10;the look &lt;code&gt;dark&lt;/code&gt;, and lightd draws it as a dark stand. That is right for the&#10;room and stays the default.&lt;/p&gt;</description></item><item><title>CHG-0039: scribe in Two, and "Hey Jarvis" in Its Prompt</title><link>https://cdeever.github.io/eds/docs/changes/2026/0039-scribe-in-two-and-hey-jarvis-in-its-prompt/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0039-scribe-in-two-and-hey-jarvis-in-its-prompt/</guid><description>&lt;h1 id="chg-0039-scribe-is-a-base-sent-once-and-its-code-built-on-the-workload-and-hey-jarvis-is-in-its-prompt"&gt;CHG-0039: scribe Is a Base Sent Once and Its Code Built on the Workload, and &amp;ldquo;Hey Jarvis&amp;rdquo; Is in Its Prompt&lt;a class="anchor" href="#chg-0039-scribe-is-a-base-sent-once-and-its-code-built-on-the-workload-and-hey-jarvis-is-in-its-prompt"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-24&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Upgrade&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-in-progress"&gt;In progress&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The services workload: &lt;code&gt;eds-scribe-base&lt;/code&gt; loaded, &lt;code&gt;eds-scribe&lt;/code&gt; built there, nowplayd and voiced sent, all restarted&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make -C deploy ship WHERE=builder&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Medium. Most likely to go wrong: the core router under the base&amp;rsquo;s one transfer (INC-0002), which is compressed to 256 MB and held to 5 MB/s&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0042-a-request-is-heard-on-the-workload/"&gt;ADR-0042&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/incidents/2026/0002-deploys-hung-the-core-router/"&gt;INC-0002&lt;/a&gt;, whose follow-up this is; &lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0038-a-misheard-play-and-a-longer-pre-roll/"&gt;CHG-0038&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The end of the wake word, kept with each request, was written &amp;ldquo;Lee Jarvis&amp;rdquo;,&#10;&amp;ldquo;Jay Jarrus&amp;rdquo;, &amp;ldquo;Travis&amp;rdquo;, &amp;ldquo;The band was very generous&amp;rdquo;, and the request after&#10;it was misheard with it. With &amp;ldquo;Hey Jarvis&amp;rdquo; in scribe&amp;rsquo;s prompt, the same&#10;recordings, cut as the device cuts them, were written &amp;ldquo;Jarvis,&amp;rdquo; each time,&#10;and nothing else changed.&lt;/p&gt;</description></item><item><title>ADR-0040: A Request Can Name an Album to Play</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0040-a-request-can-name-an-album-to-play/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0040-a-request-can-name-an-album-to-play/</guid><description>&lt;h1 id="adr-0040-a-request-can-name-an-album-to-play-and-itunes-plays-it-from-its-own-library"&gt;ADR-0040: A Request Can Name an Album to Play, and iTunes Plays It From Its Own Library&lt;a class="anchor" href="#adr-0040-a-request-can-name-an-album-to-play-and-itunes-plays-it-from-its-own-library"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10; — until &lt;code&gt;play_album&lt;/code&gt; sent to &lt;code&gt;nowplaying/command&lt;/code&gt; has played an album through nowplayd and the driver (the driver&amp;rsquo;s half is shown); see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-23&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;A sixth command, &lt;code&gt;play_album&lt;/code&gt;, that names an album rather than pressing a button; which player carries it out; and what the iTunes driver asks of the player&amp;rsquo;s library to do it. The first thing to send it is meant to be a voice (&amp;ldquo;Hey Ed, play Van Halen&amp;rsquo;s first album&amp;rdquo;), which is a decision of its own.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0020-a-touch-screen-that-can-change-what-plays/"&gt;ADR-0020&lt;/a&gt;, whose five commands press buttons on whatever is playing, and &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0011-itunes-by-remote-pairing/"&gt;ADR-0011&lt;/a&gt;, whose pairing has only read what plays and pressed those buttons&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0032-spotify-takes-commands/"&gt;ADR-0032&lt;/a&gt;, which added no command; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0038-the-turntable-names-the-original-album-by-what-is-on-it/"&gt;ADR-0038&lt;/a&gt;, which already knows an artist&amp;rsquo;s original albums&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Every command so far is a button. It acts on whatever is playing, so a&#10;controller never needs to say where it is sent, and&#10;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0020-a-touch-screen-that-can-change-what-plays/"&gt;ADR-0020&lt;/a&gt;&#10;made that a rule: a controller never names a source. A request to play an&#10;album is not a button. Nothing may be playing at all, and if something is,&#10;it may be the turntable, which takes no command.&lt;/p&gt;</description></item><item><title>CHG-0040: The Owner's Library for voiced</title><link>https://cdeever.github.io/eds/docs/changes/2026/0040-the-owners-library-for-voiced/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0040-the-owners-library-for-voiced/</guid><description>&lt;h1 id="chg-0040-voiced-matches-requests-against-an-index-of-the-owners-library"&gt;CHG-0040: voiced Matches Requests Against an Index of the Owner&amp;rsquo;s Library&lt;a class="anchor" href="#chg-0040-voiced-matches-requests-against-an-index-of-the-owners-library"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-24&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Upgrade&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-in-progress"&gt;In progress&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The services workload: voiced sent and its unit replaced; &lt;code&gt;library.json&lt;/code&gt; copied to &lt;code&gt;/var/lib/eds-voiced&lt;/code&gt;. The relay Pi: npagent, for the driver&amp;rsquo;s title matching&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make -C deploy ship WHERE=builder&lt;/code&gt;, &lt;code&gt;make -C deploy units&lt;/code&gt;, &lt;code&gt;make -C deploy library XML=…&lt;/code&gt;; the relay&amp;rsquo;s push&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: a near but wrong artist or album chosen; without the index, voiced is as it was&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0046-requests-are-matched-against-the-owners-library/"&gt;ADR-0046&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0039-scribe-in-two-and-hey-jarvis-in-its-prompt/"&gt;CHG-0039&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;voiced gains &lt;code&gt;NP_LIBRARY&lt;/code&gt;, an index of the owner&amp;rsquo;s iTunes library made from&#10;its XML, and chooses from it the artist and album a request means, by the&#10;library&amp;rsquo;s own names. The driver asks iTunes for the whole title first and&#10;its plain start after.&lt;/p&gt;</description></item><item><title>ADR-0041: An Artist's Nth Album Is Counted in MusicBrainz</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0041-an-artists-nth-album-is-counted-in-musicbrainz/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0041-an-artists-nth-album-is-counted-in-musicbrainz/</guid><description>&lt;h1 id="adr-0041-an-artists-first-album-is-their-first-studio-album-counted-in-musicbrainz"&gt;ADR-0041: An Artist&amp;rsquo;s First Album Is Their First Studio Album, Counted in MusicBrainz&lt;a class="anchor" href="#adr-0041-an-artists-first-album-is-their-first-studio-album-counted-in-musicbrainz"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10; — until an album asked for by its place has played; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-24&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;What &amp;ldquo;Aerosmith&amp;rsquo;s first album&amp;rdquo; means, where the count comes from, and how the name it gives is made to match a library. Not how a request is heard, nor what plays it.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0038-the-turntable-names-the-original-album-by-what-is-on-it/"&gt;ADR-0038&lt;/a&gt;, whose idea of an original album, a studio album with nothing else to it, is the one counted here&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0040-a-request-can-name-an-album-to-play/"&gt;ADR-0040&lt;/a&gt;, which plays an album by its names and cannot ask the library what it holds; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0022-the-owners-collection-names-the-record/"&gt;ADR-0022&lt;/a&gt;, the owner&amp;rsquo;s Discogs collection&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;A request to play &amp;ldquo;Van Halen&amp;rsquo;s first album&amp;rdquo; has to become the names&#10;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0040-a-request-can-name-an-album-to-play/"&gt;ADR-0040&lt;/a&gt;&#10;plays an album by: the artist, and the album&amp;rsquo;s title, as the iTunes library&#10;writes them. The library cannot be asked which albums it has. Something else&#10;has to know the order of an artist&amp;rsquo;s albums.&lt;/p&gt;</description></item><item><title>CHG-0041: voiced Asks eds-inventory</title><link>https://cdeever.github.io/eds/docs/changes/2026/0041-voiced-asks-eds-inventory/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0041-voiced-asks-eds-inventory/</guid><description>&lt;h1 id="chg-0041-voiced-asks-eds-inventory-for-the-owners-albums"&gt;CHG-0041: voiced Asks eds-inventory for the Owner&amp;rsquo;s Albums&lt;a class="anchor" href="#chg-0041-voiced-asks-eds-inventory-for-the-owners-albums"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-24&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Upgrade&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-complete"&gt;Complete&lt;/span&gt;&#10; 2026-10-24&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The services workload: eds-inventory installed beside EdS&amp;rsquo;s services (eds-inventory&amp;rsquo;s CHG-0001); voiced sent and its unit replaced&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;In eds-inventory: &lt;code&gt;make -C deploy image load unit WHERE=builder&lt;/code&gt;, then &lt;code&gt;make -C deploy library XML=…&lt;/code&gt;. Here: &lt;code&gt;make -C deploy ship WHERE=builder&lt;/code&gt;, &lt;code&gt;make -C deploy units&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: the inventory not answering, and albums guessed at as with no library; &lt;code&gt;make deploy&lt;/code&gt;&amp;rsquo;s restart of every EdS service&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0047-voiced-asks-eds-inventory/"&gt;ADR-0047&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0040-the-owners-library-for-voiced/"&gt;CHG-0040&lt;/a&gt;, the index this replaces&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;eds-inventory&amp;rsquo;s inventoryd goes onto the services workload with the owner&amp;rsquo;s&#10;iTunes library collected into it, and voiced is pointed at it with&#10;&lt;code&gt;NP_INVENTORY_URL&lt;/code&gt;. &lt;code&gt;library.json&lt;/code&gt; stays where it is, unread while the&#10;inventory is configured.&lt;/p&gt;</description></item><item><title>ADR-0042: A Request Is Heard on the Workload</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0042-a-request-is-heard-on-the-workload/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0042-a-request-is-heard-on-the-workload/</guid><description>&lt;h1 id="adr-0042-a-spoken-request-is-sent-whole-to-the-workload-written-down-there-and-made-a-command"&gt;ADR-0042: A Spoken Request Is Sent Whole to the Workload, Written Down There, and Made a Command&lt;a class="anchor" href="#adr-0042-a-spoken-request-is-sent-whole-to-the-workload-written-down-there-and-made-a-command"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10; — until a request said in the room has played its album; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-24&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;How &amp;ldquo;Hey Ed, play Van Halen&amp;rsquo;s first album&amp;rdquo; travels from a microphone to &lt;code&gt;play_album&lt;/code&gt;: what the device sends, where speech becomes words, and how words become a command. Not the device&amp;rsquo;s firmware, which is a decision of its own.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0040-a-request-can-name-an-album-to-play/"&gt;ADR-0040&lt;/a&gt;, whose command this sends, and &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0041-an-artists-nth-album-is-counted-in-musicbrainz/"&gt;ADR-0041&lt;/a&gt;, whose count it asks&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0003-broker-is-the-substrates/"&gt;ADR-0003&lt;/a&gt;, the broker as the one way a device reaches EdS; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0034-presence-is-heard-not-remembered/"&gt;ADR-0034&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The microphone is a reSpeaker Lite: an XMOS chip that cleans up what a room&#10;says, and a small ESP32-S3 beside it. The ESP32-S3 can listen for a wake&#10;word and keep a few seconds of audio. It cannot turn speech into words. A&#10;device can reach nothing of EdS&amp;rsquo;s but the broker&#10;(&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0003-broker-is-the-substrates/"&gt;ADR-0003&lt;/a&gt;).&lt;/p&gt;</description></item><item><title>CHG-0042: The Home Pi Becomes a Deevnet Pi</title><link>https://cdeever.github.io/eds/docs/changes/2026/0042-the-home-pi-becomes-a-deevnet-pi/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0042-the-home-pi-becomes-a-deevnet-pi/</guid><description>&lt;h1 id="chg-0042-the-home-pi-becomes-a-deevnet-pi-and-the-devices-hold-both-sites"&gt;CHG-0042: The Home Pi Becomes a Deevnet Pi, and the Devices Hold Both Sites&lt;a class="anchor" href="#chg-0042-the-home-pi-becomes-a-deevnet-pi-and-the-devices-hold-both-sites"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-26&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Migration&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-complete"&gt;Complete&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The home backend Pi, &lt;code&gt;192.168.2.40&lt;/code&gt; on DVNT-CORE, with a new card named &lt;code&gt;dv01rpi001p01&lt;/code&gt; (the card in it now calls itself &lt;code&gt;dv02rpi003p01&lt;/code&gt;); &lt;code&gt;turntable-power-01&lt;/code&gt;, &lt;code&gt;cover-screen-01&lt;/code&gt;, &lt;code&gt;lp-stand-01&lt;/code&gt;, &lt;code&gt;respeaker-01&lt;/code&gt;; the tenant&amp;rsquo;s Terraform (one &lt;code&gt;deevnet_certificate&lt;/code&gt;); the home network&amp;rsquo;s DNS&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make -C deploy/backend image fetch card&lt;/code&gt;; &lt;code&gt;deevnet-kit cert request&lt;/code&gt; and &lt;code&gt;cert install&lt;/code&gt;; &lt;code&gt;terraform apply&lt;/code&gt; in &lt;code&gt;infra/deevnet-tenant-eds&lt;/code&gt;; &lt;code&gt;make pair spotify turntable drivers status devices&lt;/code&gt;; &lt;code&gt;provision_tenant.py --site home --also mobile=terraform&lt;/code&gt; on each device&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Medium. Most likely to go wrong: a device refusing the broker&amp;rsquo;s new certificate. No ESP32 has yet verified a server through Deevnet&amp;rsquo;s Tenant Service CA to the Root&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0033-the-whole-back-end-on-one-pi/"&gt;ADR-0033&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0049-a-device-holds-two-sites-and-is-told-which/"&gt;ADR-0049&lt;/a&gt;; Deevnet ADR-0040 (site-less names) and ADR-0041 §2 (a Deevnet Pi)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0028-the-back-end-on-one-pi-on-dvntm/"&gt;CHG-0028&lt;/a&gt;, which built the card this replaces; Deevnet CHG-0054 and CHG-0056, which built the names and the kit&amp;rsquo;s &lt;code&gt;cert&lt;/code&gt; commands&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The home Pi runs EdS on a card whose certificate is signed by that card&amp;rsquo;s own&#10;CA, for names entered by hand in the home DNS. The devices dial its address&#10;and trust that CA, and hold one site&amp;rsquo;s settings.&lt;/p&gt;</description></item><item><title>ADR-0043: The reSpeaker Runs Firmware of EdS's Own</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0043-the-respeaker-runs-firmware-of-edss-own/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0043-the-respeaker-runs-firmware-of-edss-own/</guid><description>&lt;h1 id="adr-0043-the-respeaker-runs-firmware-of-edss-own-and-sends-a-request-when-its-button-is-held-then-when-it-hears-its-name"&gt;ADR-0043: The reSpeaker Runs Firmware of EdS&amp;rsquo;s Own, and Sends a Request When Its Button Is Held, Then When It Hears Its Name&lt;a class="anchor" href="#adr-0043-the-respeaker-runs-firmware-of-edss-own-and-sends-a-request-when-its-button-is-held-then-when-it-hears-its-name"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10; — until a request said into the reSpeaker has played its album; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-24&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;What runs on the reSpeaker Lite&amp;rsquo;s XIAO ESP32-S3: how it hears, when it sends, and how it is provisioned and updated. Not what a request becomes, which is &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0042-a-request-is-heard-on-the-workload/"&gt;ADR-0042&lt;/a&gt;&amp;rsquo;s.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0042-a-request-is-heard-on-the-workload/"&gt;ADR-0042&lt;/a&gt;, whose &lt;code&gt;voice/&amp;lt;device&amp;gt;/utterance&lt;/code&gt; this sends&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0004-firmware-secrets-nvs-only/"&gt;ADR-0004&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0035-firmware-is-updated-through-the-broker/"&gt;ADR-0035&lt;/a&gt;, &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0034-presence-is-heard-not-remembered/"&gt;ADR-0034&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The reSpeaker Lite is two chips. An XMOS XU316 takes two microphones and&#10;gives one cleaned-up voice: echo cancelled, noise suppressed, beam steered.&#10;Its firmware (1.0.8, read over DFU on 2026-10-24) sends that over I2S to a&#10;XIAO ESP32-S3 (8 MB PSRAM, 8 MB flash), which came with an Arduino test&#10;sketch from Seeed. The XIAO is what can be programmed.&lt;/p&gt;</description></item><item><title>CHG-0043: The Backend Pi Names the Record the Recognizer Heard</title><link>https://cdeever.github.io/eds/docs/changes/2026/0043-the-backend-pi-names-the-record-the-recognizer-heard/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0043-the-backend-pi-names-the-record-the-recognizer-heard/</guid><description>&lt;h1 id="chg-0043-the-backend-pi-names-the-record-the-recognizer-heard"&gt;CHG-0043: The Backend Pi Names the Record the Recognizer Heard&lt;a class="anchor" href="#chg-0043-the-backend-pi-names-the-record-the-recognizer-heard"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-29&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Deployment&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-complete"&gt;Complete&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The home backend Pi, &lt;code&gt;eds-backend&lt;/code&gt; (&lt;code&gt;192.168.2.40&lt;/code&gt;): its five services and the agent&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make -C deploy/backend push&lt;/code&gt;, from the branch of PR #109&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: a service not coming back after the push, which &lt;code&gt;push.sh&lt;/code&gt; checks&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0038-the-turntable-names-the-original-album-by-what-is-on-it/"&gt;ADR-0038&lt;/a&gt;, as revised by PR #109&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0042-the-home-pi-becomes-a-deevnet-pi/"&gt;CHG-0042&lt;/a&gt;, during whose last check the fault was found&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;At the end of CHG-0042, Journey&amp;rsquo;s &amp;ldquo;Wheel in the Sky&amp;rdquo;, heard on &lt;em&gt;Infinity&lt;/em&gt;,&#10;was named &lt;em&gt;Alive in America&lt;/em&gt;, a live album, and the stand lit from its&#10;cover. Deezer lists the track on live albums, best-ofs and a 2008&#10;re-recording, never on &lt;em&gt;Infinity&lt;/em&gt;, and the recognizer&amp;rsquo;s album was asked&#10;about only when the catalog had nothing.&lt;/p&gt;</description></item><item><title>ADR-0044: The Music Is Turned Down While a Request Is Heard</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0044-the-music-is-turned-down-while-a-request-is-heard/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0044-the-music-is-turned-down-while-a-request-is-heard/</guid><description>&lt;h1 id="adr-0044-the-music-is-turned-down-while-a-request-is-heard-and-comes-back-by-itself"&gt;ADR-0044: The Music Is Turned Down While a Request Is Heard, and Comes Back by Itself&lt;a class="anchor" href="#adr-0044-the-music-is-turned-down-while-a-request-is-heard-and-comes-back-by-itself"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10; — until a request said over the music has been heard to its end and played; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-24&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;What happens to what is playing between the wake word and the answer: who says the device woke, which command lowers the music, and what brings it back.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0020-a-touch-screen-that-can-change-what-plays/"&gt;ADR-0020&lt;/a&gt;, whose commands this adds two to; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0042-a-request-is-heard-on-the-workload/"&gt;ADR-0042&lt;/a&gt; and &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0043-the-respeaker-runs-firmware-of-edss-own/"&gt;ADR-0043&lt;/a&gt;, whose request it is&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0040-a-request-can-name-an-album-to-play/"&gt;ADR-0040&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The reSpeaker&amp;rsquo;s XMOS chip cancels the echo of its own speaker, not of the&#10;stereo. With an album playing beside it, a request asked over the music was&#10;heard as speech until its six-second limit, sent at twice the size, and&#10;written down with the music in it (CHG-0037). Smart speakers lower their&#10;music while they listen. EdS&amp;rsquo;s music comes from players EdS controls.&lt;/p&gt;</description></item><item><title>CHG-0044: Spotify Is Switched From the Backend Pi's Console</title><link>https://cdeever.github.io/eds/docs/changes/2026/0044-spotify-is-switched-from-the-backend-pis-console/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0044-spotify-is-switched-from-the-backend-pis-console/</guid><description>&lt;h1 id="chg-0044-spotify-is-switched-from-the-backend-pis-console"&gt;CHG-0044: Spotify Is Switched From the Backend Pi&amp;rsquo;s Console&lt;a class="anchor" href="#chg-0044-spotify-is-switched-from-the-backend-pis-console"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-29&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Deployment&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-complete"&gt;Complete&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The home backend Pi, &lt;code&gt;eds-backend&lt;/code&gt; (&lt;code&gt;192.168.2.40&lt;/code&gt;): its services, the agent, and the broker accounts &lt;code&gt;eds-console&lt;/code&gt; and &lt;code&gt;eds-np-relay&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;make -C deploy/backend push&lt;/code&gt; and &lt;code&gt;make drivers DRIVERS=itunes,spotify,turntable&lt;/code&gt;, from the branch of PR #106&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: Spotify asked all day again, which the switch defaulting to off is there to prevent&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0051-spotify-is-switched-on-and-off-from-the-console/"&gt;ADR-0051&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0024-spotify-turned-off-again/"&gt;CHG-0024&lt;/a&gt;, whose follow-up this answers; &lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0043-the-backend-pi-names-the-record-the-recognizer-heard/"&gt;CHG-0043&lt;/a&gt;, the push before&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The backend Pi ran &lt;code&gt;4e51363&lt;/code&gt; and did not run the Spotify driver. After: it&#10;runs ADR-0051&amp;rsquo;s agent and console. Spotify is allowed in &lt;code&gt;NP_DRIVERS&lt;/code&gt;, and&#10;whether it runs is the console&amp;rsquo;s switch, off unless switched on.&lt;/p&gt;</description></item><item><title>ADR-0045: An Nth Album Not Owned Is the Next One That Is</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0045-an-nth-album-not-owned-is-the-next-one-that-is/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0045-an-nth-album-not-owned-is-the-next-one-that-is/</guid><description>&lt;h1 id="adr-0045-an-artists-nth-album-when-the-library-does-not-have-it-is-the-next-of-theirs-it-does"&gt;ADR-0045: An Artist&amp;rsquo;s Nth Album, When the Library Does Not Have It, Is the Next of Theirs It Does&lt;a class="anchor" href="#adr-0045-an-artists-nth-album-when-the-library-does-not-have-it-is-the-next-of-theirs-it-does"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10; — until a first album the library lacks has been asked for and the next one played; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-24&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;What &amp;ldquo;Genesis&amp;rsquo; first album&amp;rdquo; plays when the owner&amp;rsquo;s library does not have &lt;em&gt;From Genesis to Revelation&lt;/em&gt;.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0041-an-artists-nth-album-is-counted-in-musicbrainz/"&gt;ADR-0041&lt;/a&gt;, whose count this goes on along; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0040-a-request-can-name-an-album-to-play/"&gt;ADR-0040&lt;/a&gt;, whose command gains alternatives&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;&amp;ldquo;Genesis&amp;rsquo; first album&amp;rdquo; was heard right, twice, and counted right: &lt;em&gt;From&#10;Genesis to Revelation&lt;/em&gt;, 1969. The owner&amp;rsquo;s iTunes has it as its reissue,&#10;&lt;em&gt;And the Word Was…&lt;/em&gt;, and so was asked for a title it has not got. With&#10;nothing matched it played the band&amp;rsquo;s other songs from &lt;em&gt;Abacab&lt;/em&gt;, the first by&#10;name, which the driver rightly took for a miss; where nothing at all&#10;matches, having emptied its queue, it stops. The library cannot be asked what it&#10;has (&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0040-a-request-can-name-an-album-to-play/"&gt;ADR-0040&lt;/a&gt;),&#10;so a miss is only found by trying.&lt;/p&gt;</description></item><item><title>CHG-0045: The Backend Pi's iTunes Pairing Is Kept</title><link>https://cdeever.github.io/eds/docs/changes/2026/0045-the-backend-pis-itunes-pairing-is-kept/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0045-the-backend-pis-itunes-pairing-is-kept/</guid><description>&lt;h1 id="chg-0045-the-backend-pis-itunes-pairing-is-kept"&gt;CHG-0045: The Backend Pi&amp;rsquo;s iTunes Pairing Is Kept&lt;a class="anchor" href="#chg-0045-the-backend-pis-itunes-pairing-is-kept"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-29&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Deployment&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-complete"&gt;Complete&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The home backend Pi, &lt;code&gt;eds-backend&lt;/code&gt; (&lt;code&gt;192.168.2.40&lt;/code&gt;): its tools and its iTunes pairing; iTunes on MEDIA-SERVER, which gained a remote; the owner&amp;rsquo;s Mac, which gained an age key&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;secrets/new-key.sh&lt;/code&gt;; &lt;code&gt;make -C deploy/backend push&lt;/code&gt;, &lt;code&gt;make pair&lt;/code&gt;, &lt;code&gt;make pairing&lt;/code&gt;, from the branch of PR #107&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: the Pi left unpaired by a test, which a copy set aside guarded&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0052-each-pis-itunes-pairing-is-kept-encrypted-in-the-repository/"&gt;ADR-0052&lt;/a&gt;, and ADR-0037&amp;rsquo;s first step&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0044-spotify-is-switched-from-the-backend-pis-console/"&gt;CHG-0044&lt;/a&gt;, the push before&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The backend Pi&amp;rsquo;s iTunes pairing lived on its card alone, under the name&#10;&amp;ldquo;EdS&amp;rdquo;. After: it pairs as &amp;ldquo;EdS home&amp;rdquo;, and the pairing is kept in the&#10;repository, encrypted to the owner&amp;rsquo;s age key, so a new card for this Pi&#10;starts paired.&lt;/p&gt;</description></item><item><title>ADR-0046: Requests Are Matched Against the Owner's Library</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0046-requests-are-matched-against-the-owners-library/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0046-requests-are-matched-against-the-owners-library/</guid><description>&lt;h1 id="adr-0046-requests-are-matched-against-the-owners-library-as-its-xml-lists-it"&gt;ADR-0046: Requests Are Matched Against the Owner&amp;rsquo;s Library, as Its XML Lists It&lt;a class="anchor" href="#adr-0046-requests-are-matched-against-the-owners-library-as-its-xml-lists-it"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10; — until the requests below play on the first try; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-24&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;How voiced turns a heard artist and an album, or an album&amp;rsquo;s place, into the titles &lt;code&gt;play_album&lt;/code&gt; names.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0041-an-artists-nth-album-is-counted-in-musicbrainz/"&gt;ADR-0041&lt;/a&gt;, whose count orders the library&amp;rsquo;s albums; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0045-an-nth-album-not-owned-is-the-next-one-that-is/"&gt;ADR-0045&lt;/a&gt;, whose &lt;code&gt;instead&lt;/code&gt; carries the library&amp;rsquo;s titles now&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Every miss on 2026-10-24 was a guess at how the library spells something.&#10;iTunes will not list its library to EdS&#10;(&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0040-a-request-can-name-an-album-to-play/"&gt;ADR-0040&lt;/a&gt;),&#10;so voiced asked for MusicBrainz&amp;rsquo;s titles and the driver checked what played.&#10;Each fix covered the miss before it: Genesis&amp;rsquo; first is the reissue &lt;em&gt;And The&#10;Word Was&lt;/em&gt; in the library; Skynyrd&amp;rsquo;s is &lt;em&gt;Pronounced leh-nerd skin-nerd&lt;/em&gt;, not&#10;&amp;ldquo;(pronounced &amp;rsquo;lĕh-&amp;rsquo;nérd &amp;lsquo;skin-&amp;rsquo;nérd)&amp;rdquo;; &amp;ldquo;Arrowsmith&amp;rdquo; and &amp;ldquo;Leonard Skinner&amp;rdquo;&#10;are how speech writes two bands down.&lt;/p&gt;</description></item><item><title>CHG-0046: The Backend Pi Is on Its Cable Alone</title><link>https://cdeever.github.io/eds/docs/changes/2026/0046-the-backend-pi-is-on-its-cable-alone/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/changes/2026/0046-the-backend-pi-is-on-its-cable-alone/</guid><description>&lt;h1 id="chg-0046-the-backend-pi-is-on-its-cable-alone"&gt;CHG-0046: The Backend Pi Is on Its Cable Alone&lt;a class="anchor" href="#chg-0046-the-backend-pi-is-on-its-cable-alone"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-30&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Change type&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Configuration&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge status-complete"&gt;Complete&lt;/span&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Systems&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The home backend Pi, &lt;code&gt;eds-backend&lt;/code&gt;; the backend image (&lt;code&gt;images/backend&lt;/code&gt;) and &lt;code&gt;deploy/backend/card.sh&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;nmcli&lt;/code&gt; on the Pi, over its cable; the image&amp;rsquo;s playbook and &lt;code&gt;card.sh&lt;/code&gt; changed for the next card&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Low. Most likely to go wrong: the session that makes the change riding the Wi-Fi it removes, which connecting to the wired address prevents&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Decisions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;None of its own. It is ADR-0053&amp;rsquo;s &amp;ldquo;radio off by default&amp;rdquo; before that record&amp;rsquo;s window is built, and CHG-0028&amp;rsquo;s &amp;ldquo;one address at home&amp;rdquo;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0042-the-home-pi-becomes-a-deevnet-pi/"&gt;CHG-0042&lt;/a&gt;, whose card asked for Wi-Fi; &lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0028-the-back-end-on-one-pi-on-dvntm/"&gt;CHG-0028&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="summary"&gt;Summary&lt;a class="anchor" href="#summary"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The backend Pi had two addresses on the home network: &lt;code&gt;192.168.2.40&lt;/code&gt; on its&#10;cable and &lt;code&gt;192.168.2.228&lt;/code&gt; on Wi-Fi. Both were on DVNT-CORE. The Wi-Fi was&#10;&lt;code&gt;deevnet-kit-wifi&lt;/code&gt;, which deevnet-kit made on the first boot from the&#10;network &lt;code&gt;make card&lt;/code&gt; asked for. A second address on the same network bought&#10;nothing, appeared in the kit&amp;rsquo;s address warning, and could answer for&#10;&lt;code&gt;eds-backend.local&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>ADR-0047: voiced Asks eds-inventory</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0047-voiced-asks-eds-inventory/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0047-voiced-asks-eds-inventory/</guid><description>&lt;h1 id="adr-0047-voiced-asks-eds-inventory-for-the-owners-albums-in-place-of-its-own-index"&gt;ADR-0047: voiced Asks eds-inventory for the Owner&amp;rsquo;s Albums, in Place of Its Own Index&lt;a class="anchor" href="#adr-0047-voiced-asks-eds-inventory-for-the-owners-albums-in-place-of-its-own-index"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-green"&gt;Accepted&lt;/span&gt;&#10; 2026-10-24 — settled by &lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0041-voiced-asks-eds-inventory/"&gt;CHG-0041&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-24&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Where voiced finds the owner&amp;rsquo;s artists and albums when it turns a request into &lt;code&gt;play_album&lt;/code&gt;. Not how it parses a request, or counts an artist&amp;rsquo;s albums in MusicBrainz, which are unchanged.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0046-requests-are-matched-against-the-owners-library/"&gt;ADR-0046&lt;/a&gt;, whose matching moves to the inventory unchanged&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/proposals/music-inventory/"&gt;A Music Inventory&lt;/a&gt;, the proposal this begins; eds-inventory&amp;rsquo;s &lt;a href="https://cdeever.github.io/eds-inventory/docs/architecture/decisions/0002-the-itunes-library-is-collected-from-its-xml/"&gt;ADR-0002&lt;/a&gt; and &lt;a href="https://cdeever.github.io/eds-inventory/docs/architecture/decisions/0003-it-deploys-itself-to-eds-workload/"&gt;ADR-0003&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;voiced matches requests against &lt;code&gt;library.json&lt;/code&gt;, an index of the owner&amp;rsquo;s&#10;iTunes library that EdS makes from the XML and copies to voiced by hand&#10;(ADR-0046). Knowing what the owner has is an inventory concern, and&#10;&lt;a href="https://cdeever.github.io/eds-inventory/"&gt;eds-inventory&lt;/a&gt; now does it: it&#10;collects the same XML, keeps the same albums, and answers the four&#10;questions voiced asks with the same matching and thresholds, carried over&#10;from EdS&amp;rsquo;s &lt;code&gt;internal/library&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>ADR-0048: The Turntable Is Heard on Both Channels</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0048-the-turntable-is-heard-on-both-channels/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0048-the-turntable-is-heard-on-both-channels/</guid><description>&lt;h1 id="adr-0048-the-turntable-is-heard-on-both-channels-and-one-gone-silent-is-said-on-the-console"&gt;ADR-0048: The Turntable Is Heard on Both Channels, and One Gone Silent Is Said on the Console&lt;a class="anchor" href="#adr-0048-the-turntable-is-heard-on-both-channels-and-one-gone-silent-is-said-on-the-console"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10;, until a side has played through with one channel unplugged; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-25&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;How many channels the turntable&amp;rsquo;s driver listens to, what it decides from each, and how a channel gone silent is reported: a retained topic beside the source&amp;rsquo;s status, one event, and the console&amp;rsquo;s &amp;ldquo;Song detector&amp;rdquo; line. Not how silence, gaps or stops are timed, which is unchanged.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0026-what-silence-means-on-the-turntable/"&gt;ADR-0026&lt;/a&gt;, whose silence is now the louder channel&amp;rsquo;s, and &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0034-presence-is-heard-not-remembered/"&gt;ADR-0034&lt;/a&gt;, whose &amp;ldquo;Song detector&amp;rdquo; pill gains a third color for an input heard on one side only&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0018-a-console-of-eds-own/"&gt;ADR-0018&lt;/a&gt;, the console that only looks; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0021-the-turntable-is-identified-by-listening/"&gt;ADR-0021&lt;/a&gt;, the driver; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0017-an-agent-pi-is-a-registered-device/"&gt;ADR-0017&lt;/a&gt;, the agent&amp;rsquo;s events&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;&lt;strong&gt;On the evening of 2026-10-25 (about 01:34 UTC on the 26th) the stand went&#10;to standby in the middle of a side.&lt;/strong&gt; A record was playing, the Eagles'&#10;&lt;em&gt;Live&lt;/em&gt;, and the music could still be heard in the room. The turntable&amp;rsquo;s&#10;driver had heard twenty seconds below -55 dBFS and said &lt;code&gt;stopped&lt;/code&gt;, as&#10;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0026-what-silence-means-on-the-turntable/"&gt;ADR-0026&lt;/a&gt;&#10;has it do, and nowplayd dimmed the room a second later.&lt;/p&gt;</description></item><item><title>ADR-0049: A Device Holds Two Sites, and Is Told Which</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0049-a-device-holds-two-sites-and-is-told-which/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0049-a-device-holds-two-sites-and-is-told-which/</guid><description>&lt;h1 id="adr-0049-a-device-holds-two-sites-settings-and-is-told-which-to-use-by-a-message"&gt;ADR-0049: A Device Holds Two Sites&amp;rsquo; Settings, and Is Told Which to Use by a Message&lt;a class="anchor" href="#adr-0049-a-device-holds-two-sites-settings-and-is-told-which-to-use-by-a-message"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10;, until a device has been switched both ways and has undone a switch it could not complete; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-26&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;What a device&amp;rsquo;s &lt;code&gt;creds&lt;/code&gt; partition holds for more than one site, the keys it is held under, the message that switches a device from one site to the other, and what a device does when the switch fails. Not what is in a site&amp;rsquo;s settings, which is unchanged.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0004-firmware-secrets-nvs-only/"&gt;ADR-0004&lt;/a&gt;, whose partition now holds a second site&amp;rsquo;s secrets beside the first&amp;rsquo;s, and &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0035-firmware-is-updated-through-the-broker/"&gt;ADR-0035&lt;/a&gt;, whose topics, sender and undo-it-yourself rule a switch follows&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0033-the-whole-back-end-on-one-pi/"&gt;ADR-0033&lt;/a&gt;, the backend Pi that is the second site; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0034-presence-is-heard-not-remembered/"&gt;ADR-0034&lt;/a&gt;, whose status says where a device is&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;&lt;strong&gt;EdS&amp;rsquo;s devices now live at two sites.&lt;/strong&gt; The tenant&amp;rsquo;s broker at Deevnet&#10;IoTaaS&amp;rsquo;s mobile site, on its IoT network, and the backend Pi at home, on the&#10;home network. Each site has its own Wi-Fi, its own broker accounts and, until&#10;the home Pi took a certificate from Deevnet&amp;rsquo;s Tenant Service CA, its own CA.&lt;/p&gt;</description></item><item><title>ADR-0050: How Each Track Was Completed Is Written Down</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0050-how-each-track-was-completed-is-written-down/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0050-how-each-track-was-completed-is-written-down/</guid><description>&lt;h1 id="adr-0050-how-each-tracks-album-and-cover-were-found-is-written-down-one-line-a-track-and-nowplayd-sends-it-to-the-log-store"&gt;ADR-0050: How Each Track&amp;rsquo;s Album and Cover Were Found Is Written Down, One Line a Track, and nowplayd Sends It to the Log Store&lt;a class="anchor" href="#adr-0050-how-each-tracks-album-and-cover-were-found-is-written-down-one-line-a-track-and-nowplayd-sends-it-to-the-log-store"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10;, until the lines have been read on the dashboard from a side of a record; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-27&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;What &lt;code&gt;nowplayd&lt;/code&gt; writes down about completing a track: who named its album, where its cover came from, how long each step took and why one gave up; the owner&amp;rsquo;s collection being read; how those lines reach the tenant&amp;rsquo;s log store; the dashboard that reads them. Not how a track is completed, which is unchanged.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0027-what-is-asked-of-outside-services-is-counted/"&gt;ADR-0027&lt;/a&gt;, whose &lt;code&gt;api.calls&lt;/code&gt; was the only line &lt;code&gt;nowplayd&lt;/code&gt; sent to the store&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0008-nowplayd-arbitrates-and-enriches/"&gt;ADR-0008&lt;/a&gt;, the completing; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0022-the-owners-collection-names-the-record/"&gt;ADR-0022&lt;/a&gt;, the collection; &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0038-the-turntable-names-the-original-album-by-what-is-on-it/"&gt;ADR-0038&lt;/a&gt;, the original album&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;On the evening of 2026-10-26 the turntable played &amp;ldquo;Over the Hills and Far&#10;Away&amp;rdquo;, the recognizer named it, and the stand did not follow it: the track&#10;was published with no cover. Finding out why took the journal. &lt;em&gt;Houses of&#10;the Holy&lt;/em&gt; was not in the owner&amp;rsquo;s Discogs collection; naming its original&#10;album, through Deezer and then MusicBrainz at one call a second, used the&#10;whole lookup time; and the cover&amp;rsquo;s lookup had been given the same time,&#10;already spent. That last fault is fixed (eds#101). Nothing showed any of it.&lt;/p&gt;</description></item><item><title>ADR-0051: Spotify Is Switched On and Off From the Console</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0051-spotify-is-switched-on-and-off-from-the-console/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0051-spotify-is-switched-on-and-off-from-the-console/</guid><description>&lt;h1 id="adr-0051-spotify-is-switched-on-and-off-from-the-console-and-off-asks-spotify-nothing"&gt;ADR-0051: Spotify Is Switched On and Off From the Console, and Off Asks Spotify Nothing&lt;a class="anchor" href="#adr-0051-spotify-is-switched-on-and-off-from-the-console-and-off-asks-spotify-nothing"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-green"&gt;Accepted&lt;/span&gt;&#10;: switched both ways from the console&amp;rsquo;s page on the backend Pi, 2026-10-29 (&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0044-spotify-is-switched-from-the-backend-pis-console/"&gt;CHG-0044&lt;/a&gt;); see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-28&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;A switch for the Spotify driver: where its state is kept, what &amp;ldquo;off&amp;rdquo; stops, who reads it, and the console&amp;rsquo;s second control.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0039-the-console-can-light-the-stand-for-every-source/"&gt;ADR-0039&lt;/a&gt;: a second retained setting, and the console&amp;rsquo;s second control, which that record said would bring back the question of a login.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0024-spotify-turned-off-again/"&gt;CHG-0024&lt;/a&gt;, whose follow-up this is. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0027-what-is-asked-of-outside-services-is-counted/"&gt;ADR-0027&lt;/a&gt;, whose count shows the switch working. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0020-a-touch-screen-that-can-change-what-plays/"&gt;ADR-0020&lt;/a&gt;, whose commands are never retained; this is not one of them. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0034-presence-is-heard-not-remembered/"&gt;ADR-0034&lt;/a&gt;.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The Spotify driver asks Spotify what is playing every ten seconds, all day,&#10;whether or not anything plays. Its owner does not want that all the time,&#10;and does want Spotify followed sometimes.&lt;/p&gt;</description></item><item><title>ADR-0052: Each Pi's iTunes Pairing Is Kept, Encrypted, in the Repository</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0052-each-pis-itunes-pairing-is-kept-encrypted-in-the-repository/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0052-each-pis-itunes-pairing-is-kept-encrypted-in-the-repository/</guid><description>&lt;h1 id="adr-0052-each-pis-itunes-pairing-is-kept-encrypted-in-the-repository-and-a-new-card-starts-paired"&gt;ADR-0052: Each Pi&amp;rsquo;s iTunes Pairing Is Kept, Encrypted, in the Repository, and a New Card Starts Paired&lt;a class="anchor" href="#adr-0052-each-pis-itunes-pairing-is-kept-encrypted-in-the-repository-and-a-new-card-starts-paired"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-green"&gt;Accepted&lt;/span&gt;&#10;: a pairing kept, put on a card&amp;rsquo;s boot partition and taken by the first boot&amp;rsquo;s setup, with nobody at iTunes, 2026-10-29 (&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0045-the-backend-pis-itunes-pairing-is-kept/"&gt;CHG-0045&lt;/a&gt;); see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-28&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Where an agent&amp;rsquo;s iTunes pairing is kept between cards, how it reaches a new card, and one pairing per Pi. Not Spotify&amp;rsquo;s authorization, and not the other hand-kept secrets.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0037-hand-kept-secrets-are-encrypted-in-the-repository/"&gt;ADR-0037&lt;/a&gt;: its &lt;code&gt;secrets/&lt;/code&gt;, its age key and &lt;code&gt;sops&lt;/code&gt; are built here, for this first secret. A pairing is &amp;ldquo;made where it is used&amp;rdquo;, which that record leaves where it is made; this record says why a pairing is kept anyway. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0011-itunes-by-remote-pairing/"&gt;ADR-0011&lt;/a&gt;, whose consequence &amp;ldquo;lose it and pairing is repeated&amp;rdquo; this ends.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0010-home-lan-relay/"&gt;ADR-0010&lt;/a&gt;, the relay Pi. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0033-the-whole-back-end-on-one-pi/"&gt;ADR-0033&lt;/a&gt;, the backend Pi.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The iTunes driver controls iTunes as a paired remote (ADR-0011). Pairing&#10;takes a person at the iTunes PC, typing a four-digit code that the Pi&#10;prints. What it leaves behind is one small file on the Pi,&#10;&lt;code&gt;/var/lib/eds-npagent/itunes-pairing.json&lt;/code&gt;:&lt;/p&gt;</description></item><item><title>ADR-0053: A Home Pi Opens a Maintenance Leg for the Van</title><link>https://cdeever.github.io/eds/docs/architecture/decisions/0053-a-home-pi-opens-a-maintenance-leg-for-the-van/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cdeever.github.io/eds/docs/architecture/decisions/0053-a-home-pi-opens-a-maintenance-leg-for-the-van/</guid><description>&lt;h1 id="adr-0053-a-home-pi-opens-a-maintenance-leg-for-the-van-for-a-while-when-asked-from-inside"&gt;ADR-0053: A Home Pi Opens a Maintenance Leg for the Van, for a While, When Asked From Inside&lt;a class="anchor" href="#adr-0053-a-home-pi-opens-a-maintenance-leg-for-the-van-for-a-while-when-asked-from-inside"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;span class="status-badge inc-orange"&gt;Proposed&lt;/span&gt;&#10;: until a window has been opened, used and closed on the backend Pi; see &lt;a href="#what-would-settle-it"&gt;What would settle it&lt;/a&gt;. It takes effect when the Pi&amp;rsquo;s cable leaves DVNT-CORE&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Date&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2026-10-28&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Scope&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;How the mobile site reaches an EdS Pi that lives at home: a Wi-Fi leg onto the home LAN, off unless opened, and what it admits. The day-2 jobs that use it are named here and decided elsewhere.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Extends&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0010-home-lan-relay/"&gt;ADR-0010&lt;/a&gt;: a second leg, fenced, now off by default and opened for a time. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0033-the-whole-back-end-on-one-pi/"&gt;ADR-0033&lt;/a&gt;: the backend Pi, now at home.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Related&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0042-the-home-pi-becomes-a-deevnet-pi/"&gt;CHG-0042&lt;/a&gt;, which moves the backend Pi home. &lt;a href="https://cdeever.github.io/eds/docs/changes/2026/0028-the-back-end-on-one-pi-on-dvntm/"&gt;CHG-0028&lt;/a&gt;, which chose one address at home. &lt;a href="https://cdeever.github.io/eds/docs/architecture/decisions/0052-each-pis-itunes-pairing-is-kept-encrypted-in-the-repository/"&gt;ADR-0052&lt;/a&gt;, one of the jobs. Deevnet ADR-0011, ADR-0013, ADR-0020 and ADR-0041, and Deevnet&amp;rsquo;s network segmentation standard.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The backend Pi has moved home (CHG-0042), and others may follow. At home&#10;it is on the home LAN, DVNT-CORE (&lt;code&gt;192.168.2.0/23&lt;/code&gt;, behind the home&#10;OPNsense). Its certificate, its tenant&amp;rsquo;s Terraform and the tools that&#10;look after it are on the mobile site, dvntm.&lt;/p&gt;</description></item></channel></rss>