The first live launch of the native Lightsail template (#154 Phase 4) turned up five bugs — all fixed in #355. Two of them are not purely native: the same logic exists on the NixOS side, where it is either latent or a duplication that already drifted. Filing separately so Phase 5's converge step has them written down, since #355 deliberately does not touch the module.
1. The ~/.config/agent-box tmpfiles rule is latent-broken on a fresh box
Both backends declare exactly one rule:
d /home/<user>/.config/agent-box 0700 <user> <user> - -
modules/agent-box.nix.in:2035 on the NixOS side; Renderer.tmpfiles on the native side. With no ~/.config yet, systemd-tmpfiles creates the parent itself, as root, then refuses to descend into it:
Detected unsafe path transition /home/agent (owned by agent)
→ /home/agent/.config (owned by root) during canonicalization
exit 73
~/.config/agent-box is then never created, and the supervisor's first act (mkdir ~/.config/agent-box) fails with Permission denied in a restart loop.
On a deployed NixOS box this does not bite, because ~/.config already exists user-owned by the time the rules run — on the box I checked it is drwxr-xr-x agent users, created by something else. That is luck, not design: the rule is one empty-home boot away from the same failure, and the VM tests do not cover a home with no .config.
Observed on Ubuntu 24.04, systemd 255. The NixOS box compared against runs systemd 258.
Fix: declare the parent, user-owned, in both backends. #355 does it for the native renderer:
d /home/<user>/.config 0755 <user> <user> - -
d /home/<user>/.config/agent-box 0700 <user> <user> - -
A test that starts from a home with no .config would be the thing that actually locks it.
2. The session seed exists twice, in two schemas
sessionsSeedFile (modules/agent-box.nix.in:342) and agentbox's user_seed both write the file modules/src/supervisor.sh reads. They disagreed: the native one emitted a list of {"name","agent"} where the supervisor reads {"version":1,"sessions":{"<name>":{…}}} with jq and expects every runtime field present. On the box that was
jq: error (at /home/agent/.config/agent-box/sessions.json:8):
Cannot index array with string ("0")
every two seconds, with the seeded session listed as one named 0 that never started. #355 makes the native side emit the module's shape field for field, but two hand-written producers of one consumer's schema will drift again — and neither agentbox-render nor golden-snapshot compares them, because each checks its own backend's fixture in isolation.
Options, roughly in order of preference:
- A flake check that renders both backends from one spec and diffs the seed files (this is Phase 5's stated goal — the seed is the smallest useful first slice of it, and cheap:
tests/native/expected/etc/agent-box/seed/agent-sessions.json and tests/golden/vm/payloads/agent-box-agent-sessions.json are already byte-comparable modulo formatting).
- Make the schema explicit somewhere both read — a
modules/src/ JSON Schema, or a single generator both call — so the supervisor's expectations stop being folklore.
- Have the supervisor reject a seed it cannot parse loudly and once, instead of looping on a jq error every two seconds. Worth doing regardless of 1 and 2: the restart loop gave no hint that the shape was wrong.
Refs #154, #355, #325.
The first live launch of the native Lightsail template (#154 Phase 4) turned up five bugs — all fixed in #355. Two of them are not purely native: the same logic exists on the NixOS side, where it is either latent or a duplication that already drifted. Filing separately so Phase 5's converge step has them written down, since #355 deliberately does not touch the module.
1. The
~/.config/agent-boxtmpfiles rule is latent-broken on a fresh boxBoth backends declare exactly one rule:
modules/agent-box.nix.in:2035on the NixOS side;Renderer.tmpfileson the native side. With no~/.configyet, systemd-tmpfiles creates the parent itself, as root, then refuses to descend into it:~/.config/agent-boxis then never created, and the supervisor's first act (mkdir ~/.config/agent-box) fails withPermission deniedin a restart loop.On a deployed NixOS box this does not bite, because
~/.configalready exists user-owned by the time the rules run — on the box I checked it isdrwxr-xr-x agent users, created by something else. That is luck, not design: the rule is one empty-home boot away from the same failure, and the VM tests do not cover a home with no.config.Observed on Ubuntu 24.04, systemd 255. The NixOS box compared against runs systemd 258.
Fix: declare the parent, user-owned, in both backends. #355 does it for the native renderer:
A test that starts from a home with no
.configwould be the thing that actually locks it.2. The session seed exists twice, in two schemas
sessionsSeedFile(modules/agent-box.nix.in:342) andagentbox'suser_seedboth write the filemodules/src/supervisor.shreads. They disagreed: the native one emitted a list of{"name","agent"}where the supervisor reads{"version":1,"sessions":{"<name>":{…}}}with jq and expects every runtime field present. On the box that wasevery two seconds, with the seeded session listed as one named
0that never started. #355 makes the native side emit the module's shape field for field, but two hand-written producers of one consumer's schema will drift again — and neitheragentbox-rendernorgolden-snapshotcompares them, because each checks its own backend's fixture in isolation.Options, roughly in order of preference:
tests/native/expected/etc/agent-box/seed/agent-sessions.jsonandtests/golden/vm/payloads/agent-box-agent-sessions.jsonare already byte-comparable modulo formatting).modules/src/JSON Schema, or a single generator both call — so the supervisor's expectations stop being folklore.Refs #154, #355, #325.