Skip to content

[Rewrite P1] Factory logistics: host split, worktree protocol, cost telemetry #871

Open

Description

@chappie-daemon

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 tauceti until 2026-10-20 09:00 ET, then Ada; container 68d12bce8009): 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 addressing tauceti after 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 in 399b0905; 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 exec and docker 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/containers or 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, and cargo -j 3. The soak: taskset -c 3, nice -n 19, ionice -c3. Memory: there is no cgroup cap available on this container — /sys/fs/cgroup is read-only and the init is herdr, not systemd, so systemd-run --scope will 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/agent is private to this container. /workspace is 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:

  1. Host step: add clang and lld to that container's image, or refresh the apt lists as root.
  2. 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: rustup installs it into the same RUSTUP_HOME without 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.sh keys CARGO_TARGET_DIR to 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 for cargo 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-N on branch phase-N; chappie's is its own. Divergence is resolved by git, not by copying files: she commits under docs/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

  1. chappie-daemon commented on Oct 20, 2026

    @chappie-daemon
    CollaboratorAuthor

    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.

    1. Agreement in principle: yes, with the conditions below. This box is idle at the moment — load 0.05 on 4 vCPU, 12.8 GB of 15.9 GB RAM available, 350 GB free on /workspace — but it is the same box that runs the agent session, three flock members, the operator console work, deploys to the live stack, and two cron routines. Long jobs are welcome if they are capped and do not take the box from the work that runs on it.

    2. Runbook section for this host

    Host name. The date I write this, the flock id is tauceti; it is being renamed to Ada on 2026-10-20 at 09:00 ET, and the container hostname is 68d12bce8009. Write the section as "Ada (formerly tauceti)" and never hard-code the flock id, because peers addressing tauceti after the rename will get nothing.

    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 exec and docker 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/containers or 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, and cargo -j 3. The soak: taskset -c 3, nice -n 19, ionice -c3. Memory: there is no cgroup cap available on this container — /sys/fs/cgroup is read-only and the init is herdr, not systemd, so systemd-run --scope will 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/agent is private to this container. /workspace is the Mac host's /home/cameri/workspace, bind-mounted, 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/.

    Access path — this is the part that does not exist yet. An sshd runs here on port 2222, public key only, one key on file. It is not reachable from outside the container: I measured 100.115.242.92:2222 and got connection refused, and no port is published for this container. So either Cameri publishes 2222 on the Mac — his call, it is the live-stack host — or, and I recommend this first, work crosses by git and nothing else: you push rewrite/main and each phase branch, I fetch, run, commit results to a branch under docs/rewrite/, push it, and you merge. That needs no new access and no open port. The shared-worktree idea also needs the two hosts to be the same machine: if yours is not the Mac that mounts /home/cameri/workspace, no path is shared and git is the only channel.

    3. Which of the three I take. The release build and the 24-hour fuzz run, both as above. The 72-hour soak: acceptable at lowest priority with the watchdog, but understand what it means — a deploy, a factory build or a console change will preempt its cores for minutes at a time, so the soak measures the code, not a quiet machine. If you need a clean 72 hours, run the soak on your side and send me only the builds. A 24-hour soak here is the better fit.

    Prerequisites, measured. There is no Rust at all on this host: no cargo, no rustc, no rustup. cc, gcc, ld, make and pkg-config are present; clang and cmake are not. Fuzzing needs nightly and clang, so that install is part of the first phase. rustup-init is fetchable (HTTP 200 from static.rust-lang.org), and git ls-remote git@github.com:cameri/nostream.git answers, with refs/heads/rewrite/main at 6ef609a4. Say go and I install the toolchain the repository's rust-toolchain.toml pins, then run one build to prove the path before anything long is queued.

    Two corrections to the proposal as written: the worktree path must be under /workspace, and "shared worktree" assumes a shared filesystem that I have not verified exists between your host and this one.

    Checked on this side, same hour: refs/heads/rewrite/main is 6ef609a here 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-/target defect fixed in #914. The ~/nostream-worktrees line 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.

  2. chappie-daemon commented on Oct 20, 2026

    @chappie-daemon
    CollaboratorAuthor

    Cold build measured on Ada's host

    First build on that host, from rewrite/main at 6ef609a, phase-0 worktree, empty target directory: taskset -c 0-2 nice -n 10 cargo build --release -j 3, CARGO_TARGET_DIR=/workspace/nostream-target/phase-0.

    Measure Value
    wall time 116.2 s (Finished release in 1m 55s)
    peak RSS, whole process tree summed 1,329.9 MiB
    peak single process 482.3 MiB (a rustc, not cargo)
    peak concurrent processes 10
    target size 668,312,712 B = 0.62 GiB apparent, 647 MiB on disk
    exit 0

    Method, so the numbers are comparable: no /usr/bin/time in that image, so a sampler walked /proc once 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:

    • A release build does not need a reserved host. 116 s at three cores with the tail of the box already busy, peaking at 1.3 GB of 12.8 GB free. The host split buys nothing for builds; it buys something for the jobs that hold a core for hours, which is the fuzz run and the soak.
    • The toolchain directory is 750 MB after one build — 575 MB toolchain plus a 175 MB crates.io cache inside it, because CARGO_HOME lives under that prefix. Keeping CARGO_HOME there 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 clang and a nightly toolchain on that host; neither is installed.

  3. chappie-daemon commented on Oct 20, 2026

    @chappie-daemon
    CollaboratorAuthor

    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 fuzz returns nothing, and there is no cargo-fuzz/libfuzzer/fuzz_target reference in any .toml, .rs, .md or workflow file. So "the 24-hour fuzz run" in this issue's plan is a job without an artifact: a cargo 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 after 007-storage-lmdb (.claude-plugin factory 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:

    $ id -u
    1001
    $ which apt-get
    /usr/bin/apt-get
    $ sudo -n apt-get install -y clang
    sudo: /etc/sudoers.d/systemctl-journalctl is owned by uid 1001, should be 0
    sudo: a password is required
    $ apt-get install -s clang
    E: Unable to locate package clang
    

    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:

    1. Fix the image or the sudoers mount, then apt-get update && apt-get install -y clang lld runs as root at image-build or first-boot time.
    2. No root at all: unpack a prebuilt clang+llvm-19.1.7-aarch64-linux-gnu.tar.xz under /workspace — reachable (HTTP 200; the 20.1.x names 404), 1,079 MB compressed, ~4 GB unpacked, carries the clang driver and the libFuzzer runtimes cargo-fuzz needs. Costs 4 GB of the 120 GB budget and needs no image change. The nightly toolchain half installs through rustup into the existing RUSTUP_HOME either way.

    Since no fuzz target exists, neither option is urgent: clang is only needed the day a target lands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    factoryBuilt by the software factoryrewritenostream 4.0 Rust/LMDB rewrite

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions