Skip to content

docs: propose generating the wire types behind a facade - #12

Closed
bdchatham wants to merge 1 commit into
feat/alignment-04-turn-loopfrom
docs/adr-generate-wire-types
Closed

docs: propose generating the wire types behind a facade#12
bdchatham wants to merge 1 commit into
feat/alignment-04-turn-loopfrom
docs/adr-generate-wire-types

Conversation

@bdchatham

Copy link
Copy Markdown
Collaborator

Stacked on #11. Docs and one inert script — no code changes, no dependency, nothing wired.

What this asks

AGENTS.md says the module runs no code generator, and that re-adding one is a one-way door. That rule was set on good reasoning about a previous generator, which decided the shape of the public surface. This ADR asks whether the reasoning still holds when the generated code lands in internal/, where a generated name cannot reach a consumer.

Status is Proposed. Accepting or rejecting it is a separate decision from merging this PR, which only records the question and the measurements.

Why now

The module tracks spec/openapi.json by hand across types.go, session_types.go, event.go, and enums.go — 2,643 lines.

The snapshot is one event variant behind upstream today (SessionTitleEvent, on main since 9d54826e), and the suite is green. That is the defect, not an oversight: conformance_test.go proves the module declares no field the document lacks, and by design cannot prove the reverse. A new field is invisible.

What was measured

A pre-process stage of six transforms, then oapi-codegen v2.8.0:

Transform Sites Corrects
x-go-type: float64 12 a formatless number becomes float32
x-go-type-skip-optional-pointer 71 *[]T and *map[K]V on optional collections
x-go-name 18 LlmModel, TotalCostUsd, McpStartup
enum to x-go-type: string 21 one wire enum becoming 81 Go types
schema rename 2 McpServerStartup, SessionMcpStartupEvent
x-go-type: json.RawMessage 1 deferred decode on ConversationItem.data

Result against upstream 9d54826e:

  • 10 of 10 types match field for field, type for type, and tag for tagSessionResponse (46 fields), SessionListItem (27), ChildSessionSummary (21), AgentObject (14), UpdateSessionRequest (13), ConversationItem (7), ModelUsage (6), SkillSummary, ConversationDeleted, SessionForkRequest.
  • 53 of 53 event variants generate, including the one we are missing.
  • The facade compiles and vets clean on the generated types.

Because the types are identical and the ten data types carry no methods, aliasing them is non-breaking — the public surface does not move, so this could land later as a patch.

What generation would not reach

stream.go, 579 lines. oapi-codegen ignores the OAS 3.2 itemSchema keyword, and its typed response reads the whole body, which for an SSE stream never ends. This is the piece upstream added itemSchema for, and no Go generator reads it. The ADR's Consequences section lists the rest, including three new dependencies where there are none today.

Related

Upstream omnigent-ai/omnigent#5119 asks for numeric format at the source. Worth knowing that it is not a dependency of this proposal — x-go-type: float64 closes the float32 defect locally. Accepting it upstream would retire three of the six transforms.

Verification

gofmt -l .     clean
go vet ./...   clean
go test ./...  ok
vale           0 errors, 0 warnings on the ADR

Two pre-existing vale warnings remain in AGENTS.md at lines 8 and 32, outside this diff. ruff and black are not installed here, so spec/preprocess.py is unlinted — its output was verified byte-identical to the measured run instead.

Review focus

The ADR's Consequences → Negative and Alternatives considered are the sections worth your attention. The positives are measured and dull; the costs and the rejected paths are where I would want to be wrong.

The module tracks spec/openapi.json by hand across four files and 2643 lines.
The snapshot is one event variant behind upstream today, and the suite is green,
which is the defect: the conformance test proves the module declares no field the
document lacks, and cannot prove the reverse.

ADR 0001 proposes generating those types into internal/, where a path-mangled
operation name cannot reach a consumer, and keeping the facade hand-written.
spec/preprocess.py is the evidence: six transforms that make the generated types
match the hand-written ones field for field, type for type and tag for tag, over
ten types and 53 event variants, measured with oapi-codegen v2.8.0 against
upstream 9d54826e.

Status is Proposed. Nothing runs the script, no dependency is added, and no
generated code lands here. The AGENTS.md rule against a generator stays as it is,
with a pointer so the rule and the proposal do not silently disagree.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@bdchatham

Copy link
Copy Markdown
Collaborator Author

Superseded by #13, which targets main directly rather than stacking on #11, and drops spec/preprocess.py.

The script was dead code in the tree — nothing ran it, and its only job was to keep the spike reproducible. The ADR now says plainly that a throwaway spike produced the numbers and no code here carries it, so a reader is not left hunting.

The generation work itself is what should stack on #11.

@bdchatham bdchatham closed this Aug 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant