fix: address Copilot review — const precedence, TUI variant model, decline both-keyword unions

- rootUnion: decline a schema carrying BOTH oneOf and anyOf rather than
  reading one and silently dropping the other's constraints.
- SchemaForm: handle `const` before every type dispatch and for every
  constant type, so a numeric/boolean constant, or a schema carrying both
  `const` and `enum`, can no longer offer a forbidden value.
- collectSchemaDefaults / TUI initialValue: `const` outranks `default`,
  which is an annotation a schema may set to something its const rejects.
- convertToolParameters: resolve from the first branch's merged schema, so a
  branch's specialization of a root-declared property is what types the arg.
- TUI: ink-form keys values by field name across the whole form, so two
  branches' `kind` were one field and the later section's initial value
  decided what the earlier submitted. Branch fields now render under prefixed
  names behind a Variant select, and decodeFormValues translates back on
  submit, dropping every branch but the chosen one.

Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
cliffhall 2026-08-26 01:01:54 -04:00
commit 2782ed75d1

View file

@ -382,7 +382,10 @@ describe("root composition (#2123)", () => {
).toEqual({ version: "1" });
});
it("prefers an explicit default over a const", () => {
it("prefers a const over a conflicting default", () => {
// `default` is an annotation, not a constraint, so a schema may advertise
// one its own `const` rejects — seeding it would submit an invalid value
// through a read-only field.
expect(
collectSchemaDefaults({
type: "object",
@ -390,7 +393,7 @@ describe("root composition (#2123)", () => {
v: { type: "string", const: "a", default: "b" },
},
}),
).toEqual({ v: "b" });
).toEqual({ v: "a" });
});
it("collects defaults from a root allOf", () => {