From a6e3248bc88ef36dd3bdcc829a291e7883809d25 Mon Sep 17 00:00:00 2001 From: Cameron Brooks Date: Mon, 3 Aug 2026 16:44:26 -0400 Subject: [PATCH] docs(bioreactor-v1): refresh the Pi quickstart against v0.1.40 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Walked end-to-end on pi-g1 2026-08-03 (fresh wipe, install of v0.1.40, workbench 0.14.0). Corrections, in rough order of how badly they would have misled someone: - **Safety framing.** The guide said actuators are zeroed on stop "only by the automation/full variant's safe-state hooks" and that there is "no software e-stop button yet". Both wrong, and the first is the exact conflation that hid a missing `safety.safe_state` in this project for weeks: `automation.mode_transition_hooks` fire on MODE TRANSITIONS, while `safety.safe_state` is what `POST /v0/estop` runs. The two are now described separately. The e-stop button shipped in workbench v0.14.0. - **Heater gap.** Notes that `bread0/rlht0` is not covered by the software safe state (uint64 hook args, anolishq/anolis#252), so the backplane cut is its only stop if a heater load is connected. - **I2C.** The `raspi-config` line is marked REQUIRED, with the reason: `install.sh` reports "i2c: already enabled" on any Pi with HDMI because its glob matches the DDC buses, then the install fails 30 s later without naming the cause (anolishq/anolis#249). - **Read the exit code, not the banner** — a failed install still prints "Anolis installation complete" above the failure line. - **Versions.** v0.1.38 -> v0.1.40 (install.sh URL, expected pins, the verify step). Adds `--variant manual` so the machine boots inert. - **§5 friction.** `ANOLIS_WORKBENCH_RUNTIME_URL` is load-bearing, not a nicety, and it fixes only the proxy — `/api/status` still reports nothing running, so Operate's chrome stays wrong (anolis-workbench#277). - **Compose.** The "Compose strips safe-state hooks" warning predates the canonical-authoring flip (#255) and has not been re-verified; says so plainly rather than asserting it is either still true or fixed. - Handoff section now lists the four rough edges with their issue numbers. Refs anolishq/anolis#249, anolishq/anolis#252, anolishq/anolis-workbench#255, anolishq/anolis-workbench#277 --- .../bioreactor-v1/docs/quickstart-on-pi.md | 116 ++++++++++++++---- 1 file changed, 89 insertions(+), 27 deletions(-) diff --git a/projects/bioreactor-v1/docs/quickstart-on-pi.md b/projects/bioreactor-v1/docs/quickstart-on-pi.md index f3b0cd4..caa9225 100644 --- a/projects/bioreactor-v1/docs/quickstart-on-pi.md +++ b/projects/bioreactor-v1/docs/quickstart-on-pi.md @@ -8,10 +8,24 @@ in a browser); you operate the runtime over **loopback**, so no tokens/SSH. > ⚠️ **SAFETY FIRST — read before running any actuator (live culture!).** > - **Hardware e-stop within reach at all times.** On this rig it cuts backplane > power — the strongest stop, no software trust required. When in doubt, hit it. -> - Actuators are zeroed on stop **only** by the `automation`/`full` runtime -> variant's safe-state hooks. **§3 makes that variant active — do not skip it.** -> The default install variant (`manual`) does NOT zero actuators and has no -> telemetry. There is **no software e-stop button yet.** +> - **Two different mechanisms zero the actuators. Do not confuse them** — this +> distinction hid a missing safe-state in this project for weeks: +> - **`safety.safe_state`** is what the **software e-stop** (`POST /v0/estop`, +> and the E-STOP button in the workbench's Operate view) runs. It is declared +> in **every** variant including `manual`, so the e-stop drives outputs to +> safe on any install. +> - **`automation.mode_transition_hooks`** fire on **mode transitions** +> (`AUTO→MANUAL`, `MANUAL→IDLE`, `*→FAULT`). These exist only in the +> `automation`/`full` variants — another reason §3 matters. +> - **The software e-stop is not a substitute for the backplane cut.** It drives +> the declared safe state and then *latches* actuation; clearing the latch does +> **not** restart anything, and it cannot help if the runtime itself is wedged. +> Verified on hardware 2026-08-03: with a safe state declared, pressing it +> stopped a running impeller. +> - **The heater is not covered by the software safe state** (`bread0/rlht0`). +> Its only actuating function takes `uint64` arguments, which a hook cannot +> currently express — see anolishq/anolis#252. If you connect a heater load, +> the backplane cut is its only stop. > - Mode ladder is strict: **IDLE → MANUAL → AUTO**. To stop, descend > **AUTO → MANUAL → IDLE** — the AUTO→MANUAL transition is what zeros the motors. > `AUTO → IDLE` directly is invalid. @@ -29,7 +43,7 @@ bread + ezo on I²C bus 1 at `0x0A, 0x14, 0x15, 0x61, 0x63`. ```bash sudo apt update && sudo apt install -y i2c-tools git curl -sudo raspi-config nonint do_i2c 0 # enable I²C (0 = enable) +sudo raspi-config nonint do_i2c 0 # enable I²C (0 = enable) — REQUIRED, see below i2cdetect -y 1 # EXPECT: 0a 14 15 61 63 (0x76 = non-anolis, ignore) # Clone this project — it carries this guide, the bootstrap script, and the config: @@ -41,6 +55,17 @@ export PROJ=~/anolis/anolis-projects/projects/bioreactor-v1 - [ ] `i2cdetect` shows **0a 14 15 61 63** — if any are missing, fix wiring/power before continuing (a missing address = a silently-excluded device later). +> **Do not skip the `raspi-config` line.** `install.sh` claims to enable I²C for +> you and, on any Pi with HDMI attached, does not — its check globs `/dev/i2c-*` +> and matches the HDMI DDC buses (`i2c-20`, `i2c-21`), so it reports +> `✓ i2c: already enabled` while the GPIO bus `/dev/i2c-1` does not exist. The +> install then fails 30 s later with `health: runtime not responding` and never +> names the cause. Tracked as anolishq/anolis#249; until it is fixed, enabling +> I²C by hand here is what makes the install work. +> +> Symptom if you get it wrong, visible only in the journal: +> `failed to open I2C bus '/dev/i2c-1': No such file or directory` + ## 1. Install + launch the workbench (on the Pi) There is no Pi desktop installer; the workbench runs as a local server you open in @@ -56,26 +81,43 @@ bash "$PROJ/scripts/install-workbench-pi.sh" # installs + launches; browser op ## 2. Provision the runtime + providers + observability -> We provision the **canonical, bench-proven bioreactor-v1 config** directly -> (the workbench's Compose→generate path currently strips the safe-state hooks, -> so we don't use it to drive live actuation). The workbench is our **operate + -> monitor** surface. `--with-observability` installs InfluxDB + Grafana natively -> and wires the tokens automatically. +> We provision the **canonical, bench-proven bioreactor-v1 config** directly, and +> use the workbench as the **operate + monitor** surface. +> `--with-observability` installs InfluxDB + Grafana natively and wires the tokens +> automatically. +> +> The reason for provisioning directly was that the workbench's Compose→generate +> path stripped the safe-state hooks. That predates the canonical-authoring flip +> (anolishq/anolis-workbench#255), which may well have fixed it — but **it has not +> been re-verified since**, so this guide keeps the direct path. Do not author a +> config for live actuation through Compose until someone confirms the hooks and +> the `safety:` block survive the round trip. ```bash cd ~/anolis -curl -fsSLO https://github.com/anolishq/anolis/releases/download/v0.1.38/install.sh -sudo bash install.sh --project "$PROJ" --with-observability 2>&1 | tee ~/anolis/install.log +curl -fsSLO https://github.com/anolishq/anolis/releases/download/v0.1.40/install.sh +sudo bash install.sh --project "$PROJ" --variant manual --with-observability 2>&1 | tee ~/anolis/install.log echo "exit=${PIPESTATUS[0]}" # NOT $? (that reads tee) ``` - [ ] install exits **0** ("Anolis installation complete"); it pins runtime - 0.1.38 / bread 0.3.7 / ezo 0.3.3 and starts one `anolis-runtime.service`. + 0.1.40 / bread 0.3.8 / ezo 0.3.4 and starts one `anolis-runtime.service`. + +> **Read the exit code, not the banner.** `install.sh` prints a large +> "Anolis installation complete" box *before* reporting failure, so a failed +> install still shows a success-looking banner with `✗ Runtime did not come up` +> underneath it. Trust `exit=` and the `✓/✗` lines. +> +> `--variant manual` makes the machine **boot inert** — no autonomous actuation +> until you deliberately activate automation in §3. -## 3. ⚠️ Activate the SAFE variant (safe-state hooks + telemetry) — REQUIRED +## 3. ⚠️ Activate the automation variant (mode-transition hooks + telemetry) -`install.sh` lands the `manual` variant by default (no actuator-zeroing, no -telemetry). Switch to `automation` (safe-state hooks + telemetry) and restart: +`install.sh` lands the `manual` variant by default: boot-inert, no automation, no +telemetry. The **software e-stop works on `manual` too** (every variant declares +`safety.safe_state`), but `manual` has no `mode_transition_hooks`, so nothing is +zeroed on a mode change — and no telemetry is recorded. Switch to `automation` +and restart: ```bash sudo cp /opt/anolis/projects/bioreactor-v1/config/anolis-runtime.bioreactor.automation.yaml \ @@ -84,13 +126,15 @@ sudo systemctl restart anolis-runtime ``` - [ ] `grep -c mode_transition_hooks /opt/anolis/config/runtime.yaml` → **≥1** - (safe-state hooks present — motors zero on AUTO→MANUAL and *→IDLE). + (mode hooks present — motors zero on AUTO→MANUAL, MANUAL→IDLE and *→FAULT). +- [ ] `grep -c '^safety:' /opt/anolis/config/runtime.yaml` → **1** + (the e-stop safe state; should be present on every variant). - [ ] `grep -A1 'telemetry:' /opt/anolis/config/runtime.yaml | grep enabled` → **true**. ## 4. Verify bring-up ```bash -curl -fsS localhost:8080/v0/runtime/status | python3 -m json.tool # 0.1.38, mode IDLE, 5 devices +curl -fsS localhost:8080/v0/runtime/status | python3 -m json.tool # 0.1.40, mode IDLE, 5 devices curl -fsS localhost:8080/v0/providers/health | python3 -c " import json,sys for p in json.load(sys.stdin)['providers']: @@ -118,10 +162,21 @@ state), device health, parameter get/set (min/max honored), device-function calls, the automation/behavior-tree outline + fault view, an SSE event trace, and the embedded Grafana panel. -> **Known friction:** without the `ANOLIS_WORKBENCH_RUNTIME_URL` env var the -> Operate view targets a *dev-launch* runtime, not the systemd one running the -> culture. There's no in-UI field for this yet. The env var above points it at the -> real runtime. +> **Known friction — the env var is load-bearing, not optional.** Re-verified on +> hardware 2026-08-03 with workbench 0.14.0. Without it the Operate proxy returns +> `503 {"error": "Runtime is not running"}` even though the systemd runtime is up +> and healthy on the same box. Two reasons, both in anolishq/anolis-workbench#277: +> the workbench's external-runtime discovery iterates `~/.anolis/systems`, which +> an `install.sh --project` machine never populates; and even after importing, it +> skips any runtime whose configured bind is not loopback — and `install.sh +> --project` always emits `bind: 0.0.0.0`. +> +> **The env var only fixes half of it.** It patches the proxy, so live data flows +> and the device tables work — but `launcher.get_status()` never consults it, so +> `/api/status` still reports `running: false, active_project: null`. Anything +> keyed on that (the not-running banner, active-project display, and the #264 +> logic that hides the E-stop when a *different* project is running) stays wrong. +> Treat Operate's data as trustworthy and its chrome as not, until #277 lands. ## 6. Run the experiment (follow the actuation runbook) @@ -158,8 +213,15 @@ curl -s -X POST localhost:8080/v0/mode -H 'content-type: application/json' -d '{ ### Notes for the second (identical) reactor / novice handoff This exact sequence reproduces on the second reactor **unchanged** — same -addresses, same profile, same steps. It IS the template. The two current rough -edges to warn them about: **§3** (must activate the `automation` variant — -provisioning doesn't do it for you) and **§5** (the `ANOLIS_WORKBENCH_RUNTIME_URL` -env var to point Operate at the real runtime). Both are tracked to be fixed in the -workbench so the next person doesn't need them. +addresses, same profile, same steps. It IS the template. Four rough edges to warn +them about, all tracked: + +| Where | Rough edge | Tracked as | +|---|---|---| +| §0 | `install.sh` does not actually enable I²C on a Pi with HDMI — enable it by hand | anolishq/anolis#249 | +| §2 | "installation complete" banner prints even when the install failed — read the exit code | anolishq/anolis#249 | +| §3 | must activate the `automation` variant; provisioning does not do it for you | — | +| §5 | `ANOLIS_WORKBENCH_RUNTIME_URL` is required, and only fixes Operate's data, not its chrome | anolishq/anolis-workbench#277 | + +Last walked end-to-end on real hardware **2026-08-03** (fresh wipe → install of +v0.1.40 → workbench 0.14.0 → software e-stop verified stopping a live impeller).