383 Commits
Author SHA1 Message Date
zeekay 30af8df1e7 fix(site): the sampled asset check does not glob the brackets in a route's chunk name v1 2026-09-30 07:09:57 -07:00
zeekay fece5973c3 feat(site): identical objects of a sibling site are copied by the plane, not sent 2026-09-30 06:56:52 -07:00
zeekay 524eac6ff1 fix(site): read the previous manifest from the host that serves the prefix
Claude-Session: https://claude.ai/code/session_011i2AG9nwpiKUCVxAdDzYuU
2026-09-30 01:12:27 -07:00
zeekay fb8ace6f61 perf(site): upload each batch through one parallel curl; retry only what was not accepted
Claude-Session: https://claude.ai/code/session_011i2AG9nwpiKUCVxAdDzYuU
2026-09-30 01:12:24 -07:00
zeekay cae4ed5d93 fix(site): the action names the ref whose bin/site runs; the completion is asked again on a 5xx
Claude-Session: https://claude.ai/code/session_011i2AG9nwpiKUCVxAdDzYuU
2026-09-30 01:12:22 -07:00
zeekay 84b05273ab feat(site): publish only what changed; sites publish in parallel
Claude-Session: https://claude.ai/code/session_011i2AG9nwpiKUCVxAdDzYuU
2026-09-30 01:12:18 -07:00
zeekay 44a36738bf imgver reads the published floor with the KMS GitHub token when there is no GH_PAT
The automatic token reads only a package its repository was granted, so a
caller with no GH_PAT whose image is an org package it was never linked to
read nothing published, and with no declared version it had no version at
all. The KMS GitHub token is the rung the registry logins already take
between the two, and imgver now climbs the same ladder.
v2.1.6 v1.0.123
2026-09-30 00:48:10 -07:00
zeekay aada6c224f HANZO_CI_TRUSTED is spelled out in each job, because the forge keeps env as a raw node per job v2.1.5 v1.0.122 2026-09-30 00:24:57 -07:00
zeekay 72ae7a720a Public repositories' commit messages state the engineering reason 2026-09-29 22:08:48 -07:00
zeekay 50e93e3138 A pull request from a fork runs on a one-job runner, reads no credential, and publishes nothing v1.0.121 v2.1.4 2026-09-29 21:57:52 -07:00
Hanzo Dev 312d2f2701 The site deploy token is read in the publish role only, and never for a pull request
The KMS step exported HANZO_DEPLOY_TOKEN for any caller that declares a
site, in both roles, so the test role held it while it ran the repo's own
code, and a branch pushed for a pull request could print it. The token is
sealed once per org and publishes every site of that org. The site lane
reads it only in the publish role off a pull request, so the fetch is
there and nowhere else.
2026-09-29 13:04:33 -07:00
zeekay 909203f2ef Seed the PyPI lane's clean venv with pip
uv venv makes a venv without pip, so the clean install before upload
answered "No module named pip" for every wheel and the lane published
nothing (hanzoai/python-sdk v8.5.162, run 36508815355). The install and
import move into alone(), which bin/alone_test.sh lifts out of the
workflow and runs against wheels it builds.
2026-09-29 10:11:11 -07:00
zeekay 4b737d13ec The tools checkout fetches a caller's pinned sha instead of cloning it as a branch. 2026-09-28 18:30:31 -07:00
zeekay 58fd5da11e The cut pushes to github.com with a GitHub token and to the forge with the IAM token. 2026-09-28 18:13:13 -07:00
zeekay 80a1a74f48 Probe for libclang under its versioned names
Ubuntu's ldconfig cache lists libclang-18.so.18 and libclang-18.so,
never a bare libclang.so, so the probe missed the copy the runner image
carries and fell through to sudo apt-get, which the runner refuses
("effective uid is not 0"). hanzoai/decision run 36307074308 died there.
clang-sys searches libclang-*.so itself, so no LIBCLANG_PATH is needed.

Claude-Session: https://claude.ai/code/session_018Gt5TvrE2rxXuZikWSauv3
v2.1.3 v1.0.120
2026-09-27 02:22:28 -07:00
zeekay 3ceb54383c Report each enqueue assertion so the tally counts it
The suite printed only a summary line, and the reusable's test tally,
which counts per-result lines, read that as a runner that ran nothing
and failed main.

Claude-Session: https://claude.ai/code/session_01HuMDfgFssPUptYUzgZ6Cp8
v2.1.2 v1.0.119
2026-09-24 10:47:16 -07:00
zeekay 5339715989 Freeze the enqueue suite's clock
The fake clock rode on bash's ticking SECONDS, so a starved runner
spent 14 real seconds of the 30-minute budget and the suite failed
at 1786. Unset, SECONDS is a plain variable only the fake sleep moves.

Claude-Session: https://claude.ai/code/session_01HuMDfgFssPUptYUzgZ6Cp8
2026-09-24 10:44:39 -07:00
zeekay 1efafa8f78 Back off and obey Retry-After at the build door
A fixed 30-second poll for 20 minutes was measured short: hanzoai/cd
asked 41 times on 2026-09-23 and got 429 every time, then failed a
publish whose tests had passed. Every waiting repo of an org also hit
the door in the same second a slot freed.

The wait now doubles from 15s to a 120s ceiling with jitter, takes a
numeric Retry-After as a floor, and stops at 30 minutes, since a build
holds its slot for up to ~39. bin/enqueue_test.sh lifts the function
out of build.yml and runs it against a faked wire and clock.

Claude-Session: https://claude.ai/code/session_01HuMDfgFssPUptYUzgZ6Cp8
2026-09-24 10:31:07 -07:00
zeekay e607b8bfc6 Read back only the answer that carried the body
curl -L keeps every hop's headers, and the check took the last
content-length it saw. A root that redirected once before a
chunked page was measured against the redirect's 17 bytes, which
failed a healthy publish of dev-hanzo-ai three times over.

Claude-Session: https://claude.ai/code/session_01TUxvfuta1Z44KVNYuAz71F
2026-09-24 10:29:00 -07:00
zeekay 5e2a320eba Link the runner package to this repository
ghcr.io/hanzoai/git-runner is linked to no repository, so this repo's
workflow token cannot list its versions and bin/imgver would publish
9.0.0 over and over. The source label links it on the next push.

Claude-Session: https://claude.ai/code/session_01HuMDfgFssPUptYUzgZ6Cp8
2026-09-24 10:19:55 -07:00
zeekay 4bb3d8c3dd Pin later steps to the restored Go cache
hanzo-inc/cloud's gates name their caches with ${GOCACHE:-...}, so they
built into a directory nothing restored and nothing saved. Restore now
exports the two directories it used, and every later step reads them.

Claude-Session: https://claude.ai/code/session_01HuMDfgFssPUptYUzgZ6Cp8
2026-09-24 10:18:42 -07:00
zeekay f6d6172c9b Return from delegate once the door queues
The publish job held its runner up to 40 minutes polling the registry so
it could write the version tags itself: 289 runner-minutes in 48 hours
spent waiting. The door now writes those tags in the same push and says
so in its answer, so the job ends on the 202 and names the build to
watch. A tag the door does not promise is still written here, and
`wait: 'true'` holds the job for a caller that uses the image next.

The first ref is taken by expansion: `echo | head -1` under pipefail
failed hanzoai/ci's own publish with a broken pipe.

Claude-Session: https://claude.ai/code/session_01HuMDfgFssPUptYUzgZ6Cp8
2026-09-24 10:12:12 -07:00
zeekay 5d6d7858e4 Carry the Go cache between runners
A runner lives one job, so no Go cache was ever restored: 142 Go-gate
minutes in 48 hours were 31 downloading modules and 69 compiling, and a
warm pass compiled commerce's vet in 15s against 198s cold.

The cache lives in the org's own bucket behind cloud's /v1/s3, reached
with the IAM token the KMS step already holds, so the server keeps one
org out of another's and CI holds no bucket key. Go trusts a restored
cache without re-hashing it, so only the default branch and tags write.

setup-go's own cache is off: it is GitHub's store, and the forge has none.

Claude-Session: https://claude.ai/code/session_01HuMDfgFssPUptYUzgZ6Cp8
2026-09-24 10:12:11 -07:00
zeekay 09c0fad22f Bake the toolchain into the runner image
Every job downloaded Go and Node through setup-go and setup-node, 110
runner-minutes in 48 hours, because nothing was in the tool cache they
read. Go 1.27.1 and Node 22 now sit there in their layout, beside
corepack's pinned pnpm, helm, crane and zstd.

The image is an images: entry built at the build door on every push.
Its forge lane stopped when Actions went off on the mirror, and a
runner has no docker daemon to run it anyway.

Claude-Session: https://claude.ai/code/session_01HuMDfgFssPUptYUzgZ6Cp8
2026-09-24 10:12:10 -07:00
zeekay e556ccfd53 Declare the secrets a caller may pass
`secrets: inherit` passes nothing to a reusable workflow in another
org, and a caller may only name a secret the reusable declares. Every
luxfi, zooai, lux-apps, hanzo-inc and hanzo-apps caller therefore
reached the KMS step with KMS_CLIENT_ID empty and delegate refused on
an empty HANZO_API_TOKEN. All five are optional, so a hanzoai caller's
`inherit` is unchanged.

Claude-Session: https://claude.ai/code/session_01HuMDfgFssPUptYUzgZ6Cp8
2026-09-24 10:06:55 -07:00
z 957b97ce72 Delete the forge CI caller
The forge copy is a pull mirror with Actions off. This caller ran the
same gate as .github/workflows/cicd.yml a second time on every commit.

Claude-Session: https://claude.ai/code/session_01HuMDfgFssPUptYUzgZ6Cp8
2026-09-24 09:47:42 -07:00
zeekay a9e71885a7 Gate on amd64 tests unless a repo asks for arm64
Hanzo CI/CD / cicd (push) Blocked by required conditions
Hanzo CI/CD / test (linux-amd64) (push) Skipped
Hanzo CI/CD / test (linux-arm64) (push) Skipped
Hanzo CI/CD / test-amd64 (push) Waiting to run
Hanzo CI/CD / test-advisory (push) Skipped
CI/CD / gate (push) Waiting to run
Every caller ran its tests on both architectures, which doubled runner
demand and queued the whole estate behind the smaller arm64 pool for
hours, while the arm64 leg caught almost nothing amd64 did not. A repo
with architecture-specific code names both in test-runners.

Claude-Session: https://claude.ai/code/session_01HuMDfgFssPUptYUzgZ6Cp8
v1.0.118
2026-09-24 09:12:46 -07:00
zooqueenandHanzo Dev c9541215f9 Publishing's condition calls no status function but always()
CI/CD / gate (push) Canceled after 0s
Hanzo CI/CD / cicd (push) Canceled after 0s
Hanzo CI/CD / test (linux-arm64) (push) Canceled after 0s
Hanzo CI/CD / test (linux-amd64) (push) Canceled after 0s
Hanzo Git evaluates a job's if with no job in scope, and cancelled() reads the
job's status, so a condition calling it panicked the forge's job resolver the
moment both of cicd's needs were decided. always() alone lets the condition be
asked; naming a success is what refuses when both gating jobs were skipped.

Co-authored-by: Hanzo Dev <[email protected]>
v1.0.117
2026-09-24 02:20:01 -07:00
zooqueenandHanzo Dev ec1e619f1f A caller chooses which architectures' tests gate publishing, and can run one more as advisory
test-runners selects the gating jobs: both architectures (the default, the
`test` matrix as before) or linux-amd64 alone (`test-amd64`). advisory-runners
runs the same test on one more architecture in `test-advisory`, which nothing
needs, so a slow or red leg there reports without holding a release. The choice
is a job per value, selected by `if`, because Hanzo Git does not evaluate inputs
in strategy.matrix. cicd needs both gating jobs and publishes only when the one
that ran succeeded, so a caller that passes neither input behaves exactly as
before.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-24 02:05:17 -07:00
zeekay 9f66b01ea6 Clone the public client driver anonymously
Hanzo CI/CD / cicd (push) Blocked by required conditions
Hanzo CI/CD / test (linux-amd64) (push) Waiting to run
Hanzo CI/CD / test (linux-arm64) (push) Waiting to run
CI/CD / gate (push) Waiting to run
hanzoai/openapi is public, and git.hanzo.ai refuses the org's
machine identity because no account is linked to it, so the lane
failed on every client repo. It now clones from github.com with
the runner's git config set aside, and needs no credential.

Claude-Session: https://claude.ai/code/session_01TUxvfuta1Z44KVNYuAz71F
2026-09-24 00:28:58 -07:00
zeekay 117b7ec72f Let a site declare build_secrets
Hanzo CI/CD / test (linux-amd64) (push) Successful in 3m47s
Hanzo CI/CD / test (linux-arm64) (push) Successful in 8m51s
Hanzo CI/CD / cicd (push) Successful in 1m37s
CI/CD / gate (push) Successful in 12m40s
A static export inlines its ingest key at build just as an image
bakes one, but only images[] were read, so a site had no way to
take a pk- key from KMS and fell back to committing a literal.

Claude-Session: https://claude.ai/code/session_01TUxvfuta1Z44KVNYuAz71F
2026-09-23 19:51:55 -07:00
zeekayandHanzo Dev f16bddbd30 A refused delegate names the org its credential carries
Hanzo CI/CD / test (linux-amd64) (push) Successful in 2m43s
Hanzo CI/CD / test (linux-arm64) (push) Successful in 9m27s
Hanzo CI/CD / cicd (push) Failing after 21m27s
CI/CD / gate (push) Failing after 1h2m53s
Each org's CI holds its own <org>-ci identity and the build door confines it to
that org's registry namespaces, so a 403 prints the token's org beside its
subject. The README says which identity each GitHub org holds and which
namespaces it reaches.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-23 14:53:12 -07:00
zeekayandHanzo Dev e7bd921f5e The cut writes the release's number into the version file
Hanzo CI/CD / test (linux-amd64) (push) Successful in 3m28s
Hanzo CI/CD / test (linux-arm64) (push) Successful in 8m17s
CI/CD / gate (push) Successful in 42m34s
Hanzo CI/CD / cicd (push) Successful in 1m41s
When a release handed its number down (spec-version), the cut tagged that
number but skipped rewriting the file hanzo.yml names in client.version: the
rewrite sat under the derived-patch branch alone. A fanout from cloud v8.5.189
tagged rust-sdk v8.5.189 over a Cargo.toml still at 8.5.156, so its release
refused the tag, and the npm, PyPI and Maven publishers saw an unchanged
version and published nothing.

The choice and the rewrite are now one function, `cut`, that writes whichever
number it picked. A release's number must be x.y.z before it reaches the tag
or sed: `8.5.189/;e cmd;#` ran cmd through GNU sed's e command.
bin/cut_test.sh lifts `cut` out of build.yml and runs it; it is a gate in
hanzo.yml.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-23 11:23:52 -07:00
zeekayandHanzo Dev 0875f06c15 Delegate sends an image's context to the build door
Hanzo CI/CD / test (linux-amd64) (push) Successful in 4m48s
Hanzo CI/CD / test (linux-arm64) (push) Successful in 6m51s
Hanzo CI/CD / cicd (push) Successful in 3m30s
CI/CD / gate (push) Successful in 33m0s
The door scopes a build to a context directory and reads the Dockerfile at
its root-relative path, so an image whose context is a subdirectory builds
on this lane instead of being refused.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-23 02:39:46 -07:00
zeekayandHanzo Dev a161219f0b Wait out a restarting build door too
Hanzo CI/CD / test (linux-arm64) (push) Successful in 6m3s
Hanzo CI/CD / test (linux-amd64) (push) Successful in 2m14s
Hanzo CI/CD / cicd (push) Successful in 1m34s
CI/CD / gate (push) Successful in 34m48s
cloud restarts on every deploy and is back within a minute, and a publish that
reached the door during one failed on Cloudflare's 502 — the canary's did, at
09:17:40, inside a restart from 09:17:19 to 09:18:14, after its tests had
passed on both architectures. No answer and 502/503/504 now wait on the same
budget as the per-org ceiling.

Co-authored-by: Hanzo Dev <[email protected]>
v1.0.116
2026-09-23 02:20:43 -07:00
zeekayandHanzo Dev efb58d8b87 Hand grep its input instead of piping into grep -q
Hanzo CI/CD / test (linux-amd64) (push) Successful in 9m18s
Hanzo CI/CD / test (linux-arm64) (push) Successful in 9m14s
Hanzo CI/CD / cicd (push) Failing after 5m39s
CI/CD / gate (push) Failing after 19m36s
Under pipefail, a pipe into `grep -q` reports the writer's status too, and
grep quits at its first match, so the answer depends on whether the writer
finished before the pipe closed. The imgtags suite failed that way on an amd64
runner and passed on the arm64 one at the same commit. A here-string has no
second process to lose.

Co-authored-by: Hanzo Dev <[email protected]>
v1.0.115
2026-09-23 01:57:09 -07:00
zeekayandHanzo Dev cfa459059e Wait for the build door's slot instead of failing
Hanzo CI/CD / test (linux-amd64) (push) Failing after 4m53s
Hanzo CI/CD / test (linux-arm64) (push) Successful in 9m14s
Hanzo CI/CD / cicd (push) Skipped
CI/CD / gate (push) Failing after 9m14s
The door holds one build per org, and a 429 is its queue. The delegate lane
refused on it, so two repos publishing together failed the second; the canary's
publish job died that way with both test legs green. It waits now, on the same
20-minute budget cloud's own image job gives the same answer.

Co-authored-by: Hanzo Dev <[email protected]>
v1.0.114
2026-09-23 01:47:11 -07:00
zeekayandHanzo Dev 8d1cf7c89f kms_test reports its count
Hanzo CI/CD / test (linux-amd64) (push) Successful in 4m49s
Hanzo CI/CD / test (linux-arm64) (push) Successful in 8m33s
Hanzo CI/CD / cicd (push) Failing after 2m14s
CI/CD / gate (push) Failing after 22m46s
The gate list refuses a *_test.sh that reports no result, and this suite ended
with `bin/kms: ok`, which carries none. Every other suite here prints
`<name>: N passed, M failed`; this one does now. It was hidden behind the brand
gate, which failed first on every run.

Co-authored-by: Hanzo Dev <[email protected]>
v1.0.113
2026-09-23 01:06:54 -07:00
zeekayandHanzo Dev fabcfac1d0 The verdict runs in both jobs, and adjudicates each
Hanzo CI/CD / test (linux-amd64) (push) Failing after 1m44s
Hanzo CI/CD / test (linux-arm64) (push) Failing after 7m30s
Hanzo CI/CD / cicd (push) Skipped
CI/CD / gate (push) Failing after 19m17s
The verdict must carry no `if:`, so no input can silence it; the role guard I
gave it broke exactly that, and the self-check caught it on the first run. It
now runs everywhere: in the test job it reads the receipt as before, and in the
publish job, which holds no receipt, it refuses unless the test job answered
success. The self-check asserts the two-job shape — the gate and its opt-out
guarded by the role, the publish job behind `needs: test`.

Co-authored-by: Hanzo Dev <[email protected]>
v1.0.112
2026-09-23 00:29:21 -07:00
zeekayandHanzo Dev e62a1df9e8 Write the test legs out, and give runner back its meaning
Hanzo CI/CD / cicd (push) Skipped
CI/CD / gate (push) Failing after 3m53s
cicd.yml / test (${{ fromJson(inputs.runner) }}) (push) Canceled after 0s
Hanzo CI/CD / test (linux-arm64) (push) Failing after 2m27s
Hanzo CI/CD / test (linux-amd64) (push) Failing after 3m53s
Hanzo Git expands a reusable workflow without evaluating `inputs` inside
`strategy.matrix`, so on the forge the test job became one leg labelled with the
unevaluated expression and waited for a runner that cannot exist. The legs are
now linux-amd64 and linux-arm64, written out — every image ships for both, so
both are always gated — and `runner` names the publishing runner again, as it
did before the split, so no caller changes.

Co-authored-by: Hanzo Dev <[email protected]>
v1.0.111
2026-09-22 23:44:21 -07:00
zeekayandHanzo Dev 0a06303c54 Vendor @hanzo/brand 1.4.10, the Zen sheet
cicd.yml / test (${{ fromJson(inputs.runner) }}) (push) Canceled after 0s
Hanzo CI/CD / cicd (push) Canceled after 0s
CI/CD / gate (push) Canceled after 0s
The bytes here already were brand's current sheet; the hash named the 1.4.9
Geist one, because brand changed the file without a version. Brand is 1.4.10
now and this pins it.

Co-authored-by: Hanzo Dev <[email protected]>
v1.0.110
2026-09-22 23:32:17 -07:00
zeekayandHanzo Dev 26755c1705 Test on both architectures before anything publishes
cicd.yml / test (${{ fromJson(inputs.runner) }}) (push) Canceled after 0s
Hanzo CI/CD / cicd (push) Canceled after 0s
CI/CD / gate (push) Canceled after 0s
Every image ships for amd64 and arm64, and until now its tests ran on amd64
alone, one runner at a time on the AWS cluster's single amd64 sandbox node while
the arm64 one sat idle. `test` now runs one leg per runner in `runner:` at once,
linux-amd64 and linux-arm64 by default, and `cicd` needs it: a red leg on either
architecture leaves no image, tag or release. Publishing is a job of its own
because a matrix leg cannot wait for its sibling. Both jobs share one step list
through an anchor, and HANZO_CI_ROLE picks which steps run in each.

Co-authored-by: Hanzo Dev <[email protected]>
v1.0.109
2026-09-22 23:30:35 -07:00
zeekayandHanzo Dev d604b53cea Fetch jq and crane for the machine the step runs on
Hanzo CI/CD / cicd (push) Failing after 1m51s
CI/CD / gate (push) Failing after 1m51s
The fallbacks downloaded the x86_64 builds by name. crane is not in the runner
image, so the delegate lane fetches it every run to alias version tags onto the
door's digest — and on an arm64 runner that is an exec format error at the one
step that makes a build deployable.

Co-authored-by: Hanzo Dev <[email protected]>
v1.0.108
2026-09-22 23:14:11 -07:00
zeekayandHanzo Dev a97bee10f9 Reach the build door by its public name
Hanzo CI/CD / cicd (push) Failing after 1m51s
CI/CD / gate (push) Failing after 1m51s
A runner runs whatever a repository says, so the AWS cluster walls it off: egress
is DNS and 80/443 to public addresses, every RFC1918 range excepted. cloud's
Service address is inside that wall, so a delegated build was refused in
milliseconds before the door saw it — every image on that cluster, cloud's own
included, has failed there since the wall went up. api.hanzo.ai is the name a
runner is meant to use, and from a runner it answers.

Co-authored-by: Hanzo Dev <[email protected]>
v1.0.107
2026-09-22 23:01:46 -07:00
zooqueenandHanzo Dev 3c1989c933 fix(site): increase upload attempts to 5 with 60s timeout to prevent socket drop failures
Hanzo CI/CD / cicd (push) Failing after 1m40s
CI/CD / gate (push) Failing after 1m41s
Runner image / build (amd64, linux-amd64) (push) Failing after 2m12s
Runner image / build (arm64, linux-arm64) (push) Failing after 3m2s
Runner image / merge (push) Skipped
Co-authored-by: Hanzo Dev <[email protected]>
2026-09-20 02:25:15 -07:00
zeekayandHanzo Dev 67460df3b1 The runner image is built where the runners are
This lane was written for our own pools — it names linux-amd64 and linux-arm64 —
and filed under .github/workflows, where nothing executes it. So it never ran:
the arm64 half was published by hand and the amd64 half of the current runner was
never built at all, which is what left the fleet pinned to an image that predates
the variable rename.

The entrypoint's refusal is asserted by the name it actually prints. Asserting
the old one meant the smoke test would have failed on the very image it was
meant to prove, and called it "failed for the wrong reason".

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-17 08:24:53 -07:00
zeekayandHanzo Dev 94205239af The runner image version names the runner that reads GIT_RUNNER_URL
Hanzo CI/CD / cicd (push) Failing after 1m56s
CI/CD / gate (push) Failing after 1m57s
Version 7 was published before the rename landed, so the image under that tag
still asks for the old variable and exits when it is unset. A running fleet
cannot tell those two apart by the tag, so the renamed runner gets a version of
its own.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-17 06:25:08 -07:00
zeekayandHanzo Dev 3f336a2ef7 Go 1.27.1, and the code it can say more simply
Hanzo CI/CD / cicd (push) Failing after 1m34s
CI/CD / gate (push) Failing after 1m35s
Modules declare go 1.27.1 and the build images follow. go fix applied the
modernizers; omitzero is not applied, since it changes what the JSON says.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-16 19:09:21 -07:00
zeekayandHanzo Dev d8a47494cd A gated preview answers the read-back 401, and that is the gate working
Hanzo CI/CD / cicd (push) Failing after 2m14s
CI/CD / gate (push) Failing after 2m14s
The read-back demands HTTP 200 from the live URL. A client preview cannot give
one: hanzo-apps hosts are guarded, so they answer an API caller 401 and a browser
a redirect to hanzo.id. The same workflow's "every host is gated" step REFUSES to
publish any host that answers otherwise, so the two steps asked one deploy to be
two contradictory things.

It cost 27 of 29 client sites. The first slug of each repo uploaded and flipped
live, the read-back called it unreadable, and `set -e` took the remaining sites
down with it -- leaving hosts that resolve and gate with nothing behind them.

A browser-shaped probe that does not follow tells a gate from a failure: a gate
redirects to hanzo.id naming that host as its own callback, which proves the host
is routed and guarded. Its bytes still are not read back, so the run says so
rather than counting it verified. Every other failure path is unchanged: an empty
body, a short read and a plain non-200 all still fail.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-16 14:53:31 -07:00
zeekayandHanzo Dev 9990247f51 The runner is git-runner, and it reads GIT_RUNNER_*
Hanzo CI/CD / cicd (push) Failing after 2m55s
CI/CD / gate (push) Failing after 2m56s
Hanzo Git is the product; act_runner was the upstream binary's name and
GITEA_ was its env prefix. The binary installs as git-runner and the two
variables cloud sets are GIT_RUNNER_URL and GIT_RUNNER_TOKEN.


Co-authored-by: Hanzo Dev <[email protected]>
2026-09-16 13:33:03 -07:00