Presentation
Evolution Completeness Conjecture
Any schema reaches any other by a chain of small, checked steps — or the chain halts and names what cannot survive
First given July 29, 2026 · PuPPy, F5 Tower, Seattle

05Evolution Completeness Conjecture
This is a conjecture, not a theorem — maybe we'll get there one day, but for now let's just say I've got a good feeling about it. And what I mean by evolution is the small stuff. Evolution works in tiny steps: one step succeeds, and that leads to the next step.

06Definitions
The program works on codebases that have a schema. Any codebase with a defined schema I can scan — and inside it there are interfaces that reference that schema.

07Every reference is an edge
Turn it into a graph. Tables are nodes, foreign keys connect them. Every place in your code is a node too. And when code reaches in and names a field in a schema, that's an edge. A report that reads field_name. A serializer. A CLI flag. A test fixture.

08Dependency graph G(S) — is it computable?
Can you compute the dependency graph G(S) of a codebase with a schema? Yes, using a library called LibCST. And if we have seen a pattern before, we can identify it and work with it.

09LibCST: every node, typed by parsing
LibCST is a concrete syntax tree, and the difference between that and grepping for user_id is the difference between finding a string and finding a reference. Grep hands you the comments, the log lines, and the unrelated local variable that happens to share a name. The tree knows what the code means: this is a column definition, this is an attribute access, this one is just a string that looks like your field.

10The wire scanner: where the schema leaves C
We can also scan the wire — where other systems depend on your schema. So if there is a billing service and a mobile app out there with your field names baked in, we can find those locations and mitigate problems before they occur.

11The catalogue of deviations D
In evolutionary theory they call it a mutation, but in programming we use mutation for something else, so here let's say it's a deviation. We have a catalogue of eleven deviations for database changes, and each one does exactly one thing.

12Fixation F
Apply one deviation to a schema and you get a fixation — one established step, the change that actually took hold. And when you fix one, you scan: what depends on it? Rename a field, split a table — what else is affected? The graph answers that exactly, not approximately.

13Fixations compose
And they compose. Rename, add, remove — chain them and you walk from one schema to another. That chain is what I mean by an evolution. Which gives you the conjecture: any schema reaches any other by a chain of fixations — or the chain halts and tells you exactly what could not survive. The halting is a feature. Some changes genuinely destroy information, and I would rather name the loss than paper over it.

14The Fixation Lemma
For each deviation there is a fixation with three properties. Code integrity: it still compiles, and the tests it already had still pass. Data preservation: what was stored under the old schema is recoverable under the new one. Interface compatibility: every interface touching a changed element got updated. F is total over the dependency graph — nothing joined to that node is missed.

15Fixation certificate P(F)
Every fixation ships a certificate: a generated test, written alongside the change, asserting those three properties. Imagine every Alembic migration you have ever written arriving with its own test. And be precise about what it certifies — that the data survived and the interfaces still execute. Not that your business logic still means what it meant.

18What the conjecture does not cover
The graph tells you where a field is referenced. It cannot tell you whether the meaning survived. Change an int to a string — and LibCST will find every reference and rewrite it, nothing will crash, every test will pass. And ints sort numerically while strings sort lexicographically, so now "10" < "9", and your report is just wrong. That's what happens for any logic that assumed something about a field beyond the fact that it exists — sorting, arithmetic, comparisons, range filters. Finding those is a different job and I have not done it.

19Brownfield horse, greenfield chariot
Which is exactly why the answer is not to evolve everything. Every interface was built for a particular schema, so don't change the schema underneath it. Take the system you don't own and can't regenerate — that's your horse. Don't try to evolve a horse. Instead, build a chariot: evolve your own schema, your own generated interfaces, joined to your horse by one named column. No foreign key across the boundary, no shared migration, no coupling they have to agree to.
The previous version, on video
SEAPUG and PuPPy, April 2 2026 — the same argument in its earlier form, start to finish.
Field notes
Monthly notes on AI-assisted development — what I'm shipping, what I'm learning, and which tools actually earn their place. It's also where the next talk and the next office hours get announced.