Phase 7: authored assets (diagrams, code exhibits, client wall, budget)

Phase 7 is mostly authored assets. This commit is the asset half; the
template half is a Builder child issue because this phase must not write
application code.

DoD items satisfied or advanced:

- [x] Eight diagrams present, both themes, readable at 1x and on mobile
      8 SVGs, one byte-identical <style> block across all 8 (one visual
      language by construction). Light and dark resolve from a single file
      via prefers-color-scheme, verified per file in Chrome: 8/8 return two
      distinct palettes. Geometry verified with getBBox(), not estimated:
      0 findings after fixing 74 (text overflow, partial overlap, empty
      text, out-of-viewBox). Mobile type at the 900px minimum is 14.1/12.2px.

- [x] Six code exhibits with a two-sentence rationale each
      212 verbatim lines across five eras, copied with cp/sed from the
      read-only archive. Every rationale is exactly two sentences about why
      the code is good; every exhibit also carries an honest_note, and where
      the code is not good the note says so (the 3,400-line procedural PHP
      script is presented for its operational judgement, not its structure).

- [~] Every image optimised; total page weight budgeted and recorded
      BUDGET.md records measured raw and gzip weights for all 15 served
      files: 63,802 B raw / 13,220 B gzipped. Zero rasters by design. Page
      weight of a real page is not measurable until Phase 2 templates and
      Phase 3 serving exist, and is recorded as open rather than asserted.

- [x] Archive never linked or exposed
      No mount paths or volume names under content/. Provenance recorded as
      "private archive, path withheld".

- [ ] Client wall reads as deliberate  -> needs markup/CSS (Builder)
- [ ] Lighthouse held at >= 95/95      -> needs a served page (Phase 3)

Also: the client wall is authored as data (45 entries, 44 distinct names) with
the 45-vs-46 discrepancy and the Diajio -> Diageo correction recorded
rather than papered over. No commercial marks are enabled: that is a
permission decision for Sam, so availability is recorded and permission is not
implied.
This commit is contained in:
Documenter
2026-10-26 17:35:11 +11:00
parent b267e55f8c
commit da18ab2237
22 changed files with 1711 additions and 0 deletions

View File

