From 9e896a04017fedc76de28ff5dcee70c020b49a86 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 28 Aug 2026 03:46:37 +0000 Subject: [PATCH] docs(spec): stop the def-key-collision prose committing to a live self-alias count The module doc, the pin test's comment and the user-facing remedy text all cited `export const ThemeMode = ThemeModeSchema` plus "fourteen more across api, system and ui". No such export exists anywhere in packages/spec/src, the population is not fourteen, and no `ui` def key is in it. Describe the shape instead of restating a total, cite a self-alias that really exists (api/ApiEndpoint, with the Object.assign spelling the package actually uses), and point the reader at the per-run report line build-schemas.ts has printed since #12588. Comments and one build-output string only. --- .../spec/scripts/def-key-collisions.test.ts | 7 ++++-- .../spec/scripts/lib/def-key-collisions.ts | 22 ++++++++++++++----- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/packages/spec/scripts/def-key-collisions.test.ts b/packages/spec/scripts/def-key-collisions.test.ts index 4a03cd3894..1d3fe51fb1 100644 --- a/packages/spec/scripts/def-key-collisions.test.ts +++ b/packages/spec/scripts/def-key-collisions.test.ts @@ -323,8 +323,11 @@ describe('build-schemas.ts refuses a second write of one def key (#5832)', () => expect(res.status).toBe(1); expect(output).toContain('JSON Schema def key(s) are claimed by two or more different schemas'); expect(output).toContain('json-schema/shared/HttpMethod.json <- HttpMethod, HttpMethodSchema'); - // Exactly one collision: the fourteen `export const X = XSchema` self-aliases - // this package really does carry must stay green, or the guard is unusable. + // Exactly one collision: the self-aliases this package really does carry — + // the `Object.assign(XSchema, { … })` exports under `api/` and `system/` — + // must all stay green, or the guard is unusable. Their number is deliberately + // not pinned here: it moves, and a count asserted in a comment only drifts + // (#12608). The generator reports the live population every run (#12588). expect(output).toContain('1 JSON Schema def key(s) are claimed'); // It stops BEFORE the ratchets, which would otherwise adjudicate a build // whose output already depends on export iteration order. The name here diff --git a/packages/spec/scripts/lib/def-key-collisions.ts b/packages/spec/scripts/lib/def-key-collisions.ts index ffba560bf3..72f381f6c6 100644 --- a/packages/spec/scripts/lib/def-key-collisions.ts +++ b/packages/spec/scripts/lib/def-key-collisions.ts @@ -35,9 +35,19 @@ * > same schema instance. * * Identity, not today's byte-equality. The permitted shape is the package's - * self-alias convention — `export const ThemeMode = ThemeModeSchema`, and - * fourteen more across `api`, `system` and `ui` — where the second write is the - * same object and therefore cannot change what is published. Anything else is + * self-alias convention: a second export name bound to the very same schema + * object, as `src/api/endpoint.zod.ts` does with + * `export const ApiEndpoint = Object.assign(ApiEndpointSchema, { create })` — + * `Object.assign` returns its target, so `ApiEndpoint` and `ApiEndpointSchema` + * are one object and the second write cannot change what is published. A plain + * re-export (`export const Foo = FooSchema`) is the same shape by the same test. + * + * How many of these the package carries, and which def keys they land on, is + * deliberately NOT restated here: the population moves, and nothing checks a + * comment. `build-schemas.ts` prints it on every run instead (#12588 — the + * `N emit(s) collapsed into M existing def key(s) — all self-aliases` line, + * built from `findSelfAliasedDefKeys` below, which lists each def key and the + * export keys that reach it). Read that run, not this paragraph. Anything else is * two independent declarations under one published name: even if their JSON * happens to match today, the next edit to either one makes the artifact * depend on export order again, silently. So the guard refuses at the point @@ -183,7 +193,9 @@ export function formatDefKeyCollisions(collisions: readonly DefKeyCollision[]): ` one name meaning one thing. Record the rename in scripts/lib/renamed-defs.ts when the OLD\n` + ` def key stops being emitted;\n` + ` - a duplicate DECLARATION of one schema: delete it and re-export the survivor, so both\n` + - ` names resolve to a single object (\`export const ThemeMode = ThemeModeSchema\` — that\n` + - ` shape is allowed here precisely because it cannot change what is published).\n` + ` names resolve to a single object — \`export const Foo = FooSchema\`, or the\n` + + ` \`Object.assign(FooSchema, { … })\` form src/api/endpoint.zod.ts uses for \`ApiEndpoint\`.\n` + + ` Either shape is allowed here precisely because it cannot change what is published;\n` + + ` a build's own summary lists the self-aliases it already carries.\n` ); }