You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In the schema string embedded in every Yardl file, type references are fully qualified (Namespace.Type) but type definitions carry only their unqualified name ("name":"Foo"). Because Yardl enforces name uniqueness only within a namespace, two different types from different namespaces can share an unqualified name in the same embedded schema. Any consumer that resolves the schema by definition name — e.g. a schema-only/dynamic reader, or a third-party tool — cannot disambiguate them and will misread the data.
Generated SDKs are unaffected (they use compile-time type knowledge and never resolve by name at runtime). This only affects consumers that interpret the embedded schema.
Root cause
Uniqueness is checked on the fully-qualified name, so cross-namespace collisions are legal: tooling/pkg/dsl/validation_type_resolution.go:32 → fullName := fmt.Sprintf("%s.%s", namespace, meta.Name)
References are serialized qualified: tooling/pkg/dsl/validation_type_resolution.go:157 → simpleType.Name = meta.GetQualifiedName()
Definitions serialize only the unqualified name (DefinitionMeta: Name json:"name", Namespace json:"-" — tooling/pkg/dsl/types.go:223-224).
Reproduction
Two namespaces each defining a different, non-alias record named Foo:
A reader that keys definitions by unqualified name resolves Imported.Foo to the wrong body and misreads the stream (in practice: reads the int32 as a string length → EOFError). The generated SDK reads the same bytes correctly.
Note: the existing TestModel schemas already contain unqualified-name collisions (e.g. Image — the real Image.Image generic vs. a TestModel.Image re-export alias). Those happen to be alias/real pairs resolving to the same structure, so they're benign today — but nothing guarantees that; the case above is a genuine, silent mismatch.
Proposed fix
Qualify definition names for imported types in the embedded schema (leave base-model types unqualified), matching the already-qualified references. Because within-namespace names are unique, every possible collision is cross-namespace, so qualifying the imported side makes the key sets provably disjoint (dot-free base names can never equal dotted imported names). Consumers then resolve via exact match, falling back to the unqualified name only for base-namespace references.
Alternative: fully qualify all definition names. Simpler for consumers (pure exact-match; no fallback), at the cost of changing every embedded schema string.
Notes
Either option changes the embedded schema string and thus interacts with the same back-compat concern raised in Fix embedded schema to distinguish between flags and enums #297 (readers do exact string-equality on the schema). A structural/canonical schema comparison would address both together.
Assumes one namespace per package (true today). If a package could ever span multiple namespaces, "base = unqualified" breaks and full qualification would be required.
Acceptance criteria
The embedded schema uniquely identifies every type definition even when unqualified names collide across imported namespaces.
A schema-only reader can correctly resolve and read the reproduction model above.
Summary
In the schema string embedded in every Yardl file, type references are fully qualified (
Namespace.Type) but type definitions carry only their unqualified name ("name":"Foo"). Because Yardl enforces name uniqueness only within a namespace, two different types from different namespaces can share an unqualified name in the same embedded schema. Any consumer that resolves the schema by definition name — e.g. a schema-only/dynamic reader, or a third-party tool — cannot disambiguate them and will misread the data.Generated SDKs are unaffected (they use compile-time type knowledge and never resolve by name at runtime). This only affects consumers that interpret the embedded schema.
Root cause
tooling/pkg/dsl/validation_type_resolution.go:32→fullName := fmt.Sprintf("%s.%s", namespace, meta.Name)tooling/pkg/dsl/validation_type_resolution.go:157→simpleType.Name = meta.GetQualifiedName()DefinitionMeta:Name json:"name",Namespace json:"-"—tooling/pkg/dsl/types.go:223-224).Reproduction
Two namespaces each defining a different, non-alias record named
Foo:yardl generatesucceeds, and the embedded schema contains two same-named, different-bodied definitions:A reader that keys definitions by unqualified name resolves
Imported.Footo the wrong body and misreads the stream (in practice: reads theint32as a string length →EOFError). The generated SDK reads the same bytes correctly.Note: the existing
TestModelschemas already contain unqualified-name collisions (e.g.Image— the realImage.Imagegeneric vs. aTestModel.Imagere-export alias). Those happen to be alias/real pairs resolving to the same structure, so they're benign today — but nothing guarantees that; the case above is a genuine, silent mismatch.Proposed fix
Qualify definition names for imported types in the embedded schema (leave base-model types unqualified), matching the already-qualified references. Because within-namespace names are unique, every possible collision is cross-namespace, so qualifying the imported side makes the key sets provably disjoint (dot-free base names can never equal dotted imported names). Consumers then resolve via exact match, falling back to the unqualified name only for base-namespace references.
Alternative: fully qualify all definition names. Simpler for consumers (pure exact-match; no fallback), at the cost of changing every embedded schema string.
Notes
Acceptance criteria