Module adcp.validation.oneof_hints
Heuristic hint strings for oneOf near-miss validation failures.
When a payload fails a discriminated-union (oneOf) shape because the
caller used the wrong key as the discriminator (the v3 ref seller
pricing_options regression: {"type": "cpm", ...} instead of
{"pricing_model": "cpm", ...}), the standard jsonschema diagnostic is
"<value> is not valid under any of the given schemas" — accurate but
unactionable for an LLM client.
This module computes an additive hint string that names the closest
matching variant and the wrong / expected discriminator keys:
Looks like you may have meant the 'cpm' variant. Use 'pricing_model'
instead of 'type' as the discriminator.
The hint is best-effort: if no clear winner exists across variants, no hint is emitted (silent is better than misleading).
Functions
def compute_oneof_hint(schema: dict[str, Any],
schema_path_segments: list[Any],
instance_path_segments: list[Any],
payload: Any) ‑> str | None-
Expand source code
def compute_oneof_hint( schema: dict[str, Any], schema_path_segments: list[Any], instance_path_segments: list[Any], payload: Any, ) -> str | None: """Compute a near-miss hint for an ``oneOf`` failure. Args: schema: The compiled validator's root schema (refs already inlined). schema_path_segments: ``absolute_schema_path`` from the validation error — points at the ``oneOf`` keyword. instance_path_segments: ``absolute_path`` from the validation error — points at the offending value in the payload. payload: The full request/response payload that failed validation. Returns the hint string, or ``None`` if the heuristic can't pick a clear winner (no detectable discriminator, no clear best variant, or no obvious wrong-discriminator key). """ if not schema_path_segments or schema_path_segments[-1] != "oneOf": return None parent = _navigate(schema, list(schema_path_segments[:-1])) if not isinstance(parent, dict): return None variants_raw = parent.get("oneOf") if not isinstance(variants_raw, list) or len(variants_raw) < 2: return None variants: list[dict[str, Any]] = [v for v in variants_raw if isinstance(v, dict)] if len(variants) < 2: return None value = _navigate_input(payload, list(instance_path_segments)) if not isinstance(value, dict): return None discriminator = _detect_discriminator(variants) if discriminator is None: return None # Skip the hint when the caller already used the right discriminator # — they merely picked a value that doesn't match any variant. The # default "value not in allowed enum" message is more accurate there. if discriminator in value: return None scored = [(_score_variant(v, value, discriminator), idx, v) for idx, v in enumerate(variants)] # Sort by const_match (strongest), then required_present, then total_present. # seen_key (index 3 of the score tuple) is metadata, not a ranking signal. scored.sort(key=lambda s: (-s[0][0], -s[0][1], -s[0][2], s[1])) best_score, _, best_variant = scored[0] if len(scored) > 1: runner_up = scored[1][0] # Compare the ranking signals only — ignore seen_key. if best_score[:3] == runner_up[:3]: # No clear winner; silent rather than misleading. return None if best_score[:3] == (0, 0, 0): return None expected_const = _variant_const_value(best_variant, discriminator) if expected_const is None: return None # Prefer the seen_key recorded during scoring (exact key/value match # against the winning variant's const). Fall back to "extraneous # top-level key" only when no const-carrying key was found. seen_key = best_score[3] or _fallback_seen_key(value, discriminator, variants) if seen_key is None: return None return ( f"Looks like you may have meant the {expected_const!r} variant. " f"Use {discriminator!r} instead of {seen_key!r} as the discriminator." )Compute a near-miss hint for an
oneOffailure.Args
schema- The compiled validator's root schema (refs already inlined).
schema_path_segmentsabsolute_schema_pathfrom the validation error — points at theoneOfkeyword.instance_path_segmentsabsolute_pathfrom the validation error — points at the offending value in the payload.payload- The full request/response payload that failed validation.
Returns the hint string, or
Noneif the heuristic can't pick a clear winner (no detectable discriminator, no clear best variant, or no obvious wrong-discriminator key).