fix: make the document projectable into Java

The java row could not produce a client that compiles. Four separate causes,
all found by building the tree rather than reading it:

- library `native` is unusable at this spec size. Its oneof_model.mustache
  iterates the raw `oneOf` type-name set and emits `{{{.}}}.class`, which stops
  being legal Java the moment a variant is an array — `List<CloudEvent>.class`.
  Three schemas have an inline array in a oneOf, and that is 532 javac errors.
  Every other Java library iterates `composedSchemas.oneOf` and guards on
  `isArray`; okhttp-gson, jersey3 and apache-httpclient all compile. Still
  broken in 7.24.0, so it is not waiting on a version bump. okhttp-gson also
  puts the two JVM rows on one HTTP+JSON stack — kotlin is already okhttp4+gson.

- `skipFormModel` defaults to true, so the generator skips a multipart form
  model but still imports it from the API class that used it. edge_deployFunction
  offers octet-stream AND multipart, so FunctionsApi imported a class nobody
  emitted. generate.py now merges a per-row `global:` map into
  --global-property; only the java row sets it, because changing it for
  everyone would churn every other client's committed output.

- affiliates' `isAffiliate: {type: boolean, const: true|false}` projects as a
  single-member enum whose member is a String assigned to a Boolean field. The
  invariant moves into the description; the wire value is unchanged.

- vector's PointId is `oneOf: [integer, string+format:uuid]`, and inside a
  oneOf that format maps to java.util.UUID, on which the generator then calls
  UUID.validateJsonElement() — a method only its own models have. `format` is
  an annotation, not a constraint, so dropping it changes no wire value and the
  description still says what the field is.

The two spec edits are at the per-service source and re-woven, so merge.py does
not undo them: 2 insertions, 3 deletions in hanzo.yaml and nothing else.

Co-authored-by: Hanzo Dev <[email protected]>
This commit is contained in:
2026-07-31 09:25:59 -07:00
co-authored by Hanzo Dev
parent 42d7189d8c
commit f9ec999745
5 changed files with 44 additions and 9 deletions
+8 -2
View File
@@ -354,7 +354,11 @@ components:
properties:
isAffiliate:
type: boolean
const: false
# Always false — this is the not-enrolled shape. Stated in prose
# rather than as `const: false` because openapi-generator projects a
# boolean const as a single-member enum whose member is a String
# assigned to a Boolean field, which is not valid Java (or Kotlin).
description: Always false — this is the not-enrolled shape.
defaultRateBps:
type: integer
format: int64
@@ -366,7 +370,9 @@ components:
properties:
isAffiliate:
type: boolean
const: true
# Always true here — see the note on NotEnrolled.isAffiliate for why
# this is prose and not `const: true`.
description: Always true — this org is an affiliate.
id:
type: string
status:
+8 -2
View File
@@ -88,13 +88,19 @@ def prune(stage, drops):
def emit(name, cfg, spec, version, out):
"""Run the generator for one language into a staging dir."""
props = ",".join(f"{k}={v}" for k, v in cfg.get("properties", {}).items())
# Docs and stub tests are ~4000 files of nothing at this spec size. A row
# may add its own global properties; they are per-language for the same
# reason `properties` is — changing one here would churn every other
# client's committed output.
glob = ["apis", "models", "supportingFiles",
"apiDocs=false", "modelDocs=false", "apiTests=false", "modelTests=false"]
glob += [f"{k}={v}" for k, v in cfg.get("global", {}).items()]
cmd = [
"java", "-Xmx2g", "-jar", jar(version), "generate",
"-g", cfg["generator"],
"-i", spec,
"-o", out,
# Docs and stub tests are ~4000 files of nothing at this spec size.
"--global-property", "apis,models,supportingFiles,apiDocs=false,modelDocs=false,apiTests=false,modelTests=false",
"--global-property", ",".join(glob),
]
if props:
cmd += ["--additional-properties", props]
+2 -3
View File
@@ -58346,7 +58346,7 @@ components:
properties:
isAffiliate:
type: boolean
const: true
description: "Always true \u2014 this org is an affiliate."
id:
type: string
status:
@@ -58460,7 +58460,7 @@ components:
properties:
isAffiliate:
type: boolean
const: false
description: "Always false \u2014 this is the not-enrolled shape."
defaultRateBps:
type: integer
format: int64
@@ -90874,7 +90874,6 @@ components:
oneOf:
- type: integer
- type: string
format: uuid
vector_PointStruct:
type: object
required:
+21 -1
View File
@@ -107,8 +107,28 @@ sdks:
repo: java-sdk
generator: java
take: { src/main/java/ai/hanzo/cloud: hanzo-java-cloud/src/main/java/ai/hanzo/cloud }
# edge_deployFunction offers both application/octet-stream and
# multipart/form-data. The generator skips a multipart form model by default
# yet still imports it from the API class that used it, so FunctionsApi
# imports a class nobody emitted. Emitting it is the fix; it is set here and
# not in generate.py because it would churn every other client's output.
global:
skipFormModel: "false"
properties:
library: native # java.net.http — no third-party HTTP dependency
# `native` (java.net.http, no third-party HTTP dependency) is the library
# this row wants and cannot have: its oneof_model.mustache iterates the
# raw `oneOf` type-name set and emits `{{{.}}}.class`, which is illegal
# Java the moment a variant is an array — `List<CloudEvent>.class`. Three
# schemas in hanzo.yaml have an inline array in a oneOf
# (cloud_post_v1_event's body, gateway_createCompletion's `prompt`,
# search_deleteDocumentsByFilter's `filter`), so `native` produces 532
# javac errors. Every other Java library iterates `composedSchemas.oneOf`
# and guards on `isArray`, so okhttp-gson, jersey3 and apache-httpclient
# all compile; the bug is still present in 7.24.0, so this is not waiting
# on a version bump. okhttp-gson is the generator's default and puts the
# two JVM rows on ONE HTTP+JSON stack — the kotlin row below is already
# okhttp4 + gson.
library: okhttp-gson
groupId: ai.hanzo
artifactId: hanzo-java-cloud
invokerPackage: ai.hanzo.cloud
+5 -1
View File
@@ -105,8 +105,12 @@ components:
description: A point identifier — an integer or a UUID string.
oneOf:
- type: integer
# `format: uuid` is deliberately absent: inside a oneOf, openapi-generator
# maps it to java.util.UUID and then emits UUID.validateJsonElement(),
# a method only its own generated models have. The format is an
# annotation, not a constraint — the wire value is unchanged and the
# description above still says what it is.
- type: string
format: uuid
DenseVector:
description: One unnamed vector.
type: array