Files
gen/schemas/CONFORMANCE.md

2.5 KiB

Conforming a Hanzo .zap sketch to canonical grammar

71 of 73 Hanzo .zap files are written in a sketch dialect that no compiler accepts (no package, no field offsets, capnp-cased types, List(T), -> methods). zapgen is the one compiler; this is the mechanical rewrite that makes a sketch compile. It is deterministic — one way.

The six rewrites

# Sketch Canonical Note
1 (no header) package <service> on line 1 required; lowercase service name
2 workflowId Text workflowId text @0 lowercase type; add explicit byte offset
3 metadata Bytes metadata bytes @N Bytes→bytes, Text→text, etc.
4 items List(Payload) items list<Payload> @N List(T)→list<T>
5 m (req X) -> (resp Y) m(req: X) returns (resp: Y) :-typed params; returns keyword
6 enum E { a b c } model as u8 @N + doc the values v1 grammar has no enum; append later

Assigning offsets (rewrite #2)

Offsets are author-controlled, append-only, non-overlapping. Fixed section slot sizes: bool/u8/i8=1, u16/i16=2, u32/i32/f32=4, u64/i64/f64=8, text/bytes/list=8 (relOff+len), nested struct=4 (relOff), bytes_fixed[N]=N. Lay fields out in declaration order at natural alignment; never renumber an existing field when appending (that is the wire-stability guarantee). zapgen validates non-overlap and fails loudly on a mistake.

Worked example — tasks.zap

Sketch (hanzoai/tasks/schema/tasks.zap):

struct Payload
  metadata Bytes
  data Bytes

interface Tasks
  startWorkflow (req StartWorkflowRequest) -> (resp StartWorkflowResponse)
  health () -> (service Text, status Text)

Conformed (this repo's schemas/tasks.zap — compiles with zapgen):

package tasks

struct Payload {
  metadata bytes @0
  data     bytes @8
}

struct HealthResponse {
  service text @0
  status  text @8
}

interface Tasks {
  startWorkflow(req: StartWorkflowRequest) returns (resp: StartWorkflowResponse)
  health() returns (resp: HealthResponse)
}

Note rewrite #5 also folds a multi-value return (-> (service Text, status Text)) into a single response struct (HealthResponse) — a ZAP method carries exactly one struct payload per direction.

After conforming

The conformed .zap becomes the committed source of truth in the service repo (<service>/schema/<service>.zap), and bin/zapsdk <lang> <service>.zap regenerates every client. Verify parity: zapgen --emit=openapi output must match what the service's zip app serves at /.well-known/openapi.json.