Skip to content

build(core): stabilize generated schema alias names against dep churn - #626

Merged
lmorchard merged 3 commits into
mainfrom
fix/stable-schema-alias-names
Jul 27, 2026
Merged

build(core): stabilize generated schema alias names against dep churn#626
lmorchard merged 3 commits into
mainfrom
fix/stable-schema-alias-names

Conversation

@lmorchard

Copy link
Copy Markdown
Collaborator

Problem

ts-json-schema-generator names anonymous/aliased definitions from their source position, e.g.:

alias-1270300533-2282-2347-1270300533-0-234984

Those numbers encode where the AI SDK's JSONValue type happens to sit in its source files. Any upstream dependency bump that reshuffles types changes the names — even when the resulting schema is identical in shape. That trips the schemas/ drift gate in check:schemas.

Dependabot can't run codegen, so every ai-sdk group bump fails CI on nothing but renamed internal aliases and needs a manual regenerate. Most recently #616, and #597 before it.

Fix

Extend normalize-schema.cjs to rename each volatile alias to a stable alias-<contenthash> derived from the definition's structure, then rewrite every $ref to match. Alias references are neutralized to a sentinel before hashing so mutual recursion (JSONValue ↔ its object form) doesn't leak the volatile names back into the hash.

The committed artifact now changes only when the schema's actual shape changes.

Also refactors the script to export a pure normalizeSchema() so it can be unit-tested directly, and adds tests covering both normalization passes.

Verification

The property that matters is that the artifact survives a real dependency bump. Tested directly:

  • Cherry-picked this commit onto build(deps): bump the aisdk group across 1 directory with 7 updates #616's branch, kept the artifact generated under the old ai-sdk versions, reinstalled the new ones, and regenerated → byte-identical, gate passes.
  • On this branch against current main: check:schemas passes.
  • Full pnpm run check green on both: 948 core / 229 cli / 103 server / 273 extension tests, typecheck, format.

Once this lands, #616 can be rebased and should go green without hand-edits.

🤖 Generated with Claude Code

ts-json-schema-generator names anonymous/aliased definitions from their
source position (e.g. alias-1623388915-2282-2347-1623388915-0-228060).
Those names churn whenever an upstream dependency reshuffles its types,
even when the resulting schema is identical in shape — so benign dep
bumps (e.g. the ai-sdk group) trip the schemas/ drift gate and require a
manual regenerate. Dependabot can't run the codegen, so those PRs fail
CI on nothing but renamed internal aliases.

Extend normalize-schema.cjs to rename each volatile alias to a stable
alias-<contenthash> derived from the definition's structure (with alias
refs neutralized so mutual recursion doesn't leak the volatile names
into the hash), then rewrite all $refs. The artifact now only changes
when the schema's actual shape changes.

Refactor the script to export a pure normalizeSchema() and add unit
tests covering the deprecated-string fix and alias stabilization,
including the key property that a pure position-hash change normalizes
to identical output.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the core schema normalization pipeline to prevent spurious schemas/ drift caused by ts-json-schema-generator’s position-derived alias naming, making generated artifacts stable across benign dependency bumps.

Changes:

  • Extends normalize-schema.cjs to rewrite volatile alias-<position> definition names into stable alias-<contenthash> names and updates all $refs accordingly.
  • Refactors the normalization script to export a pure normalizeSchema() function for direct unit testing, while keeping the CLI entrypoint.
  • Adds Vitest coverage for both deprecated-string normalization and alias stabilization, and updates the committed webagent-event.json artifact to use stable aliases.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
packages/core/scripts/normalize-schema.cjs Adds content-hash-based alias stabilization + exports normalizeSchema() while retaining CLI behavior.
packages/core/test/normalize-schema.test.ts Introduces unit tests validating deprecated normalization and stable alias renaming behavior.
packages/core/schemas/webagent-event.json Updates generated schema artifact to use stabilized alias names and rewritten $refs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +96 to +98
const rename = {};
const used = new Set();
for (const oldName of volatileNames) {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — this was reachable, so I took it.

Confirmed before changing anything: I planted a definition under the exact key the alias shape hashes to, and the re-key loop overwrote it, dropping the definition and leaving its $refs pointing at the alias shape. Test fails before the change, passes after.

Fixed in 8247cc9 by seeding used with the non-volatile definition names, so the existing disambiguation loop routes around them the same way it already routes around generated-vs-generated collisions — consistent with the defensive posture the suffix loop had already established.

The committed artifact is unchanged, confirming no such collision exists in the real schema today.

lmorchard and others added 2 commits July 27, 2026 12:27
stabilizeAliasNames() seeded its collision set with only the names it
generated, so a stable alias-<contenthash> could match a definition key
already present in the schema. The re-key loop then overwrote that
definition, silently dropping it and leaving its $refs pointing at the
alias shape instead.

Seed the set with the non-volatile definition names up front, so the
existing disambiguation loop routes around them the same way it already
routes around generated-vs-generated collisions.

Reachability confirmed by a test that plants a definition under the key
the shape hashes to; it fails before the change and passes after. The
committed artifact is unchanged — no such collision exists today.

Reported by Copilot review on #626.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@lmorchard
lmorchard merged commit 0f6cc15 into main Jul 27, 2026
13 checks passed
@lmorchard
lmorchard deleted the fix/stable-schema-alias-names branch July 27, 2026 19:48
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