@@ -713,18 +713,36 @@ func mergeOpenapiSchemas(s1, s2 *base.Schema) (*base.Schema, error) {
713713 // Required. We merge these.
714714 result .Required = append (s1 .Required , s2 .Required ... )
715715
716- // We merge all properties
716+ // We merge all properties. When both schemas declare a property with
717+ // the same name, the typed declaration wins over an untyped one
718+ // (which usually only carries annotations like example or
719+ // description). Without this, the later schema silently overwrote
720+ // the earlier one and any type/enum/constraint it carried was lost.
721+ //
722+ // We deliberately pick one of the original SchemaProxies rather
723+ // than fabricating a merged proxy via CreateSchemaProxy: downstream
724+ // code reads GoLow().GetReference() to attribute properties back to
725+ // the spec, and a synthetic proxy has no low-level backing.
717726 for k , v := range s1 .Properties .FromOldest () {
718727 if result .Properties == nil {
719728 result .Properties = orderedmap .New [string , * base.SchemaProxy ]()
720729 }
721730 result .Properties .Set (k , v )
722731 }
723732 for k , v := range s2 .Properties .FromOldest () {
724- // TODO: detect conflicts
725733 if result .Properties == nil {
726734 result .Properties = orderedmap .New [string , * base.SchemaProxy ]()
727735 }
736+
737+ if existing , exists := result .Properties .Get (k ); exists {
738+ if len (getSchemaType (existing .Schema ())) == 0 && len (getSchemaType (v .Schema ())) > 0 {
739+ result .Properties .Set (k , v )
740+ }
741+ // Otherwise the existing (s1's) property keeps its place;
742+ // either it already has a type and we don't want to drop it,
743+ // or neither side has a type and the choice is moot.
744+ continue
745+ }
728746 result .Properties .Set (k , v )
729747 }
730748
0 commit comments