Pierre Rouanet 8b1b7e5109 Three papercuts, and the two things one of them was hiding
Each was found by the docs audit (#154) and written down there rather than
fixed, because a docs change is not the place for code.

**`cargo test --workspace` now works on a Mac.** `vendor/platform.c` reaches
the bus through `linux/i2c.h`, so `build.rs` compiles it only when the *target*
is Linux — read from `CARGO_CFG_TARGET_OS`, since a build script is compiled
for the host and `cfg!` there would answer for the laptop. The driver's calls
go with it, and off a board `Sensor` is uninhabited: `open` is the only
constructor and it always fails, so the compiler discharges every other method
instead of leaving a body that could one day invent a frame. `tofd` still
builds, `tofd --fake` still serves, and 942 tests pass with nothing excluded.

**`install.sh` stops reporting `tofd` as a daemon it forgot.** The hook enables
every unit with an `[Install]` section a step earlier, so the warning was noise
on every fresh install. Named as known, with no `enable_unit` of its own:
nothing depends on it, so there is no ordering to have an opinion about.

**`dev-push.sh` checks all seven daemons**, not six — and the comment saying
five, restarted in a set of three, was two daemons out of date.

That last one could not work on its own, and finding out why turned up two
faults rather than one:

- **`tofd` published no identity.** Six daemons call `log_startup_identity!`;
  `tofd` had a hand-rolled `warn!` that logged a version and wrote no
  `/run/tofd/identity.json`. That macro exists because `padd` was once the one
  daemon whose journal could not say which build was running — and its own doc
  comment predicts this: "a shared definition makes the next daemon's omission
  a missing call rather than a missing idea". `tofd` was the next daemon.
- **`configd::units::MANAGED` was still five units.** `mediad` and `tofd`
  shipped units two releases ago. So the `units` block of `robotctl health` —
  the one a person reads after an update to find which daemon is still on the
  old release — could not report either of them at all. Same defect as the
  restart set in `restart-order.md` that #154 fixed, one file over.

Docs follow the code: the macOS caveat in CONTRIBUTING, the `tofd` note in
`restart-order.md` §6, and `dev-push.md`, which claimed `robotctl version`
could answer for `tofd` — it could not, for both reasons above.

Verified: `cargo test --workspace` 942 passing on macOS with no exclusions,
`cargo board -p tof --bins` still cross-compiles the driver for the board,
clippy clean for what this touches, `shellcheck -S warning` clean on both
scripts.

Assisted-by: Claude:claude-opus-5[1m]
2026-08-26 17:14:37 +02:00
..

Docs

The README is the front door — what a microduck is, and where to go. If you have one in front of you and want to drive it, start at the cheat sheet.

robot/ — you have a robot

cheatsheet.md Every robotctl command.
pair-a-gamepad.md Once per pad: pairing mode, pad pair, and what to do when it will not bond.
cheatsheet-dev.md The commands that need a dev board: branch builds, candidates, dev pushes.
dev-push.md Build on your machine and install on the board over ssh, with no CI run.
duckctl.md Every duckctl command — the robot from a laptop, over Bluetooth.
install-dev.md Setting up a board for development, from nothing.
install-by-hand.md The same install as separate commands, for testing one step at a time.

design/ — you are changing the daemon

How it works and why. These change rarely; when behaviour and a design doc disagree, the doc is the bug.

One page owns a mechanism, and the others link to it. The table below is that assignment: if a fact belongs to a page listed here, every other page says one sentence and points, rather than explaining it again. A fact written down in six places drifts in six directions, each of them locally reasonable — which is how six documents came to promise that updaterd and btd kept their old binaries until the next reboot, two releases after they stopped doing so, including the two pages someone reads while diagnosing exactly that. So when two documents disagree, the one that does not own the mechanism is the bug.

architecture.md The service split, the IPC contract, state ownership, safety and authority.
robotd-design.md The control loop: the Dynamixel bus and who owns the port, the model, sensing, observations, policy, safety — and what else hangs off the tick.
updater-design.md The update engine: verification, atomic swap, health gate, rollback, release format.
restart-order.md Which unit restarts, at which step, on every path that moves current — and at boot.
app-path-design.md btd and configd — how a phone configures a robot over BLE.
remote-webrtc.md WebRTC sessions, signalling, and the control channel — how a peer drives and observes the robot.
webrtc-console.md The WebRTC client: serving it from the robot, finding the robot, and what the page should be.
boot-recovery-net.md Falling back to golden when the release that booted cannot start its daemons.

project/ — you are running the project

Dated records rather than reference. They describe a moment, and go stale on purpose.

roadmap.md Milestones, and what works today versus what is designed.
ci-setup.md One-time setup for the release pipeline: keys, secrets, rotation.
install-path-gap.md Why four install-path bugs reached a board, and what closed it. Closed.
slice-2-bringup.md What a real Radxa Zero 3W did with slice 2.
update-over-ble.md Driving the update path from a phone: what it turned up, and what rollback over a radio was decided on.
media-bringup.md What a Radxa Zero 3W does about video: the VPU, what MPP needs, and the two plugins that have to be built.
pad-minimal-pairing.md The smallest board configuration a gamepad will bond under, found by taking one away at a time.

ideas/ — not designed yet

Holding pens. Something that is going to need a design doc, written down before it has one, so the thinking is not lost and does not get mistaken for a decision.

autonomous_behavior.md The behavior stack: what the runtime's brain has to give up, and the ideas the chorale and theremin work left behind.

Elsewhere

../CONTRIBUTING.md Building, testing, repo layout, conventions, releasing.
../deploy/README.md What a robot image is configured with, and what provisioning actually does.