Skip to content

fix(mutator-framework): keep derivedModels in sync on mutated models - #106

Draft
steverice wants to merge 1 commit into
mainfrom
srice/mutator-derived-models
Draft

steverice wants to merge 1 commit into
mainfrom
srice/mutator-derived-models

Conversation

@steverice

Copy link
Copy Markdown

Summary

$.type.clone copies a model's derivedModels as a shallow array, so a mutated base model kept pointing at the source derived models. Nothing in the framework ever rewired that back-reference: ModelMutationNode has half-edges for baseModel, properties and indexer, but the derived side of the inheritance link was left alone.

Two changes:

  • @typespec/mutator-framework — the base-model edge already keeps baseModel in sync from the derived side. It now also swaps the source derived model for the mutated one in the mutated base's derivedModels (appending when it wasn't listed), and removes it again when the derived node is deleted. Works regardless of mutation order (base first or derived first). The source graph is never touched.
  • @typespec/graphql — flattenBaseModel severs baseModel on the derived model but left the base's back-reference in place, so a flattened graph still advertised inheritance. It now drops the flattened model from the mutated base's derivedModels. Only a mutated base is touched; an un-mutated base is the source type.

Why

Found while reviewing pinboard's staged mutation pipeline. After several cloning stages, V5_Animal.derivedModels pointed at a flattened, un-prefixed Dog instance that was not registered anywhere, and downstream code (canonicalizeNestedReferences) grew a by-name repoint pass to paper over it. With this change the pipeline's probe shows derivedModels correct after every stage with no repair pass.

Not covered here

  • templateMapper.args has the same shallow-copy problem and is also never rewired. Separate change.
  • onTailReplaced (base replaced by another model) does not touch derivedModels on the replacement, because the replacement type may be a raw source type.

Tests

  • mutator-framework: 3 new tests in mutation-node/model.test.ts (sync on base mutation, sync when the base mutated before the derived connected, removal on derived deletion). Suite 59/59.
  • graphql: 1 new test in test/mutation-engine/models.test.ts asserting the flattened base has no derived back-reference and the source is untouched. Package suite 369/369.

PinClaw logo Generated with PinClaw

`$.type.clone` copies `derivedModels` as a shallow array, so a mutated base model kept pointing at the *source* derived models. `ModelMutationNode`'s base-model edge already keeps `baseModel` in sync from the derived side; it now also swaps the source derived model for the mutated one in the mutated base's `derivedModels` (appending when absent) and removes it again when the derived node is deleted. The source graph is never touched.

`@typespec/graphql`'s `flattenBaseModel` severs `baseModel` on the derived model but left the base's back-reference in place, so a flattened graph still advertised inheritance; it now drops the flattened model from the (mutated) base's `derivedModels` too.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants