diff --git a/.changeset/9103-census-pairing-optional-default.md b/.changeset/9103-census-pairing-optional-default.md new file mode 100644 index 0000000000..ff1fe1bf13 --- /dev/null +++ b/.changeset/9103-census-pairing-optional-default.md @@ -0,0 +1,6 @@ +--- +--- + +Correct the objectui#9034 census pairing, which was blind at every +`.optional().default()` node, and stop publishing its figures as hard-coded +prose (objectui#9103). Test only; no package is released by this change. diff --git a/packages/types/src/__tests__/imported-defaults-describe-9034.test.ts b/packages/types/src/__tests__/imported-defaults-describe-9034.test.ts index e708981d9e..faf72c25fc 100644 --- a/packages/types/src/__tests__/imported-defaults-describe-9034.test.ts +++ b/packages/types/src/__tests__/imported-defaults-describe-9034.test.ts @@ -5,10 +5,26 @@ * * `../zod/imported-defaults.ts` promises "the same keys, the same checks, the * same descriptions and the same accept set". The description half was the one - * that was NOT true: measured across `@objectstack/spec` 17.4.0, 2024 of the - * 2024 described `ZodDefault` nodes reachable from the published surface came - * back with no description at all, and 1364 described CONTAINER nodes lost - * theirs as well. Zero survived either way. + * that was NOT true: across `@objectstack/spec` 17.4.0, every described + * `ZodDefault` node reachable from the published surface came back with no + * description at all, and every described CONTAINER node lost theirs as well. + * Zero survived either way. + * + * ⚠️ The two integers this paragraph used to quote for those populations — + * "2024 of the 2024" and "1364" — are DELETED rather than corrected + * (objectui#9103). They were not values: they were LOWER BOUNDS, produced by a + * pairing that stopped dead at every `.optional().default()` node, and a + * hand-copied integer cannot say how much it failed to look at. The live + * figures are printed by the census below, derived at run time from the spec + * version actually installed: + * + * pnpm --filter @object-ui/types exec vitest run \ + * src/__tests__/imported-defaults-describe-9034.test.ts + * + * ⛔ Nothing in this file ASSERTS an integer copied out of that print. Every + * assertion is a floor, a total-equals-kept identity, or an emptiness, so an + * upstream spec release moves the populations without looking like a + * regression here. * * ## Why it was two losses with one cause, and why the cause is not obvious * @@ -48,6 +64,15 @@ * `@objectstack/spec` for every other consumer in the workspace, and every * other assertion here would still be green. * + * 5. **⭐ The instrument, before anything it measures (objectui#9103).** The + * census pairs the spec's graph against its stripped twin node by node, + * and a pairing that goes wrong does not raise: it walks off the graph, + * stops, and reports a SMALLER population with nothing lost — "0 lost" + * true by construction because it never looked. So the pairing is + * self-tested first on a hand-built corpus whose answer is counted off the + * source, and the superseded rule is kept and run as the control that + * fires on the real surface. + * * Every count below carries a control that FIRES. A differential whose two * sides are the same object, or a census that matched nothing, is green for * reasons that have nothing to do with objectui#9034. @@ -168,21 +193,197 @@ const hasRestlessTuple = (root: z.ZodType): boolean => { return false; }; -/* ── the population, read out of the spec's own `exports` map ─────────────── */ +/* ── the pairing walker, and how it picks the `default` arm's twin ─────────── */ -interface Census { - subpathsDeclared: number; - subpathsLoaded: number; - loadFailures: string[]; - roots: [string, z.ZodType][]; +/** + * ⭐ WHICH NODE IS THE STRIPPED TWIN OF A DEFAULT'S INNER TYPE (objectui#9103). + * + * `../zod/imported-defaults.ts`'s `default` arm, re-derived from the file: + * + * const inner = walk(schema.removeDefault()); + * const next = isAlreadyOptional(inner) ? inner : z.optional(inner); + * out = carryRegistryMeta(schema, next); + * + * The re-wrap is CONDITIONAL. So the twin of `removeDefault()` is + * `after.innerType` when a wrap was added, and `after` ITSELF when it was not — + * and only the SOURCE side still knows which, because `optin` is what the + * walker branched on and `optin` is invariant under the walk. + * + * - `'inner-optin'` asks the unwrapped SOURCE node the same question + * `isAlreadyOptional` asks. The live rule. + * - `'output-type'` is ⛔ the superseded rule, kept ONLY as the control that + * fires and ⛔ never used for a published figure. It asked the OUTPUT's + * `def.type === 'optional'`; on the `.optional().default()` spelling the + * output is a `ZodOptional` whether or not a wrap was added, so it paired + * the spec's own `ZodOptional(T)` against `walk(T)`, no child label matched, + * and the recursion STOPPED. Every population taken under it is a lower + * bound — which is why the docblock above no longer quotes one. + */ +type DefaultArmRule = 'inner-optin' | 'output-type'; + +interface Tally { nodesVisited: number; referenceEqualNodes: number; describedDefaults: number; describedDefaultsKept: number; describedDefaultsLost: string[]; + /** Described `ZodDefault` nodes whose unwrapped inner was ALREADY omissible. */ alreadyOptionalInner: number; + /** + * EVERY default arm whose unwrapped inner was already omissible, described or + * not — objectui#9103's population. Overwhelmingly the `.optional().default()` + * spelling; a default directly under a default lands here too, because a + * `ZodDefault` answers `optin: 'optional'` as well. + */ + alreadyOptionalArms: number; + /** `.describe().default()` — the description sits on the node UNDER the default. */ + describedInnerUnderDefault: number; + /** …where the OUTER node is described too, and the two say different things. */ + describedInnerDisagrees: number; rebuiltDescribed: number; rebuiltDescribedLost: string[]; + /** ⭐ Pairs whose two sides are not the same kind of node — see `pairRoots`. */ + misaligned: string[]; + /** …where no child label matched either, so the walk stopped there. */ + misalignedStops: number; +} + +/** + * Walk each `(before, after)` pair in lockstep and tally what crossed. + * + * ⭐ THE ALIGNMENT INVARIANT, which is what objectui#9103 added. The strip + * changes a node's KIND in exactly one place — the `default` arm — so at every + * other node the two sides must report the same `def.type`. A pair that does + * not is a defect in THIS walk, not a finding about the strip, and it is + * counted rather than left invisible: a mis-paired node almost never has a + * matching child label either, so the walk stops and every "nothing was lost" + * assertion downstream is true by construction beneath it. + */ +const pairRoots = (roots: readonly [string, z.ZodType][], rule: DefaultArmRule): Tally => { + const t: Tally = { + nodesVisited: 0, + referenceEqualNodes: 0, + describedDefaults: 0, + describedDefaultsKept: 0, + describedDefaultsLost: [], + alreadyOptionalInner: 0, + alreadyOptionalArms: 0, + describedInnerUnderDefault: 0, + describedInnerDisagrees: 0, + rebuiltDescribed: 0, + rebuiltDescribedLost: [], + misaligned: [], + misalignedStops: 0, + }; + const seen = new Set(); + + const pair = (before: z.ZodType, after: z.ZodType, path: string, depth: number): void => { + if (depth > 60 || seen.has(before)) return; + seen.add(before); + t.nodesVisited++; + if (before === after) { t.referenceEqualNodes++; return; } + + const bd = defOf(before); + const ad = isZod(after) ? defOf(after) : undefined; + const bDesc = before.description; + const aDesc = isZod(after) ? after.description : undefined; + + const misaligned = bd.type !== 'default' && ad !== undefined && ad.type !== bd.type; + if (misaligned) t.misaligned.push(`${path} :: ${bd.type} paired against ${ad!.type}`); + + if (bd.type === 'default') { + if (bDesc !== undefined) { + t.describedDefaults++; + if (aDesc === bDesc) t.describedDefaultsKept++; + else t.describedDefaultsLost.push(`${path} :: ${JSON.stringify(bDesc)} -> ${JSON.stringify(aDesc)}`); + } + // Unwrapped through `.removeDefault()`, the call the walker itself makes, + // rather than by reaching for `def.innerType` behind its back. Section 1 + // pins the two equal, so a zod that changed one and not the other reddens + // there instead of silently re-pointing this walk. + const removed = (before as unknown as { removeDefault: () => z.ZodType }).removeDefault(); + const innerWasOptional = optinOf(removed) === 'optional'; + if (innerWasOptional) { + t.alreadyOptionalArms++; + if (bDesc !== undefined) t.alreadyOptionalInner++; + } + if (removed.description !== undefined) { + t.describedInnerUnderDefault++; + if (bDesc !== undefined && removed.description !== bDesc) t.describedInnerDisagrees++; + } + + const wrapped = rule === 'inner-optin' + ? !innerWasOptional + : ad?.type === 'optional' && ad.innerType !== undefined; + if (wrapped && ad?.type !== 'optional') { + t.misaligned.push(`${path} :: the re-wrap expected a ZodOptional twin, found ${ad?.type ?? 'a non-schema'}`); + } + const twin = wrapped ? ad?.innerType : (isZod(after) ? after : undefined); + if (twin) pair(removed, twin, `${path}(default)`, depth + 1); + else { + t.misaligned.push(`${path} :: the default arm found no twin for its inner type`); + t.misalignedStops++; + } + return; + } + + if (bDesc !== undefined) { + t.rebuiltDescribed++; + if (aDesc !== bDesc) { + t.rebuiltDescribedLost.push(`${path} [${bd.type}] :: ${JSON.stringify(bDesc)} -> ${JSON.stringify(aDesc)}`); + } + } + + const aMap = new Map(isZod(after) ? childrenOf(after) : []); + const kids = childrenOf(before); + let matched = 0; + for (const [label, child] of kids) { + const twin = aMap.get(label); + if (twin) { matched++; pair(child, twin, `${path}${label}`, depth + 1); } + } + if (misaligned && kids.length > 0 && matched === 0) t.misalignedStops++; + }; + + for (const [name, root] of roots) pair(root, stripImportedDefaults(root), name, 0); + return t; +}; + +/** + * Every described node in a subtree, paired with the description it carries NOW. + * + * Used by the non-mutation pin, which re-reads these same node objects after a + * strip: a carry that relabelled its target in place would show up here and + * nowhere else. + * + * ⚠️ Forces `z.lazy` getters, exactly as `reaches` does. A recursive spec + * subtree whose getter mints a fresh graph per call defeats the seen-set, so + * the node budget is the real terminator and some collected nodes belong to a + * throwaway graph — harmless, since a throwaway node is never the one a + * mutation would damage. + */ +const describedNodes = (root: z.ZodType): [z.ZodType, string][] => { + const seen = new Set(); + const out: [z.ZodType, string][] = []; + const stack = [root]; + let budget = 20_000; + while (stack.length && budget-- > 0) { + const n = stack.pop()!; + if (seen.has(n)) continue; + seen.add(n); + if (n.description !== undefined) out.push([n, n.description]); + for (const [, c] of childrenOf(n)) stack.push(c); + } + return out; +}; + +/* ── the population, read out of the spec's own `exports` map ─────────────── */ + +interface Census extends Tally { + specVersion: string; + subpathsDeclared: number; + subpathsLoaded: number; + loadFailures: string[]; + roots: [string, z.ZodType][]; } /** @@ -196,7 +397,7 @@ interface Census { */ const buildCensus = async (): Promise => { const pkg = (await import('@objectstack/spec/package.json', { with: { type: 'json' } })) as { - default: { exports: Record }; + default: { version: string; exports: Record }; }; // Every subpath the spec publishes, minus the two that are not modules. Read // rather than listed, so a subpath added upstream is measured or RED. @@ -222,70 +423,13 @@ const buildCensus = async (): Promise => { } } - let nodesVisited = 0; - let referenceEqualNodes = 0; - let describedDefaults = 0; - let describedDefaultsKept = 0; - let alreadyOptionalInner = 0; - let rebuiltDescribed = 0; - const describedDefaultsLost: string[] = []; - const rebuiltDescribedLost: string[] = []; - const seen = new Set(); - - const pair = (before: z.ZodType, after: z.ZodType, path: string, depth: number): void => { - if (depth > 60 || seen.has(before)) return; - seen.add(before); - nodesVisited++; - if (before === after) { referenceEqualNodes++; return; } - - const bd = defOf(before); - const bDesc = before.description; - const aDesc = isZod(after) ? after.description : undefined; - - if (bd.type === 'default') { - if (bDesc !== undefined) { - describedDefaults++; - if (aDesc === bDesc) describedDefaultsKept++; - else describedDefaultsLost.push(`${path} :: ${JSON.stringify(bDesc)} -> ${JSON.stringify(aDesc)}`); - const removed = (before as unknown as { removeDefault: () => z.ZodType }).removeDefault(); - if (optinOf(removed) === 'optional') alreadyOptionalInner++; - } - const ad = isZod(after) ? defOf(after) : undefined; - const inner = bd.innerType!; - if (ad?.type === 'optional' && ad.innerType) pair(inner, ad.innerType, `${path}(default)`, depth + 1); - else if (isZod(after)) pair(inner, after, `${path}(default)`, depth + 1); - return; - } - - if (bDesc !== undefined) { - rebuiltDescribed++; - if (aDesc !== bDesc) { - rebuiltDescribedLost.push(`${path} [${bd.type}] :: ${JSON.stringify(bDesc)} -> ${JSON.stringify(aDesc)}`); - } - } - - const aMap = new Map(isZod(after) ? childrenOf(after) : []); - for (const [label, child] of childrenOf(before)) { - const twin = aMap.get(label); - if (twin) pair(child, twin, `${path}${label}`, depth + 1); - } - }; - - for (const [name, root] of roots) pair(root, stripImportedDefaults(root), name, 0); - return { + specVersion: pkg.default.version, subpathsDeclared: subpaths.length, subpathsLoaded, loadFailures, roots, - nodesVisited, - referenceEqualNodes, - describedDefaults, - describedDefaultsKept, - describedDefaultsLost, - alreadyOptionalInner, - rebuiltDescribed, - rebuiltDescribedLost, + ...pairRoots(roots, 'inner-optin'), }; }; @@ -314,6 +458,47 @@ describe('the zod 4 facts that make the carry necessary (objectui#9034)', () => ).toBeUndefined(); }); + it('⭐ `.removeDefault()` returns the very node `def.innerType` holds', () => { + // The census unwraps through `.removeDefault()` because the walker does, + // and then reads that node's `optin` to know which branch the walker took. + // If a zod ever made these two different objects, the census would pair one + // node against a DIFFERENT node's twin, silently — this is the only place + // that would say so. + expect( + (described as unknown as { removeDefault: () => z.ZodType }).removeDefault(), + 'zod no longer returns `def.innerType` from `.removeDefault()` — the census pairing (objectui#9103) ' + + 'unwraps through one and branches on the other, and must be re-derived before it is trusted', + ).toBe(defOf(described).innerType); + }); + + it('⭐ `optin` tells the two default spellings apart — and the OUTPUT does not (objectui#9103)', () => { + const bare = z.string().default('x'); + const alreadyOptional = z.string().optional().default('x'); + expect(defOf(bare).type).toBe('default'); + expect(defOf(alreadyOptional).type).toBe('default'); + + // The source side knows which spelling it is… + expect( + optinOf(defOf(bare).innerType!), + 'a bare default unwraps to a REQUIRED node, which is why the strip re-wraps it', + ).toBeUndefined(); + expect( + optinOf(defOf(alreadyOptional).innerType!), + '`.optional().default()` unwraps to an already-omissible node, which the strip leaves alone', + ).toBe('optional'); + + // …and the output side does NOT. This is objectui#9103's defect stated as a + // zod fact: a pairing that branches on the output's `def.type` cannot tell + // "the strip added a wrap" from "the wrap was already there". + const armOf = (schema: z.ZodType): string => + defOf(defOf(stripImportedDefaults(z.object({ k: schema }))).shape!.k).type; + expect( + [armOf(bare), armOf(alreadyOptional)], + 'the two spellings now produce DIFFERENT output kinds — the output\'s `def.type` would be a valid ' + + 'discriminator again and the census could go back to it', + ).toEqual(['optional', 'optional']); + }); + it('⭐ a raw `new Ctor({...def})` rebuild — what `cloneWithDef` does — drops the description', () => { // The firing control for the SECOND half of the defect: the clone rule // preserves `def.checks` and preserved nothing about the description, which @@ -383,6 +568,94 @@ describe('hand-built controls — each fires on the region it tests', () => { }); }); +/* ── 2b. the instrument itself, on a corpus whose answer is counted by hand ── */ + +describe('the census pairing is measured BEFORE it is pointed at the spec (objectui#9103)', () => { + /** + * ⭐ A pairing walk cannot be checked against the surface it measures. When it + * goes wrong it does not raise — it walks off the graph, stops, and reports a + * SMALLER population with nothing lost, which is indistinguishable from a + * clean boundary. So it is run first over five hand-built schemas whose + * answers are counted off the literals below, ⛔ never copied out of a run. + */ + const corpus = (): [string, z.ZodType][] => [ + // 1 described default; no `.optional().default()` anywhere. + ['bare', z.object({ a: z.string().default('x').describe('A') })], + // ⭐ objectui#9103's worked example. 2 described defaults (K, J); the K arm + // is `.optional().default()`, and J lives underneath it. + // + // ⚠️ The card spells the default value `{}`; zod types `.default()` against + // the schema's INPUT, so the value is filled in here. The pairing never + // reads a default's VALUE — only the node kinds around it — so this is a + // type-level spelling difference and not a different case. + ['card', z.object({ + k: z.object({ j: z.string().default('x').describe('J') }).optional().default({ j: 'x' }).describe('K'), + })], + // 3 described defaults (O, P, Q); two nested `.optional().default()` arms, + // so a rule that stops at the first one sees exactly O. + ['deep', z.object({ + o: z.object({ + p: z.object({ q: z.string().default('q').describe('Q') }).optional().default({ q: 'q' }).describe('P'), + }).optional().default({ p: { q: 'q' } }).describe('O'), + })], + // 2 described defaults (K, E); E sits under an ARRAY under the arm, so the + // blind spot is not specific to objects. + ['array', z.object({ + k: z.array(z.string().default('e').describe('E')).optional().default([]).describe('K'), + })], + // 1 described default (N) over a default-under-a-default. ⭐ BOTH rules pair + // this one correctly — it is here so the differential below cannot be + // explained by "the new rule just counts more everywhere". + ['nested', z.object({ n: z.string().default('a').default('b').describe('N') })], + ]; + + // Counted off the five literals above, ⛔ not read off a run. + const DESCRIBED_DEFAULTS = 1 + 2 + 3 + 2 + 1; // 9 + const ALREADY_OPTIONAL_ARMS = 0 + 1 + 2 + 1 + 1; // 5 — `nested`'s inner is a ZodDefault, which is omissible + + it('⭐ the live rule sees every described default the corpus holds', () => { + const t = pairRoots(corpus(), 'inner-optin'); + expect(t.describedDefaults, 'the pairing lost sight of a described default it was handed').toBe(DESCRIBED_DEFAULTS); + expect(t.alreadyOptionalArms).toBe(ALREADY_OPTIONAL_ARMS); + expect(t.describedDefaultsKept).toBe(t.describedDefaults); + expect(t.describedDefaultsLost).toEqual([]); + expect(t.misaligned, 'the live rule mis-paired a node on a corpus built to be paired correctly').toEqual([]); + expect(t.misalignedStops).toBe(0); + }); + + it('⛔ the superseded rule is blind on the same corpus — the control that FIRES', () => { + const t = pairRoots(corpus(), 'output-type'); + // `bare` 1 + `card` 1 (stops at K) + `deep` 1 (stops at O) + `array` 1 + // (stops at K) + `nested` 1 = 5 of the 9 the corpus holds. + expect( + t.describedDefaults, + 'the superseded rule no longer under-counts this corpus — if zod stopped making the two default ' + + 'spellings look alike on the output side, objectui#9103\'s defect is gone and this control is dead', + ).toBe(5); + // One per arm actually REACHED: `card`'s K, `deep`'s O, `array`'s K. `deep`'s + // P is never reached, which is the point. + expect(t.misaligned.length).toBe(3); + expect(t.misalignedStops, 'every mis-paired node also stopped the walk').toBe(3); + expect(t.nodesVisited).toBeLessThan(pairRoots(corpus(), 'inner-optin').nodesVisited); + }); + + it('⭐ the differential is the blind spot and nothing else', () => { + const live = pairRoots(corpus(), 'inner-optin'); + const blind = pairRoots(corpus(), 'output-type'); + // Every described default the superseded rule missed is one beneath an + // `.optional().default()` arm: J, P, Q, E. Both rules agree on `bare` and + // `nested`, which carry no such arm above a described default. + expect(live.describedDefaults - blind.describedDefaults).toBe(4); + // ⭐ objectui#9103's worked example, re-derived rather than quoted: on + // `card` the superseded rule "sees 1 of 2 described defaults". + expect(pairRoots([corpus()[1]], 'output-type').describedDefaults).toBe(1); + expect(pairRoots([corpus()[1]], 'inner-optin').describedDefaults).toBe(2); + expect(pairRoots([corpus()[0], corpus()[4]], 'inner-optin').describedDefaults).toBe( + pairRoots([corpus()[0], corpus()[4]], 'output-type').describedDefaults, + ); + }); +}); + /* ── 3. the published spec surface, re-derived ────────────────────────────── */ describe('every described node survives the boundary, across the whole published spec surface', () => { @@ -394,6 +667,42 @@ describe('every described node survives the boundary, across the whole published expect(census.nodesVisited, 'the walk barely moved — every count below is vacuous').toBeGreaterThan(5_000); }); + it('⭐ reports the live populations — printed, ⛔ never pinned to an integer', () => { + // ⭐ objectui#9103: this print REPLACES the hand-copied figures the docblock + // used to carry. A figure quoted in prose is a figure taken against some + // tree nobody can name later; these are taken against the spec version + // named on the first line, by the same pairing every assertion below uses. + console.log( + `[objectui#9103 census] @objectstack/spec ${census.specVersion} · ` + + `${census.subpathsLoaded}/${census.subpathsDeclared} subpaths · ${census.roots.length} roots\n` + + ` nodesVisited=${census.nodesVisited} referenceEqual=${census.referenceEqualNodes} ` + + `ratio=${(census.referenceEqualNodes / census.nodesVisited).toFixed(4)}\n` + + ` describedDefaults=${census.describedDefaults} kept=${census.describedDefaultsKept} ` + + `lost=${census.describedDefaultsLost.length}\n` + + ` rebuiltDescribed=${census.rebuiltDescribed} lost=${census.rebuiltDescribedLost.length}\n` + + ` alreadyOptionalArms=${census.alreadyOptionalArms} (described: ${census.alreadyOptionalInner})\n` + + ` describedInnerUnderDefault=${census.describedInnerUnderDefault} ` + + `(disagreeing with the outer description: ${census.describedInnerDisagrees})\n` + + ` misaligned=${census.misaligned.length} stops=${census.misalignedStops}`, + ); + expect(census.nodesVisited, 'the walk visited nothing — every figure printed above is vacuous').toBeGreaterThan(5_000); + }); + + it('⭐ `.describe().default()` DOES occur — the spelling objectui#9034 reported as absent', () => { + // objectui#9034 stated, as measured, that no reachable node is spelled + // `.describe().default()`. It is not: some carry a description on the node + // UNDER the default, and some of those disagree with the outer one. Both + // survive the strip — the outer through `carryRegistryMeta`, the inner + // because it is the node that is kept — so nothing is broken, but the + // sentence was wrong and this is the population that says so. + expect( + census.describedInnerUnderDefault, + 'no described inner under any default — `.describe().default()` really is absent now, so ' + + 'objectui#9034\'s sentence has become true and this control no longer measures anything', + ).toBeGreaterThan(0); + expect(census.describedInnerDisagrees).toBeGreaterThan(0); + }); + it('positive control — the described-default population is large and the branch is exercised', () => { expect( census.describedDefaults, @@ -417,6 +726,54 @@ describe('every described node survives the boundary, across the whole published it('⭐ not one rebuilt container loses its description', () => { expect(census.rebuiltDescribedLost.slice(0, 10)).toEqual([]); }); + + it('⭐ the pairing stayed ALIGNED across the whole surface (objectui#9103)', () => { + // ⭐ THE PIN THIS CARD EXISTS FOR. Without it the two "not one … loses its + // description" assertions above are partly true BY CONSTRUCTION: the + // superseded rule stopped at every `.optional().default()` arm, so it could + // not have seen a loss beneath one. This says the walk actually got there. + expect( + census.alreadyOptionalArms, + 'no default arm on the published surface unwraps to an already-omissible node — objectui#9103\'s ' + + 'population is empty on this spec version, so this pin proves nothing and the control below is dead', + ).toBeGreaterThan(100); + expect( + census.misaligned.slice(0, 10), + 'a node was paired against a twin of a DIFFERENT kind. The strip changes a node\'s kind in exactly ' + + 'one place — the `default` arm — so this is a defect in the pairing in THIS file, not a finding ' + + 'about `../zod/imported-defaults.ts`, and every assertion above is true by construction beneath it.', + ).toEqual([]); + expect(census.misalignedStops, 'the walk stopped early somewhere — the population above is a lower bound').toBe(0); + }); + + it('⛔ the superseded pairing rule is measurably blind HERE — the control that FIRES', () => { + // The corpus self-test above proves the old rule is blind on schemas built + // to expose it. This proves the published spec surface actually contains + // that shape, so the correction is not theoretical — and it republishes, as + // a derived number rather than a quoted one, exactly how much the figures in + // objectui#9034's prose were under-counting. + const blind = pairRoots(census.roots, 'output-type'); + console.log( + `[objectui#9103 control] superseded rule: misaligned=${blind.misaligned.length} ` + + `stops=${blind.misalignedStops} nodesVisited=${blind.nodesVisited} (live ${census.nodesVisited}) ` + + `referenceEqual=${blind.referenceEqualNodes} (live ${census.referenceEqualNodes}) ` + + `describedDefaults=${blind.describedDefaults} (live ${census.describedDefaults}) ` + + `rebuiltDescribed=${blind.rebuiltDescribed} (live ${census.rebuiltDescribed})`, + ); + expect( + blind.misaligned.length, + 'the superseded rule pairs this surface correctly — either zod stopped making the two default ' + + 'spellings look alike on the output side, or the spec stopped publishing `.optional().default()`', + ).toBeGreaterThan(0); + expect( + blind.misalignedStops, + 'a mis-paired node did NOT stop the walk — the two populations have come apart and the ' + + 'under-count below is no longer explained by the blind spot alone', + ).toBe(blind.misaligned.length); + expect(blind.describedDefaults).toBeLessThan(census.describedDefaults); + expect(blind.rebuiltDescribed).toBeLessThan(census.rebuiltDescribed); + expect(blind.nodesVisited).toBeLessThan(census.nodesVisited); + }); }); /* ── 4. the identity property, and the spec's graph left alone ────────────── */ @@ -497,7 +854,18 @@ describe('the carry buys nothing at the identity property\'s expense', () => { ).toEqual([]); // ⭐ PROVING REMOVAL: restore `: undefined` at the `tuple` arm's `const rest` - // in `../zod/imported-defaults.ts` and this assertion is the one that reddens. + // in `../zod/imported-defaults.ts` and THREE assertions in this file redden, + // ⛔ not one. Measured with that single line reverted and nothing else: + // + // - this one; + // - `⭐ every export with nothing to strip comes back REFERENCE-EQUAL`; + // - `the ONLY clean exports that are rebuilt are behind a z.lazy`. + // + // ⚠️ The count matters because it is what the note is FOR: a reader who + // reverts the line, sees three reds, and was promised one has no way to tell + // an over-broad pin from a correct one. The fenced file's own note on this + // same ablation names the wider population; this one was the narrower of the + // two and is corrected to agree with it (objectui#9103). }); it('⭐ most visited nodes are reference-equal — the walk did not start rebuilding the world', () => { @@ -507,11 +875,37 @@ describe('the carry buys nothing at the identity property\'s expense', () => { }); it('⛔ the spec\'s own graph still carries every default AND every description', () => { + // ⚠️ objectui#9103: this name used to over-claim its body. The body read + // `hasDefault` on the FIRST 200 carriers and never read a description, so + // the "AND every description" half was words. Both halves are checked now, + // across every carrier rather than a prefix, and the description half + // carries its own non-vacuity floor — a mutation-detector with nothing to + // detect is the failure mode this file exists to refuse. const carriers = census.roots.filter(([, s]) => hasDefault(s)); expect(carriers.length, 'nothing to check — this control does not fire').toBeGreaterThan(50); - for (const [name, schema] of carriers.slice(0, 200)) { + + const before = carriers.map(([name, schema]) => [name, schema, describedNodes(schema)] as const); + const describedCount = before.reduce((n, [, , d]) => n + d.length, 0); + expect( + describedCount, + 'no described node under any carrier — the description half of this assertion is vacuous', + ).toBeGreaterThan(500); + + const mutated: string[] = []; + for (const [name, schema, described] of before) { stripImportedDefaults(schema); - expect(hasDefault(schema), `${name} was stripped IN PLACE — every other consumer sees it`).toBe(true); + if (!hasDefault(schema)) mutated.push(`${name} :: the default was stripped IN PLACE`); + for (const [node, desc] of described) { + if (node.description !== desc) { + mutated.push( + `${name} :: a description was rewritten IN PLACE ${JSON.stringify(desc)} -> ${JSON.stringify(node.description)}`, + ); + } + } } + expect( + mutated.slice(0, 10), + 'the spec\'s own graph was mutated — every other consumer in the workspace sees it', + ).toEqual([]); }); });