.amadan: the job table is true again after all four ports
Merging cross@5, the one-definition gate and this step together left the README describing a runner that no longer exists: it still claimed `cross` covered three targets, that `minio-contract` was unportable, and that `gofmt` was absent because it needs a base SHA. The last of those was the only real argument, and it is answered by widening rather than imitation — `make test` already runs a repo-wide gofmt check, stricter than the changed-files job, and the three unformatted files that scoping protected are gone. So nothing is missing now, and the sentence about the gate being "still whole on GitHub" goes with it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
4 files changed,
+65
−36
.amadan/README.md+28 −21.amadan/ci.d/10-gate+14 −7.amadan/ci.d/{20-cross@3 => 20-cross@5}+15 −6Makefile+8 −2
diff --git a/.amadan/README.md b/.amadan/README.md| index 6bf22c116..2f411b85f 100644 |
| --- a/.amadan/README.md |
| +++ b/.amadan/README.md |
| @@ -9,28 +9,35 @@ here. |
| | workflow job | here | | |
| |---|---|---| |
| | `gate` | `10-gate` | build · vet · `go test ./... -count=1` | |
| -| `cross` | `20-cross@3` | one target per shard | |
| +| `cross` | `20-cross@5` | one target per shard, all five | |
| | `minio-contract` | `30-minio-contract` | MinIO on loopback, no container | |
| -| `gofmt` | **not ported** | see below | |
| - |
| -## What is deliberately missing, and why |
| - |
| -One job is absent. Writing that down is the point of this file: a |
| -`ci.d/` directory that quietly covers less than the workflow next to it |
| -is worth less than no `ci.d/` at all, because it invites people to read |
| -a green run as meaning more than it does. |
| - |
| -**`gofmt`** checks only the files a PR changed, deliberately — three |
| -pre-existing unformatted files elsewhere are left alone, and a |
| -repo-wide check would fail on arrival and teach everyone to ignore the |
| -job. That needs the PR's **base SHA**, which is a GitHub concept. amadan |
| -CI hands a job its commit and its branch and has no notion of what it |
| -is a pull request against, so the job cannot be reproduced faithfully |
| -here. Reproducing it *unfaithfully* — repo-wide, or diffed against a |
| -guessed base — is worse than not running it. |
| - |
| -That is a gap in this runner, not in the gate. The gate is still whole |
| -on GitHub. |
| +| `gofmt` | `10-gate` | repo-wide, via `make test` — see below | |
| + |
| +## `gofmt`: ported by widening it, not by reproducing it |
| + |
| +Nothing is missing now. Writing that down is still the point of this |
| +file: a `ci.d/` directory that quietly covers less than the workflow |
| +next to it is worth less than no `ci.d/` at all, because it invites |
| +people to read a green run as meaning more than it does. This file is |
| +the check on that, so it has to stay true. |
| + |
| +**`gofmt`** was the last gap, and it closed by widening rather than by |
| +imitation. The workflow checks only the files a PR changed, because it |
| +needs a **base SHA** — a GitHub concept. amadan CI hands a job its |
| +commit and its branch and has no notion of what it is a pull request |
| +against, so that job cannot be reproduced faithfully here. |
| + |
| +It does not need to be. The scoping existed to protect three |
| +pre-existing unformatted files, and those are gone: `gofmt -l .` over |
| +the whole tree is clean today. So `10-gate` runs `make test`, whose |
| +recipe already contains a **repo-wide** gofmt check — which is stricter |
| +than the job it replaces, and one definition shared with what a |
| +developer runs locally rather than a second list that can drift. |
| + |
| +The rule that survives from the old scoping is the one worth keeping: |
| +if a repo-wide check ever starts failing on arrival, fix the tree |
| +rather than narrowing the check, because a gate people learn to ignore |
| +is not a gate. |
| ## `minio-contract`, and why it turned out to be portable |
diff --git a/.amadan/ci.d/10-gate b/.amadan/ci.d/10-gate| index 9276c1635..abb3ada43 100755 |
| --- a/.amadan/ci.d/10-gate |
| +++ b/.amadan/ci.d/10-gate |
| @@ -8,13 +8,20 @@ |
| # definition of green; where the two disagree, the workflow is the one |
| # that gates a merge and the difference is a bug in this file. |
| # |
| -# -count=1 is the same rule for the same reason it is there: never |
| -# satisfy the gate from a cached pass. The 30m timeout is above Go's |
| -# 10m default because the root package's e2e tests compile the carlos |
| -# binary many times over — copied from the workflow rather than |
| -# re-derived, so a change there is a change in one place. |
| +# One definition, not two. Everything past the build is `make test` — the |
| +# same target a maintainer runs on a laptop — so CI and the local gate |
| +# cannot drift apart, and a check added to one is a check added to both. |
| +# That is how the gofmt check gets here at all: `make test` runs vet, a |
| +# repo-wide `gofmt -l .`, then the tests, and this file no longer restates |
| +# any of it. |
| +# |
| +# `go build ./...` stays spelled out because `make test` does not do it — |
| +# the Makefile's test target starts at vet. |
| +# |
| +# -count=1 and -timeout 30m moved to the Makefile's go test line along with |
| +# the reasoning for them; they are still in force here, just no longer |
| +# written down twice. |
| set -eu |
| go build ./... |
| -go vet ./... |
| -go test ./... -count=1 -timeout 30m |
| +exec make test |
diff --git a/.amadan/ci.d/20-cross@3 b/.amadan/ci.d/20-cross@5| similarity index 66% |
| rename from .amadan/ci.d/20-cross@3 |
| rename to .amadan/ci.d/20-cross@5 |
| index 6f79790c5..9dec4b177 100755 |
| --- a/.amadan/ci.d/20-cross@3 |
| +++ b/.amadan/ci.d/20-cross@5 |
| @@ -9,9 +9,16 @@ |
| # built it was on Linux. Cross-compiling catches it in seconds and needs |
| # no Mac. |
| # |
| -# The @3 is amadan's whole sharding interface: it runs this script three |
| +# Windows is a CLIENT target: `carlos deploy` from a Windows workstation |
| +# against a Linux fleet. The box-side packages still have to COMPILE |
| +# there, because the CLI is the same binary as the agent, so unix-only |
| +# syscalls live behind per-OS files (internal/edge/purge_listen_*.go, |
| +# internal/host/{statfs,flock}_*.go). These two shards are what stops |
| +# the next syscall.Foo from silently un-shipping the Windows build. |
| +# |
| +# The @5 is amadan's whole sharding interface: it runs this script five |
| # times concurrently and tells each copy which one it is. One target per |
| -# shard rather than three builds in a row, because they are independent |
| +# shard rather than five builds in a row, because they are independent |
| # and this box has the cores — and because a failing target then names |
| # itself in the shard that failed, instead of being the first line of a |
| # combined log. |
| @@ -22,12 +29,12 @@ shards=${AMADAN_SHARD_COUNT:?this step must be run by amadan CI, which sets AMAD |
| # The fence. The targets below are a fixed list, and the shard count in |
| # this file's name is what deals them out — so the two MUST agree. Rename |
| -# this to @2 and, without this check, one platform silently stops being |
| +# this to @4 and, without this check, one platform silently stops being |
| # compiled while CI stays green. That is the exact shape of the bug the |
| # job exists to catch, arriving through the job that catches it. |
| -if [ "$shards" -ne 3 ]; then |
| - echo "this step deals 3 fixed targets but was run with $shards shards —" |
| - echo "rename the file back to 20-cross@3, or add a target below" |
| +if [ "$shards" -ne 5 ]; then |
| + echo "this step deals 5 fixed targets but was run with $shards shards —" |
| + echo "rename the file back to 20-cross@5, or add a target below" |
| exit 1 |
| fi |
| @@ -35,6 +42,8 @@ case "$shard" in |
| 0) GOOS=darwin GOARCH=arm64 ;; |
| 1) GOOS=darwin GOARCH=amd64 ;; |
| 2) GOOS=linux GOARCH=arm64 ;; |
| +3) GOOS=windows GOARCH=amd64 ;; |
| +4) GOOS=windows GOARCH=arm64 ;; |
| *) echo "no target for shard $shard"; exit 1 ;; |
| esac |
diff --git a/Makefile b/Makefile| index 7e858f35a..5a963c1e4 100644 |
| --- a/Makefile |
| +++ b/Makefile |
| @@ -5,10 +5,16 @@ GOARCH ?= |
| .PHONY: test build fmt |
| +# The build gate: vet, format, tests. `.amadan/ci.d/10-gate` runs this same |
| +# target, so what CI checks and what you check are one definition. |
| +# |
| +# -count=1 is CLAUDE.md's rule: never satisfy the gate from a cached pass. |
| +# The 30m timeout is above Go's 10m default because the root package's e2e |
| +# tests compile the carlos binary many times over. |
| test: |
| go vet ./... |
| - @fmt_out=$$(gofmt -l .); if [ -n "$$fmt_out" ]; then echo "gofmt needed:"; echo "$$fmt_out"; exit 1; fi |
| - go test ./... |
| + @fmt_out=$$(gofmt -l .); if [ -n "$$fmt_out" ]; then echo "gofmt needed:"; echo "$$fmt_out"; exit 1; fi; echo "gofmt -l .: clean" |
| + go test ./... -count=1 -timeout 30m |
| build: |
| CGO_ENABLED=0 GOOS=$(GOOS) GOARCH=$(GOARCH) go build -ldflags "$(LDFLAGS)" -o carlos . |