What a model change does to a character

Nothing in your code changed. The definition is byte-identical, the assembly logic is untouched, and the character reads differently — a little more verbose, a little more agreeable, declining things it used to handle and handling things it used to decline. Somewhere underneath, the model changed.

A character definition is not a specification. It is text that one particular model interprets in one particular way, and a large part of what users recognise as the character was never in your text at all.

The definition is an input, not a contract

What reaches the user is the product of your state and the model’s own defaults. Register, verbosity, how strongly an instruction binds, what counts as a boundary, how eagerly the model agrees: all of these have defaults, and your definition only ever nudges them.

That is why the same definition on a different model does not produce the same character. The parts you wrote explicitly transfer reasonably well. The parts you never wrote — the ones the previous model was supplying without being asked — do not transfer at all, and they are the parts that made the character feel specific.

A model change is therefore a change to the whole persona, of which your definition is the small documented portion. No amount of care in the text prevents this, because the text is not where the missing behaviour lived.

Three secondary shifts matter as much as the register, and all three are easy to miss.

Instruction adherence changes, unevenly across your instruction set. Constraints that were binding may weaken and others may strengthen, so the depths at which each constraint holds all move at once and in different directions.

Refusal behaviour changes. Boundaries sit in different places, so intervention rates shift and the seam appears in new conversations where it previously did not.

Summarisation behaviour changes. If the same model writes your summaries, then what your continuity mechanism preserves and discards has changed — a memory change disguised as a model change, and the one most likely to be misdiagnosed.

Old conversations mask it; new conversations show it

This is the exact inverse of what happens when you edit the definition, and the symmetry is worth holding onto.

A definition edit lands immediately in new conversations and slowly in old ones, because history is counter-evidence to the new text.

A model change lands immediately in new conversations and is masked in old ones, because history is evidence of the old character. The new model reads hundreds of turns demonstrating a register and follows them partway. So your longest-standing users see the smallest immediate change and your newest see the largest, which is the opposite of the cohort pattern you get from a definition edit and the reason model-change reports are so often dismissed as unreproducible: whoever checks it is usually checking their own long-running test conversation.

The masking is partial and it decays. As the old history ages out of the window or gets compressed into a summary — and if the new model is doing the summarising, compressed by different criteria — the old character’s evidence thins, and the new model’s defaults show through more. Weeks after a change, conversations that initially looked unaffected can start to shift.

Derived state was built by the previous model

The summaries and extracted facts in your store are artifacts of the old model’s behaviour. They encode what it thought was worth keeping, in its phrasing, with its notion of salience.

That has two consequences. The old artifacts keep exerting the old model’s judgement over what the character remembers, indefinitely, which is a form of continuity you get for free and did not choose. And the first rebuild under the new model is a discontinuity in memory as well as voice — a summary rewritten by a different model can drop things the old one had reliably kept, and it will look like a memory bug arriving weeks after an unrelated change.

If you have a rebuild-from-originals strategy, this is where it earns its cost: the originals are model-agnostic and can be re-summarised. If your summaries are built from previous summaries, the old model’s decisions are baked in and unrecoverable, which is the generational problem with an extra generation of provenance.

The turn

THE TURN — a model change

  · Take upstream changes as they come
                    → no version management, no migration work,
                      current behaviour by default.

  · Undocumented character comes with it
                    → VARIES BY MODEL, and the parts you never
                      wrote are the parts that made the
                      character specific.

  · Adherence and boundaries move
                    → every constraint's binding depth changes
                      at once, in different directions.
                      MODERATION SITS OUTSIDE, and it moves too.

  · Long conversations mask the change
                    → history is evidence of the old character.
                      Your test conversation is the worst place
                      to look.

  · Re-validation per change
                    → PAID EVERY TURN of a full depth-graded
                      suite, on every model change, forever. It
                      is the recurring cost of not pinning.

  · Derived state stays old
                    → summaries and facts were written by the
                      previous model, and the first rebuild is
                      a memory discontinuity.

Detection

Stamp the model identity and version on every turn you serve, permanently, alongside the definition version. It is one field and it is the difference between a diagnosable report and an argument. Nothing else in this post is possible without it.

Run the offline suite against a candidate before switching, at every depth, and diff per instruction rather than in aggregate. The aggregate will usually look fine, because gains and losses across instructions cancel. What you want is the list of instructions whose binding depth moved, and that list is what a migration is actually about — the same per-instruction reporting rule as any other change, applied to a change you did not make.

After a switch, separate cohorts by conversation age at the moment of the change and watch them independently. Expect the new-conversation cohort to move first and the long-conversation cohort to move later, and read a delayed shift in old conversations as masking decaying rather than as a new incident.

Watch intervention rates and summary content specifically, not just register. Both change silently and both produce complaints that name something else.

What this costs and what it doesn’t fix

Pinning a model version, where that is available, buys stability and pays for it in eventual forced migration — usually on someone else’s schedule, with more accumulated divergence to absorb. Not pinning pays a re-validation cost on every upstream change: the full depth-graded suite, per instruction, indefinitely. Maintaining a definition variant per model is the most thorough option and forks the artifact you were trying to keep singular, which then has to be maintained and tested in parallel.

What none of it fixes is that a character is not portable. The definition transfers; the behaviour it produced does not, because part of that behaviour was never yours. The realistic position is to write down as much of the character as you can — so that less of it depends on defaults — accept that the remainder will move when the model does, and know from your own measurements which of your constraints are the ones that will move with it.