fix: address Copilot review round 3 — conjunctive keywords, unflattenable allOf, branch inference

- rootUnion: a branch restating a constraint the root states differently is
  declined (keywords at one level are conjunctive and no intersection is
  computed here), while annotations may disagree freely. An `allOf` with a
  member it cannot fold in — JSON Schema's boolean form, or a $ref whose
  constraints are unknown rather than absent — is left intact instead of
  merged-and-stripped, which would turn an unsatisfiable schema into a
  fillable form.
- rootUnion: `declaresAnyFields` counts the raw composition members, so
  `hasInputFields` reports fields for a union the resolver declines and an
  App tool is never auto-invoked with empty arguments.
- SchemaForm: the picker opens on the branch the supplied values identify
  (an App deep link overlays its args, so they can name another branch), and
  a branch switch no longer carries a value the outgoing branch declared —
  the branches may type the same name differently.
- TUI: a base property some branch redeclares is offered in EVERY branch's
  section under that branch's inherited or specialized declaration, so a
  branch that does not redeclare it can still supply a required root
  argument.

Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
cliffhall 2026-08-26 02:01:44 -04:00
commit 1a271e4931

View file

@ -536,6 +536,32 @@ describe("schemaToForm", () => {
});
});
it("offers a shared base property in every branch's section", () => {
const schema = {
type: "object",
properties: { count: {} },
required: ["count"],
anyOf: [
{ type: "object", properties: { count: { type: "integer" } } },
{ type: "object", properties: { other: { type: "string" } } },
],
};
const form = schemaToForm(schema, "shared");
// Rendered only in branch A's section, branch B could never supply the
// required root argument — the chosen branch's fields are what decode.
expect(form.sections[2]!.fields.map((field) => field.name)).toEqual([
"__b1__other",
"__b1__count",
]);
expect(
decodeFormValues(schema, {
__variant: "1",
__b1__other: "x",
__b1__count: "4",
}),
).toEqual({ other: "x", count: "4" });
});
it("keeps its generated names clear of the schema's own", () => {
const form = schemaToForm(
{