Every fact in a system should be written down once.
Everything else that needs it should be generated from that one place, and checked.
When the same fact lives in four places, every change has to find all four. An agent working from its context window finds the ones it can see.
The result is the whack-a-mole from the zero-eyes chapter, but for facts: types that disagree with the API, docs that disagree with the code, examples that no longer compile.
Derivation removes the copies. There's one place to change, and the rest follows.
Illustrative change.
The Camunda Orchestration Cluster SDKs (TypeScript, Python, C#, Go, Java, Rust, PHP) are generated from one OpenAPI spec in the camunda/camunda monorepo.
A shared bundler fetches and normalises the spec. Each SDK's pipeline generates the models, the client, the facade and the semantic key types: JobKey and ProcessInstanceKey are distinct types in every language, because the spec says so.
The hand-written part is the runtime: auth, retry, backpressure, workers. That's where the judgement lives.
Every SDK marks its generated directories as never hand-edit: src/gen/, client/, generated/. When the output is wrong, the fix goes in a numbered post-processing hook, so the pipeline stays reproducible.
A hand edit is the most tempting fix for an agent: it's local, it's quick, and the test passes. And the next regeneration silently wipes it out.
Illustrative file names.
Documentation is the copy that drifts most, because nothing executes it. So we make sure something does.
README code blocks are injected from compiled example files. If the API changes, the example stops compiling, long before a user copies broken code.
Otherwise “generated” is just a comment at the top of the file. Each gate regenerates and compares: sync-readme-snippets --check, make config-reference-check, make example-coverage.
Upstream drift is handled differently. The Go SDK re-bundles the spec nightly. When the spec has moved, the drift job is report-only: it uploads a patch for a follow-up regeneration PR instead of failing, so routine upstream churn doesn't hide a real regression.
Generator changes are small and meaningful. Regenerated output is large and mechanical. Mix them, and nobody (human or agent) can review the change.
Keeping them apart also keeps backports clean (the target branch regenerates its own output) and keeps git blame useful on both sides.
Illustrative commits; the convention is from the SDKs' AGENTS.md.
Write each fact once. Generate types, clients, docs, help and examples from it. Fix the generator, never the output. Let CI prove the derived files match, and keep generator changes reviewable.