Files
cli/hanzo.yml
zeekay 39726fe671 The nightly re-pin lands on main, because the patch it opened could not exist
The last step of drift.yml pushed a `repin` branch and then asked the forge to
open a pull request for it. This repo has the pull unit turned off, so the
forge answered `curl: (22) The requested URL returned error: 500` to the POST
and answers 404 to `GET /pulls` — a control repo with the unit on answers 200.
The step therefore failed every night it had anything to do, after leaving a
branch behind that nobody could turn into a patch.

It now commits the re-pin to main. What made a patch worth reading was that a
re-pin is not always safe to take — cloud's source states a route before
production deploys it, and the gate calls that AHEAD — but that condition is
`make verify`, which already rules on it. So verify runs on the regenerated
tree before the commit and the push happens only behind it; when it refuses,
nothing is written and the red nightly carries the gate's own reasons.

hanzo.yml described this step as pulling cloud's newest tag and opening a
patch. It reads main, and now it commits.
2026-08-12 20:07:04 -07:00

76 lines
4.4 KiB
YAML

# Canonical CI config for hanzoai/cli — read by the hanzoai/ci reusable
# (.github/workflows/cicd.yml) and by platform.hanzo.ai. This repo had neither
# this file nor a Makefile, which is why `genspec` — the one thing that keeps
# the CLI's command surface honest — was reachable only by a maintainer typing
# it. A capture nothing re-asks goes stale silently, and this one did: it was
# 7 operations short and 8 operations wrong against the document cloud had
# already committed.
#
# NO images: the CLI is a binary a person installs, not a container a cluster
# runs. NO binaries: this repo's binaries are the five-target cross-build in
# .hanzo/workflows/release-matrix.yml (cargo-zigbuild + a vendored macOS SDK) —
# that is genuinely per-repo build logic and it is already correct; the generic
# Go-shaped lane here cannot produce it. NO deploy: nothing here rolls out.
#
# That path is `.hanzo/`, not `.github/`: the runners belong to git.hanzo.ai and
# github.com has none, so a pipeline under `.github/` queues forever instead of
# building. Both CI files in this repo live under `.hanzo/workflows/` for that
# one reason.
#
# What CI owns for this repo is the two gates below and the client lane.
client:
# The document, by value at a pinned ref: the lane fetches openapi.yaml at the
# ref .spec-lock names and refuses on a digest mismatch. It does not choose the
# ref and does not write the lock — on a push it is check-only at the locked
# one. What MOVES the pin is the nightly re-pin in .hanzo/workflows/drift.yml,
# which reads hanzoai/cloud's main and commits the result once `make verify`
# rules on it. Reading api.hanzo.ai here would name whatever is serving now
# rather than a release.
spec: { repo: hanzoai/cloud, path: openapi.yaml }
generate: ./scripts/generate.sh
# PATCH only, derived. The command surface is the document's; this crate only
# restates it, so it never earns a minor or a major.
version: "Cargo.toml:grep -m1 '^version' Cargo.toml | sed -E 's/.*\"(.*)\".*/\\1/'"
# THE CAPTURE GATE is NOT here, and that is the point: hanzoai/ci's `client:` lane
# asks it for all eight client repos in one place, on every push — fetch the
# document .spec-lock names, refuse if the ref moved under it, re-run the
# derivation, refuse any delta, write nothing. `make spec-check` is the same
# question a human asks locally, through the same script.
#
# THE DRIFT GATE is a different question — a capture can equal its inputs exactly
# and still describe a surface production stopped serving, or miss a product
# production started — and it IS here, inside `cargo test`, because it stopped
# needing the network. It rules on `spec/live.json`: the raw answers the live
# server gave to every probe and to a nonsense-sibling CONTROL for each, captured
# by `make live` and committed. So the push gate asks both directions on every
# push, in the one lane, with nothing to fail for a reason that is not drift.
#
# It used to need the wire, and that is what made it fragile: a gate needing the
# network in CI gets switched off, and this one first sat in the list below where
# a failure in the client step or the KMS login meant it was never reached at all.
# It was never asked once that way.
#
# What still needs the wire is the OTHER half — has production moved under the
# committed evidence? — and that has its own job, its own triggers and nothing
# else in it: `.hanzo/workflows/drift.yml`, nightly and on a click, `make
# live-check`. One predicate per place, and neither shares its fate with anything.
#
# `make test`, never a bare `cargo test`: the gates below exec maintainer
# binaries that `cargo test` does not build, and a gate that dies on NotFound
# reads exactly like a gate that passed. One invocation, in the Makefile.
#
# THE LINT GATE HAS TO INSTALL WHAT IT LINTS WITH. `dtolnay/rust-toolchain@stable`
# provisions rustc and cargo and no components, so `cargo clippy` answered
# "'cargo-clippy' is not installed for the toolchain" and every main build went
# red on it — six in a row, while `make test` above passed every one of them. A
# gate that cannot run is worse than no gate whichever way it lands: red, it
# teaches people the build lies; green, it teaches them nothing at all. It asks
# for the component first now, which is idempotent and costs a cached download.
test:
- name: cargo-test
run: make test
- name: clippy
run: rustup component add clippy && cargo clippy --locked --all-targets -- -D warnings