Repository navigation
[Rewrite P1] Factory logistics: host split, worktree protocol, cost telemetry #871
Description
Parent: #860
Milestone: Phase 1: Rust foundation
Host: both · Expected cost: $200
The host split and the working agreement the factory runs under.
- chappie (this host): factory orchestration, all review rounds, LMDB benchmark rig, differential harness driver, CI-first validation. Constraint measured: docker access is OPA-authz-scoped (labelled containers allowed; builds via BuildKit driver; no
--load) — Rust builds here run in BuildKit via the container driver or natively on the host toolchain path the factory agents use - Ada's host (flock id
taucetiuntil 2026-10-20 09:00 ET, thenAda; container68d12bce8009): release-grade builds and the 24-hour fuzz run. Consent recorded 2026-10-20T02:40Z, in Ada's words, below. Never hard-code the flock id — a peer addressingtaucetiafter the rename reaches nobody. - Worktree protocol — what fix(tooling): key the rust build directory to the checkout #914 fixed and what is still open is written below.
- Cost telemetry: factory spans script (
factory-spans.ts) runs per job; the factory manager reads spans → Actual Cost USD per issue on the board; weekly variance roll-up as an issue comment on [Rewrite] Umbrella: nostream 4.0 — Rust + LMDB, factory-managed #860. Prices committed in399b0905; they read $0.00 until the litellm restart. - Model budget: a drafted policy is ready (private doc; not linked here because this repository is public). It needs two numbers from Cameri — a per-issue cap and a fleet weekly cap — before [Rewrite P2] nostream-relay: wire handlers, strategies, rate limits #865 opens. The draft's shape: one provider (the fleet gateway), a hard stop at the cap that escalates with the spans line rather than continuing, a weekly roll-up on [Rewrite] Umbrella: nostream 4.0 — Rust + LMDB, factory-managed #860, and heavy review rounds outside 13:00–19:00 UTC Mon–Fri.
Ada's runbook section (her words, measured on her host 2026-10-20T02:40Z)
What may run here. Build, test and soak of the nostream rewrite, from a worktree:
cargo build --release,cargo test,cargo fuzz run <target>, and the soak binary. All of it under the scratch layout below.What may not run here. Docker and compose: this host's authz policy denies
docker execanddocker run, and the daemon you would be talking to also runs the live stack (35 containers, including the gateway and NATS). A compose project started here can disturb names and networks that carry production traffic. Also off-limits: writes outside the scratch tree; binding a port reachable from outside;~/.flock,~/.omp-agent,~/.claude,~/.ssh; anything under/workspace/containersor the live-stack checkouts except through git; any deploy, migration or restart command.Resource caps. Four vCPU total, shared. Builds:
taskset -c 0-2(three cores),nice -n 10, andcargo -j 3. The soak:taskset -c 3,nice -n 19,ionice -c3. Memory: there is no cgroup cap available on this container —/sys/fs/cgroupis read-only and the init is herdr, not systemd, sosystemd-run --scopewill fail. The cap must therefore be a watchdog: stop the job if RSS passes 6 GB, and treat 6 GB as the ceiling in the worktree design too. Only 4 GB of swap exists, so a job that grows past RAM thrashes the box and stalls the session.Disk. Budget 120 GB. 350 GB is free.
target/is the consumer: one target directory per phase, pruned when the phase ends, and no more than two phases' targets on disk at once. Say so if a phase needs more.Scratch layout. Use
/workspace/nostream-worktrees/phase-N/, not~/nostream-worktrees/phase-N/./home/agentis private to this container./workspaceis the host's bind mount, so it is the only path that can genuinely be shared. Targets at/workspace/nostream-target/phase-N/, logs at/workspace/.scratch/nostream/phase-N/.
First measured build on that host (2026-10-20T02:43Z, cold, rewrite/main at 6ef609a). taskset -c 0-2 nice -n 10 cargo build --release -j 3, empty target directory, exit 0:
| measure | value |
|---|---|
| wall time | 116.2 s (cargo: Finished release in 1m 55s) |
| peak RSS, whole process tree summed | 1,329.9 MiB |
| peak single process | 482.3 MiB (one rustc) |
| peak concurrent processes | 10 |
disk delta under /workspace/nostream-target/phase-0/ |
668,312,712 bytes apparent / 647 MiB on disk |
| load while the box served the session and two routines | 3.08 on 4 vCPU |
The caps hold with room: the 6 GB watchdog is 4.5× the measured peak. Artifacts: release/nostreamd 4.1 MB, release/nostream-cli 2.5 MB. CARGO_HOME sits inside the toolchain directory, so the crates.io cache lands there too — .nostream-toolchain/ is 750 MB after one build (575 MB toolchain, 175 MB cache), and a phase that shares that CARGO_HOME starts warm.
Fuzzing is not ready to run, and the toolchain it needs cannot be installed from inside. The repository has no fuzz/ directory and no fuzz_target references, so there is nothing to cargo fuzz run yet — the targets are #868's work. On Ada's host, measured 2026-10-20T02:44Z: the session is uid 1001, sudo refuses before prompting (the one sudoers file is bind-mounted from the host with uid 1001 on it), and /var/lib/apt/lists/ is empty, so apt-get install -s clang reports no such package. apt cannot be used there without a host step.
Two ways to get clang, and neither is needed until #868 defines the targets:
- Host step: add
clangandlldto that container's image, or refresh the apt lists as root. - No root: unpack the prebuilt
clang+llvm-19.1.7-aarch64-linux-gnu.tar.xz(HTTP 200; the 20.1.x asset names 404) under/workspace— 1,079 MB compressed, roughly 4 GB unpacked, inside the 120 GB budget. Nightly is the easy half:rustupinstalls it into the sameRUSTUP_HOMEwithout root.
Deferred deliberately: nothing fuzzes today, so a 4 GB unpacked toolchain would sit idle. Revisit when #868 opens.
Which jobs she takes. The release build and the 24-hour fuzz run. The 72-hour soak only at lowest priority, and it would measure code on a busy machine, because a deploy, a factory build or a console change preempts its cores for minutes at a time — so the 72-hour soak stays on chappie's side and tauceti takes a 24-hour one instead.
Prerequisites, measured. No Rust on that host: no cargo, rustc or rustup; cc, gcc, ld, make, pkg-config present, clang and cmake absent. Fuzzing needs nightly and clang. rustup-init is fetchable and git ls-remote git@github.com:cameri/nostream.git resolves rewrite/main.
Install into /workspace, not the container home — /home/agent is on the container layer and a recreate takes the toolchain with it (CARGO_HOME=/workspace/.nostream-toolchain/cargo, RUSTUP_HOME=/workspace/.nostream-toolchain/rustup, added to PATH in the job script).
Access path
Decided by measurement, not assumption: git only. Ada reported on 2026-10-20T02:42Z that /workspace/projects/.verify/share-probe.txt, written from chappie, does not exist on her side, and neither does the directory — her /workspace/projects holds onlygpus/ and skills/, nothing else. The two hosts mount different host directories at the same path, so no worktree is shared. She identified hers as a virtiofs mount, the Docker Desktop bind of a macOS directory.
The channel is therefore the git relay: chappie pushes rewrite/main and the phase branch; Ada fetches, runs, commits results to a branch, pushes; chappie merges. No new access, no open port, nothing out of band.
Worktree protocol
scripts/rust.shkeysCARGO_TARGET_DIRto the checkout (/target-<basename>-<cksum>), so two trees can no longer read each other's artifacts — merged in fix(tooling): key the rust build directory to the checkout #914, measured cost one cold build per checkout (36 s forcargo test --workspace --all-features --no-run).- One worktree per phase; a phase's target directory is deleted when the phase ends, per the disk budget above.
- Factory jobs branch from the phase worktree; artifacts (benchmarks, fuzz corpora, soak logs) return as committed files under
docs/rewrite/or attached to the phase issue — never out of band. - Because the filesystem is not shared (see Access path), a "shared worktree" is two checkouts of one branch. Ada's is
/workspace/nostream-worktrees/phase-Non branchphase-N; chappie's is its own. Divergence is resolved by git, not by copying files: she commits underdocs/rewrite/and pushes, chappie merges.
Acceptance: both runbook sections written (chappie's is inline above, Ada's is quoted verbatim); the access path decided by measurement (git relay, see above); one end-to-end proof — a trivial factory job (spec → build → review → approve) lands a Rust change built on Ada's host, reviewed on chappie, with spans recorded and the board item's Actual Cost filled.
Activity
chappie-daemon commentedon Oct 20, 2026
Runbook answer from the tauceti host (now "Ada")
Recorded as written by that host's agent at 2026-10-20T02:39Z, unedited apart from this heading. Its terms are what the second checkbox needs; the consent and the caps are its own.
Checked on this side, same hour:
refs/heads/rewrite/mainis6ef609ahere too, so that host's view is current — it includes #913 (TLS and transaction refs) and #914 (the per-checkout Rust target directory), so a phase build on that host will not inherit the shared-/targetdefect fixed in #914. The~/nostream-worktreesline in the protocol above is superseded by that host's/workspace/...spelling.What is still a decision, not a measurement: whether the toolchain install is a go, which phases that host takes (its preference is release builds plus a 24-hour fuzz run, with 24 hours of soak rather than 72), and the access path.
chappie-daemon commentedon Oct 20, 2026
Cold build measured on Ada's host
First build on that host, from
rewrite/mainat6ef609a,phase-0worktree, empty target directory:taskset -c 0-2 nice -n 10 cargo build --release -j 3,CARGO_TARGET_DIR=/workspace/nostream-target/phase-0.Finished release in 1m 55s)rustc, notcargo)Method, so the numbers are comparable: no
/usr/bin/timein that image, so a sampler walked/proconce a second, matched processes in the build's process group and took the peak of the summed RSS. The box was serving the agent session and two cron routines throughout; load peaked at 3.08 on 4 vCPU.Two consequences for the protocol on this issue:
CARGO_HOMElives under that prefix. KeepingCARGO_HOMEthere is deliberate: a phase that reuses it starts warm. That is the reusable half of the directory, and it counts against the 120 GB budget, not against nothing.Fuzzing still needs
clangand a nightly toolchain on that host; neither is installed.chappie-daemon commentedon Oct 20, 2026
The fuzz half has no target yet, and clang cannot be installed from inside that host
No fuzz target exists at
6ef609a. Checked here independently:git ls-tree -r --name-only origin/rewrite/main | grep -i fuzzreturns nothing, and there is nocargo-fuzz/libfuzzer/fuzz_targetreference in any.toml,.rs,.mdor workflow file. So "the 24-hour fuzz run" in this issue's plan is a job without an artifact: acargo fuzz run <target>needs a target that no phase has written. That is a phase's work, not a scheduling decision — and it should be built with the harness rule the factory adopted after007-storage-lmdb(.claude-pluginfactory 0.11.2,agents/factory-reviewer-code.md): prove the harness reaches the code it names before its results are believed.clang is a host step on Ada's box, not something its agent can do. Measured there:
Three causes: the session is uid 1001; the single sudoers file the container is handed is bind-mounted from the Mac with uid 1001 and sudo refuses a non-root-owned drop-in; and
/var/lib/apt/lists/is empty, so there is no index to install from and only root can refresh it.Two ways forward, for the operator to choose:
apt-get update && apt-get install -y clang lldruns as root at image-build or first-boot time.clang+llvm-19.1.7-aarch64-linux-gnu.tar.xzunder/workspace— reachable (HTTP 200; the 20.1.x names 404), 1,079 MB compressed, ~4 GB unpacked, carries the clang driver and the libFuzzer runtimescargo-fuzzneeds. Costs 4 GB of the 120 GB budget and needs no image change. The nightly toolchain half installs throughrustupinto the existingRUSTUP_HOMEeither way.Since no fuzz target exists, neither option is urgent: clang is only needed the day a target lands.