ReviewOS

home-lang/home

fix(ts): transfer qualified namespace declaration graphs

#670
Closed chris opened this 8 days ago ·
8 days ago

Parent: #548

Problem

After #666–#669, the complete mapped/conditional/Extract/indexed-access handler graph transfers losslessly when its dependencies use named type imports. The equivalent three-module declaration loses contextual callback types when the exporting module spells the same dependencies through a namespace import:

// schemas.ts
export interface A { _zod: { def: { type: "a" } }; a: number }
export interface B { _zod: { def: { type: "b" } }; b: string }
export interface TypeDef { type: "a" | "b" }
export type Types = A | B;

// visit.ts
import * as schemas from "./schemas.js";
type Kind = schemas.TypeDef["type"];
type TypeOfKind<K extends Kind> = Extract<schemas.Types, { _zod: { def: { type: K } } }>;
export type Handlers = { [K in Kind]?: (item: TypeOfKind<K>, rewritten: boolean) => schemas.Types };

An imported overloaded call with handler property a is exact under TypeScript 6.0.3 and the native preview: callback item is A, rewritten is boolean, and the only diagnostics are deliberate TS2322/TS2339 controls. ReleaseFast Home emits two false TS7006 diagnostics and misses those controls.

Changing only import * as schemas plus schemas.X references to equivalent named type imports makes Home match. This isolates qualified namespace reference admission in the Program declaration schema, not mapped keys, overload selection, Extract, indexed access, or the consumer call.

Zod 4.5.2 contains the same qualified-reference boundary in core/visit.ts, but its much larger declaration graph remains an admission audit rather than proof that this is the last handler edge. A disposable named-import control must determine whether an additional downstream unsupported edge remains.

Fair strict oracle

  • Three real modules with NodeNext, strict, and noEmit.
  • Same files and root order for TypeScript 6.0.3, native TypeScript, and ReleaseFast Home.
  • Named-import spelling is a differential control, not the benchmark target.
  • Valid "a" and "b", invalid key, wrong assignment, missing discriminated member, and missing boolean member remain independent controls.

Acceptance

  • Preserve a namespace-qualified reference as an ordinary declaration edge when its complete source-owned declaration graph is already losslessly supported.
  • Apply the same support proof used for unqualified declaration graphs; do not admit opaque leaves, contextual-only declarations, unsupported utilities, classes/functions with unsafe semantics, or partially transferable graphs as whole types.
  • Preserve declaration and type-parameter identity across the transitive schemas.ts → visit.ts → consumer boundary.
  • Keep projection-only behavior for genuinely unsupported qualified graphs and keep existing qualified callable-shell behavior unchanged.
  • Add permanent schema and Program regressions for namespace-qualified mapped/conditional/indexed handler graphs plus rejected unsupported controls.
  • Match the exact TypeScript 6.0.3/native diagnostic multiset with no TS7006/TS2345.
  • Run complete Program/checker suites, ReleaseFast, formatting, whitespace, and required Pickier.
  • Run the unchanged pinned Zod 4.5.2 graph twice, require zero additions, and document exact removals or unchanged results.
  • Publish the detailed audit and linked README table.

No Zod/package/path/name/property/line special cases, source-text matching, namespace flattening, broad any, fabricated members, or callback-value-driven overload selection.

8 days ago

Implemented and pushed directly to main as solely-authored commit 24f4376f1 (fix(ts): admit qualified declaration graphs (#670)).

The Program schema now treats a namespace-qualified type reference as an ordinary declaration edge only after an identity-aware walk proves its complete graph lossless. The proof admits the expression forms already supported by ordinary Program schemas (objects, indexed objects, arrays, tuples, functions, mapped types, conditionals, indexed access, keyof, exact Extract, and their parameter/declaration identities) while rejecting:

  • opaque or unsupported leaves;
  • projection-only/contextual-projection edges;
  • contextual-only declarations;
  • classes and declared functions;
  • records, typeof classes, unsupported utilities, and built-in generic approximations.

No namespace flattening or any fallback was added. Existing callable-shell handling for opaque qualified leaves remains unchanged.

Permanent regressions cover a three-module schemas.ts → namespace-qualified visit.ts → consumer graph with overloads, mapped keys, indexed access, conditional fallback, and distributive Extract. A pre-existing qualified structured-object control now verifies that fully supported object graphs are ordinary edges; the existing opaque Set callback control still remains contextual-only.

Exact strict three-module oracle:

EngineDiagnostics
TypeScript 6.0.32× TS2322, 2× TS2339
Native TypeScript 7 preview2× TS2322, 2× TS2339
ReleaseFast Home2× TS2322, 2× TS2339

All three preserve "a" | "b", infer callback item A and rewritten value boolean, and emit no TS7006/TS2345.

Pinned Zod 4.5.2, two independent ReleaseFast runs:

Metric#669 main#670 candidateChange
Diagnostics4003946 TS2339 removed; 0 added
Unique identities3953896 removed; 0 added
Unique identities vs immutable 597 baseline395389208 removed overall; 0 added

Removed identities are exactly classic/errors.ts lines 61, 62, 65, and 66 (six TS2339 sites). Candidate runs are byte-identical, stderr SHA-256 67875e08fc1bbe6fe9d18a9ac0396cbfe7afa166dd1b71830ab4cd3e705557e6; normalized identity SHA-256 is dd266a4d67c6f5575d6ab19d80d37d0eec97fa06be26e8eb04cef5113596d643.

A disposable Zod control changing only the relevant schemas.X type references to equivalent named imports retains the same 394/389 identity set (only visit.ts line numbering shifts). The 16 classic/in-out.ts / mini/in-out.ts TS7006 diagnostics therefore remain a separate downstream graph gap; this issue does not overclaim them.

Final gates:

  • Program suite: 196/196;
  • complete checker suite: pass;
  • ReleaseFast build: pass;
  • exact TypeScript 6/native/Home oracle: pass;
  • zig fmt --check and git diff --check: pass;
  • repository-wide Pickier: unchanged existing baseline, 22,427 findings (11,834 errors, 10,593 warnings).

Zod still differs from TypeScript's zero-diagnostic result, so it remains excluded from cross-compiler timing. Shared-host elapsed times are also excluded.

8 days ago

Completed on main.

  • implementation + permanent regressions: 24f4376f1
  • detailed audit + linked README table: e8a92aa2a
  • production evidence: /home-lang/home/issues/670#issuecomment-5561365837

The strict three-module TypeScript 6/native/Home oracle now matches exactly at 2× TS2322 + 2× TS2339 with no TS7006/TS2345. The pinned Zod graph improves from 400/395 diagnostics/identities to 394/389, removing six TS2339 identities with zero additions. A named-import production control confirms the remaining 16 handler TS7006 sites are a separate downstream gap.

Sign in to comment on this issue.