Skip to content

feat: install the latest release of every tool on each apply - #22

Merged
undeemed merged 13 commits into
mainfrom
fm/cf-toolchain-latest-l1
Oct 1, 2026
Merged

undeemed merged 13 commits into
mainfrom
fm/cf-toolchain-latest-l1

Conversation

@undeemed

@undeemed undeemed commented Oct 1, 2026

Copy link
Copy Markdown
Owner

Intent

"update all pinned to no mistakes, node, bun, gh, treehouse, and all axi tools to check and install latest, the rest i do not use so throw it away"

Context for reading that ask: Code-Factory today pins most of its toolchain. Native tools (node, bun, uv, gh, no-mistakes, treehouse, rustup-init, plus the rust toolchain) carry exact versions and per-architecture SHA-256 hashes in toolchain.lock.json. The npm tools (pi, codex, pnpm, and the axi family: chrome-devtools-axi, gh-axi, lavish-axi, quota-axi, tasks-axi) carry exact versions in tools/npm/package.json and tools/npm/package-lock.json. Only herdr and omp are already resolved to their latest release on every apply (docs/architecture.md "update" steps 1 and 2, scripts/install_tools.py resolve_latest). The list the request was answering was: no-mistakes, node, bun, gh, treehouse, codex, pi, pnpm, and the axi tools. So "latest" covers no-mistakes, node, bun, gh, treehouse, and the five axi tools, and "the rest ... throw it away" covers codex, pi, and pnpm.

On pnpm, which the fleet-guard worktree tooling used for pnpm dev: "update to use latest bun only and drop it" - pnpm is dropped completely, and bun, installed at its latest release on every apply, is the single package manager and runner the recipe relies on, so anything Code-Factory ran through pnpm runs through bun instead. Node stays.

"make sure stuff is not pinned and instead is latest" - everything Code-Factory installs resolves to its latest release on every apply, including uv, rustup-init, the Rust toolchain (the stable channel), the Obscura browser binary, the Chrome pruner's psutil, the shared Supabase CLI, the Docker worker base image (ubuntu:latest), and the omp marketplace plugins the recipe uses (installed and upgraded to latest on every apply). Every download is still verified against the checksum or digest its publisher posts for that exact release, and a release without one is refused. Code-Factory's own uv.lock development environment stays locked.

"ci: pin latest" - in .github/workflows, every GitHub Action stays pinned to a full commit SHA, moved to the SHA of that action's latest release tag with the tag in a trailing comment, and .github/dependabot.yml adds a weekly github-actions update so the pins keep moving to the newest release.

What Changed

  • scripts/install_tools.py now resolves every tool it installs to its latest release on each apply: node, bun, gh, uv, no-mistakes, treehouse, rustup-init, the Rust stable toolchain, the axi npm tools, Obscura, the Supabase CLI and the Chrome pruner's psutil. Each download is checked against the checksum, digest or npm integrity its publisher posts for that release. A release with no published checksum is refused. The omp marketplace plugins are installed and upgraded to their default branch instead. codex, pi and pnpm are dropped, and the acpx default agent is switched from codex to omp. Removed: toolchain.lock.json, schemas/toolchain.schema.json, the tools/npm and fleet/shared-supabase package files, and maintenance/requirements.txt. The Ansible tasks, templates, config and docs are updated to match, and the Obscura version and SHA keys in the factory schema are marked deprecated and no longer required.
  • Fleet worktree tooling runs through bun instead of pnpm. worktree-env-seed.sh writes a heap-capping node wrapper into each pool slot instead of a per-worktree .npmrc. chrome-autoprune.py recognises per-version chrome-devtools-axi install prefixes as well as the retired shared npm prefix.
  • The Docker worker base image is now ubuntu:latest, with the digest pin removed. In CI, uv and Bun install at latest, and each action is pinned to the commit SHA of its latest release. .github/dependabot.yml adds a weekly github-actions update. Tests are updated for the new installer behaviour, and new tests cover the Chrome pruner and the worktree env seeder.

Risk Assessment

🚨 High: The host-wide BUN_OPTIONS=--env-file=.env.fleet silently stops every bun process from loading .env and .env.local, including the Supabase env the fleet seeds into worktrees. Bootstrap also now depends on unauthenticated multi-source resolution, which is a likely image-build failure. Two intent gaps (legacy codex/pnpm survive upgrades, unverified omp plugins) need author decisions.

Testing

I ran the real installer in a scratch HOME from a checkout under ~ Every native and axi tool resolved to the latest upstream release and installed with its checksum verified. The retired tools were removed correctly, tampered or unsafe inputs were refused, and the omp plugins landed in the target home while the real ~/.omp record stayed untouched. Separately I leased a fresh treehouse lane and confirmed the first bun/npx dev server reports the capped 2144 MB heap; the plain shell node stays at 4192 MB. The Herdr unit render, Obscura, psutil and Supabase, config validation, CI pins and a 21/21 container smoke also passed, plus 78 targeted pytest cases. Not exercised: a hosted GitHub Actions run and Dependabot opening PRs.

  • Live validation: ✅ go - 13 of 14 scenarios driven live against the product