@@ -0,0 +1,111 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 540" width="960" height="540" role="img" aria-labelledby="ttl dsc">
<title id="ttl">Distributed audio</title>
<desc id="dsc">Music and speech sources feed one Snapcast server, which streams one clock-synchronised mix to eight Pi endpoints. Voice announcements arrive as a priority lane: duck the music, speak, restore.</desc>
<style>
text{font-family:ui-sans-serif,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;fill:#1b222b;font-size:15px}
.hd{font-size:15px;font-weight:600}
.sub{font-size:13px;fill:#5b6673}
.cap{font-size:12px;fill:#5b6673;letter-spacing:.06em;text-transform:uppercase;font-weight:600}
.big{font-size:19px;font-weight:600}
.node{fill:#f4f6f8;stroke:#c3ccd6;stroke-width:1.4}
.node-a{fill:#e9f1fd;stroke:#1a6bc4;stroke-width:1.4}
.node-t{fill:#e6f4f2;stroke:#0f766e;stroke-width:1.4}
.node-w{fill:#fdf1e3;stroke:#b45309;stroke-width:1.4}
.zone{fill:none;stroke:#aab4c0;stroke-width:1.4;stroke-dasharray:7 6}
.rule{stroke:#d0d7df;stroke-width:1}
.ln{stroke:#6b7684;stroke-width:1.6;fill:none}
.ln.d{stroke-dasharray:6 5}
.ln.a{stroke:#1a6bc4}
.ln.t{stroke:#0f766e}
.ln.w{stroke:#b45309}
.mN{fill:#6b7684}
.mA{fill:#1a6bc4}
.mT{fill:#0f766e}
.mW{fill:#b45309}
.dot{fill:#6b7684}
.tick{stroke:#aab4c0;stroke-width:1.2}
@media (prefers-color-scheme: dark){
text{fill:#e7edf4}
.sub,.cap{fill:#98a4b3}
.node{fill:#182028;stroke:#35424f}
.node-a{fill:#11253d;stroke:#5aa2f0}
.node-t{fill:#0d2624;stroke:#38b3a6}
.node-w{fill:#2a1d10;stroke:#d98b3f}
.zone{stroke:#43525f}
.rule{stroke:#2c3743}
.ln{stroke:#8496a6}
.ln.a{stroke:#5aa2f0}
.ln.t{stroke:#38b3a6}
.ln.w{stroke:#d98b3f}
.mN{fill:#8496a6}
.mA{fill:#5aa2f0}
.mT{fill:#38b3a6}
.mW{fill:#d98b3f}
.dot{fill:#8496a6}
.tick{stroke:#43525f}
}
</style>
<defs>
<marker id="aN" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path class="mN" d="M0,0 L10,5 L0,10 z"/></marker>
<marker id="aA" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path class="mA" d="M0,0 L10,5 L0,10 z"/></marker>
<marker id="aT" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path class="mT" d="M0,0 L10,5 L0,10 z"/></marker>
<marker id="aW" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path class="mW" d="M0,0 L10,5 L0,10 z"/></marker>
</defs>
<text x="24" y="40" class="big">Distributed audio — sources, synchronous endpoints, voice injection</text>
<rect x="24" y="92" width="200" height="120" rx="7" class="node "/>
<text x="38" y="118" class="hd">Sources</text>
<path d="M24,130 L224,130" class="rule"/>
<text x="38" y="156" class="sub">Spotify → Mopidy</text>
<text x="38" y="180" class="sub">Piper / MiniMax TTS</text>
<text x="38" y="204" class="sub">announcements</text>
<path d="M224,152 L268,152" class="ln " marker-end="url(#aN)"/>
<rect x="268" y="92" width="210" height="120" rx="7" class="node "/>
<text x="282" y="118" class="hd">Snapcast server</text>
<text x="282" y="138" class="sub">one clock, one stream</text>
<path d="M268,150 L478,150" class="rule"/>
<text x="282" y="176" class="sub">per-client latency offset</text>
<text x="282" y="198" class="sub">new clients join mid-stream</text>
<path d="M478,152 L522,152" class="ln t" marker-end="url(#aT)"/>
<rect x="522" y="74" width="414" height="156" rx="7" class="node "/>
<text x="536" y="100" class="hd">8 endpoints — Pi 2W</text>
<text x="536" y="120" class="sub">one stream, eight speakers, in sync</text>
<path d="M522,132 L936,132" class="rule"/>
<rect x="536" y="146" width="42" height="42" rx="7" class="node "/>
<text x="557.0" y="172.0" class="hd" text-anchor="middle">1</text>
<rect x="586" y="146" width="42" height="42" rx="7" class="node "/>
<text x="607.0" y="172.0" class="hd" text-anchor="middle">2</text>
<rect x="636" y="146" width="42" height="42" rx="7" class="node "/>
<text x="657.0" y="172.0" class="hd" text-anchor="middle">3</text>
<rect x="686" y="146" width="42" height="42" rx="7" class="node "/>
<text x="707.0" y="172.0" class="hd" text-anchor="middle">4</text>
<rect x="736" y="146" width="42" height="42" rx="7" class="node "/>
<text x="757.0" y="172.0" class="hd" text-anchor="middle">5</text>
<rect x="786" y="146" width="42" height="42" rx="7" class="node "/>
<text x="807.0" y="172.0" class="hd" text-anchor="middle">6</text>
<rect x="836" y="146" width="42" height="42" rx="7" class="node "/>
<text x="857.0" y="172.0" class="hd" text-anchor="middle">7</text>
<rect x="886" y="146" width="42" height="42" rx="7" class="node "/>
<text x="907.0" y="172.0" class="hd" text-anchor="middle">8</text>
<text x="536" y="214" class="sub">music in one room does not arrive in another room late</text>
<rect x="24" y="262" width="470" height="152" rx="7" class="node node-t"/>
<text x="38" y="288" class="hd">Voice injection — the part that is not just streaming</text>
<rect x="38" y="304" width="136" height="38" rx="7" class="node "/>
<text x="106.0" y="328.0" class="hd" text-anchor="middle">TTS audio in</text>
<path d="M174,323 L200,323" class="ln t" marker-end="url(#aT)"/>
<rect x="200" y="304" width="126" height="38" rx="7" class="node "/>
<text x="263.0" y="328.0" class="hd" text-anchor="middle">duck music</text>
<path d="M326,323 L352,323" class="ln t" marker-end="url(#aT)"/>
<rect x="352" y="304" width="120" height="38" rx="7" class="node "/>
<text x="412.0" y="328.0" class="hd" text-anchor="middle">announce</text>
<text x="38" y="372" class="sub">then restore the music to its previous level</text>
<text x="38" y="392" class="sub">an announcement is a priority lane over the music</text>
<rect x="516" y="262" width="420" height="152" rx="7" class="node "/>
<text x="530" y="288" class="hd">Why it is built this way</text>
<text x="530" y="312" class="sub">· one source of time, not one source of audio</text>
<text x="530" y="336" class="sub">· endpoints are disposable; the server holds the state</text>
<text x="530" y="360" class="sub">· voice reuses the same endpoint fleet</text>
<text x="530" y="384" class="sub">· ducking is a mix decision, not a volume hack</text>
<text x="24" y="452" class="sub">Eight synchronised endpoints with music ducking for voice.</text>
<text x="24" y="472" class="sub">The endpoints are the cheapest part of the system, which is the point.</text>
<text x="936" y="500" class="sub" text-anchor="end">confidence: delivered · 8 endpoints · Pi 2W</text>
</svg>

After

Width:  |  Height:  |  Size: 6.7 KiB