fix: address Copilot review round 5 — union member faithfulness, partial discriminators, const-null siblings

- rootUnion: union members get the same flattenability test as allOf members,
  so a branch whose nested `allOf: [false]` makes it unsatisfiable is no
  longer offered as a callable alternative with that constraint erased.
- selectBranchIndex: weigh only the pinned constants the caller SUPPLIED. One
  it did not supply is a value this identification exists to seed, so
  requiring it meant a deep link naming `kind` alone matched no branch
  whenever the branches also pinned, say, a `version`. A supplied constant
  that disagrees is still evidence against.
- admitsNull: `const: null` is conjunctive with its siblings, not an
  override — `{ type: "string", const: null }` and
  `{ const: null, anyOf: [...] }` reject every value, so the claim is made
  only where the type and a sibling union leave null on the table.

Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
cliffhall 2026-08-26 02:38:14 -04:00
commit f556f8831b

View file

@ -211,10 +211,13 @@ v2/main/
│ │ # intersections: a union whose members are not ALL
│ │ # field-carrying objects (or whose member `type`
│ │ # rules objects out), a branch restating a
│ │ # constraint the root states differently, an allOf
│ │ # carrying a member it cannot fold in (`false`, a
│ │ # $ref) — dropping the keyword there would turn an
│ │ # UNSATISFIABLE schema into a fillable form — and a
│ │ # constraint the root states differently, ANY member
│ │ # stating more than the merge applies (only
│ │ # type/properties/required — a `false`, a $ref, a
│ │ # nested applicator would have its constraint erased
│ │ # with the keyword, turning an UNSATISFIABLE schema
│ │ # into a fillable form; allOf members are checked
│ │ # against the ACCUMULATED merge, not the root), and a
│ │ # schema carrying BOTH oneOf and anyOf. Does not
│ │ # interpret `not` at all. Declining changes what
│ │ # RENDERS, never whether the tool takes arguments: