Repository navigation
Build, install and roll back a darwin-arm64 fork binary on this Mac - #34
Merged
Merged
Conversation
Red on purpose: install.sh, rollback.sh and build.sh do not exist yet. Issue: #3
…64 binary Issue: #3
…e probe The cargo step now runs from / with its own CARGO_HOME under the gitignored target/, so a host-level crates.io source replacement in a parent or home cargo config no longer breaks the build. Each smoke probe gets curl --max-time 2, and the poll loop breaks once 60s have elapsed, so a connection that hangs while the server initialises cannot stall the build. Issue: #3
…for launchd to unload The launchctl stub now keeps the job loaded for two print polls after bootout and fails bootstrap with EIO while loaded (or when LAUNCHCTL_BOOTSTRAP_FAIL is set). Red before the fix: the second install and the rollback exit 5 because the scripts bootstrap straight after bootout. The new failure-case describe cannot even set up (its second install hits the same exit 5), so the bad-archive, empty-version and failed-restart cases are skipped rather than individually red. Issue: #3
…n; restart waits for bootout to finish Issue: #3
…and restart retry Closes three gaps from the testing review: - reinstalling the current version leaves previous untouched, so rollback still lands on the older version - invalid-version guard is tested for both the empty and '..' archive names - the failed-restart rollback retry now asserts it ends with bootstrap instead of re-checking current Issue: #3
rawphp
marked this pull request as ready for review
October 15, 2026 11:03
Author
|
Factory gate: passed (attempt 1, run by the factory in a fresh checkout of the pull request's head
|
Author
|
Factory gate: passed again (attempt 2, run by the factory in a fresh checkout of the pull request's head
|
…dirty builds - build.sh smoke-tests the archive in its stage dir and moves it to release/ only after the smoke passes, so a failed smoke leaves no archive install.sh would take. T3FAC_SMOKE_TIMEOUT sets the deadline (60 s). - Uncommitted changes to tracked files add `.dirty` to the version, so a rebuild of the same commit never replaces the clean build on install. - install.sh and rollback.sh source factory/scripts/lib/t3fac.sh for the install root, the LaunchAgent label and plist, and restart_job. T3FAC_UNLOAD_WAIT sets the unload wait (10 s). - Tests: the whole of build.sh with stubbed vp and cargo (pass, early exit, no 200, no "factory started"), a dangling `previous`, and a job that never unloads.
…ed changes Two builds of one commit with different uncommitted edits used to share the `.dirty` version, so installing the second deleted the first. The suffix is now `.dirty.<8 hex>` from `git diff HEAD --binary`, so only identical contents share a name.
A version named after the commit could not tell builds of one commit apart when the tree held edits or untracked files, and installing a second such build deleted the first. build.sh now refuses to build when `git status --porcelain` lists anything, naming the first ten paths, so the version always names exactly what was built. The `.dirty` suffix is gone. .worktrees/ joins .gitignore (a new seam in factory/SEAMS) so the main checkout, which holds local worktrees, counts as clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #3
Contract
factory/scripts/build.shbuildsrelease/t3fac-<version>-darwin-arm64.tar.gzthrough upstream'sapps/server/scripts/cli.ts build-exeandscripts/build-cli-archive.ts(none copied), version =factory/UPSTREAMtag minusvwhen nightly, elseapps/server/package.json, then+fac.<short sha>; it ends with a smoke test of the builtt3 serve(200 on/.well-known/t3/environmentwithin 60 s,factory startedin the server log, server stopped, temp dir deleted).install.sh <archive>unpacks to~/.local/share/t3fac/versions/<version>/, pointscurrentat it, writes the LaunchAgent plist fromfactory/launchd/io.github.rawphp.t3fac.plist, boots the job out when loaded and bootstraps it.rollback.shpointscurrentat the version installed before it and restarts; with none it exits 1 and says so. A vitest test drives both scripts withHOMEin a temp dir, fake archives and a stublaunchctl.install.shagainst the real HOME, multi-level rollback.vp test run apps/server/src/factory→ pass (22 tests).factory/scripts/build.shrun by hand at the tip → pass (smoke output below).Acceptance criteria
build.shproducesrelease/t3fac-<version>-darwin-arm64.tar.gzwitht3,client/,resource-monitor/,node_modules/via upstream's scripts —factory/scripts/build.sh:49-66; archive listing checked withtar -tzf(top level:t3,client,resource-monitor,node_modules).v, else package.json, then+fac.<sha>) —installScripts.test.ts"build.sh --print-version" cases; the real build printed0.0.46-nightly.20261015.3145+fac.a2df0cec7.factory started, server stopped, temp dir deleted, non-zero on any failure —factory/scripts/build.sh:73-111; output below.install.sh: versions dir,currentsymlink, plist from template, bootout when loaded then bootstrap; job argscurrent/t3 serve --base-dir ~/.config/t3fac --port 3876; logs in~/Library/Logs/t3fac/— tests "installs the first version and bootstraps the job without a bootout", "keeps the old version as previous and boots the job out first when loaded".rollback.shpointscurrentat the earlier version and restarts; exit 1 with a message when none — tests "rolls back to the previous version", "exits 1 ... when there is no earlier version".HOMEin a temp dir, fake archive, stublaunchctlonPATH; checks symlink, plist, launchctl calls —apps/server/src/factory/installScripts.test.ts.~/.t3,~/.config/softfac, 3773 or 3874 —grep -nE '\.t3($|[^a-z])|softfac|3773|3874'over the scripts and plist finds nothing; the smoke runs withHOMEset to its temp dir.build.sh smoke output (run at a2df0ce on this Mac)
Two things the build host needed, both noted in the script or here rather than hidden:
/with its ownCARGO_HOMEundernative/resource-monitor/target/. Cargo reads.cargo/config.tomlfrom every parent of the working directory and fromCARGO_HOME, and this Mac's home-level config replaces crates.io with a private registry whose credentials expire, which failed the first run. The lockfile pins crates.io, so the build ignores host cargo config.stablerustc is 1.94.0 and thesysinfocrate needs 1.95, which rustup has installed. The runs above usedRUSTUP_TOOLCHAIN=1.95.0.rustup update stableremoves the need; the script does not pin a toolchain.Gate
vp test run apps/server/src/factory→ exit 0 (4 files, 22 tests)vp run --filter t3 typecheck→ exit 0factory/scripts/check-seams.sh→ exit 0 (no upstream file changed;factory/SEAMSunchanged)Models
Review
versions/<v>before validating the archive and accepted an empty version (now unpacks beside, checkst3, then swaps; rejects empty,.,..,/); bootstrap raced bootout in both scripts (now waits up to 10 s forlaunchctl printto report unloaded); rollback deletedpreviousbefore the restart succeeded (now after); build.sh probes had no per-request deadline (nowcurl --max-time 2, 60 s overall); mutation pass: 9/9 named mutants killed, one untested branch (reinstalling the current version keepsprevious) covered in cycle 3 with two test nits.Lessons
build.shfailed on the host's cargo config, and the smoke loop would have hung next. Cause: a long script surfaces one host failure per run. Default: after a build script lands, the orchestrator runs its steps one at a time from the worktree, collects every host failure, and sends one fix packet..factory/, not an inline command. Symptom: an inline Bash withkillandrm -rfwas denied by the host, and a second attempt stalled with no output. Default: write the check to.factory/<name>.sh, run it with a bounded timeout, and read its log file..factory/before running a path-filtered test gate. Symptom:vp test run apps/server/src/factoryreported 8 files instead of 4. Cause: the detached reviewer worktree lived inside the main worktree, so the path filter matched its copy of the tests. Default:git worktree removeit as soon as the reviewer reports, and before the gate.Commits
212cf434etest: install, rollback and build version scripts— Make slice (red)10a3b70f5feat(factory): build, install and rollback scripts for the darwin-arm64 binary— Make slice (green)fb7399f8bfix(factory): build.sh ignores host cargo config and bounds each smoke probe— Make fix after the first real build (no red phase: shell behavior proven by rerunning build.sh)3c841833dtest: install keeps the live version on a bad archive; restart waits for launchd to unload— Check cycle 1 (red)d0229babcfix(factory): install validates the archive before replacing a version; restart waits for bootout to finish— Check cycle 1 (green)a2df0cec7test: reinstalling the current version keeps previous; invalid names and restart retry— Check cycle 2 (tests for behavior that already works; red shown by removing the guards locally)Files
current, write plist, restart jobcurrenttoprevious, restart job@HOME@placeholder