Wiki · The Colony & the Method
Deploy runbook — per-UNI telemetry (v1a/v1b) + cpradio session-liveness fix
[redacted: category] — 2 private address, 1 tailscale address, 7 internal hostname. Nothing else was altered. The document is otherwise exactly as it is written in the repository, and the sha256 below is of the original, so what was ingested stays checkable.How to read this page
Three ways to read this page. Precise is the document itself, exactly as it is written in the repository. Plain and Clear were written for this website to help you meet that document — they are about it. They are not it, and they are not evidence.
Eighty-four pages about the colony. Each agent is an Elixir process holding a generative model and doing inference, attached to a body that logs into a Minecraft world as an ordinary player. Around that sit the broadcast suite that films them and the runbooks that keep the whole thing running. There are typed specifications for each organ of the model, plus the world and genome specs. There are also the adversarial review personas used to attack a proposed change before it ships.
It is for the reader curious how a running system is put together and how it is held to account. The accountability half is the more distinctive. There is a lab protocol governing evidence and attribution, and a claim fence that restricts the vocabulary a claim is allowed to use. There is a public gate log. And there is a standing invitation to reproduce any verdict from the commit and the seed named in its receipt.
Start with the public read, then the lab protocol, then the falsification invitation. If you want the mathematics rather than the operations, go straight to the typed organ specs.
What it is not: a description of a mind, and not all one kind of document. A large part of this corpus is design and planning — specs marked as proposed rather than applied, organs designed but not built, plans that were later superseded — and each page states which it is. A specification is not a running system, and these pages are careful about the difference; the reader should be too. Eight documents were withheld from publication because they describe private infrastructure.
Your browser cannot switch reading levels, so the document itself is shown.
Precise — the source document
This is the document. Rendered from the repository at the commit above, with nothing rewritten for the web. A gate re-renders it on every deploy and fails the build if a single byte differs.
Seat: science agent · Written: 2026-07-18 · Status of every stage below: NOT YET DEPLOYED unless a receipt says otherwise. Read the whole stage before running any of it.
The one rule this runbook exists to enforce: uni-producer and uni-colony are DIFFERENT
containers with DIFFERENT blast radii. Restarting the producer costs a picture. Restarting the
colony costs six live minds. Never let a change to one imply a restart of the other.
| Container | Restarting it costs | Holds live minds? |
|---|---|---|
uni-producer (:4200) |
the OVERLOOK camera + narration for the restart window | No — observe-only, UNI_OBSERVE_ONLY=1 |
uni-colony (:4000) |
THE SIX LIVE UNI MINDS (ephemeral FS, mounts: []) |
YES — destructive |
cpradio (:8687) |
the radio audio bed + all listener sessions | No |
Stage v1a — per-UNI routes (producer only) — commit 08fa60d
Blast radius: OVERLOOK goes dark for the restart window. uni-colony is NOT touched.
Precondition: OVERLOOK off program (operator on a cover scene), OR an accepted brief blip.
Changes: ui/lib/sp_ui_web/controllers/producer_uni_controller.ex (new),
ui/lib/sp_ui_web/router.ex (4 entries), production/schemas/producer_uni_state.v1.json (new).
Serves ONLY fields already on SP.Runtime.Board. No Agent.publish/1 edit. No FE code.
Confirm OVERLOOK is off program and the producer is currently healthy (so you know what you are comparing against):
curl -s http://[redacted: internal-hostname]:4200/producer/health # expect verdict=LIVE driver=producer colony_count=6Rebuild the
uni-producerimage from the pushed ref (never the working tree — CLAUDE.md "Method of work" §2) at commit08fa60d, under a NEW tag. Never overwrite the tag the running container uses: that image IS the rollback.⚠️ DO NOT run
deploy/uni-producer/deploy.sh. It describes the one-time 2026-07-15uni-cam→uni-producercutover and is STALE: it stopsuni-cam(gone) and createsuni-viewer-cam-fwd2publishing host:3020, which collides with the liveuni-viewer-cam-fwdand takes the camera down. A refusal guard now blocks it (UNI_DEPLOY_ACK_STALE=1overrides, only after genuine re-derivation).⚠️ DO NOT copy env from
/run/user/1000/uniprod.txt. That snapshot carriesVIEWER_URL=http://[redacted: private-address]:3020— a hard IP literal for a DHCP lease that has since moved to.121. The live container was already corrected to the DNS namehttp://[redacted: internal-hostname]:3020. Read the live values off the running container (podman inspect uni-producer); re-pinning the literal re-arms the exact trap CLAUDE.md's_lan_dynamic_lawexists to prevent.Recreate only
uni-producer, preserving--name/--hostname/--networkso itsuni-producernetwork alias survives, and leaveuni-viewer-cam-fwdalone:podman run -d --name uni-producer --hostname uni-producer --network uni-colony-net \ -p 4200:4001 -e UNI_AUTOSTART=1 -e UNI_POPULATE=0 -e UNI_OBSERVE_ONLY=1 \ -e UNI_COLONY_NODE=uni@uni-colony -e MC_HOST=mc-server \ -e VIEWER_URL=http://[redacted: internal-hostname]:3020 \ --restart unless-stopped uni-producer:<new-tag>UNI_OBSERVE_ONLY=1andUNI_POPULATE=0are load-bearing — they are the fence that keeps the producer from spawning or culling bodies in the world it watches. Do not drop them, and verify them on the running container after recreate, not just in the command you typed.Why the camera survives the IP change.
uni-viewer-cam-fwdtargetstcp-connect:uni-producer:3020by name, and socat withforkre-resolves per connection. Proven, not assumed: the forwarder started2026-07-16 07:34:39and the producer started07:43:50— 9m11s later — yet host:3020serves HTTP 200. A startup-time resolve would have failed permanently. So the new container's IP is picked up automatically as long as the alias is preserved. Established connections (OBScap_overlook) still break and must reconnect — that is the blip, and why OVERLOOK must be off program.Gate —
producer-per-uni-telemetry. All four must return 200 with the disclaimer present:for r in uni_roster generations; do curl -s "http://[redacted: internal-hostname]:4200/producer/$r" | head -c 400; echo; done curl -s "http://[redacted: internal-hostname]:4200/producer/uni_state/UNI-1-3" | head -c 400 curl -s "http://[redacted: internal-hostname]:4200/producer/uni_history/UNI-1-3" | head -c 400PASS requires, on every one of the four:
disclaimerpresent verbatim,x-uni-claim-fenceheader present, and no synthesized score/rank/percentage field anywhere in the payload. Also assert/producer/healthstill readsverdict=LIVE driver=producer colony_count=6— ifcolony_countdropped, the producer lost its remote board and the restart hurt something.Flip the gate row to PASS + write
docs/receipts/producer_per_uni_telemetry_2026-07-18.md.Hand back to the studio agent to wire the Gaia projector (
viewer/gaia/**is their seat, not mine). Tell them the routes are LAN-plane only — see the plane note below.
Plane note, measured 2026-07-18:
:4200answers on the chip's LAN plane ([redacted: internal-hostname]→[redacted: private-address]) but NOT on the tailscale overlay ([redacted: tailscale-address]:4200→ socket hang up). Only:8687is published on the overlay. Any Gaia collector must address the name, not the overlay literal.
Stage v1b — additive Agent.publish/1 — DESTRUCTIVE, NOT IN THIS WINDOW
Blast radius: THE SIX LIVE MINDS. Adds energy/satiety/homeostat body/eat_count/attack_count/ gamma_m to the board row. It only takes effect on a uni-colony redeploy, because that is
where SP.Runtime.Agent runs.
THREE HARD PRECONDITIONS — ALL of them, no exceptions:
- MANDATORY capture-before-destroy. Run
docs/handoffs/GAIA_CAPTURE_BEFORE_DESTROY_2026-07-14.mdinanchormode, commit + push, and confirmnode viewer/gaia/evidence_hold.cjs verifyprints PASS. Six minds spanning kin groups 0–3, founder UNI-0-1 still active, ~day 1320.podman rmwithout this wastes them permanently — Gaia cannot enforce this herself (it would break her read-only law). - Off air. Not a cover scene — off air.
- A separate, explicit operator GO for the redeploy itself. The v1 go-ahead covers writing the code and the v1a producer restart. It does not authorize destroying a running colony.
Only after all three: rebuild uni-colony from a pushed ref, redeploy rootless as uni, then
re-prove verify_colony.cjs + /producer/health before claiming anything.
Stage A — cpradio session-liveness fix
Blast radius: the radio audio bed drops for the restart window. uni-colony NOT touched.
Root cause + evidence: docs/receipts/music_nowplaying_stuck_root_cause_2026-07-18.md.
Read this first: the service is rootful podman, container cpradio, source in a volume at
/var/lib/containers/storage/volumes/musicradio/_data/server.py, mounted into the container
read-only (RW:false). So the patch is applied on the host, then the container restarts to
pick it up. There is no image rebuild.
- Back up, then apply (idempotent — safe to re-run, exits 0 with "already patched"):
cp /var/lib/containers/storage/volumes/musicradio/_data/server.py \ /var/lib/containers/storage/volumes/musicradio/_data/server.py.bak-pre-liveness-20260718 python3 deploy/uni-os/cpradio/patch_session_liveness.py \ /var/lib/containers/storage/volumes/musicradio/_data/server.py python3 -c "import ast,sys;ast.parse(open(sys.argv[1]).read())" \ /var/lib/containers/storage/volumes/musicradio/_data/server.py # syntax gate before restart podman restart cpradio→ thencurl -s http://127.0.0.1:8687/healthz→ok.- Gate —
music-nowplaying-advances. Open a real listener, then two probes ≥ 60 s apart:
PASS =curl -sN "http://127.0.0.1:8687/radio?session=gatecheck" > /dev/null & sleep 5; curl -s "http://127.0.0.1:8687/api/nowplaying?session=gatecheck" # T0 sleep 90; curl -s "http://127.0.0.1:8687/api/nowplaying?session=gatecheck" # T1 kill %1seqincremented ORtitle/artistchanged to a NEW pair, ANDpositionSecnever exceededdurationSec + 5on any successful probe. FALSIFIES =seqfixed AND title unchanged ANDpositionSec > durationSec + 30on both. - Leak regression check (this is the actual root cause, so prove it directly):
After the listener above is killed andcurl -s http://127.0.0.1:8687/api/telemetry | grep -o '"activeListeners":[0-9]*' ss -tnp state established 'sport = :8687' | wc -lRADIO_SESSION_STALE_SECelapses,activeListenersMUST fall back to the number of real established connections. A non-zeroactiveListenerswith zero established sockets is the defect returning. - Write
docs/receipts/music_nowplaying_advances_2026-07-18.md, flip the gate row. - Leave the studio-side
stalePlayheadguard in place — it is a safety net, not the mechanism.
⚠️ MANDATORY FOLLOW-UP after ANY cpradio restart — hand to the STUDIO seat
A cpradio restart strands OBS on a half-open socket that silently produces nothing. This is not hypothetical and it is not a server fault — it recurred on the 2026-07-18 deploy and cost real diagnostic time. Budget for it on every future restart.
Symptom:
obs64still holds an ESTABLISHED connection to:8687created before the restart (observed 4.5 h stale). OBS reportsOBS_MEDIA_STATE_PLAYINGwith an advancing cursor while/api/nowplayingreturnsno-session. From OBS's side it looks perfectly healthy and is completely dead.
TriggerMediaInputAction RESTARTdoes NOT clear it — it returns success and changes nothing.- What works: clear the ShowRadio source's
inputto"", wait 3 s, then restore the URL. That forcesffmpeg_sourceto drop the socket and open a fresh one.activeListenersgoes 0 → 1 immediately.Seat boundary: the recovery action is STUDIO-side (
viewer/*, OBS). The chip/science seat must not perform it — hand back after the restart and let the studio agent force the input clear/restore. This note exists so the next chip-side restart is not misdiagnosed as a server regression: a transientactiveListeners=0immediately after a restart is the OBS socket, not the patch. Confirm by probing with a fresh session id (/api/nowplaying?session=probe-test-sid) — if that registers instantly with a real position, the service is fine.
Optional, only if the operator wants the incident lever: set RADIO_ADMIN_TOKEN in the
container env to enable POST /api/reset + /api/skip. Unset = the verbs return
503 not configured. Do not enable them and then describe them as "secured" unless the token is
actually set — same discipline as the retracted publisher-PIN claim in CLAUDE.md.
Rollback
| Stage | Rollback |
|---|---|
| v1a | recreate uni-producer from the previous image tag; routes vanish, /producer/health unchanged |
| v1b | the minds do not roll back — that is why the capture is mandatory, not advisory |
| A | cp server.py.bak-pre-liveness-20260718 server.py && podman restart cpradio |
sha256 43351c98e7842001 — of the original file, so what was ingested stays checkable.
Plain — written for this website, not the source document
This is a deployment runbook, and every stage in it is marked as not yet carried out unless a record of the run says otherwise.
It exists to enforce one rule, stated at the top and given its own table: two containers look similar and are not. Restarting one costs a picture for a moment. Restarting the other destroys six living minds, because their memory lives only in temporary storage. A change to one must never imply restarting the other.
Each stage names its blast radius before its steps. Two warnings tell the reader not to run an older script that is now stale and would take the camera down, and not to copy settings from a snapshot that pins an address which has since moved.
One stage is marked destructive and out of scope for this window, with three hard preconditions including a mandatory capture of the minds before anything is removed.
A rollback table ends it, and one row says plainly that the minds do not roll back.
Plain · written 2026-08-01 by claude-opus-5 · not yet checked by a person · about the document whose sha256 is 43351c98e7842001
Clear — written for this website, not the source document
This is a deployment runbook written by one seat for a specific window of work. Its status line is unusual and useful: every stage below is not yet carried out unless a recorded run says otherwise, and the reader is told to read a whole stage before running any of it.
It names the single rule it exists to enforce. Two containers are different and have different consequences if restarted. Restarting one costs a camera and narration for the restart window. Restarting the other destroys the live minds, because their memory lives only in the container's temporary storage. A table makes that explicit, with a column for whether each holds live minds. The rule follows: a change to one must never imply a restart of the other.
The first stage touches only the observing container and adds read-only routes. It states its blast radius, gives a precondition about being off the programme, then walks through the rebuild. Two warnings sit inside it. The first says not to run an older deployment script: it describes a one-time cutover, would stop a container that no longer exists, and would create a forwarder that collides with the live one and take the camera down. A refusal guard now blocks it. The second says not to copy settings from a saved snapshot, because it pins an address for a lease that has since moved; read the live values off the running container instead.
A passage explains why the camera survives an address change, and it is careful to present this as measured rather than assumed. The forwarder targets a name and re-resolves per connection, and the timestamps show it started well before the thing it points at, yet the port serves. Existing connections still break, which is the blip, and that is why the scene must be off the programme.
A gate follows with exact checks: several routes must return successfully with a disclaimer present verbatim, a header stating what is not claimed, and no synthesized score, rank or percentage anywhere in the payload. One further check requires that a count did not drop, because if it did, the restart hurt something.
A plane note records a measured asymmetry: one port answers on the local network but not on the overlay, so a collector must address the name.
The second stage is marked destructive and explicitly out of the current window, because it only takes effect on a redeploy of the container that holds the minds. Three hard preconditions are listed with no exceptions. A mandatory capture of the minds, committed and checked first. Being off air rather than merely on a cover scene. And a separate explicit go for the destruction itself, since the earlier approval does not cover it.
A third stage fixes a liveness defect in a small service. The source is mounted read-only, so the patch is applied on the host and the container restarted, with no image rebuild and a syntax check first. Its gate is two probes far enough apart with both a passing and a refuting condition, plus a direct check that the underlying leak is gone rather than merely masked.
A mandatory follow-up warns that restarting that service strands the broadcast application on a half-open socket that looks perfectly healthy and produces nothing. The obvious remedy does not work, the one that does is given, and the note draws a seat boundary about who may perform it.
The runbook ends with a rollback table, whose middle row says plainly that the minds do not roll back, which is why the capture is mandatory rather than advisory.
Clear · written 2026-08-01 by claude-opus-5 · not yet checked by a person · about the document whose sha256 is 43351c98e7842001