# ADR-0009: Engine entity types are codegenned via `pydantic-to-typescript`

**Status:** Accepted (Phase 2; codegen pipeline lands Phase 16)

## Context

ADR-0005 sets the contract-authority split: engine entities are SSOT in
Pydantic. The TypeScript clients still need accurate types — hand-typed
mirrors are Anti-Pattern 4 ("no shadow types"). The Python ecosystem has
several Pydantic-to-TS tools; the team-evaluated options are
`pydantic-to-typescript` (full TS interfaces, mature), `datamodel-code-
generator` (TS via openapi-typescript-codegen — lossy enums), and
hand-rolled emitters.

## Decision

Use `pydantic-to-typescript` to codegen engine entity types into
`packages/contracts/src/generated.ts`. Phase 16 wires the pipeline: a
pre-build script reads the engine's Pydantic models from `recoil/pipeline/
core/*.py` and emits a single TS file. Pre-Phase-16 the file is
`export {};` (empty) and consumers use fixture-local types. The codegen
output is checked into git (CI verifies it matches a freshly run codegen).

## Consequences

Engine refactors propagate to the console without manual TS work. The cost:
the codegen step adds ~5s to a clean build; CI must run it to detect drift.
A future Pydantic v2 breaking change requires re-evaluating the tool.
Contracts that mix engine + UI ownership are explicitly disallowed (one
shape, one owner).
