refactor(module): purge Nix antiquotes from payload bodies (#154 Phase 2) - #182
Conversation
9645ae2 to
5dc1350
Compare
|
Phases 0 and 1 are on master now (#179 Rebase recipe. A plain That reduces it to 4 payload files plus The real conflicts — master changed these four bodies after this PR was written:
Phase 2 dialect, confirmed from
Why I stopped. Verification available once resolved: Happy to push through if you want it — say the word and I'll resolve all seven hunks and let the VM tests arbitrate. Also worth noting: #199's |
6725fa9 to
9f9c164
Compare
|
Rebased and resolved. Head is The Two corrections to the recipe I left last time, both load-bearing:
A bug this found, which is the one worth reviewing: Worth noting the near-miss in tooling too: a combined Resolutions
On "no byte-identity oracle" — there is a partial one, and it passes. The rendered Also green locally: all six aarch64 checks ( Two things I did not fold in, both deliberate:
Not merging: this needs your review, and the fixture delta is the thing to read. |
|
@defangdevs rebase |
… Phase 2)
Every modules/src/ payload is now a genuine, backend-neutral file — real
shell/python/markdown/Caddyfile with no ${pkgs.*}/${cfg.*} — spliced via
the escaping @@include:@@ marker. Values reach the scripts per the issue's
conventions:
- binaries: bare names on the owning unit's PATH (ttyd unit gains tmux;
the webhook daemon unit gains jq/coreutils/agent-box-session; the spot
monitor unit gains curl/tmux/jq/util-linux/systemd/coreutils), or
AGENT_BOX_*_BIN unit env where deliberately NOT on the agent PATH
(grep/find, hostname).
- config: AGENT_BOX_* env — on the unit for daemons, exported by a
two-line generated wrapper for the user-invoked CLIs (agent-box-session,
agent-box-webhook).
- the supervisor is ONE user-independent script (agent-box-supervisor):
per-user values (sessions seed, agent→binary map, host label, env-exec
wrapper, codex-rc wrapper, AGENTS.md pointer, webhook repo/flag) are now
its unit-environment contract — the exact surface Phase 3's template
units + drop-ins need.
- Caddyfile fragments are plain @token@ templates bound by one
replaceStrings call each — the placeholder contract for the Phase 4
native renderer. Rendered Caddyfile is BYTE-IDENTICAL.
- default AGENTS.md is plain markdown with a @WEBHOOK_SECTION@ token;
rendered guides are BYTE-IDENTICAL.
- password helper keeps its per-user paths COMPILED IN (sudo boundary —
env-supplied paths would be a root-write redirect primitive); they moved
to a generated tail after the real-python body.
Byte-stable where required: Caddyfile, AGENTS.md guides, update script,
sudoers, tmpfiles all identical. The reviewed golden diff is confined to
unit env/PATH additions and the script bodies themselves (store-path
references → PATH/env lookups).
All src scripts pass bash -n / py_compile; eval checks green
(golden-snapshot, module-generated-up-to-date, multi-user,
module-single-file, download-route, webhook-route).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NPHNnT2DsWHLhbbhsq2Wc7
…bel in tests The Phase 2 rename to one shared agent-box-supervisor script broke the settings daemon's /proc argv scan (it looked for agent-box-<user>-start), so the page's "restart" button silently degraded from a unit bounce to a session bounce — caught by the settings-page VM test's MainPID-change wait, exactly what that assertion exists for. The scan's own-uid restriction is what scopes the now-shared name to the right unit. sessions.nix likewise asserted the old baked-in literals; the host label now rides the unit environment and the Remote Control name derives from $USER, so assert those. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NPHNnT2DsWHLhbbhsq2Wc7
…n the miss The Phase 2 rename to the shared agent-box-attach left the sessions test's grep -o matching nothing; the empty substitution turned `grep -q '-T hyperlinks'` into a stdin read on the backdoor shell, which hung the run to the 25-minute CI cap (conclusion "cancelled", no assertion output). Point it at the new name and guard the substitution with `|| echo /missing` + head -n1 so a future rename fails in seconds instead. Footgun filed as #183. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NPHNnT2DsWHLhbbhsq2Wc7
Rebase resolution for the four bodies master changed after this PR was written: the `--` end-of-options guards in supervisor.sh (#180/#191), the `--when`/`--drop` help in webhook-cli.sh (#199), the ownership seeding in webhook-spawn.sh (#194), and the guide edits in default-agents.md (whose webhook half now lives in default-agents-webhook.md). Also unescapes two lines in codex-remote-control.sh that the rebase merged WITHOUT a conflict. Its marker had already flipped to the escaping `@@include:` form, so master's Phase 1 `''${reason#...}` was escaped a second time and rendered as a literal `''${reason#...}`. Bash concatenates the empty `''` and still expands, so nothing would have failed a test — exactly the silent-render class of bug Phase 2 has no byte-identity oracle for. Found by reading the regenerated fixture, which is what that diff is for. Golden fixture regenerated: the rendered delta is the `--` guards reaching the supervisor, the bare-binary purge reaching webhook-spawn, and codex-remote-control returning to master's rendered text.
9f9c164 to
55e2be5
Compare
|
Rebased onto master (4 commits kept). The branch is mergeable again. Master moved 8 commits ahead and touched the same payload bodies this PR
One real fix came out of the regeneration: the committed golden had These checks pass locally: |
Review feedback: an indented standalone file is weird. session-cli.sh, webhook-spawn.sh and codex-remote-control.sh still carried the 4-space indentation they had while they sat inside a Nix indented string, so they did not read as the real scripts Phase 2 makes them. Dedent the code and let the @@include@@ marker carry the indentation, as the already-converted payloads do. Two kinds of line keep their exact column, because there the column IS the value: - heredoc bodies and their terminator (codex-remote-control.sh) — that text is what the pane prints; - lines already at column 0 — continuations inside multi-line shell string literals (the webhook spawn preamble, session-cli's newline-in-a-case-pattern). Whitespace only: every rendered payload is byte-identical to before once leading indentation is stripped, and the heredoc message text does not move at all. Also answer the "missing a }?" question in caddyfile-header.caddy: the fragment ends inside the vhost block on purpose. Say so where the question came up; the rendered config balances 71/71. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T3WmpdY3zc555sNdkY9dzQ
Phase 2 of #154, stacked on #181 (Phase 1); retarget after it merges. This is the content-review PR of the series: every
modules/src/payload becomes a genuine, backend-neutral file — real shell/python/markdown/Caddyfile, zero${pkgs.*}/${cfg.*}— and the committedtests/golden/diff in this PR is the exact rendered-behavior delta for review.Conventions applied (from the issue)
tmux), webhook spawner (daemon unit gainsjq/coreutils/agent-box-session), spot monitor (unit gainscurl tmux jq util-linux systemd coreutils), supervisor/CLIs usejq/tmux/bashalready on the agent PATH.AGENT_BOX_*_BINenv where a binary is deliberately not on the agent PATH:grep/find(transcript lookups),hostname(codex UTS re-exec). Keeping them off the agent-visible PATH avoids a behavior change for sessions.AGENT_BOX_*config env: unit environment for daemons (spot monitor's USERS/GRACE/POLL/MSG — with%→%%escaping, a hazard the baked-in path never had); a two-line generated wrapperexports config for the user-invoked CLIs.agent-box-supervisorreplaces per-useragent-box-<user>-start). Its whole per-user contract is unit env:AGENT_BOX_SESSIONS_SEED,AGENT_BOX_AGENT_BINS(name=path pairs replacing the generated case arms),AGENT_BOX_HOST_LABEL,AGENT_BOX_ENV_EXEC,AGENT_BOX_CODEX_RC,AGENT_BOX_AGENTS_POINTER,AGENT_BOX_WEBHOOK_REPO(doubles as the webhook flag). This is precisely the surface Phase 3'sagent-box@.servicetemplate unit + drop-ins will consume. env-exec and attach are likewise now singletons.@TOKEN@templates (@USER@,@USER_ENV@,@SETTINGS_SOCKET@,@DOWNLOADS_DIR@,@TTYD_PORT@,@WEBHOOK_PATH@,@WEBHOOK_SOCKET@,@DOMAIN@) bound by onereplaceStringseach — the placeholder contract the Phase 4 native renderer reuses. Rendered Caddyfile is byte-identical.@WEBHOOK_SECTION@; rendered guides byte-identical in both webhook-on and -off configs.update.shkept its pre-existing REPO/CURRENT_REV/PIN_FILE env names (unit-internal; renaming would be churn). ThewebAuthSecretsServicescript body (a per-user eval-time loop) is deferred to the Phase 3 unit redesign, where it needs restructuring anyway.Verification
bash -n/py_compile; flake8 still gates the assembled settings daemon & password helper viawritePython3Bin.golden-snapshot(fixture regenerated & reviewed),module-generated-up-to-date,multi-user,module-single-file,download-route,webhook-route(aarch64). The x86_64 VM tests in CI (sessions, webhook, settings-page, download-files, self-serve-domain) execute all converted scripts end-to-end.Third checkbox of #154.
🤖 Generated with Claude Code
https://claude.ai/code/session_01NPHNnT2DsWHLhbbhsq2Wc7