Scenario Result Live Evidence
Fresh install of herdr, node, bun, uv, gh, no-mistakes and treehouse resolves each tool to its latest upstream release ✅ pass live final-install-verify.txt and github-latest-tags.txt: installed versions equal GitHub releases/latest for herdr 0.9.3, bun 1.4.2, gh 2.102.0, no-mistakes 1.84.0, treehouse 3.1.0 and uv 0.12.21, and nod…
The axi tools, omp, acpx and chrome-devtools-mcp install at the npm registry's latest version ✅ pass live final-install-verify.txt versus npm view: chrome-devtools-axi 0.1.36, gh-axi 0.1.35, lavish-axi 0.1.80, quota-axi 0.1.55, tasks-axi 0.2.6, omp 18.4.6, acpx 0.19.4, chrome-devtools-mcp 1.10.1
A second apply changes nothing (idempotent) ✅ pass live final-install-run2.out reports changed=false; container smoke 'installer-idempotent' and 'ansible-second-pass' (changed=0)
codex and pnpm are retired: their managed links are removed, the legacy npm directory stays, a same-named command installed elsewhere is kept, and codex, pi and pnpm are not provisioned ✅ pass live final-install-verify.txt: codex and pnpx links gone, pnpm still points to /tmp/cf-other-bin/pnpm, and the legacy npm/node_modules/.bin still holds codex, pnpm and pnpx; codex and pi are not on PATH
Adversarial: a tampered SHA-256, an empty SHA-256, an http:// asset URL, and an unsafe npm version are all refused with nothing installed or changed ✅ pass live final-adversarial-refusals.txt: 'checksum mismatch' for the real bun asset, 'downloads require HTTPS and an explicit SHA-256' for the empty digest and for the http URL, and 'unsafe gh-axi version' wit…
Rust toolchain follows the stable channel with rustfmt and clippy, installed through the latest rustup-init ✅ pass live final-rust-and-mcp-link.txt: stable-x86_64 active, rustc 1.98.1 equals upstream channel-rust-stable, rustfmt and clippy present
Obscura, the Chrome pruner's psutil and the shared Supabase CLI resolve to their latest releases and are verified, and a wrong psutil digest is refused ✅ pass live final-obscura.txt (downloaded sha equals publisher digest, 0.2.3 is GitHub's latest); final-psutil-supabase.txt (psutil 7.2.2 via --require-hashes, wrong hash rc=1; supabase 2.119.0 equals the npm lat…
omp marketplace plugins install into the target --home even when the installer starts from a checkout under another home that has its own .omp (regression from round 1) ✅ pass live final-install-verify.txt: scratch home has caveman, i-have-adhd and ponytail records, installed from a worktree under ~; the real ~/.omp record md5 b714925b... was unchanged; the…
A new chrome-devtools-mcp release re-points the stable current link and leaves the managed MCP path and the Herdr unit text unchanged, so Herdr does not restart; a Herdr upgrade still changes the un… ✅ pass live final-rust-and-mcp-link.txt (installer moved current 1.10.1 to 1.9.0 and back to 1.10.1 and kept both versions on disk) and final-herdr-unit-render.txt (real Ansible template render identical for MCP…
A fresh treehouse lane's first bun run dev is heap-capped: the seeder writes the slot-level node wrapper before bun install, the cap survives rm -rf node_modules, the override works, and a plain… ✅ pass live final-fresh-lane-heap-cap.txt: after the seeder and before bun install the slot holds the wrapper; the first bun run dev and npx report heap_limit_mb=2144 and execArgv --max-old-space-size=2048;…
Config: legacy obscura pins are accepted with a warning, a malformed legacy sha is still rejected, and the shipped default validates ✅ pass live final-validate-config.txt: default rc=0; legacy pins rc=0 with the 'no longer used and are ignored' warning; malformed sha rc=1 on the schema pattern
Container worker image builds on ubuntu:latest and the in-container smoke passes end to end ✅ pass live container-smoke-final.log: base is docker.io/library/ubuntu:latest, '21/21 checks ran, 0 failed', smoke exit=0
Every GitHub Action in .github/workflows is pinned to a full commit SHA with its tag in a trailing comment, that SHA is the action's latest release, and Dependabot has a weekly github-actions update ✅ pass live final-ci-pins-vs-latest.txt: checkout v7.0.1, setup-uv v10.2.0 and setup-bun v2.2.0 each resolve to the SHA of the latest GitHub release (checked against GitHub); dependabot.yml parses to package-ecos…
The GitHub Actions workflow runs green on GitHub, and Dependabot opens its first weekly github-actions PR ⏸️ untested no Both run only on GitHub-hosted infrastructure after the branch is pushed, which this local test phase cannot trigger. Remote CI covers the workflow run; the first Dependabot PR appears after merge on…
Evidence: Container smoke on ubuntu:latest, 21/21 checks, exit 0
==> docker build --target smoke --tag code-factory-smoke:3103495
#0 building with "default" instance using docker driver

#1 [internal] load build definition from Dockerfile
#1 transferring dockerfile: 8.43kB 0.0s done
#1 DONE 0.0s

#2 [internal] load metadata for docker.io/library/ubuntu:latest
#2 DONE 0.5s

#3 [internal] load .dockerignore
#3 transferring context: 1.55kB done
#3 DONE 0.0s

#4 [base 1/3] FROM docker.io/library/ubuntu:latest@sha256:da6fc2be547864451aa253836dd926da33623312df4a9a243e35dc877c378a78
#4 resolve docker.io/library/ubuntu:latest@sha256:da6fc2be547864451aa253836dd926da33623312df4a9a243e35dc877c378a78 0.0s done
#4 DONE 0.0s

#5 [internal] load build context
#5 transferring context: 7.45kB 0.1s done
#5 DONE 0.1s

#6 [worker 4/9] RUN set -eux; chmod +x bootstrap.sh factory tests/container-smoke.sh
#6 CACHED

#7 [base 3/3] RUN set -eux;     if getent passwd "1000" >/dev/null; then         existing_user="$(getent passwd "1000" | cut -d: -f1)";         if [ "${existing_user}" != "coder" ]; then             userdel -r "${existing_user}" >/dev/null 2>&1 || userdel "${existing_user}";         fi;     fi;     if getent group "1000" >/dev/null; then         existing_group="$(getent group "1000" | cut -d: -f1)";         if [ "${existing_group}" != "coder" ]; then groupdel "${existing_group}"; fi;     fi;     if ! getent group "coder" >/dev/null; then         groupadd --gid "1000" "coder";     fi;     if ! getent passwd "coder" >/dev/null; then         useradd --create-home --home-dir "~"                 --uid "1000" --gid "1000"                 --shell /bin/bash "coder";     fi;     install -d -o "coder" -g "coder" -m 0755         "~/.local"         "~/.local/bin"         "~/.local/share"         "~/.local/state"         "~/.config"         "~/.cache"         "~/Dev"         /opt/code-factory;     printf '%s ALL=(ALL) NOPASSWD:ALL\n' "coder" > /etc/sudoers.d/90-code-factory;     chmod 0440 /etc/sudoers.d/90-code-factory;     visudo -cf /etc/sudoers.d/90-code-factory
#7 CACHED

#8 [worker 2/9] RUN set -eux;     printf 'role=worker\nsource=/opt/code-factory\nuser=%s\nhome=%s\nworkspace=%s\nconfig=%s\nsystemd=absent\ntailscale=absent\ndesktop=absent\n'         "coder" "~" "~/Dev" "containers/factory.container.yml"         > /etc/code-factory-image;     chmod 0444 /etc/code-factory-image
#8 CACHED

#9 [worker 1/9] COPY --chown=coder:coder . /opt/code-factory
#9 CACHED

#10 [worker 8/9] RUN --mount=type=secret,id=github_token,env=GITHUB_TOKEN     set -eux; ./factory apply --config "containers/factory.container.yml"
#10 CACHED

#11 [base 2/3] RUN set -eux;     apt-get update;     apt-get install -y --no-install-recommends         bash         build-essential         ca-certificates         curl         git         iproute2         jq         less         libssl-dev         openssh-client         pkg-config         procps         python3         python3-apt         python3-venv         sudo         tar         unzip         xz-utils         zstd;     rm -rf /var/lib/apt/lists/*
#11 CACHED

#12 [worker 5/9] RUN --mount=type=secret,id=github_token,env=GITHUB_TOKEN     set -eux; ./bootstrap.sh
#12 CACHED

#13 [worker 9/9] WORKDIR ~/Dev
#13 CACHED

#14 [worker 3/9] WORKDIR /opt/code-factory
#14 CACHED

#15 [worker 6/9] RUN set -eux; ./factory validate --config "containers/factory.container.yml"
#15 CACHED

#16 [worker 7/9] RUN set -eux; uv run --project . --locked python containers/assert-image-config.py "containers/factory.container.yml"
#16 CACHED

#17 [smoke 1/1] WORKDIR /opt/code-factory
#17 CACHED

#18 exporting to image
#18 exporting layers done
#18 exporting manifest sha256:77733f2b4e799b1db7be525f9bf0db66c71503061439a6dcee39a5dc6c973336 done
#18 exporting config sha256:e81089a2df170e21680b449865141417b89773a4ec2a389611e581154719ca5f done
#18 exporting attestation manifest sha256:1b197ff6c982bf54c0455d83a91c5f2f2ba3fa80366882b821a5d6225b14e95f 0.0s done
#18 exporting manifest list sha256:d88e8f6290d4d772d5cb22be2669a6a84784d5fabc4944624e399be1d434b055 done
#18 naming to docker.io/library/code-factory-smoke:3103495 done
#18 unpacking to docker.io/library/code-factory-smoke:3103495 0.0s done
#18 DONE 0.1s
==> docker run code-factory-smoke:3103495 (memory=4g cpus=2 pids=4096)
== Code Factory container smoke (image role: smoke)
== Linux x86_64

ok    identity                           0s
        uid=1000 user=coder home=~ shell=/bin/bash
ok    no-systemd                         0s
        pid1=docker-init no systemd, no linger marker (start_services=false honored)
ok    no-host-surface                    0s
        no docker socket, host mount, desktop or browser profile state
ok    profiles-disabled                  0s
        docker, tailscale and desktop profiles produced no binaries
ok    source-checkout                    0s
        checkout /opt/code-factory owned by coder, config /opt/code-factory/containers/factory.container.yml
ok    workspace                          0s
        workspace ~/Dev writable and owned by coder
ok    core-tools                         0s
        node   v26.10.0                         (expected 26.10.0)
        bun    1.4.2                            (expected 1.4.2)
        uv     uv 0.12.21 (x86_64-unknown-linux-gnu) (expected 0.12.21)
ok    resolved-releases                  0s
        herdr 0.9.3
        gh 2.102.0
        no-mistakes 1.84.0
        treehouse 3.1.0
        omp 18.4.6
        chrome-devtools-axi 0.1.36
        gh-axi 0.1.35
        lavish-axi 0.1.80
        quota-axi 0.1.55
        tasks-axi 0.2.6
        acpx 0.19.4
        chrome-devtools-mcp 1.10.1
        installed releases match ~/.local/share/code-factory/resolved.json
ok    herdr-install-layout               0s
        herdr symlink -> ~/.local/share/code-factory/tools/herdr/0.9.3/linux-x86_64/herdr
ok    herdr-unit                         0s
        unit ExecStart=~/.local/share/code-factory/tools/herdr/0.9.3/linux-x86_64/herdr server runs herdr 0.9.3, statically enabled, not started
ok    development-toolchain              0s
        rustc  rustc 1.98.1 (48a229cea 2026-09-01) (~/.local/bin/rustc)
        cargo  cargo 1.98.1 (797e8a9bc 2026-08-05) (~/.local/bin/cargo)
ok    login-shell-environment            0s
        login shell resolves ~/.local/bin/herdr and pins the MCP entrypoint at ~/.local/share/code-factory/chrome-devtools-mcp/current/node_modules/chrome-devtools-mcp/build/src/bin/chrome-devtools-mcp.js
ok    agent-gate                         1s
        quota-axi 0.1.55 (floor 0.1.54)
        tasks-axi 0.2.6 (floor 0.2.6)
        gate agent acp:omp via acpx, ponytail-review on omp, omp plugins installed
ok    no-baked-credentials               0s
        no credential stores, tokens or .env files in the image
ok    herdr-config                       0s
        rendered config matches the document: agent_panel_sort=spaces, headless_cols=120, headless_rows=40, sidebar_agent_rows=3 rows, sidebar_bg=reset, sidebar_max_width=56, sidebar_space_rows=4 rows, sidebar_width=46, theme=catppuccin, toast_delivery=herdr
        herdr config check: config: ok
ok    herdr-server-headless              2s
        headless server answered on ~/.config/herdr/herdr.sock after 1s and stopped over the API socket; no GUI state created
ok    factory-validate                   0s
        Valid host configuration: /opt/code-factory/containers/factory.container.yml
        ./factory validate --config /opt/code-factory/containers/factory.container.yml accepted
ok    factory-validate-invalid           0s
        ./factory validate rejected an invalid document as expected
ok    factory-init-no-overwrite          1s
        Created /opt/code-factory/.local/host.yml; review profiles before ./factory apply.
        ./factory init wrote .local/host.yml once and refused to overwrite it
ok    installer-idempotent               8s
        installer re-run changed=false, installed entries: 8
ok    ansible-second-pass               73s
        recap: localhost                  : ok=66   changed=0    unreachable=0    failed=0    skipped=145  rescued=0    ignored=0   
        second apply idempotent across 1 host line(s)

== 21/21 checks ran, 0 failed
smoke exit=0
Evidence: Live install run 1 (changed=true) and run 2 (changed=false)
{"changed": true, "installed": ["herdr", "node", "bun", "uv", "gh", "no-mistakes", "treehouse", "rustup-init"], "npm": true, "development": true}
Evidence: Installed versions, retirement outcome, MCP current link and omp plugin record
== resolved record
== bin links
.  
..  
acpx -> /tmp/cf-scratch-home/.local/share/code-factory/acpx/0.19.4/node_modules/acpx/dist/cli.js
bun -> /tmp/cf-scratch-home/.local/share/code-factory/tools/bun/1.4.2/linux-x86_64/bun-linux-x64-baseline/bun
cargo -> /tmp/cf-scratch-home/.cargo/bin/cargo
cargo-clippy -> /tmp/cf-scratch-home/.cargo/bin/cargo-clippy
cargo-fmt -> /tmp/cf-scratch-home/.cargo/bin/cargo-fmt
chrome-devtools -> /tmp/cf-scratch-home/.local/share/code-factory/chrome-devtools-mcp/1.10.1/node_modules/chrome-devtools-mcp/build/src/bin/chrome-devtools.js
chrome-devtools-axi -> /tmp/cf-scratch-home/.local/share/code-factory/chrome-devtools-axi/0.1.36/node_modules/chrome-devtools-axi/dist/bin/chrome-devtools-axi.js
chrome-devtools-mcp -> /tmp/cf-scratch-home/.local/share/code-factory/chrome-devtools-mcp/1.10.1/node_modules/chrome-devtools-mcp/build/src/bin/chrome-devtools-mcp.js
clippy-driver -> /tmp/cf-scratch-home/.cargo/bin/clippy-driver
gh -> /tmp/cf-scratch-home/.local/share/code-factory/tools/gh/2.102.0/linux-x86_64/gh_2.102.0_linux_amd64/bin/gh
gh-axi -> /tmp/cf-scratch-home/.local/share/code-factory/gh-axi/0.1.35/node_modules/gh-axi/dist/bin/gh-axi.js
herdr -> /tmp/cf-scratch-home/.local/share/code-factory/tools/herdr/0.9.3/linux-x86_64/herdr
lavish-axi -> /tmp/cf-scratch-home/.local/share/code-factory/lavish-axi/0.1.80/node_modules/lavish-axi/dist/cli.mjs
no-mistakes -> /tmp/cf-scratch-home/.local/share/code-factory/tools/no-mistakes/1.84.0/linux-x86_64/no-mistakes
node -> /tmp/cf-scratch-home/.local/share/code-factory/tools/node/26.10.0/linux-x86_64/node-v26.10.0-linux-x64/bin/node
npm -> /tmp/cf-scratch-home/.local/share/code-factory/tools/node/26.10.0/linux-x86_64/node-v26.10.0-linux-x64/bin/npm
npx -> /tmp/cf-scratch-home/.local/share/code-factory/tools/node/26.10.0/linux-x86_64/node-v26.10.0-linux-x64/bin/npx
omp -> /tmp/cf-scratch-home/.local/share/code-factory/omp/18.4.6/node_modules/@oh-my-pi/pi-coding-agent/dist/cli.js
pnpm -> /tmp/cf-other-bin/pnpm
quota-axi -> /tmp/cf-scratch-home/.local/share/code-factory/quota-axi/0.1.55/node_modules/quota-axi/dist/bin/quota-axi.js
rustc -> /tmp/cf-scratch-home/.cargo/bin/rustc
rustfmt -> /tmp/cf-scratch-home/.cargo/bin/rustfmt
rustup -> /tmp/cf-scratch-home/.cargo/bin/rustup
rustup-init -> /tmp/cf-scratch-home/.local/share/code-factory/tools/rustup-init/1.29.1/linux-x86_64/rustup-init
tasks-axi -> /tmp/cf-scratch-home/.local/share/code-factory/tasks-axi/0.2.6/node_modules/tasks-axi/dist/bin/tasks-axi.js
treehouse -> /tmp/cf-scratch-home/.local/share/code-factory/tools/treehouse/3.1.0/linux-x86_64/treehouse
uv -> /tmp/cf-scratch-home/.local/share/code-factory/tools/uv/0.12.21/linux-x86_64/uv-x86_64-unknown-linux-gnu/uv
uvx -> /tmp/cf-scratch-home/.local/share/code-factory/tools/uv/0.12.21/linux-x86_64/uv-x86_64-unknown-linux-gnu/uvx
== retirement: codex/pnpx links removed, pnpm elsewhere kept, legacy dir kept
codex: absent
pnpm -> /tmp/cf-other-bin/pnpm
pnpx: absent
codex
pnpm
pnpx
== tool versions (HOME=scratch)
herdr: herdr 0.9.3
node: v26.10.0
bun: 1.4.2
uv: uv 0.12.21 (x86_64-unknown-linux-gnu)
gh: gh version 2.102.0 (2026-09-30)
no-mistakes: no-mistakes version v1.84.0 (4822244) 2026-09-26T08:30:42Z
treehouse: v3.1.0
chrome-devtools-axi: 0.1.36
gh-axi: 0.1.35
lavish-axi: 0.1.80
quota-axi: 0.1.55
tasks-axi: 0.2.6
acpx: 0.19.4
omp: omp/18.4.6
== dropped tools not installed
codex: not on PATH
pi: not on PATH
/tmp/cf-scratch-home/.local/bin/pnpm
== current link
total 0
drwxrwxr-x  3 ubuntu ubuntu  80 Oct  1 04:20 .
drwxrwxr-x 12 ubuntu ubuntu 260 Oct  1 04:20 ..
drwxrwxr-x  3 ubuntu ubuntu 100 Oct  1 04:20 1.10.1
lrwxrwxrwx  1 ubuntu ubuntu   6 Oct  1 04:20 current -> 1.10.1
== omp plugin record
["caveman@caveman","i-have-adhd@i-have-adhd","ponytail@ponytail"]
Evidence: Upstream latest GitHub tags for the native tools
herdrdev/herdr latest=v0.9.3
oven-sh/bun latest=bun-v1.4.2
cli/cli latest=v2.102.0
kunchenguid/no-mistakes latest=v1.84.0
kunchenguid/treehouse latest=v3.1.0
astral-sh/uv latest=0.12.21
Evidence: Refusals: tampered SHA, empty SHA, http URL, unsafe version, plus the control run
== A. tampered SHA-256 on the real bun 1.4.2 asset (fresh home): refused, nothing installed
rc=1  install_tools: checksum mismatch for https://github.com/oven-sh/bun/releases/download/bun-v1.4.2/bun-linux-x64-baseline.zip
bun links in fresh home: 0
== B. empty SHA-256: refused
rc=1  install_tools: downloads require HTTPS and an explicit SHA-256
== D. http:// asset URL: refused
rc=1  install_tools: downloads require HTTPS and an explicit SHA-256
== C. unsafe npm version '../../evil' on the already-provisioned home: refused, tree unchanged
rc=1  install_tools: unsafe gh-axi version
install tree unchanged
== E. control: the untampered resolved record installs/no-ops cleanly on the provisioned home
{"changed": false, "installed": ["herdr", "node", "bun", "uv", "gh", "no-mistakes", "treehouse", "rustup-init"], "npm": true, "development": true}
Evidence: Fresh treehouse lane: seeder, bun install, bun run dev capped at 2144 MB
tools: bun 1.4.2 node v26.10.0 treehouse v3.1.0
== 1. treehouse leases a brand-new lane
lane=/tmp/cf-scratch-home/.treehouse/swarms-platform-3e5ee3/1/swarms-platform
slot dir contents BEFORE seeder: swarms-platform 
lane has node_modules? no
== 2. re-check: does bun run pass .env.local NODE_OPTIONS to the script's node? (bun 1.4.2)

1 package installed [2.00ms]
dev-server node=v26.10.0 heap_limit_mb=4192 execArgv=[] NODE_OPTIONS=(unset)
   (heap_limit ~4192 and NODE_OPTIONS=(unset) means bun did NOT pass the .env.local value; ~2144 would mean it did)
== 3. seeder runs as the path unit would (real script from this commit), BEFORE bun install
seeder rc=0
slot dir contents AFTER seeder: node_modules swarms-platform 
#!/bin/sh
# fleet-managed heap cap for the lane in this pool slot
exec /tmp/cf-scratch-home/.local/bin/node --max-old-space-size=2048 "$@"
.env.local seeded: # fleet-shared-supabase
== 4. first bun install + first dev server in the fresh lane (no further seeder run)

1 package installed [1.00ms]
-- bun run dev:
dev-server node=v26.10.0 heap_limit_mb=2144 execArgv=["--max-old-space-size=2048"] NODE_OPTIONS=(unset)
-- npx dev-server:
dev-server node=v26.10.0 heap_limit_mb=2144 execArgv=["--max-old-space-size=2048"] NODE_OPTIONS=(unset)
-- control: plain shell node in same lane (must stay uncapped):
shell heap_limit_mb=4192
== 5. rm -rf node_modules then reinstall: cap survives
1 package installed [1.00ms]
dev-server node=v26.10.0 heap_limit_mb=2144 execArgv=["--max-old-space-size=2048"] NODE_OPTIONS=(unset)
== 6. idempotent: wrapper mtime unchanged on re-run
unchanged
== 7. FLEET_NODE_HEAP_MB override
dev-server node=v26.10.0 heap_limit_mb=1120 execArgv=["--max-old-space-size=1024"] NODE_OPTIONS=(unset)
== 8. return lane (run again from outside the lane: treehouse terminates processes whose cwd is the lane)
🌳 Worktree returned to pool.
Evidence: Rust stable toolchain and installer-driven MCP release bump with a stable current link
== Rust: stable channel, rustfmt+clippy
stable-x86_64-unknown-linux-gnu (default)
rustc 1.98.1 (48a229cea 2026-09-01)
rustfmt 1.9.0-stable (48a229ceae 2026-09-01)
clippy 0.1.98 (48a229ceae 2026-09-01)
   upstream stable: version = "1.98.1 (48a229cea 2026-09-01)"
== stable MCP path: current link survives a release bump
current -> 1.10.1
1.10.1
entrypoint via stable path exists: yes
== second install (changed=false) re-points nothing: current -> 1.10.1
stable path: /tmp/cf-scratch-home/.local/share/code-factory/chrome-devtools-mcp/current/node_modules/chrome-devtools-mcp/build/src/bin/chrome-devtools-mcp.js
== before: current -> 1.10.1
== installer applies an older MCP release
{"changed": true, "installed": ["herdr", "node", "bun", "uv", "gh", "no-mistakes", "treehouse", "rustup-init"], "npm": true, "development": true}
current -> 1.9.0; version through stable path: 1.9.0
== installer applies the latest MCP release again (a 'new release' arriving)
{"changed": true, "installed": ["herdr", "node", "bun", "uv", "gh", "no-mistakes", "treehouse", "rustup-init"], "npm": true, "development": true}
current -> 1.10.1; version through stable path: 1.10.1
versions kept on disk: 1.10.1 1.9.0 
== no-op rerun
{"changed": false, "installed": ["herdr", "node", "bun", "uv", "gh", "no-mistakes", "treehouse", "rustup-init"], "npm": true, "development": true}
Evidence: Herdr unit text identical across MCP releases, changes on a Herdr upgrade
render rc=0 -> unit-mcp190
render rc=0 -> unit-mcp1101
render rc=0 -> unit-herdr094
# ExecStart is the absolute versioned path of the release this apply resolved,
ExecStart=~/.local/share/code-factory/tools/herdr/0.9.3/linux-x86_64/herdr server
Environment="CHROME_DEVTOOLS_AXI_MCP_PATH=~/.local/share/code-factory/chrome-devtools-mcp/current/node_modules/chrome-devtools-mcp/build/src/bin/chrome-devtools-mcp.js"
unit text identical between MCP 1.9.0 and 1.10.1 (no Herdr restart): True
unit text differs on a Herdr upgrade 0.9.3 -> 0.9.4 (restart expected): True
--- diff of the Herdr-upgrade render:
4c4
< # Herdr 0.9.3 (linux-x86_64) as a user service.
---
> # Herdr 0.9.4 (linux-x86_64) as a user service.
15c15
< ExecStart=~/.local/share/code-factory/tools/herdr/0.9.3/linux-x86_64/herdr server
---
> ExecStart=~/.local/share/code-factory/tools/herdr/0.9.4/linux-x86_64/herdr server
Evidence: psutil hash-verified install and Supabase CLI latest
== psutil/supabase latest resolved: {"psutil":"7.2.2","psutil_digests":21,"supabase":"2.119.0"}
   PyPI latest: 7.2.2   npm latest supabase: 2.119.0
-- hash-verified install
psutil 7.2.2
-- adversarial: wrong digest is refused
         Expected:
         Computed:
rc=1
-- Supabase CLI: latest from npm into a scratch prefix, integrity checked by npm

added 8 packages in 3s
2.119.0
Evidence: Obscura latest asset digest match
== Obscura: latest release resolved with the publisher's digest
version=0.2.3 url=https://github.com/h4ckf0r0day/obscura/releases/download/v0.2.3/obscura-x86_64-linux.tar.gz
downloaded sha256 1534d1e6ddaf3d080ec4091eb41d0a4d8cc042a48b607d3c410fc13b482a9eec
publisher  sha256 1534d1e6ddaf3d080ec4091eb41d0a4d8cc042a48b607d3c410fc13b482a9eec
match: True
GitHub's own latest tag for obscura: v0.2.3
Evidence: Config validation: default, legacy obscura pins, malformed sha
== shipped default config validates
Valid host configuration: config/default.yml
rc=0
== legacy host config (fleet_guards on) still carrying obscura pins: accepted with warning
WARNING: factory.browsers.obscura_version and factory.browsers.obscura_sha256 are no longer used and are ignored; Obscura always resolves to its latest release. Remove them from /tmp/cf-legacy.yml when convenient.
Valid host configuration: /tmp/cf-legacy.yml
rc=0
== adversarial: malformed legacy sha still rejected
factory: factory.schema.json: invalid factory.browsers.obscura_sha256 (pattern)
rc=1
Evidence: CI action pins versus latest releases, and Dependabot config
.github/workflows/ci.yml:config-and-python actions/checkout pinned=3d3c42e5aa comment=v7.0.1 (comment resolves to pin: True) latest_release=v7.0.1 latest_sha=3d3c42e5aa -> OK latest
.github/workflows/ci.yml:config-and-python astral-sh/setup-uv pinned=c18668ad3c comment=v10.2.0 (comment resolves to pin: True) latest_release=v10.2.0 latest_sha=c18668ad3c -> OK latest
.github/workflows/ci.yml:config-and-python oven-sh/setup-bun pinned=0c5077e514 comment=v2.2.0 (comment resolves to pin: True) latest_release=v2.2.0 latest_sha=0c5077e514 -> OK latest
dependabot: {"version": 2, "updates": [{"package-ecosystem": "github-actions", "directory": "/", "schedule": {"interval": "weekly"}}]}
github-actions weekly update present: True
Evidence: Targeted pytest, 78 passed
============================= test session starts ==============================
platform linux -- Python 3.13.14, pytest-9.0.2, pluggy-1.6.0 -- ~/.no-mistakes/worktrees/381d71ab9820/01M3TFPSB498776P7MT7VR1YDH/.venv/bin/python
rootdir: ~/.no-mistakes/worktrees/381d71ab9820/01M3TFPSB498776P7MT7VR1YDH
configfile: pyproject.toml
collecting ... collected 78 items

tests/test_configuration.py::test_valid_configuration_is_accepted_by_real_schema PASSED [  1%]
tests/test_configuration.py::test_legacy_obscura_keys_are_ignored_with_one_warning_and_apply_proceeds PASSED [  2%]
tests/test_configuration.py::test_workspace_cannot_escape_operator_home[~/Dev] PASSED [  3%]
tests/test_configuration.py::test_workspace_cannot_escape_operator_home[~/../other/Dev] PASSED [  5%]
tests/test_configuration.py::test_workspace_cannot_escape_operator_home[~] PASSED [  6%]
tests/test_configuration.py::test_invalid_secret_field_is_rejected_without_echoing_value PASSED [  7%]
tests/test_configuration.py::test_firstmate_cannot_silently_omit_its_agent_dependencies PASSED [  8%]
tests/test_configuration.py::test_firstmate_revision_pin_is_rejected PASSED [ 10%]
tests/test_configuration.py::test_fleet_guards_require_docker_and_firstmate PASSED [ 11%]
tests/test_configuration.py::test_fleet_guards_accept_the_default_document_when_enabled PASSED [ 12%]
tests/test_configuration.py::test_browsers_valid_block_accepted PASSED   [ 14%]
tests/test_configuration.py::test_fleet_fixture_archive_cannot_traverse PASSED [ 15%]
tests/test_configuration.py::test_unknown_fleet_field_is_rejected PASSED [ 16%]
tests/test_configuration.py::test_bad_polling_window_cannot_disable_idle_accrual PASSED [ 17%]
tests/test_configuration.py::test_init_preserves_existing_local_configuration PASSED [ 19%]
tests/test_configuration.py::test_root_operator_is_rejected_before_config_is_written PASSED [ 20%]
tests/test_configuration.py::test_questions_launch_only_on_an_interactive_terminal_outside_ci[False--False] PASSED [ 21%]
tests/test_configuration.py::test_questions_launch_only_on_an_interactive_terminal_outside_ci[True-true-False] PASSED [ 23%]
tests/test_configuration.py::test_questions_launch_only_on_an_interactive_terminal_outside_ci[True--True] PASSED [ 24%]
tests/test_configuration.py::test_second_apply_does_not_reopen_the_questions PASSED [ 25%]
tests/test_configuration.py::test_questions_wait_for_an_omp_sign_in PASSED [ 26%]
tests/test_configuration.py::test_another_accounts_apply_skips_questions_without_reading_the_unreadable_home PASSED [ 28%]
tests/test_configuration.py::test_apply_warns_when_firstmate_still_tracks_the_stale_fork PASSED [ 29%]
tests/test_configuration.py::test_verify_fails_when_firstmate_origin_is_not_the_configured_url PASSED [ 30%]
tests/test_configuration.py::test_verify_passes_when_firstmate_origin_is_the_configured_url PASSED [ 32%]
tests/test_configuration.py::test_existing_omp_config_gets_the_status_row_keys_once PASSED [ 33%]
tests/test_configuration.py::test_omp_config_that_has_the_status_row_keys_is_left_alone PASSED [ 34%]
tests/test_configuration.py::test_omp_config_without_the_custom_preset_is_left_alone[theme: {dark: titanium}\n] PASSED [ 35%]
tests/test_configuration.py::test_omp_config_without_the_custom_preset_is_left_alone[statusLine:\n  preset: default\n  showHookStatus: true\n] PASSED [ 37%]
tests/test_configuration.py::test_omp_config_without_the_custom_preset_is_left_alone[statusLine:\n  leftSegments: [path, git]\n  showHookStatus: true\n] PASSED [ 38%]
tests/test_configuration.py::test_absent_omp_config_is_not_created_by_the_status_row_step PASSED [ 39%]
tests/test_configuration.py::test_acpx_config_that_still_defaults_to_codex_gets_omp_once PASSED [ 41%]
tests/test_configuration.py::test_acpx_config_with_another_default_is_left_alone[{"defaultAgent": "claude"}\n] PASSED [ 42%]
tests/test_configuration.py::test_acpx_config_with_another_default_is_left_alone[{"ttl": 300}\n] PASSED [ 43%]
tests/test_configuration.py::test_seeded_acpx_config_defaults_to_omp_and_absent_one_is_not_created PASSED [ 44%]
tests/test_configuration.py::test_the_managed_environment_never_carries_a_process_wide_runtime_limit[False] PASSED [ 46%]
tests/test_configuration.py::test_the_managed_environment_never_carries_a_process_wide_runtime_limit[True] PASSED [ 47%]
tests/test_configuration.py::test_a_new_chrome_devtools_mcp_release_leaves_the_managed_environment_unchanged PASSED [ 48%]
tests/test_install_tools.py::test_verified_install_runs_and_second_install_changes_nothing PASSED [ 50%]
tests/test_install_tools.py::test_bad_checksum_never_installs_command PASSED [ 51%]
tests/test_install_tools.py::test_unmanaged_command_is_preserved PASSED  [ 52%]
tests/test_install_tools.py::test_local_binary_drift_is_not_silently_accepted PASSED [ 53%]
tests/test_install_tools.py::test_archive_traversal_cannot_escape_staging[tar] PASSED [ 55%]
tests/test_install_tools.py::test_archive_traversal_cannot_escape_staging[zip] PASSED [ 56%]
tests/test_install_tools.py::test_download_rejects_plain_http PASSED     [ 57%]
tests/test_install_tools.py::test_latest_releases_are_pinned_to_the_digests_their_publishers_list PASSED [ 58%]
tests/test_install_tools.py::test_release_without_a_published_checksum_is_refused[herdrdev/herdr] PASSED [ 60%]
tests/test_install_tools.py::test_release_without_a_published_checksum_is_refused[oven-sh/bun] PASSED [ 61%]
tests/test_install_tools.py::test_release_without_a_published_checksum_is_refused[cli/cli] PASSED [ 62%]
tests/test_install_tools.py::test_release_without_a_published_checksum_is_refused[kunchenguid/no-mistakes] PASSED [ 64%]
tests/test_install_tools.py::test_release_without_a_published_checksum_is_refused[kunchenguid/treehouse] PASSED [ 65%]
tests/test_install_tools.py::test_release_without_a_published_checksum_is_refused[astral-sh/uv] PASSED [ 66%]
tests/test_install_tools.py::test_release_without_a_published_checksum_is_refused[h4ckf0r0day/obscura] PASSED [ 67%]
tests/test_install_tools.py::test_release_without_a_published_checksum_is_refused[node] PASSED [ 69%]
tests/test_install_tools.py::test_release_without_a_published_checksum_is_refused[rustup-init] PASSED [ 70%]
tests/test_install_tools.py::test_release_without_a_published_checksum_is_refused[psutil] PASSED [ 71%]
tests/test_install_tools.py::test_github_token_goes_only_to_the_github_api[env-token-Bearer env-token] PASSED [ 73%]
tests/test_install_tools.py::test_github_token_goes_only_to_the_github_api[-None] PASSED [ 74%]
tests/test_install_tools.py::test_resolve_covers_only_the_requested_tools PASSED [ 75%]
tests/test_install_tools.py::test_resolve_selection_matches_what_the_flags_install[argv0-expected0] PASSED [ 76%]
tests/test_install_tools.py::test_resolve_selection_matches_what_the_flags_install[argv1-expected1] PASSED [ 78%]
tests/test_install_tools.py::test_resolve_selection_matches_what_the_flags_install[argv2-expected2] PASSED [ 79%]
tests/test_install_tools.py::test_resolve_selection_matches_what_the_flags_install[argv3-expected3] PASSED [ 80%]
tests/test_install_tools.py::test_resolve_refuses_a_source_that_does_not_exist PASSED [ 82%]
tests/test_install_tools.py::test_the_dropped_npm_set_loses_its_links_but_keeps_the_prefix_and_other_installs PASSED [ 83%]
tests/test_install_tools.py::test_omp_plugins_are_managed_from_the_target_home_whatever_the_installer_cwd PASSED [ 84%]
tests/test_install_tools.py::test_current_follows_the_newest_release_and_a_repeat_changes_nothing PASSED [ 85%]
tests/test_install_tools.py::test_an_apply_merges_its_resolved_record_into_the_existing_one[argv0-expected0] PASSED [ 87%]
tests/test_install_tools.py::test_an_apply_merges_its_resolved_record_into_the_existing_one[argv1-expected1] PASSED [ 88%]
tests/test_install_tools.py::test_a_failed_command_reports_why_it_failed PASSED [ 89%]
tests/test_worktree_env_seed.py::test_a_fresh_lane_gets_the_heap_cap_before_and_after_its_first_install PASSED [ 91%]
tests/test_worktree_env_seed.py::test_seeding_is_idempotent_and_never_touches_the_checkouts_node_modules PASSED [ 92%]
tests/test_chrome_autoprune.py::test_only_installed_or_retired_prefix_bridges_are_recognized[.local/share/code-factory/chrome-devtools-axi/0.4.1/node_modules/chrome-devtools-axi/dist/bin/chrome-devtools-axi-bridge.js-True] PASSED [ 93%]
tests/test_chrome_autoprune.py::test_only_installed_or_retired_prefix_bridges_are_recognized[.local/share/code-factory/chrome-devtools-axi/0.3.0/node_modules/chrome-devtools-axi/dist/bin/chrome-devtools-axi-bridge.js-True] PASSED [ 94%]
tests/test_chrome_autoprune.py::test_only_installed_or_retired_prefix_bridges_are_recognized[.local/share/code-factory/npm/node_modules/chrome-devtools-axi/dist/bin/chrome-devtools-axi-bridge.js-True] PASSED [ 96%]
tests/test_chrome_autoprune.py::test_only_installed_or_retired_prefix_bridges_are_recognized[.local/share/code-factory/chrome-devtools-axi/node_modules/chrome-devtools-axi/dist/bin/chrome-devtools-axi-bridge.js-False] PASSED [ 97%]
tests/test_chrome_autoprune.py::test_only_installed_or_retired_prefix_bridges_are_recognized[.local/share/code-factory/other/node_modules/chrome-devtools-axi/dist/bin/chrome-devtools-axi-bridge.js-False] PASSED [ 98%]
tests/test_chrome_autoprune.py::test_only_installed_or_retired_prefix_bridges_are_recognized[.local/share/code-factory/npm/other/node_modules/chrome-devtools-axi/dist/bin/chrome-devtools-axi-bridge.js-False] PASSED [100%]

============================= 78 passed in 30.33s ==============================
- Outcome: 🔧 3 issues found → auto-fixed ✅ across 2 runs (40m57s)

Pipeline

Updates from git push no-mistakes

... (106 earlier update rounds omitted to keep the PR body within GitHub's 65536-char limit; full history is in the run log.)

⚠️ **Review** - 2 infos

The pin has a stated safety reason. A floating Postgres tag would move a data volume across major versions it cannot read. CI also enforces the pin at .github/workflows/ci.yml:230.

No change is needed. If the author wants these floating too, that is a separate decision. It would also mean removing the CI digest audit and the docs exception.

  • ℹ️ bootstrap.sh:9 - Judged after the advisory. The behavior change is real, but it is not a new failure of a flow that worked before, so no action is needed.

What changed: line 9 now always runs install_tools.py --tools uv. An unmanaged regular file at ~/.local/bin/uv, such as an Astral standalone install or pip --user, makes link_binary raise unmanaged command exists. set -e then aborts the bootstrap. Only stdout is discarded, so the error still shows on stderr. The base skipped the installer when uv --version matched the lock pin, which was uv 0.12.5.

Why it does not hold as a regression:

  1. Base link_binary is identical to head, so any version mismatch already hit the same error. Standalone uv installs track the newest release, so only hosts on exactly 0.12.5 got through bootstrap.
  2. Those hosts failed one step later. factory_core_tools is [herdr, node, bun, uv] in base and head. ./factory apply runs install_asset(&#39;uv&#39;) and then the same link_binary raise.
  3. docs/configuration.md states the recipe refuses to overwrite unmanaged commands. Head moves the failure earlier and keeps the same actionable message.

The one narrow loss is a contributor on exactly uv 0.12.5 who used bootstrap only to build the dev venv. Keeping the old skip would contradict the intent's latest-uv requirement and README step 3, 'the latest uv'. The intent-driven cost is that bootstrap now makes a GitHub API call on every run. docs/dependencies.md documents the rate limit and the GITHUB_TOKEN option.

🔧 **Test** - 3 issues found → auto-fixed ✅
  • ⚠️ scripts/install_tools.py:465 - omp_plugins runs omp plugin ... with no cwd, so the plugin step depends on the directory the installer starts in. ansible/tasks/tools.yml runs the installer with chdir: code_factory_repo and become_user: factory_cfg.user. If the checkout sits under another user's tree that has its own .omp, omp plugin list reports that tree's records as already installed. Reproduced live with --tools node,bun --npm (omp-plugins-cwd-dependence.txt): --home was a scratch HOME and cwd was a checkout under ~, which has .omp. The installer exited 0, but the target HOME had no ~/.omp/plugins/installed_plugins.json. omp plugin list printed ponytail, i-have-adhd and caveman from ~/.omp, so omp install was skipped. With cwd set to --home, the list was empty and all three plugins installed. The real ~/.omp record was not modified. The container smoke passed because /opt/code-factory has no .omp ancestor, and a checkout under the target user's own home is also unaffected. Fix: pass cwd=home to the subprocess.run in the nested omp() helper.
  • ℹ️ My cleanup ran rm -rf /tmp/cf-*.json /tmp/cf-*.yml /tmp/cf-req*.txt. Those globs could have matched /tmp/cf-* files that other sessions created, and I cannot tell afterwards whether any existed. Files with other extensions (.toml, .txt, .patch, .log, .out, .body, .intent) and directories were not matched by the globs and are still there. If another session reports a missing /tmp/cf-*.json or /tmp/cf-*.yml, this is the likely cause. Nothing in the worktree or the evidence directory was affected.
  • 🚨 live validation verdict: no-go (13 of 14 scenarios were driven live against the product); failed: Adversarial: omp plugins install into --home regardless of the directory the installer starts in (checkout under another user's home that has its own .omp)
  • Live validation: ❌ no-go - 13 of 14 scenarios driven live against the product
Scenario Result Live Evidence
Resolve latest: every tool resolves to its newest release with a publisher checksum, and pi, codex and pnpm are no longer part of the set ✅ pass live resolve-latest.json: bun 1.4.2, node 26.10.0, gh 2.102.0, no-mistakes 1.84.0, treehouse 3.1.0, uv 0.12.21, rustup-init 1.29.1, obscura 0.2.3, psutil 7.2.2 (12 hashes), supabase 2.119.0, five axi tools…
Install everything into a clean HOME, then re-run: tools install at the latest versions and the second run reports changed=false ✅ pass live install-run1.out, install-run2.out, install-run3.out: node 26.10.0, bun 1.4.2, gh 2.102.0, no-mistakes 1.84.0, treehouse 3.1.0, uv 0.12.21, herdr 0.9.3, omp 18.4.6, all five axi tools and acpx answer…
Adversarial: a tampered sha256 or an unsafe version string is refused and nothing is installed or relinked ✅ pass live tamper.err: 'checksum mismatch' for bun, exit 1, bun link still points at 1.4.2; unsafe.err: 'unsafe gh-axi version', exit 1, no gh-axi directory created
Retire dropped npm tools: codex and pnpm links removed, legacy npm prefix directory kept, same-named pnpx link elsewhere kept ✅ pass live Scratch HOME after install run 2: no codex or pnpm in ~/.local/bin, legacy npm/node_modules/.bin/{codex.js,pnpm.js} still on disk, pnpx -> /tmp/cf-elsewhere/pnpx untouched
chrome-devtools-mcp stable current link: a release bump re-points the link, the exported path and Herdr unit text do not change, the old release stays on disk ✅ pass live stable-mcp-current.txt (current -> 1.9.0 then 1.10.1; node runs the same exported path and prints 1.9.0, then 1.10.1) and herdr-unit-stable-across-mcp-release.txt (unit identical for 1.9.0 vs 1.10.1,…
Heap cap on a lane whose slot the seeder has already run on: the first bun run dev after the first bun install is capped, the cap survives rm -rf node_modules and reuse of slot 1, and plain shell node… ✅ pass live fresh-lane-heap-cap.txt: with the seeder run after lease and before bun install, bun run dev, bun run probe and npx all report heap limit about 2144 MB with execArgv --max-old-space-size=2048; plain s…
A fresh lane's first dev server is capped without a manual seeder run, i.e. the path unit fires the seeder when treehouse creates the slot, before the agent's first bun run dev ⏸️ untested no No real systemd user session here (the container image has none and ansible-playbook is not on PATH). To drive it, run ./factory apply on a host with start_services enabled, create a new treehouse…
omp marketplace plugins install and upgrade to latest, and the smoke asserts the install record, not the marketplace directory ✅ pass live smoke-plugin-and-ci-pins.txt: the exact jq from tests/container-smoke.sh passes for ponytail, i-have-adhd and caveman against the real installed_plugins.json, rejects an uninstalled plugin, and reject…
Adversarial: omp plugins install into --home regardless of the directory the installer starts in (checkout under another user's home that has its own .omp) ❌ fail live omp-plugins-cwd-dependence.txt (both arms run with --tools node,bun --npm): from a checkout under ~, the installer exited 0 but the target HOME had no installed_plugins.json; omp plugin lis…
Rust toolchain follows the stable channel: latest rustup-init plus stable with rustfmt and clippy, and a second apply is a no-op ✅ pass live rust-install.txt: rustc 1.98.1 and cargo 1.98.1, stable-x86_64-unknown-linux-gnu (active, default) with rustfmt and clippy; the second run returned changed=false
Obscura, psutil and shared Supabase CLI resolve to latest and are verified: Obscura against its publisher digest, psutil with --require-hashes (a wrong digest is rejected), Supabase through npm integr… ✅ pass live obscura-psutil-supabase.txt: Obscura 0.2.3 sha256 matches the publisher digest; psutil 7.2.2 installs, and a corrupted hash exits 1; supabase 2.119.0 installs and reports 2.119.0
Config: the obscura pins are gone; a legacy host config with them is accepted with a warning, a malformed sha is still rejected, and fleet_guards validates without pins ✅ pass live factory-validate-config.txt: default config valid; legacy keys print an 'ignored' warning and validate; obscura_sha256 'nothex' fails the schema pattern with rc=1; a fleet_guards, docker and firstmate…
CI: every GitHub Action is pinned to the full SHA of its latest release tag with the tag in a trailing comment, and dependabot has a weekly github-actions update ✅ pass live smoke-plugin-and-ci-pins.txt: checkout v7.0.1, setup-uv v10.2.0 and setup-bun v2.2.0 match the GitHub API latest tag and SHA; dependabot.yml has github-actions at / weekly
Docker worker image on ubuntu:latest builds with a real ./factory apply, and the behavior smoke passes with the second apply idempotent ✅ pass live container-smoke.log: 21/21 checks ran, 0 failed; core tools match resolved.json; login shell pins the MCP path at chrome-devtools-mcp/current; installer re-run changed=false; second ansible pass ok=66…
  • python3 scripts/install_tools.py --resolve for every source against live GitHub, npm, nodejs.org, PyPI and rust-lang
  • install_tools.py --npm into a scratch HOME: run 1 with older chrome-devtools-mcp 1.9.0, run 2 live latest, run 3 no-op
  • install_tools.py --tools bun --development into the scratch HOME, plus a no-op second run
  • Adversarial --resolved runs: wrong sha256 for bun, and unsafe gh-axi version 1.0.0/../../evil
  • Legacy npm prefix pre-seeded with codex and pnpm links plus a pnpx link elsewhere, then retired by the installer
  • Real treehouse v3.1.0 lane with fleet/doctor/worktree-env-seed.sh run by hand after the lane was created: bun install, bun run dev, bun run probe, npx, rm -rf node_modules, FLEET_NODE_HEAP_MB=1024, return and re-lease of slot 1, treehouse destroy --all --yes
  • A second newly leased slot (slot 2) with no seeder run, to see what an unseeded slot gets
  • node launching the chrome-devtools-mcp entrypoint through the current path at 1.10.1 and 1.9.0; chrome-devtools-axi --help with CHROME_DEVTOOLS_AXI_MCP_PATH set
  • ansible/templates/herdr.service.j2 rendered with real Jinja2 against ansible/group_vars/all.yml for mcp 1.9.0, mcp 1.10.1 and a Herdr bump
  • The exact jq assertion from tests/container-smoke.sh against the real omp installed_plugins.json, plus a never-installed plugin and a marketplace-only plugin
  • install_tools.py --tools node,bun --npm --resolved ... run from a checkout cwd under ~ (which has .omp) and again from cwd=--home, then omp plugin list --json from each cwd
  • ./factory validate on the default config, a legacy config with obscura pins, a malformed legacy sha, and a fleet_guards config with no pins
  • CI pins: every uses: in .github/workflows/ci.yml compared with the GitHub API latest release tag and commit SHA; .github/dependabot.yml parsed
  • Obscura latest asset sha256 compared with the publisher digest; psutil uv pip install --require-hashes (good and bad digest); npm install supabase@2.119.0
  • uv run --frozen pytest tests/test_configuration.py tests/test_install_tools.py tests/test_worktree_env_seed.py tests/test_chrome_autoprune.py (77 passed)
  • CF_SMOKE_MEMORY=6g CF_SMOKE_CPUS=2 tests/container-smoke.sh (docker build of the smoke target on ubuntu:latest, then 21 in-container checks)

🔧 Fix applied.
✅ Re-checked - no issues remain.

  • Live validation: ✅ go - 13 of 14 scenarios driven live against the product
Scenario Result Live Evidence
Fresh install of herdr, node, bun, uv, gh, no-mistakes and treehouse resolves each tool to its latest upstream release ✅ pass live final-install-verify.txt and github-latest-tags.txt: installed versions equal GitHub releases/latest for herdr 0.9.3, bun 1.4.2, gh 2.102.0, no-mistakes 1.84.0, treehouse 3.1.0 and uv 0.12.21, and nod…
The axi tools, omp, acpx and chrome-devtools-mcp install at the npm registry's latest version ✅ pass live final-install-verify.txt versus npm view: chrome-devtools-axi 0.1.36, gh-axi 0.1.35, lavish-axi 0.1.80, quota-axi 0.1.55, tasks-axi 0.2.6, omp 18.4.6, acpx 0.19.4, chrome-devtools-mcp 1.10.1
A second apply changes nothing (idempotent) ✅ pass live final-install-run2.out reports changed=false; container smoke 'installer-idempotent' and 'ansible-second-pass' (changed=0)
codex and pnpm are retired: their managed links are removed, the legacy npm directory stays, a same-named command installed elsewhere is kept, and codex, pi and pnpm are not provisioned ✅ pass live final-install-verify.txt: codex and pnpx links gone, pnpm still points to /tmp/cf-other-bin/pnpm, and the legacy npm/node_modules/.bin still holds codex, pnpm and pnpx; codex and pi are not on PATH
Adversarial: a tampered SHA-256, an empty SHA-256, an http:// asset URL, and an unsafe npm version are all refused with nothing installed or changed ✅ pass live final-adversarial-refusals.txt: 'checksum mismatch' for the real bun asset, 'downloads require HTTPS and an explicit SHA-256' for the empty digest and for the http URL, and 'unsafe gh-axi version' wit…
Rust toolchain follows the stable channel with rustfmt and clippy, installed through the latest rustup-init ✅ pass live final-rust-and-mcp-link.txt: stable-x86_64 active, rustc 1.98.1 equals upstream channel-rust-stable, rustfmt and clippy present
Obscura, the Chrome pruner's psutil and the shared Supabase CLI resolve to their latest releases and are verified, and a wrong psutil digest is refused ✅ pass live final-obscura.txt (downloaded sha equals publisher digest, 0.2.3 is GitHub's latest); final-psutil-supabase.txt (psutil 7.2.2 via --require-hashes, wrong hash rc=1; supabase 2.119.0 equals the npm lat…
omp marketplace plugins install into the target --home even when the installer starts from a checkout under another home that has its own .omp (regression from round 1) ✅ pass live final-install-verify.txt: scratch home has caveman, i-have-adhd and ponytail records, installed from a worktree under ~; the real ~/.omp record md5 b714925b... was unchanged; the…
A new chrome-devtools-mcp release re-points the stable current link and leaves the managed MCP path and the Herdr unit text unchanged, so Herdr does not restart; a Herdr upgrade still changes the un… ✅ pass live final-rust-and-mcp-link.txt (installer moved current 1.10.1 to 1.9.0 and back to 1.10.1 and kept both versions on disk) and final-herdr-unit-render.txt (real Ansible template render identical for MCP…
A fresh treehouse lane's first bun run dev is heap-capped: the seeder writes the slot-level node wrapper before bun install, the cap survives rm -rf node_modules, the override works, and a plain… ✅ pass live final-fresh-lane-heap-cap.txt: after the seeder and before bun install the slot holds the wrapper; the first bun run dev and npx report heap_limit_mb=2144 and execArgv --max-old-space-size=2048;…
Config: legacy obscura pins are accepted with a warning, a malformed legacy sha is still rejected, and the shipped default validates ✅ pass live final-validate-config.txt: default rc=0; legacy pins rc=0 with the 'no longer used and are ignored' warning; malformed sha rc=1 on the schema pattern
Container worker image builds on ubuntu:latest and the in-container smoke passes end to end ✅ pass live container-smoke-final.log: base is docker.io/library/ubuntu:latest, '21/21 checks ran, 0 failed', smoke exit=0
Every GitHub Action in .github/workflows is pinned to a full commit SHA with its tag in a trailing comment, that SHA is the action's latest release, and Dependabot has a weekly github-actions update ✅ pass live final-ci-pins-vs-latest.txt: checkout v7.0.1, setup-uv v10.2.0 and setup-bun v2.2.0 each resolve to the SHA of the latest GitHub release (checked against GitHub); dependabot.yml parses to package-ecos…
The GitHub Actions workflow runs green on GitHub, and Dependabot opens its first weekly github-actions PR ⏸️ untested no Both run only on GitHub-hosted infrastructure after the branch is pushed, which this local test phase cannot trigger. Remote CI covers the workflow run; the first Dependabot PR appears after merge on…
  • python3 scripts/install_tools.py --home /tmp/cf-scratch-home --tools herdr,node,bun,uv --npm --development, run from the worktree under ~ (which has its own .omp), against a scratch home seeded with legacy codex/pnpm/pnpx links
  • Second identical installer run: changed=false
  • Version check of every installed command against the registry or GitHub latest: npm view for the axi tools, omp, acpx and chrome-devtools-mcp; nodejs.org/dist/index.json; GitHub releases/latest for herdr, bun, gh, no-mistakes, treehouse and uv; rustup's release-stable.toml
  • Retirement check in the scratch home: codex and pnpx links removed, a pnpm link pointing elsewhere kept, legacy npm/ directory kept
  • Adversarial --resolved runs: wrong SHA-256 on the real bun 1.4.2 asset, empty SHA-256, http:// URL, and an unsafe npm version ../../evil
  • Installer-driven chrome-devtools-mcp bump (1.9.0 to 1.10.1) checking the stable current link, plus a real Ansible render of ansible/templates/herdr.service.j2 for two MCP releases and for a Herdr upgrade
  • Fresh treehouse lane (treehouse get --lease) with the real fleet/doctor/worktree-env-seed.sh, then bun install, bun run dev and npx. The check also re-measured whether bun passes .env.local NODE_OPTIONS (it does not on 1.4.2), rm -rf node_modules, the seeder's second-run idempotence, and the FLEET_NODE_HEAP_MB override
  • --resolve --also obscura,psutil,supabase: Obscura asset downloaded and compared with the publisher digest, psutil installed with uv --require-hashes (a wrong digest is refused), Supabase CLI installed from npm at the resolved version
  • ./factory validate on config/default.yml, on a legacy document carrying obscura pins (accepted with a warning), and on one with a malformed obscura sha (rejected)
  • CI workflow pins: all uses: are 40-char SHAs with tag comments, and each equals the commit of the action's latest GitHub release (git ls-remote plus releases/latest); .github/dependabot.yml parsed for a weekly github-actions update
  • tests/container-smoke.sh: full image build on ubuntu:latest, 21/21 checks, including resolved-releases, installer-idempotent and ansible-second-pass
  • .venv/bin/python -m pytest tests/test_configuration.py tests/test_install_tools.py tests/test_worktree_env_seed.py tests/test_chrome_autoprune.py -v: 78 passed
  • Confirmed the real ~/.omp/plugins/installed_plugins.json md5 was unchanged after the installer runs
⚠️ **Document** - 1 info
  • ℹ️ docs/configuration.md:79 - The development profile row still lists "development-mode npm packages". --development only runs rust_install, and apt supplies the build packages. The base commit already behaved this way, so this change did not make the row stale and I left it. A follow-up could reword the row to "Rust toolchain, build essentials".
  • ℹ️ ansible/tasks/tools.yml:100 - The Ansible task name: "Assert the managed symlink resolves to the locked executable" still says "locked", but the herdr executable is now the resolved latest release. This is a task name that shows in plan/apply output, not a doc comment, so it is outside this phase's edit rule and I did not rename it. Herdr was already resolved to latest before this change, so the wording was not newly made stale. A follow-up could rename it to "resolved executable". No test references the string.

🔧 Fix applied.
1 info still open:

  • ℹ️ CONTRIBUTING.md:46 - CONTRIBUTING.md tells contributors to run ./scripts/ci-local.sh, but that file does not exist. It was also missing at the base commit, so this change did not cause it and I left the line alone. A follow-up could drop the line or add the script.
✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

…s; drop codex and pnpm

Every apply now resolves the newest release of node (nodejs.org index, not
LTS), bun, gh, no-mistakes and treehouse, verified against the SHA-256 the
publisher lists for that release (GitHub release-asset digest, or Node's
SHASUMS256.txt), and the npm registry's latest chrome-devtools-axi, gh-axi,
lavish-axi, quota-axi and tasks-axi, each in its own versioned prefix like
omp. Only uv, rustup-init and the Rust toolchain stay pinned in the lock.

codex and pnpm leave the npm set; acpx defaults to omp, and the installer
unlinks commands whose managed package is gone.
The worktree seeder now writes a git-excluded .env.fleet with the node heap
cap, and the managed shell and Herdr environment set
BUN_OPTIONS=--env-file=.env.fleet under fleet guards, so every bun started
in a worktree root (bun run dev, omp) hands NODE_OPTIONS to the node
processes it spawns. pnpm is gone from the reaper chain and the docs.
… checksums

Nothing the recipe installs is pinned any more. uv, rustup-init, Obscura,
acpx and chrome-devtools-mcp join the latest-resolution path; the Rust
toolchain follows stable; psutil is the latest PyPI release installed with
--require-hashes against PyPI's digests; the Supabase CLI is the registry's
latest; the worker image builds FROM ubuntu:latest. Every download is still
verified against the checksum its publisher posts for that release.

toolchain.lock.json, its schema, tools/npm, maintenance/requirements.txt,
the shared-supabase package lock and the obscura config keys are gone.
Apply also installs and upgrades the ponytail, i-have-adhd and caveman omp
plugins. uv.lock and the SHA-pinned GitHub Actions stay.
… the pins

astral-sh/setup-uv moves to v10.2.0; actions/checkout v7.0.1 and
oven-sh/setup-bun v2.2.0 are already their latest releases. A weekly
github-actions Dependabot update keeps the SHA pins on the newest release.
@undeemed
undeemed merged commit f718774 into main Oct 1, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant