| 1 | # The local gate |
| 2 | |
| 3 | A solo repo with no CI still needs one command that decides whether a revision |
| 4 | may land. Write it in the repo's own scripting language, and keep it small. |
| 5 | Snowbound's working example is |
| 6 | [`tools/ci.py`](https://shale.paperclover.net/snowbound/tree/-/tools/ci.py). |
| 7 | |
| 8 | ## What it does |
| 9 | |
| 10 | - **Gates a revision, not the working copy.** It defaults to main and takes a |
| 11 | revision as an argument. It checks that revision out into its own |
| 12 | workspace, with its own build cache, so agents' half-finished edits can't |
| 13 | leak in. A working-copy mode freezes the tree as it was when the run |
| 14 | started. |
| 15 | - **Holds a lock**, so two runs never share a build directory. The second run |
| 16 | says it is waiting. |
| 17 | - **Runs lanes:** format, lint with warnings as errors, tests, and a build for |
| 18 | each other platform the project ships. Each lane has its own time limit. |
| 19 | - **Skips a lane whose toolchain is missing, and says why** ("needs zig"). It |
| 20 | never passes that lane silently. |
| 21 | - **Is fast by default.** The default run finishes in minutes. Exhaustive or |
| 22 | fuzz-like sweeps sit behind an opt-in flag or env var. Snowbound's tests went |
| 23 | from about half an hour to under three minutes once its sweeps moved out. |
| 24 | - **Can run only what changed.** A changed-files mode runs just the lanes and |
| 25 | test packages that the diff from main reaches. |
| 26 | - **Reports failures by owner.** The output is a table of failures, each with |
| 27 | its first errors at file and line, so the agent whose edit broke it is |
| 28 | obvious. |
| 29 | - **Keeps logs.** Each run writes its lane logs and a machine-readable summary |
| 30 | into a folder, and the last twenty folders are kept. |
| 31 | - **Keeps the build cache under a size budget** after each run. A cache of a |
| 32 | million files once slowed font tests by minutes. |
| 33 | - **Clears env vars that tests read** before running, so the agent's own |
| 34 | environment doesn't change results. |
| 35 | - **Exits with the result.** |
| 36 | |
| 37 | ## Rules around it |
| 38 | |
| 39 | - **Gate the exact revision you are about to land**, after rebasing onto main. |
| 40 | A green working copy proves nothing about the commit. |
| 41 | - **Never pipe the gate through `grep`, `awk` or `tail` to judge it.** Read its |
| 42 | exit status. A filtered "clean" once hid a check that had never run. |
| 43 | - **The release script runs the gate on the commit it is about to publish.** |
| 44 | - **After a usage limit or a crash, gate the cut-off agents' work before landing |
| 45 | any of it.** |