internal/mcp/jsonschema: check for structure separately

Redo iteration. It was too subtle.

Write a separate recursive check for whether the schemas form a tree and
have any invalid nils.

While doing that, assign paths to schemas for better error messages,
even as we check structure. This also lets us detect re-occurring
schemas without a separate map.

Everything else, including the iterators, can now assume valid structure
and populated paths.

Change-Id: I90ec93d79d1d95c92258ad7afc94ef068fdf123f
Reviewed-on: https://go-review.googlesource.com/c/tools/+/676376
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Alan Donovan <adonovan@google.com>
Auto-Submit: Jonathan Amsterdam <jba@google.com>
This commit is contained in:
Jonathan Amsterdam 2025-05-26 13:12:35 -04:00 • committed by Gopher Robot
commit b0d437f1c5

View file

@ -32,8 +32,7 @@ func (rs *Resolved) Validate(instance any) error {
// state is the state of single call to ResolvedSchema.Validate.
type state struct {
rs *Resolved
depth int
rs *Resolved
// stack holds the schemas from recursive calls to validate.
// These are the "dynamic scopes" used to resolve dynamic references.
// https://json-schema.org/draft/2020-12/json-schema-core#scopes
@ -48,9 +47,6 @@ func (st *state) validate(instance reflect.Value, schema *Schema, callerAnns *an
defer func() {
st.stack = st.stack[:len(st.stack)-1] // pop
}()
if depth := len(st.stack); depth >= 100 {
return fmt.Errorf("max recursion depth of %d reached", depth)
}
// We checked for nil schemas in [Schema.Resolve].
assert(schema != nil, "nil schema")