fix: address Copilot review round 16 — tie-breaking, const-aware gating, malformed declarations
- selectBranchIndex no longer stops when several branches share the supplied
constant. A branch is dropped only when a supplied value CONTRADICTS one of
its constants; the required-field and exclusive-name passes then run over the
remaining candidates, so { version: 1, phone: "555" } resolves to the SMS
branch instead of falling back to the first.
- hasMissingRequiredFields counts only the branches the values could be making
(new branchAcceptsValues): { kind: "sms", address: "x" } supplies
everything the EMAIL branch requires while contradicting its discriminator,
and would otherwise enable a submit the server refuses.
- convertToolParameters ignores a malformed property declaration when branches
agree on a type, rather than storing a non-schema as the coercion schema.
Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
09914772ea
commit
7792ad71e9
2 changed files with 133 additions and 43 deletions
|
|
@ -493,6 +493,15 @@ describe("root composition (#2123)", () => {
|
|||
expect(hasMissingRequiredFields(UNION, { kind: "email" })).toBe(true);
|
||||
});
|
||||
|
||||
it("does not count a branch whose discriminator the values contradict", () => {
|
||||
// `{ kind: "sms", address: … }` supplies everything the EMAIL branch
|
||||
// requires while carrying a `kind` that branch rejects — and the SMS
|
||||
// branch it does name is still missing `phone`.
|
||||
expect(
|
||||
hasMissingRequiredFields(UNION, { kind: "sms", address: "a@b.c" }),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("allows submission once one branch is satisfied", () => {
|
||||
expect(hasMissingRequiredFields(UNION, { kind: "sms", phone: "555" })).toBe(
|
||||
false,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import {
|
|||
normalizeNullableUnion,
|
||||
} from "@inspector/core/json/nullableUnion.js";
|
||||
import {
|
||||
branchAcceptsValues,
|
||||
resolveRootUnion,
|
||||
selectBranchIndex,
|
||||
} from "@inspector/core/json/rootUnion.js";
|
||||
|
|
@ -266,7 +267,14 @@ export function hasMissingRequiredFields(
|
|||
// direction that matters: it never blocks arguments the schema accepts.
|
||||
const { base, branches } = resolveRootUnion(schema);
|
||||
if (branches.length > 0) {
|
||||
return branches.every((branch) => hasMissingIn(branch.schema, values));
|
||||
// Only the branches the values could actually be making are considered: a
|
||||
// required-name count alone would let `{ kind: "sms", address: "x" }` look
|
||||
// like a complete *email* call, whose discriminator it contradicts.
|
||||
const applicable = branches.filter((branch) =>
|
||||
branchAcceptsValues(branch, values),
|
||||
);
|
||||
if (applicable.length === 0) return true;
|
||||
return applicable.every((branch) => hasMissingIn(branch.schema, values));
|
||||
}
|
||||
return hasMissingIn(base, values);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue