Files

74 lines
4.0 KiB
YAML

# Hanzo CI — the ONE way this repo is gated, read by hanzoai/ci.
#
# No `images:` and no `deploy:`: this is a client library. A consumer installs
# it from npm at a tag, so what CI owes is a gate, not an artifact. Publishing
# stays where it already is — .github/workflows/publish.yml, on a push to main.
# Two publish paths would be one too many.
test:
- name: test
# `npm ci`, not `npm install`: the lockfile is committed and a gate that
# silently resolves a different axios than the release does is not a gate.
#
# Then `npm test` — package.json's own statement of what passing means,
# rather than a second one written here that can disagree with it. Four
# steps, each proving what the others cannot:
#
# `build` is both halves (CJS and the bundler-facing ESM), the only thing
# that type-checks the whole generated tree.
#
# `smoke` LOADS the built package by name, through package.json exports —
# the entry point `npm i hanzoai` opens. build and examples both read source; a
# broken module graph or an entry point that does not resolve is a fact
# about the published artifact that neither of them can see.
#
# `wire` runs the six capabilities — budget, policy, audit, search, kb,
# graph — and the typed usage refusals against a scripted fetch, asserting
# the exact request each one sends and decoding a realistic answer, `denied`
# and `held` included. They are hand-written over the generated client, so
# what has to be proved about them is what goes out and what is made of what
# comes back; nothing else in this gate calls them at all.
#
# `examples` compiles the nine canonical flows — models, hello, chat,
# money, store, agent, tools, six, limits — against the client the way a consumer does, importing
# `from 'hanzoai'` and reading real fields off real response models. It has
# already earned its place: `choices[0].message.content` failed to compile
# here (TS2339: Property 'message' does not exist on type 'object') because
# the spec typed chat choices as a bare object. That became hanzoai/openapi's
# ChatChoice schema, which fixed the same hole in every other language at
# once. No unit test on generated code would have found it — only calling
# the client does.
run: |
set -e
npm ci --no-audit --no-fund
npm test
# THE CLIENT LANE — this repo is a PROJECTION of one API document at one version.
#
# hanzoai/cloud's release sends `repository_dispatch: spec-update` carrying
# (version, sha, spec_sha256); hanzoai/ci fetches openapi.yaml AT THAT SHA,
# REFUSES if the bytes hash to anything else, runs `generate:`, writes
# `.spec-lock` beside the code, and — only after the `test:` block below has
# passed over exactly those bytes — commits and cuts a patch.
#
# The input is hanzoai/cloud `openapi.yaml` — emitted from the code by each
# app's own router and gated on every cloud release — not hanzoai/openapi
# `hanzo.yaml`, which is hand-merged and fed by nothing. A document the routers
# write beats one a human curates: it cannot name an address the server does not
# serve. `.spec-lock` records which one this tree projects.
client:
# WHICH cloud, said out loud. hanzoai/ci defaults this to `hanzoai/cloud`, and
# that path now serves the re-rooted OSS core -- a twelve-commit line sharing no
# ancestor with the product, and carrying no openapi.yaml at all. So the fetch
# 404s for every ref this projection could name, on check and move alike, and
# has since the repoint. It reads as a credential fault and is not one.
#
# The product line is what this SDK is a projection of, so it is what is named.
# `.spec-lock`'s own repo= line does NOT set this -- ci reads the repo from here
# and uses the lock's copy for a commit message -- so the two can disagree in
# silence. They are one fact; keep them equal.
spec:
repo: hanzo-inc/cloud
generate: ./scripts/generate.sh
version: 'package.json:jq -r .version package.json'