From 70b4b356bb3b79b026b107beb58732ff0673b204 Mon Sep 17 00:00:00 2001 From: mintaka Date: Sun, 6 Sep 2026 00:32:16 -0400 Subject: [PATCH 1/2] fix(devenv): build the operator CLI so the box never serves a stale binary (RIG-3342) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `devenv.nix` builds four binaries — `compass-server`, `compass-runner`, `compass-gen-cert`, `compass-mint-runner-token` — but never `./cmd/compass`. Each of those four is built by the task that immediately execs it, so their freshness is a side effect of being invoked at boot. The operator CLI is invoked later, by a human over ssh, so nothing rebuilt it: the mattfw dogfood box served an Aug 23 binary missing the `agent` and `message` verbs while `main.go` had registered all five for weeks. The drift was invisible from the CLI itself, because `--version` prints the same static "0.1.0" for a months-old build and a current one (that blind spot is RIG-3346). Add `dogfood:build-cli`, deliberately the only build-only task here — it has no `exec`, since there is nothing to run at boot; the point is to leave a current binary in the state dir. Ordered `before` the server purely to pin it into the `up` graph, with no runtime dependency on it. Verified on the box: the state-dir path held a 22,064,753-byte Aug 23 binary; running the task's build replaced it with an 18,782,067-byte current one exposing all five verbs (`agent`, `agent-config`, `message`, `secret`, `token`). Refs RIG-3342, RIG-3068 (the dogfood validation that surfaced it). Co-authored-by: Matt Wilkinson --- devenv.nix | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/devenv.nix b/devenv.nix index 920943bc..76de5539 100644 --- a/devenv.nix +++ b/devenv.nix @@ -518,6 +518,26 @@ in before = [ "devenv:processes:compass-server" ]; }; + # build-cli: build the operator CLI (`./cmd/compass`) into the state dir so a + # human driving the box always has a binary matching the deployed source. + # DELIBERATELY BUILD-ONLY — the only task here with no `exec`. The other four + # binaries are built by the task that immediately runs them, so their freshness + # is a side effect of being invoked at boot; the operator CLI is invoked LATER, + # by a human over ssh, so nothing would otherwise rebuild it. Before this task + # the box served a months-old CLI missing the `agent` and `message` verbs while + # `--version` printed the same static "0.1.0" as a current build, making the + # drift invisible from the CLI itself (RIG-3342; the identical-version blind + # spot is RIG-3346). Ordered `before` the server purely to pin it into the `up` + # graph — it has no runtime dependency on the server. + "dogfood:build-cli" = { + exec = '' + bin="${config.devenv.state}/compass/compass" + go build -o "$bin" ./cmd/compass + ''; + cwd = "${config.devenv.root}/go"; + before = [ "devenv:processes:compass-server" ]; + }; + # mint-runner-token: register the `dogfood` runner and write its enrollment # token 0600 (raw, no newline) to the state dir. Reads COMPASS_DATABASE_DSN # (the same DSN the server uses) so its store precedence matches. Runs after From 7e12e76d46c3ae1c73a787da892a8e4531f2e9fe Mon Sep 17 00:00:00 2001 From: mintaka Date: Sun, 6 Sep 2026 01:08:17 -0400 Subject: [PATCH 2/2] fix(devenv): order build-cli after the server; correct the task comment (RIG-3342) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Review findings on the build-cli task. The `before` edge inverted a failure mode: `go build ./cmd/compass` pulls cobra, viper and the connect client, so any compile error in the operator CLI's import graph blocked compass-server from starting — and with it compass-ui and compass-runner, which chain off the server. A broken CLI took down the whole dogfood backend, which is backwards: you want the server up in order to diagnose. Switch to `after`, mirroring dogfood:mint-runner-token. That still pins the task into the `up` graph, but the edge is inert. The comment also claimed this was "the only task here with no `exec`", which is false twice over: the task does have an `exec` attribute two lines below the claim, and under the intended reading dogfood:agent-image and dogfood:clean also never exec-replace. Restate it as the narrower true claim — it is the only *binary-building* task that does not exec what it produces — and stop conflating tasks with processes (gen-cert and mint-runner-token are tasks; compass-server and compass-runner are processes). Also document the two things a reader needs and could not get from the file: that the unconditional rebuild is deliberate (a present-but-stale binary is the bug, so skip-if-present would skip exactly when the build is required), and the invocation path, since the state dir is not on PATH. Add build-cli to the two indexes that enumerate the `up` graph — the chain comment and the tasks-block platform header — which otherwise under-describe it, reproducing the same documentation drift this change exists to fix. Refs RIG-3342. Co-authored-by: Matt Wilkinson --- devenv.nix | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/devenv.nix b/devenv.nix index 76de5539..85f8c474 100644 --- a/devenv.nix +++ b/devenv.nix @@ -326,6 +326,10 @@ in # (the readiness probe gates on the migrated store). # compass-runner — enrolls over the TLS door with that token, then # idles in RunSessions awaiting Provision/Start. + # dogfood:build-cli — builds the operator CLI (./cmd/compass) into the state + # dir so a human driving the box over ssh never gets a + # stale binary; nothing execs it, and its `after` edge is + # inert so a CLI compile error cannot gate the backend. # # Opt-in (NOT wired into up): `dogfood:agent-image` builds+loads the agent # base image (heavy closure — kept off the hot up path), and `dogfood:clean` @@ -494,9 +498,9 @@ in }; }; - # Dogfood loop tasks. gen-cert and mint-runner-token run cross-platform (they - # back the macOS-native server/UI dogfood); agent-image and clean stay - # Linux-only, as the whole podman-backed loop targets the Linux dev box. + # Dogfood loop tasks. gen-cert, build-cli and mint-runner-token run + # cross-platform (they back the macOS-native server/UI dogfood); agent-image and + # clean stay Linux-only, as the whole podman-backed loop targets the Linux dev box. tasks = { # gen-cert: mint the self-signed TLS trust anchor the network door serves and # the runner trusts. Built into the state dir and run the same way the server @@ -520,22 +524,27 @@ in # build-cli: build the operator CLI (`./cmd/compass`) into the state dir so a # human driving the box always has a binary matching the deployed source. - # DELIBERATELY BUILD-ONLY — the only task here with no `exec`. The other four - # binaries are built by the task that immediately runs them, so their freshness - # is a side effect of being invoked at boot; the operator CLI is invoked LATER, - # by a human over ssh, so nothing would otherwise rebuild it. Before this task - # the box served a months-old CLI missing the `agent` and `message` verbs while - # `--version` printed the same static "0.1.0" as a current build, making the - # drift invisible from the CLI itself (RIG-3342; the identical-version blind - # spot is RIG-3346). Ordered `before` the server purely to pin it into the `up` - # graph — it has no runtime dependency on the server. + # Unlike the other four binary builds here, this task does not `exec` what it + # produces — there is nothing to run at boot. Those four are each built by the + # task or process that immediately execs them (gen-cert and mint-runner-token + # as tasks; compass-server and compass-runner as processes), so their freshness + # is a side effect of being invoked; the operator CLI is invoked LATER, by a + # human over ssh, so nothing would otherwise rebuild it (RIG-3342; the + # identical-version blind spot that hid the drift is RIG-3346). + # The build is unconditional ON PURPOSE — a present-but-stale binary IS the + # bug, so skip-if-present would skip exactly when the build is required. + # Ordered `after` the server, not `before`: this pins the task into the `up` + # graph while keeping the edge inert, so a compile error anywhere in the CLI's + # import graph cannot stop the backend from serving. Invocation path is + # explicit — the state dir is not on PATH, so an operator runs + # `"$(devenv info devenv.state)"/compass/compass` (or the absolute path). "dogfood:build-cli" = { exec = '' bin="${config.devenv.state}/compass/compass" go build -o "$bin" ./cmd/compass ''; cwd = "${config.devenv.root}/go"; - before = [ "devenv:processes:compass-server" ]; + after = [ "devenv:processes:compass-server" ]; }; # mint-runner-token: register the `dogfood` runner and write its enrollment