Skip to content

conflicting-redeclaration discards the losing type with no Unmodeled record #424

Description

@fuad-daoud

The gap

When allOf branches declare the same field with incompatible types, compilers/openapi/internal/merge/merge.go:98,251-264 keeps the first declaration and emits openapi/conflicting-redeclaration naming both pointers.

The losing type is not written to Unmodeled. Verified in source: the merge path (merge.go:80-109) merges docs, default, constraints, deprecation, XML, examples and unmodeled — but not the discarded type.

Why this one stands out

Every other degradation in this compiler keeps the thing it could not model. That is the whole discipline: an Unmodeled entry with a Reason, so nothing reaches the IR in no form. This path is the exception, and it is silent to any consumer that reads the document rather than the diagnostic stream.

Example and scale

102 occurrences in GitHub's published spec, e.g. webhook-fork/properties/forkee/allOf/1/properties/clone_url: t/prim/url in one branch, t/prim/string in the other, first wins.

A consumer diffing two versions of that document sees "no change" across a release where the losing branch's type moved.

Suggested fix

Keep the losing declaration verbatim under Unmodeled with ReasonDegradedLowering, the way the co-declared-keyword paths already do.


Found by a study of dexpace/spaceapi adopting morphic IR as its input format (spaceapi#56), 2026-09-05. Related: #418 (non-emitter consumer), #419 (cross-revision identity).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    type:bugDefect in shipped behavior

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions