carlos / platform Public

AGENTS.md: amadan is the source of truth; squash before landing

The "every change lands through a PR" rule pointed at GitHub (gh pr
merge, then push main to amadan), while the issues rule already said main
lands through `amadan branch merge`. Both were followed. GitHub-first
merges ran CI only after the change was on main.

Now: push the branch to amadan, describe it with `amadan branch
describe`, squash it to one commit, and land it with `amadan branch
merge` once CI is green on that tip. GitHub is a mirror that follows
amadan's main; no PRs or merges there. The Build & test bullets that
called GitHub the source of truth and told you to push main to amadan
after a GitHub merge are replaced to match.

Bill's ruling, 2026-09-24.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bill Horsman pushed by bill@keymail.dev e989ccacb4a86fd7906b1a120c51ebb8a2617522 parent 38639c1
1 file changed, +66 −52
  • AGENTS.md +66 −52

CI passed — run details

diff --git a/AGENTS.md b/AGENTS.md
index 542447ec0..9415e5890 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -86,36 +86,58 @@ The rationale is concrete: on September 15, an SES spike created
production account. It was removed minutes later, but cleanup does not
substitute for approval.
-## Every change lands through a PR (Paul's rule, 2026-08-10)
-
-**Nothing merges to `main` without a pull request.** No local merge to
-`main`, no direct commit to `main`, no fast-forward "it's only a docs
-change" — every change, however small, goes up as a branch and lands
-through a PR. That includes doc-only edits, one-line fixes, and revert
-commits.
-
-Agents: this rule is on you as much as on people. When work is complete,
-push the branch and open the PR — never a local merge, never a direct
-commit, however small the change.
-
-**Merging that PR is fine** (Paul, 2026-08-16, clarifying an earlier
-wording that read as a blanket ban and cost a session a round trip). The
-rule is about how work REACHES `main`, not about whose hand lands it: the
-PR has to exist, so that it can carry the context, the iterations and the
-several commits that a single squashed push to `main` would flatten. Once
-it exists and is green, `gh pr merge` is an ordinary step — followed by
-pushing `main` to `amadan`, which is what gates the merged result (see
-Build & test).
-
-Use the judgement the rest of this file asks for: a PR that is still
-collecting review, that is gated on something (`#62`), or whose diff you
-would want a second pair of eyes on, waits for a person.
-
-The reason is timing, not ceremony. A locally merged change does still
-meet the gate — but only **after** it is on `main`, where a red run is an
-incident to clean up rather than a merge that simply doesn't happen. The
-PR is the one place the branch's diff is read as a single piece rather
-than commit by commit, while the change can still be turned away.
+## Every change lands through a reviewed branch on amadan (Paul's rule, 2026-08-10; amadan made the source of truth by Bill, 2026-09-24)
+
+**Nothing reaches `main` except through a branch landed on amadan.** No
+local merge to `main`, no direct commit to `main`, no fast-forward "it's
+only a docs change" — every change, however small, goes up as a branch
+and lands through `amadan branch merge`. That includes doc-only edits,
+one-line fixes, and revert commits.
+
+**amadan (`carlos/platform` on amadan.net) is the source of truth.** Its
+`main` is the real one, its CI is the only CI, and its branch description
+is where a change's context lives. GitHub is a mirror of it: do not open
+pull requests there, and never merge there. (Until 2026-09-24 this rule
+said "through a PR" and pointed at GitHub, while the issues rule below
+already said `main` lands through `amadan branch merge`. Both were
+followed, and GitHub-first merges ran CI only after the merge. That
+contradiction is what this rewrite removes.)
+
+The steps, for agents and people alike:
+
+1. **Push the branch to amadan.** The push is what triggers CI. The remote
+ may be named `amadan` or `origin` depending on the checkout; it is
+ whichever one points at `amadan.net`.
+2. **Describe it** — what changes, why, how it was tested and reviewed.
+ This is the pull request's job and it carries the same weight:
+
+ amadan branch describe carlos/platform <branch> -body -
+
+3. **Squash it to one commit** before landing, with a message that says
+ what the change is and why. `amadan branch merge` has no squash mode,
+ so this is done on the branch: `main` then gets the hub's merge commit
+ and exactly one change commit under it, not the branch's iterations.
+ The iterations are not lost: the description and the reviews record
+ them. Squashing moves the tip, so CI runs again on it.
+4. **Land it once CI is green on that tip:**
+
+ amadan ci status carlos/platform -branch <branch>
+ amadan branch merge carlos/platform <branch> -expect <tip> -message "..."
+
+ The merge refuses a branch whose CI is not green (exit 2) and, with
+ `-expect`, one that moved after you checked it. That ordering is the
+ point: a red run stops the merge instead of landing on `main` as an
+ incident to clean up.
+
+**Merging is fine** (Paul, 2026-08-16, clarifying an earlier wording that
+read as a blanket ban and cost a session a round trip). The rule is about
+how work REACHES `main`, not about whose hand lands it: the described
+branch has to exist, so that it can carry the context, the iterations and
+the review. Once it is green, `amadan branch merge` is an ordinary step.
+
+Use the judgement the rest of this file asks for: a branch that is still
+collecting review, that is gated on something, or whose diff you would
+want a second pair of eyes on, waits for a person.
## Work is tracked on amadan, not GitHub (Paul's rule, 2026-09-05)
@@ -171,28 +193,20 @@ anything.
records why the switch was safe. `10-gate` is `go build ./...` then
`make test`, so CI and what you run locally are one definition rather
than two that can drift.
-- **CI is triggered by a push to the `amadan` remote, not by GitHub.**
- `origin` is still where PRs live and where `main` is source of truth,
- but nothing on GitHub runs a build any more. A branch pushed only to
- `origin` has been gated by exactly nothing — push it to `amadan` too,
- and read the run, before calling it green.
-- **After a PR lands, push `main` to `amadan` too.** Merging happens on
- `origin`, and nothing moves amadan's `main` by itself, so the mirror
- falls behind silently: on 2026-08-31 it was 86 commits and three days
- back, which meant the gate had not run on `main` once in that window.
- A fast-forward is the whole job, and it is the last step of landing a
- change, not a separate chore:
-
- git fetch origin && git push amadan origin/main:refs/heads/main
-
- What it buys is the one thing per-branch CI cannot tell you: each
- branch was green against the base it was cut from, not against what
- landed beside it. Read that run too — a red `main` is worth knowing
- about the same day, which is the whole argument for the PR gate one
- section up. (The intended end state is an auto-mirror the other way,
- amadan to GitHub, so that `main` moves on the hub that gates it and
- GitHub follows. Until that exists this push is the habit that stands
- in for it.)
+- **CI is triggered by a push to amadan, not by GitHub.** Nothing on
+ GitHub runs a build. A branch that exists only on GitHub has been gated
+ by exactly nothing. Read a branch's verdict with
+ `amadan ci status carlos/platform -branch <branch>` (exit 0 pass, 1
+ fail, 2 pending, 3 no status yet) before calling it green.
+- **After a merge, read `main`'s run too.** Each branch was green against
+ the base it was cut from, not against what landed beside it. A red
+ `main` is worth knowing about the same day. On 2026-08-31, when merges
+ still happened on GitHub, amadan's `main` was 86 commits and three days
+ behind, and the gate had not run on `main` once in that window; landing
+ on amadan is what ends that.
+- **GitHub follows amadan.** If GitHub's `main` is behind amadan's after a
+ merge, fast-forward it from amadan; never the other way round, and
+ never with anything that is not already on amadan's `main`.
- `20-cross@5` adds `GOOS=darwin`/`windows`/`linux-arm64` compiles, one
per shard. **The gate is not Linux-only**: `internal/host` is linked
into the CLI, which people run on Macs, so a Linux-only type assumption