Source: Apr 2026 conventions audit
Problem
`lib/action.ts` uses `zod-to-json-schema` with default options, which produces `anyOf` for discriminated unions. `anyOf` matches "at least one branch"; `oneOf` matches "exactly one branch". With const discriminators they're behaviorally equivalent, but `oneOf` is the more accurate signal:
- JSON Schema 2020-12 spec says discriminated unions SHOULD use `oneOf`
- OpenAPI tooling (which the model's tool-selection layer may resemble) uses `oneOf`+`discriminator` keyword
- Some MCP clients may treat `anyOf` permissively (multi-branch match) whereas `oneOf` is exclusive
Fix
```ts
// lib/action.ts
const _raw = zodToJsonSchema(ActionSchema, {
$refStrategy: "none",
target: "openApi3", // emits oneOf with discriminator
});
```
Or post-process the output to rename `anyOf` → `oneOf`.
Acceptance criteria
Source: Apr 2026 conventions audit
Problem
`lib/action.ts` uses `zod-to-json-schema` with default options, which produces `anyOf` for discriminated unions. `anyOf` matches "at least one branch"; `oneOf` matches "exactly one branch". With const discriminators they're behaviorally equivalent, but `oneOf` is the more accurate signal:
Fix
```ts
// lib/action.ts
const _raw = zodToJsonSchema(ActionSchema, {
$refStrategy: "none",
target: "openApi3", // emits oneOf with discriminator
});
```
Or post-process the output to rename `anyOf` → `oneOf`.
Acceptance criteria