fix: address Copilot review round 31 — proto-safe results, set-valued types, core keywords

- convertToolParameters defines its result keys rather than assigning them, so
  a discriminator legally named `__proto__` reaches the call instead of the
  prototype setter. It also collapses a nullable declaration before dispatching,
  so `type: ["number","null"]` coerces as a number rather than being sent
  as text.
- typeNameOf sorts an array `type`: JSON Schema reads it as a SET, so
  `["number","null"]` and `["null","number"]` are one declaration
  and must not read as branches disagreeing.
- nullableUnion's non-asserting keyword set covers `$defs`, `$id`,
  `$schema`, `$anchor`, `$dynamicAnchor` and `$vocabulary` — they
  identify or declare rather than assert. `$ref` stays out: it applies
  whatever it points at.

Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
cliffhall 2026-08-26 12:25:46 -04:00
commit c9162d0e73

View file

@ -440,6 +440,15 @@ const ANNOTATION_ONLY_KEYWORDS = new Set([
"readOnly",
"writeOnly",
"$comment",
// Core keywords that identify or declare rather than assert. `$ref` is
// deliberately absent: it applies whatever it points at, which is exactly an
// assertion this module cannot see.
"$defs",
"$id",
"$schema",
"$anchor",
"$dynamicAnchor",
"$vocabulary",
]);
/** Whether a schema states no assertion at all. */