main
10
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
6b8612eb74 |
two red gates, neither of them about the artifact
--check asks one question: is hanzo.yaml what its own pinned input projects to? It answers that at the ref .spec-lock NAMES, so which remote is cloud's main cannot change the answer — and it was resolving that remote anyway, before anything read it, and dying there. Measured on main: it exited on `forge/main, forgeinc/main, inc/main each carry openapi.yaml and have diverged` while the artifact it was asked about was byte-for-byte correct. The branch is resolved only where it is used now — `--current`, whose whole question is whether the tip moved past the pin, and a re-pin with no `--ref` to say where. The ambiguity itself is real and stays refused. Three remotes carry the document and none contains the rest; guessing between them is how a projection gets published from the wrong lineage. test_flows.py named four operations the document does not have. The keys route answers under the app that owns it, and the store plane moved again: this file said /v1/instances/kv, and that address is now 404 with a 404 control, which is this repo's own definition of refuted. /v1/provisioning/kv answers 403 with a 404 control — served. The notes carried the old probe as if it still held, so they are re-measured rather than re-worded, and they now say what the bare /v1/kv actually is: a separate bucket-keyed value plane whose root answers 200 to anyone, which is the one shape a round-trip must not be built on. Every flow renders into every SDK's examples, so an id here that the document lacks is a broken example in eight languages. hanzo.yaml, CAPABILITIES.md and .spec-lock are untouched. The pin stays where it is: at 22aedc87 the deployment fails to answer for 16 published operations, and at cloud's main it is 351 — the pin is the newest release api.hanzo.ai answers for, not the newest release. |
||
|
|
5b4379a876 |
name the repository that holds the document
The receipt is a coordinate a consumer resolves -- <repo>@<ref>:<path> -- and it named a repository whose main is a different lineage, one that does not contain the ref. Nothing could re-derive this artifact from that coordinate. The constant now carries a note saying why it reads the way it does, because it is the string a prose sweep reaches for first and a comment-only edit is how it last moved. |
||
|
|
0b132a8881 |
Name the thing instead of calling it a door
One word stood for several: the MCP server, one address that accepts requests, the single way in, and the boundary a credential is validated at. Each site now names its own sense — endpoint, entry point, the MCP server, the edge, address, relay — or, where none of those fit, takes the word the surrounding code already uses. Prose and comments only, 1:1 line for line. Identifiers keep their names: CSS classes, DOM ids, struct fields, enum variants, config values and the doc comments that must open with the identifier they document. |
||
|
|
b8b05087c9 |
carry the github copy onto the forge
Both hosts had moved. Resolved each file on what api.hanzo.ai actually serves:
- hanzo.yaml keeps this host's /v1/sentinel/{project}/envelope/. Measured: that
path answers 403 with and without a trailing slash, /v1/event/{project}/envelope
answers 404 both ways, and every other sentinel operation in the served document
is tagged o11y. The published document still names the event path, so it
describes a route nothing answers.
- publish.py and its test come from github, the only side that defines the
security scheme it requires. Its literal for the document's repo is corrected to
hanzo-inc/cloud, which is where the document is held — this host settled that in
'the lock names the repo that holds the document'.
- capabilities.yaml is the union of both tag sets across all nine domains, 213
tags from 191 and 120. github's commands and replay are real (GET /v1/commands
answers 200); this host's leaderboard, treasury, visor and the rest are kept.
pytest: 27 passed.
|
||
|
|
0df9fb2432 |
spec sync asks the repository that holds the document
hanzoai/cloud is the re-rooted OSS core: a twelve-commit line sharing no ancestor with the product and carrying no openapi.yaml at all. It is PUBLIC, so the workflow's checkout succeeded and publish.py failed one step later with "no remote of .cloud carries openapi.yaml on `main`" — which the step then threw away, printing instead its own fixed sentence, that hanzo.yaml had been hand-edited. It had not: re-derived at its own pinned ref, the committed artifact is byte-for-byte what that ref projects to. Every push and every hourly run has reported a drift that never existed. So the address is the value it always should have been. SPEC_REPO names hanzo-inc/cloud — where every ref this repo and every SDK has pinned resolves, and hashes to the digest its lock already carries — and .spec-lock, info.x-spec and CAPABILITIES.md's header follow it rather than restating it. The receipt was repointed on its own once and the artifact, the receipt and the test then named three different repositories; test_the_artifact_names_the_release_it_came_from now asserts the three AGREE instead of repeating the string a fourth time. Both canned ::error:: wrappers are gone. A step that replaces a precise diagnosis with a fixed sentence is worse than a step with no message: publish.py already says what is wrong and which command fixes it, and `set -e` fails the step. hanzo-inc/cloud is private, and the per-job token Hanzo Git mints reads the run's OWN repository and anything public — nothing else. Measured on hanzoai/python-sdk run 91449, which named the right repo and still took `curl: (22) ... 404`. The checkout therefore takes HANZO_GIT_TOKEN, the one name in this fleet for a credential that reads git.hanzo.ai, and the job says which credential is missing before actions/checkout can report a private repo as "repository not found". generate.py's own fetch takes the same name, so one read needs one credential. Cloud declares its own `bearer` scheme now, and the projection's addition stopped adding and started corrupting: setdefault no longer fired while the document-level `security` it wrote still did, so the published document required `bearerAuth` and defined nothing by that name. Generated typescript, measured: 2498 bearer call sites from cloud's document, 0 from the projection, leaving 191 files importing a credential helper none of them called. The rule is gone — cloud says both halves — and test_a_client_can_authenticate refuses a document that requires a scheme it does not define, whoever supplies it. Co-authored-by: Hanzo Dev <[email protected]> |
||
|
|
5ca53ab23f |
the receipt names a commit, and the projection catches up to it
hanzo.yaml described cloud@613cc065 while cloud's main had moved to 38a803e4, so every SDK and doc page generated from it described a router that had changed. Re-derived at the tip. publish.py resolved `ref` to a commit only when one was handed to it; a default run left the remote-tracking branch it discovered. That name went into `x-spec.ref`, into CAPABILITIES.md, and into `.spec-lock` — and a branch is not resolvable in the CI clone that re-derives the artifact, which has no remotes. Resolving once, before anything reads it, is what makes those three name one thing and keeps --check able to answer. |
||
|
|
353b50d2b6 |
tools: a tool name is the id the door answers to, not codegen's rename
`publish.py` rule 6 suffixes an operationId when two collide under the identity
a GENERATOR uses — punctuation stripped, case folded — so that Go does not
declare one request type twice. `deleteSession` (POST /v1/iam/sessions/delete)
and `DeleteSession` (DELETE /v1/o11y/sessions) are that collision, and the
second is published as `DeleteSession_2`.
An operationId is not only a codegen identifier. It is the WIRE NAME of an MCP
tool, and `POST /v1/mcp` answers to no `DeleteSession_2` — measured against the
live door, which lists `DeleteSession` and `deleteSession` and nothing else. The
suffix shipped verbatim in the tool catalogue of three client distributions:
npm @hanzo/mcp, PyPI hanzo-mcp, crates.io hanzo-mcp, all three byte-identical at
d6d49a17, 2279 tools. A catalogue that names a tool nothing can be told to run is
the one defect the catalogue exists to remove.
So rule 6 records what it renamed. `x-id` is the id hanzoai/cloud emitted,
written only where the projection had to change it — one operation in 2279, so
its meaning is its presence — and `tools.py`'s `wire()` is the ONE place a tool
takes its name. Nothing else moves: same rules, same drops, same count.
MEASURED, catalogue against the live door's 1323 tools:
before 1299/1323
after 1300/1323 and the remaining 23 are exactly the compat-tagged IAM
operations rule 2 drops on purpose, each of which has a
canonical twin in the published document
(add-user -> POST /v1/iam/users, and so on for all 23).
test_tools.py pins it from the document alone, offline: where `x-id` is present
the catalogue must carry it and must NOT carry the codegen name. hanzo.yml runs
the file, because a gate that is not in the `test:` block does not run.
openapi-generator 7.14.0 is indifferent to the new key — python, typescript,
java and kotlin each emit a full client tree from the document that carries it.
Co-authored-by: Hanzo Dev <[email protected]>
|
||
|
|
a40884ab95 |
publish: cloud's main is the remote that CARRIES the document, not the one called origin
`--current` resolved `origin/main`, and `origin` is not a fact about a checkout —
it is the name a clone happened to use. hanzoai/cloud answers on three remotes
here and they are not one lineage: `origin` is the GitHub OSS mirror, whose main
holds no openapi.yaml at its root at all, so `git show origin/main:openapi.yaml`
fatalled before the pin was ever compared. The one question this file asks on a
clock could only die or agree by accident, and it died — silently, for 24
releases, while nothing went red. A gate that cannot fail is not a gate.
The remote is DISCOVERED now, never named: fetch every one, keep those whose
`main` holds the document, take the one that contains all the others. A checkout
with a `forge` remote gets no special case — forge wins on this box because it
carries the file, `origin` wins on a normal clone, and neither is written down.
The same resolution is the default when re-pinning, so `python3 publish.py` with
no `--ref` can no longer publish from the wrong lineage either. Unreachable is
not fatal, because a mirror nobody can read decides nothing; stale is, so every
remote is fetched before any is read.
MEASURED, all four verdicts, against this checkout:
pin v1.801.452 (a real older release) -> forge/main is bab535c2 with a
different document, exit 1
pin 292e2fa8 (one commit back) -> forge/main has moved (bab535c2) but
the document has not, exit 0
pin bab535c2 (the tip that carries it) -> hanzoai/cloud@bab535c2 - forge/main,
exit 0
--cloud pointed at a checkout carrying -> "no remote carries openapi.yaml on
no openapi.yaml `main`", exit 1, not a git fatal
The committed artifact does not move: `--check` re-derives hanzo.yaml to the same
bytes at v1.801.476, `--served` refutes all 2305 published operations against
api.hanzo.ai and finds none missing, and 17 tests pass. Nothing here changes what
is published, only which repository gets asked whether it is still current — so
`info.version` stays 8.0.0, which is the shape of the publication and the shape
did not change.
Prose follows the code: the `--current` and default-re-pin help, the LLM.md
command block and the gates table all said "cloud's origin/main" and now say what
runs.
Co-authored-by: Hanzo Dev <[email protected]>
|
||
|
|
c63f667452 |
gate: refute the published document against the deployment, in the lane that runs
The drift gate this repo already had could not run, so nothing did.
`publish.py --check` is the right question — is hanzo.yaml what its own pinned
input projects to — and it needs a hanzoai/cloud CHECKOUT. hanzoai/cloud is
private, hanzoai is on the GitHub Free plan (where an org secret resolves to the
empty string inside a private repo), and this repo's one repo-level secret is
SDK_DISPATCH_TOKEN. On top of that,
|
||
|
|
a96449bcc6 |
publish: the document is generated, so a route nobody serves cannot be described
hanzo.yaml stops being where the API is DECIDED and becomes where hanzoai/cloud's emission is PUBLISHED. `publish.py` derives it from `cloud@<ref>:openapi.yaml`; `publish.py --check` regenerates and diffs. An operation no code declares is now structurally impossible to publish, in this repo and in everything downstream. MEASURED at hanzoai/[email protected], both documents loaded and keyed by (METHOD, path): the hand-merged master carried 2093 operations, cloud's emission 2333, shared 1908. So the master described 185 operations nothing serves under that name and MISSED 425 that are served — 8% invented, 18% blind — while being the input to seven SDKs, the doc site, the MCP catalogue and the agent-skills plane, which has no liveness filter at all. THE 185, each probed with its OWN method and a nonsense-sibling CONTROL: 36 ABSENT (real 404, control 404), 44 unfalsifiable behind a prefix auth gate, 66 absorbed by a {wildcardN} relay door, 39 SERVED and undescribed. A 404 on both sides IS a refutation and is the only way absence can ever be shown; the control exists to stop a 401/403/200 being read as existence. The 39 are hanzoai/cloud's to fix and every one is itemised in LLM.md. DELETED: 52 `<svc>/openapi.yaml`, shared/, cloud/, generated/, merge.py, sync.py, audit.py, test_audit.py, test_placement.py — and 14 Swagger 2.0 documents for `api.hanzo.io`, which is a parked domain: `/account`, `/store` and the control `/account-zzq9` all return the same registrar lander, and HTTPS has no certificate for the name. THE PROJECTION IS SIX RULES AND NOTHING ELSE — no operation added, none removed that is served, no prose written. It exists because openapi-generator 7.14.0 refuses cloud's emission with 1012 errors (one per route published with an address and no `responses`) and writes ZERO files in every language; against hanzo.yaml it reports 0 errors and go/python/typescript-axios/kotlin all emit. Every rule is a candidate to move upstream into cloud's emitter, and rule 5 alone is 90% of the file. BLOCKING, and new with this release rather than with the projection: three o11y schemas cannot be projected into Go. `o11y.GettableAgentCheckIn` declares `integration_config` AND `integrationConfig`, `removed_at` AND `removedAt`; `o11y.O11yPodOnboarding` has `hasClusterName` beside `clusterName`; `o11y.PostableProfile` the same. `go build ./...` fails on those three and on NOTHING else — renaming the keys in a scratch copy and regenerating gives exit 0. This repo must not rename a field, because a field name is the wire, so test_publish.py pins them as a ceiling instead. BREAKING: operationIds lose the `<svc>_` prefix merge.py applied — it existed to keep 52 authored specs from colliding and there is exactly ONE collision in 2284 operations now. Two flows.yaml journeys moved with the hand-authored ids that vanished: `hello` is get_v1_keys (403 with no key AND with a bogus one, control 404), `tools` is get_v1_tools. capabilities.yaml keeps one job — which DOMAIN a capability is shown under — and is gated both ways: a served capability it does not group fails the publish, and a name it groups that the document does not carry fails too. generate.py's fallback to this checkout's hanzo.yaml returns, superseding 3953d66's removal of it. That removal was right about authority and wrong about consequence: pointed at cloud's raw emission the four clients generate nothing. The file it refused to fall back to no longer exists — this one is derived. publish.py --check hanzo.yaml is the projection of [email protected] pytest (16 tests) passed openapi-generator validate 0 errors (was 1012 against the raw emission) go build ./... on the client exit 0, with the three o11y schemas patched Co-authored-by: Hanzo Dev <[email protected]> |