Protocol types are generated from the C++ codegen model
Table of Contents
1. Status
Accepted, and implemented. The ores.ts.protocol and ores.ts.domain facets
exist, and their output is committed under
packages/wire-protocol/src/generated/.
2. Context
The TypeScript client must encode msgpack bodies whose keys are the exact C++ member names the codec writes. A single renamed field desynchronises the client silently: the server cannot decode the request, and because the C++ IAM handlers do not reply when decoding fails, the client sees a thirty second timeout rather than an error.
Hand-writing those names in TypeScript makes every protocol change a two-place edit with no compiler help across the language boundary.
3. Decision
Extend the existing code generator, which already renders the C++ structs from the org entity model, to also render the TypeScript protocol types and their validation schemas from that same model.
The org files are the single source of truth. Each entity under
projects/<component>/**/modeling/*.org already declares :type:,
:cpp_type:, :nullable:, and :primary_key: per column, and codegen renders
book_protocol.hpp from it. A TypeScript target renders beside it from the same
input, so the two cannot disagree.
The generated artefact lives under packages/wire-protocol/src/generated/.
It is committed, and the drift gate covers it.
4. Consequences
The generator covers the codegen-managed entities and the operation models.
The TypeScript projection writes one protocol module per entity, junction, or
operation model, and one domain module per entity or junction, under
packages/wire-protocol/src/generated/{component}/.
The authentication surface is modelled, and it is not hand-written.
Not every protocol header is modelled. 16 of the 251 *_protocol.hpp files
carry no AUTO-GENERATED banner. Six are in marketdata: crm_protocol.hpp,
curve_republish_protocol.hpp, curve_snapshot_protocol.hpp,
import_protocol.hpp, market_feed_config_protocol.hpp, and
market_series_export_protocol.hpp.
5. The authentication protocols
login_protocol.hpp and account_protocol.hpp are generated files: each
carries the AUTO-GENERATED banner. Their operation models are
projects/ores.iam/modeling/ores.iam.login_messages.org and
projects/ores.iam/modeling/ores.iam.account_messages.org. Their TypeScript
twins are under packages/wire-protocol/src/generated/iam/protocol/.
The account aggregate is modelled by the entity model
projects/ores.iam/modeling/ores.iam.account.org, and the generator renders
account.ts under packages/wire-protocol/src/generated/iam/domain/. The
knowledge page projects/ores.iam/core/modeling/iam_account.org is not the
model.
6. Considered alternatives
Add a codegen model type for operations. The tree took this alternative. An
ores.codegen.operation model expresses subject-scoped request and response
pairs with arbitrary field lists. 29 models use it, under
projects/<component>/modeling/, across 12 components. The ores.ts.protocol
facet admits the operation model type, so each model renders a TypeScript
module as well as a C++ header. The entity model cannot express these shapes:
it always emits offset and limit fields, so it cannot render an empty
refresh_request, and its reply shapes are fixed.
Emit JSON Schema from C++ reflection. A reflection library's schema output already works in this tree, and every message type is reflectable because the handlers decode them. A small binary that walks an explicit list of message types and prints JSON Schema would be the absolute single source of truth and would cover the hand-written protocols without refactoring them. It costs more C++ work and a build step.
Hand-write the TypeScript schemas. Rejected. It is not the current state:
ores.codegen renders the schemas from the same models, and hand-writing is
the largest ongoing drift risk.
7. Current implementation
ores.codegen renders the TypeScript with the ores.ts.protocol and
ores.ts.domain facets. The templates are
projects/ores.codegen/library/templates/ores.ts.protocol.org and
ores.ts.domain.org, and the output is committed under
packages/wire-protocol/src/generated/.
scripts/emit_protocol_ir.py is a separate tool, run by the workspace script
ir:protocol. It emits a language-neutral protocol IR for the entity CRUD
messages, and it supports --all and --check.