Found in review of #436 (Wahbeh-Mohammad).
typesConflict compares PrimKinds for equality and has no notion of narrowing, so a format-narrowed primitive reads as incompatible with its bare primitive:
allOf:
- {type: string, format: uri}
- {type: string}
The intersection is {type: string, format: uri}, which the IR expresses exactly as t/prim/url — the very type the merge keeps. Nothing is lost, yet the pair is reported as a conflict and now also takes an Unmodeled entry claiming a degradation that did not occur.
ir-design §4.8 defines degraded_lowering as "no faithful target for the shape as written", and attaches preservation where the weaker shape "actually loses something". Neither holds here.
The same false positive fires for every format-narrowing pair:
| declared |
redeclared |
kept |
actually lost |
string/uri |
string |
t/prim/url |
nothing |
string/date-time |
string |
t/prim/timestamp |
nothing |
integer/int32 |
integer |
t/prim/int32 |
nothing |
number/double |
number |
t/prim/double |
nothing |
string/uuid |
string |
t/prim/uuid |
nothing |
Scale: 102 occurrences in the published GitHub spec, each producing a diagnostic and an entry that is noise for exactly the consumer §12 names.
Suggested fix: teach typesConflict that a format-narrowed primitive is a subtype of its bare primitive, so the narrower one wins the shape and neither a diagnostic nor an entry is produced.
Related, and worth doing with it: testdata/conformance/openapi/allof-conflicting-type.yaml currently uses the uri/string pair as its headline case, so the golden entrenches this behaviour. Identified (integer vs string) in the same fixture is a genuinely unsatisfiable pair and is the better subject.
Deferred from #436: the detection predicate is upstream of that PR's scope, and changing it moves goldens across the corpus.
Found in review of #436 (Wahbeh-Mohammad).
typesConflictcomparesPrimKinds for equality and has no notion of narrowing, so a format-narrowed primitive reads as incompatible with its bare primitive:The intersection is
{type: string, format: uri}, which the IR expresses exactly ast/prim/url— the very type the merge keeps. Nothing is lost, yet the pair is reported as a conflict and now also takes an Unmodeled entry claiming a degradation that did not occur.ir-design §4.8 defines
degraded_loweringas "no faithful target for the shape as written", and attaches preservation where the weaker shape "actually loses something". Neither holds here.The same false positive fires for every format-narrowing pair:
string/uristringt/prim/urlstring/date-timestringt/prim/timestampinteger/int32integert/prim/int32number/doublenumbert/prim/doublestring/uuidstringt/prim/uuidScale: 102 occurrences in the published GitHub spec, each producing a diagnostic and an entry that is noise for exactly the consumer §12 names.
Suggested fix: teach
typesConflictthat a format-narrowed primitive is a subtype of its bare primitive, so the narrower one wins the shape and neither a diagnostic nor an entry is produced.Related, and worth doing with it:
testdata/conformance/openapi/allof-conflicting-type.yamlcurrently uses the uri/string pair as its headline case, so the golden entrenches this behaviour.Identified(integer vs string) in the same fixture is a genuinely unsatisfiable pair and is the better subject.Deferred from #436: the detection predicate is upstream of that PR's scope, and changing it moves goldens across the corpus.