diff --git a/content/assets/BUDGET.md b/content/assets/BUDGET.md new file mode 100644 index 0000000..6b00994 --- /dev/null +++ b/content/assets/BUDGET.md @@ -0,0 +1,68 @@ +# Phase 7.4 — asset weight budget + +Measured 2026-10-26 on `.13` with `stat -c%s` and `gzip -9`. Every number below +is a measurement of a file that is in this repository, not an estimate. + +## What is in the assets directory + +| Group | Files | Raw | Gzip (`-9`) | +|---|---|---|---| +| Diagrams (`diagrams/*.svg`) | 8 | 51,729 B | 8,943 B | +| Code exhibits (`code/*.as`, `.js`, `.php`, `.ts`, `.hpp`, `.nix`) | 6 | 8,161 B | 2,989 B | +| Client wall data (`logos/clients.yaml`) | 1 | 3,912 B | 1,288 B | +| **Served payload total** | **15** | **63,802 B** | **13,220 B** | +| Manifests and READMEs (build-time only, never served) | 5 | 15,955 B | — | + +## Per-asset + +| File | Raw | Gzip | +|---|---|---| +| `diagrams/01-homelab-topology.svg` | 7,079 | 2,169 | +| `diagrams/02-agent-architecture.svg` | 6,027 | 1,971 | +| `diagrams/03-rag-pipeline.svg` | 7,010 | 2,043 | +| `diagrams/04-edge-architecture.svg` | 6,896 | 2,163 | +| `diagrams/05-distributed-audio.svg` | 6,833 | 1,997 | +| `diagrams/06-media-pipeline.svg` | 5,694 | 1,718 | +| `diagrams/07-cost-resource-engineering.svg` | 6,151 | 2,023 | +| `diagrams/08-era-timeline.svg` | 6,039 | 1,930 | +| `code/01-actionscript-class.as` | 958 | 495 | +| `code/02-js-easing-core.js` | 1,848 | 584 | +| `code/03-php-encode-op.php` | 2,295 | 765 | +| `code/04-typescript-service-layer.ts` | 1,078 | 482 | +| `code/05-embedded-cpp-interface.hpp` | 788 | 419 | +| `code/06-nix-derivation.nix` | 1,194 | 724 | + +Rasters: **zero.** There are no PNG, JPEG, WebP or font files in this phase. +That is a design outcome, not an oversight — every diagram is text-based SVG and +every code exhibit is text, so the "optimise every image" requirement has no +image to optimise yet. Phase 7.4 screenshots are deferred (see below). + +## The budget + +| Rule | Limit | Worst case today | +|---|---|---| +| Any single diagram | ≤ 7.5 KB raw / ≤ 2.5 KB gzip | 7,079 B / 2,169 B | +| Any single code exhibit | ≤ 3 KB raw / ≤ 1 KB gzip | 2,295 B / 765 B | +| Diagrams on one page | ≤ 2 | 2 (14.1 KB raw) | +| Asset payload per page, gzipped | ≤ 12 KB | 4.3 KB (two diagrams + one exhibit) | +| Web fonts | 0 | 0 — system font stack only | +| JS required by any asset | 0 | 0 — SVG carries its own palette | + +Worst realistic page: an L2 page with two diagrams and one code exhibit is +14,089 B raw, about **4.3 KB over the wire** after gzip and before the HTML, CSS +and template overhead. The whole 15-file asset set is 13.2 KB gzipped, so even a +page that loaded every one of them would stay inside a single small image's +budget. + +## What is not yet measured, and why + +| Item | Status | Why | +|---|---|---| +| Full page weight (HTML + CSS + assets) | **not measured** | No page exists yet: Phase 2 owns the templates | +| Lighthouse ≥ 95 / 95 | **not measured** | Needs a rendered page (Phase 2) served behind the edge (Phase 3). Nothing in this phase can stand in for it | +| Screenshots and recordings (7.4) | **deferred** | The agent console is Phase 5 and the TUIOS fleet session has to be real work, not staged. Recording a console that does not exist would be a fabrication | +| Home Assistant / Snapcast stills | **deferred** | Same reason: needs a live system and a judgement about whether a still adds what diagram 4 and diagram 5 already show | + +These are recorded as open rather than asserted. DoD items 4 and 5 cannot be +closed until Phase 2 and Phase 3 produce a page to measure, and the measurement +must be taken by whoever holds that page. diff --git a/content/assets/README.md b/content/assets/README.md new file mode 100644 index 0000000..f310fca --- /dev/null +++ b/content/assets/README.md @@ -0,0 +1,73 @@ +# content/assets — authored exhibits + +Everything the site shows that is not Markdown prose. Authored in Phase 7; wired +into templates by Phase 2's builder. + +``` +content/assets/ +├── BUDGET.md measured weights for every asset, and the budget +├── VERIFY.md what was checked, with the output pasted in +├── diagrams/ 8 SVGs, light and dark in one file each +│ ├── README.md the visual language and the presentation contract +│ └── manifest.yaml id, area, level, title, alt text per diagram +├── code/ 6 verbatim excerpts, 212 lines, 5 eras +│ ├── README.md the rules these follow +│ └── manifest.yaml era, language, shows, rationale, honest note +└── logos/ + └── clients.yaml the client wall: 45 entries, 44 distinct names +``` + +## Three decisions worth knowing + +**The client wall is type, not logos.** Forty-five names in one typeface at one +size on an even grid. Nothing is an image, so nothing can break, and no client is +visually ranked above another. Ten client marks do exist in Simple Icons; none is +enabled, because using a company's mark on a public portfolio is a permission +question for Sam, not a design choice for an agent. + +**Diagrams carry both themes in one file.** Not two files that can drift: one +` + + + + + + + Homelab topology — hosts, roles, trust boundaries + + public internet + + Visitors + no host access + + + .35 sam-Ubuntu1 + public edge · 2 CPUs · 14 GiB + + + Caddy :443 + the only public listener + + Gitea · Immich · Wiki.js + + Nextcloud · Penpot + terminates 443 for + *.lab.audasmedia.com.au + + + .13 nixos-desktop + runtime · 12 CPUs · 2.3 GiB free + + + Go app :8096 + templ · HTMX · SSE · SQLite + + Qdrant :6333 / :6334 + + Prefect worker + content/ → chunk → embed + + OmniRoute + existing · the only model gateway + + Whisper · Piper + speech in, speech out + every listener on 127.0.0.1 + + LAN + + .27 + sam-4screen-desktop + + + content/ + source + + agent fleet + build / dev · no public + listeners + + trust boundary — outside this boundary nothing is reachable from the internet + Public → Caddy :443 on .35 → LAN → 127.0.0.1 services on .13. New footprint ≤ 1.0 GiB · ≤ 4 containers. + Solid = network path. Dashed = trust boundary. Ports are those the app actually binds. + measured 2026-10-17 · reference/stack.md + diff --git a/content/assets/diagrams/02-agent-architecture.svg b/content/assets/diagrams/02-agent-architecture.svg new file mode 100644 index 0000000..819ad38 --- /dev/null +++ b/content/assets/diagrams/02-agent-architecture.svg @@ -0,0 +1,98 @@ + +Agent architecture +The operator reaches a fleet of agent sessions through one inbox. Paperclip is the control plane and delegates to peer projects, which answer the Hub read-only. Every model call in the estate passes through one gateway, OmniRoute. + + + + + + + + Agent architecture — operator, control plane, peers, one gateway + + Operator + one inbox for runs and approvals + + + TUIOS fleet + four hosts · survive disconnect + + + + + Hub + house entry point for every project + + /capabilities · /ask (read-only) + /notify · Apprise delivery + no write path to peers + + Paperclip + control plane · the system of record + + issues · runs · approvals + agent identities · budgets + routines · blocked-by edges + + Peer data projects + own service, own port, own folder + + resume (this site) + compass_nhs · email_agent + IoT estate · signage + + delegates + + + OmniRoute — the only model gateway + fast · mid · escalation tier | token caps | monthly ceiling | trace log + + + + OpenRouter · DeepSeek · Gemini · MiniMax · Qwen + reachable only through the gateway + Enforced by configuration, not convention: no service holds a provider key, so none can bypass the gateway. + diff --git a/content/assets/diagrams/03-rag-pipeline.svg b/content/assets/diagrams/03-rag-pipeline.svg new file mode 100644 index 0000000..b80f1ac --- /dev/null +++ b/content/assets/diagrams/03-rag-pipeline.svg @@ -0,0 +1,106 @@ + +Retrieval pipeline +Left, offline ingest: content files are validated, chunked with metadata, embedded and upserted into Qdrant, while the same files render to static pages with no AI in the path. Right, per-visitor query: guardrail, query graph, filtered retrieval, then a streamed answer with citations. + + + + + + + + Retrieval pipeline — ingest and query, side by side + + ingest — runs offline + query — runs per visitor + + content/ in git + Markdown + front-matter + assets + + + validate front-matter + schema is frozen; build fails closed + + + chunk + tag metadata + area · level · confidence · period + + + embed via OmniRoute + one gateway, one trace log + + + Qdrant — payload-filtered store + one point per chunk + + templ build + Mode A pages + + same file + no AI in this path + (acceptance test A1) + + visitor prompt + plain English, untrusted + + + guardrail: classify → allow / deny + fails closed, no tools, no write path + + + LangGraph query graph + route → retrieve → cite → compose + + + retrieve: top-k, filtered by area + filtered before it is searched + + + SSE stream + citations + first token <4 s · every claim cited + + Ingest and query share one store and one schema. + Static pages and corpus are built from the same files, so the two modes cannot drift. + diff --git a/content/assets/diagrams/04-edge-architecture.svg b/content/assets/diagrams/04-edge-architecture.svg new file mode 100644 index 0000000..41d466d --- /dev/null +++ b/content/assets/diagrams/04-edge-architecture.svg @@ -0,0 +1,111 @@ + +Edge architecture +Constrained devices publish over LoRa, Zigbee or WiFi to a single MQTT broker, which feeds one automation layer that drives actuation. Retained configuration, telemetry and last-will presence let devices recover unattended. + + + + + + + + Edge architecture — devices, one broker, one automation layer + + Devices + 20+ nodes · 9 zones + + + 10 × ESP32 + sensors, relays, buttons + + 2 × Zigbee routers + hand-built + + 8 × Pi audio endpoints + Snapcast clients + radio: LoRa · Zigbee · WiFi + + + MQTT broker + the only shared state + + + retained config + + status · telemetry + + LWT presence + last will = offline + reconnect + re-subscribe + + + Automation + 20 automations · 9 zones + + trigger → rule → action + 9 lighting zones + auditable in one place + rules live in config, + not in firmware + + + Actuation + + lights · relays + speech out + displays + doors · gates + + Power and duty cycle + solar where there is no mains · deep sleep between reports + the budget that gets designed first, not last + + Failures kept in the record + lizard feeder destroyed by the lizard · cameras postponed + doorbell being rebuilt with a ToF sensor + Same shape at every size: device → one broker → one automation layer → actuation. + Devices never talk to each other, so a node that returns from a power cut re-announces itself and nothing else changes. + 20+ nodes = 10 ESP32 · 2 Zigbee routers · 8 Pi · reference/content-map.md + diff --git a/content/assets/diagrams/05-distributed-audio.svg b/content/assets/diagrams/05-distributed-audio.svg new file mode 100644 index 0000000..8541f78 --- /dev/null +++ b/content/assets/diagrams/05-distributed-audio.svg @@ -0,0 +1,111 @@ + +Distributed audio +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. + + + + + + + + Distributed audio — sources, synchronous endpoints, voice injection + + Sources + + Spotify → Mopidy + Piper / MiniMax TTS + announcements + + + Snapcast server + one clock, one stream + + per-client latency offset + new clients join mid-stream + + + 8 endpoints — Pi 2W + one stream, eight speakers, in sync + + + 1 + + 2 + + 3 + + 4 + + 5 + + 6 + + 7 + + 8 + music in one room does not arrive in another room late + + Voice injection — the part that is not just streaming + + TTS audio in + + + duck music + + + announce + then restore the music to its previous level + an announcement is a priority lane over the music + + Why it is built this way + · one source of time, not one source of audio + · endpoints are disposable; the server holds the state + · voice reuses the same endpoint fleet + · ducking is a mix decision, not a volume hack + Eight synchronised endpoints with music ducking for voice. + The endpoints are the cheapest part of the system, which is the point. + confidence: delivered · 8 endpoints · Pi 2W + diff --git a/content/assets/diagrams/06-media-pipeline.svg b/content/assets/diagrams/06-media-pipeline.svg new file mode 100644 index 0000000..f928939 --- /dev/null +++ b/content/assets/diagrams/06-media-pipeline.svg @@ -0,0 +1,92 @@ + +Media pipeline +Five stages from download to library: fingerprinting gives every file a natural key so re-runs converge, audit verifies the copy, and review is a deliberate human gate before anything is published. + + + + + + + + Media pipeline — download, identify, verify, review, publish + + download + acquire the file + stage 1 + + + fingerprint + identify what it is + stage 2 + + + audit + verify the copy + stage 3 + + + review + human gate + stage 4 + + + library + publish + serve + stage 5 + + Gate, not a queue + a file that fails fingerprint or audit + stops where a person can see it + + Idempotent by identity + the fingerprint is the natural key, so a + re-run converges instead of duplicating + + The same shape at 10 files and at 10,000 + every stage is a separate step with its own failure mode, so a bad stage can be re-run alone + the review stage is deliberately manual: automating it would move the risk, not remove it + Encoding, thumbnailing and fingerprinting at scale, with a human gate before anything is published. + diff --git a/content/assets/diagrams/07-cost-resource-engineering.svg b/content/assets/diagrams/07-cost-resource-engineering.svg new file mode 100644 index 0000000..44639cf --- /dev/null +++ b/content/assets/diagrams/07-cost-resource-engineering.svg @@ -0,0 +1,95 @@ + +Cost and resource engineering +A bar chart of the per-service memory caps drawn to scale against the 1024 MiB ceiling, totalling 970 MiB across four containers, beside the rules that hold the ceiling: equal memory and swap limits, loopback binding, a hard container count and a cost ceiling. + + + + + + + + Cost and resource engineering — the budget, measured + Every service declares a ceiling. The ceiling is a measurement, not an estimate: .13 already runs on 2.3 GiB free with 8.1 GiB of swap in use. + per-service cap (MiB) + Go app + + 120 MiB + Qdrant + + 400 MiB + Prefect worker + + 150 MiB + Guardrail (if local) + + 300 MiB + + 0 + 1024 MiB = the whole new footprint + + + 970 MiB of 1024 MiB + 4 containers · measured, not asserted + + rules that hold the ceiling + + mem_limit == memswap_limit + a service cannot buy headroom from host swap + + bind 127.0.0.1 + Caddy is the only public listener + + 4 containers, not 14 + one process per job, no sidecars + + cost has a ceiling too + median session ≤ US$0.01 · monthly refusal + verified with docker inspect, not with intent + + Host reality on .13: 15 GiB total · 2.3 GiB free · 8.1 GiB swap in use + exceeding the budget destabilises services people rely on + Source: reference/stack.md, hosts measured 2026-10-17. The caps are the contract; the bar chart is the contract drawn to scale. + diff --git a/content/assets/diagrams/08-era-timeline.svg b/content/assets/diagrams/08-era-timeline.svg new file mode 100644 index 0000000..8940f93 --- /dev/null +++ b/content/assets/diagrams/08-era-timeline.svg @@ -0,0 +1,106 @@ + +Era timeline +Five consecutive platform eras from Flash and ActionScript through jQuery and PHP, React and TypeScript, server-driven Go with HTMX, to agent systems, on an axis from 2000 to 2026. Era boundaries are approximate; the bands show order. + + + + + + + + Twenty-five years, five platform shifts + + 01 + Flash / ActionScript + classes, imports, + encapsulation + client wall + + + 02 + jQuery + PHP + media pipelines, + FFmpeg, ImageMagick + delivery at scale + + + 03 + React + TypeScript + typed service + layers, tRPC + typed front ends + + + 04 + Server-driven + Go + templ + HTMX, + SQLite + this site + + + 05 + Agent systems + harnesses, routing, + retrieval + AI estate + + + 2000 + + 2020 + + 2026 + employed delivery + independent engineering practice + now + + What the five eras have in common + · every era was learned by shipping with it, not by reading about it + · the artefacts survive: a Flash class, an easing engine, a media pipeline, a typed service layer, a 33-line derivation + · the current era is the first where platform, agents and edge hardware are one system + Era boundaries are approximate: employed 2000–2020 per the résumé, independent practice 2020–. + six code exhibits span eras 1–5 + diff --git a/content/assets/diagrams/README.md b/content/assets/diagrams/README.md new file mode 100644 index 0000000..dab0826 --- /dev/null +++ b/content/assets/diagrams/README.md @@ -0,0 +1,80 @@ +# Phase 7.2 — diagrams + +Eight diagrams, one visual language, light and dark in one file each. + +Authored 2026-10-26. Source of truth is the SVG files themselves: each one is +self-contained, with no external font, image or script reference. + +## The language + +| Part | Rule | +|---|---| +| Canvas | `viewBox="0 0 960 540"`, `width`/`height` set so a bare file view is 1× | +| Type | 19 px section title · 15 px heading · 13 px label · 12 px caption, all `ui-sans-serif` system stack | +| Boxes | `rx=7`, 1.4 px stroke, four semantic tones: neutral, accent (the thing being described), teal (store / gateway), amber (guard, failure, limit) | +| Arrows | solid = data or control flow, dashed = trust boundary or approximate relationship | +| Colour | greys carry structure; one blue accent, one teal, one amber, nothing else | +| Text | every `` is real text in the SVG, so it scales, selects and reads to a screen reader | + +Every file carries a **byte-identical `