Repository: pb33f/libopenapi
Pull request #408: Improve rendering of schemas with circular references
Author: login: geniegeist
Created: 2025-05-03T08:15:51Z | Merged: 2025-05-12T11:03:39Z

This PR enhances the rendering of schemas containing circular references.
Previously, circular references caused excessively deep nesting, only terminating when the maximum depth limit was hit. This update introduces more intelligent handling to avoid that behavior.

## Example 1

Assume we are given this schema `S`
```
schemas:
  human:
    type: object
    properties:
      name:
        type: string
        example: John Doe
      pets:  
        type: array
        items: 
          $ref: "#/schemas/animal"
  animal:
    type: object
    properties:
      name:
        type: string
        example: Bob the cat
      offspring:
        type: array
        items:
          $ref: "#/schemas/animal"
    required:
      - name
      - offspring
```

Currently, it renders an example based on `S` as follows
```
{
  "name":"John Doe",
  "pets":[{
     "name":"Bob the cat","
     offspring":[{
       "name":"Bob the cat",
       "offspring":[{
         "name":"Bob the cat",
          "offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":[{"name":"Bob the cat","offspring":"to deep to continue rendering..."}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}
```

This PR will render an example based on schema `S` as follows
```
{
  "name":"John Doe",
  "pets":[{
    "name":"Bob the cat",
    "offspring":[]
  }]
}
```

## Example 2

Assume we are given this schema `S`
```
schemas:
  country:
    type: object
    properties:
      president:
        $ref: "#/schemas/human"
  human:
    type: object
    properties:
      name:
        type: string
        example: John Doe
      pet:
        $ref: "#/schemas/pet"
  pet:
    type: object
    properties:
      name:
        type: string
        example: Hilbert the fish
      bestFriend:
        anyOf:
          - $ref: "#/schemas/pet"
          - $ref: "#/schemas/toy"
  toy:
    type: object
    properties:
      model:
        type: string
        example: ball
      age: 
        type: number
        example: 1
```
Currently, it renders an example based on `S` as a deeply nested object similar to Example 1 due to the circular dependency of `pet.bestFriend -> pet`.

This PR will render an example based on schema `S` as follows
```
{"name":"John Doe","pet":{"bestFriend":{"age":1,"model":"ball"},"name":"Hilbert the fish"}}
```
Note how the `bestFriend` property skips the `$ref: "#/schemas/pet"` reference since it detects a cycle and uses the `$ref: "#/schemas/toy"` reference instead.


## TO-DO

- [x] Add more tests


Diff:
diff --git a/renderer/schema_renderer.go b/renderer/schema_renderer.go
index 9ef8ca386..7798da612 100644
--- a/renderer/schema_renderer.go
+++ b/renderer/schema_renderer.go
@@ -87,7 +87,8 @@ func CreateRendererUsingDefaultDictionary() *SchemaRenderer {
 func (wr *SchemaRenderer) RenderSchema(schema *base.Schema) any {
 	// dive into the schema and render it
 	structure := make(map[string]any)
-	wr.DiveIntoSchema(schema, rootType, structure, 0)
+	visited := make(map[string]bool)
+	wr.DiveIntoSchema(schema, rootType, structure, visited, 0)
 	return structure[rootType]
 }
 
@@ -100,20 +101,20 @@ func (wr *SchemaRenderer) DisableRequiredCheck() {
 
 // DiveIntoSchema will dive into a schema and inject values from examples into a map. If there are no examples in
 // the schema, then the renderer will attempt to generate a value based on the schema type, format and pattern.
-func (wr *SchemaRenderer) DiveIntoSchema(schema *base.Schema, key string, structure map[string]any, depth int) {
+func (wr *SchemaRenderer) DiveIntoSchema(schema *base.Schema, key string, structure map[string]any, visited map[string]bool, depth int) bool {
 	// got an example? use it, we're done here.
 	if schema.Example != nil {
 		var example any
 		_ = schema.Example.Decode(&example)
 
 		structure[key] = example
-		return
+		return true
 	}
 
 	// emergency break to prevent stack overflow from ever occurring
 	if depth > 100 {
 		structure[key] = "to deep to continue rendering..."
-		return
+		return true
 	}
 
 	// render out a string.
@@ -154,7 +155,7 @@ func (wr *SchemaRenderer) DiveIntoSchema(schema *base.Schema, key string, struct
 						}
 					}
 					structure[key] = renderedExamples
-					return
+					return true
 				} else {
 					// render the first example
 					exmp := schema.Examples[0]
@@ -164,7 +165,7 @@ func (wr *SchemaRenderer) DiveIntoSchema(schema *base.Schema, key string, struct
 						renderedExample = fmt.Sprint(ex)
 					}
 					structure[key] = renderedExample
-					return
+					return true
 				}
 			}
 
@@ -224,7 +225,7 @@ func (wr *SchemaRenderer) DiveIntoSchema(schema *base.Schema, key string, struct
 				}
 			}
 		}
-		return
+		return true
 	}
 
 	// handle numbers
@@ -262,7 +263,7 @@ func (wr *SchemaRenderer) DiveIntoSchema(schema *base.Schema, key string, struct
 						renderedExample = ex
 					}
 					structure[key] = renderedExample
-					return
+					return true
 				}
 			}
 
@@ -281,7 +282,7 @@ func (wr *SchemaRenderer) DiveIntoSchema(schema *base.Schema, key string, struct
 				structure[key] = wr.RandomInt(minimum, maximum)
 			}
 		}
-		return
+		return true
 	}
 
 	// handle booleans
@@ -293,6 +294,14 @@ func (wr *SchemaRenderer) DiveIntoSchema(schema *base.Schema, key string, struct
 	if slices.Contains(schema.Type, objectType) || (schema.Properties != nil && schema.Properties.Len() > 0) ||
 		schema.AllOf != nil || (schema.DependentSchemas != nil && schema.DependentSchemas.Len() > 0) || schema.OneOf != nil || schema.AnyOf != nil {
 
+		if schema.ParentProxy.IsReference() {
+			if visited[schema.ParentProxy.GetReference()] {
+				return false
+			}
+			visited[schema.ParentProxy.GetReference()] = true
+		}
+
+
 		properties := schema.Properties
 		propertyMap := make(map[string]any)
 
@@ -313,8 +322,16 @@ func (wr *SchemaRenderer) DiveIntoSchema(schema *base.Schema, key string, struct
 			for propName, propValue := range checkProps.FromOldest() {
 				// render property
 				propertySchema := propValue.Schema()
+				required := slices.Contains(schema.Required, propName)
 				if propertySchema != nil {
-					wr.DiveIntoSchema(propertySchema, propName, propertyMap, depth+1)
+					success := wr.DiveIntoSchema(propertySchema, propName, propertyMap, copyMap(visited), depth+1)
+					if !success {
+						if required {
+							return false
+						}
+						delete(propertyMap, propName)
+						continue
+					}
 				} else {
 					// If the property is required but not specified in the schema,
     			// any value is allowed for this property (no specific validation).
@@ -330,7 +347,11 @@ func (wr *SchemaRenderer) DiveIntoSchema(schema *base.Schema, key string, struct
 			allOfMap := make(map[string]any)
 			for _, allOfSchema := range allOf {
 				allOfCompiled := allOfSchema.Schema()
-				wr.DiveIntoSchema(allOfCompiled, allOfType, allOfMap, depth+1)
+				success := wr.DiveIntoSchema(allOfCompiled, allOfType, allOfMap, copyMap(visited), depth+1)
+				if !success {
+					return false
+				}
+
 				if m, ok := allOfMap[allOfType].(map[string]any); ok {
 					for k, v := range m {
 						propertyMap[k] = v
@@ -350,7 +371,10 @@ func (wr *SchemaRenderer) DiveIntoSchema(schema *base.Schema, key string, struct
 				// only map if the property exists
 				if propertyMap[k] != nil {
 					dependentSchemaCompiled := dependentSchema.Schema()
-					wr.DiveIntoSchema(dependentSchemaCompiled, k, dependentSchemasMap, depth+1)
+					success := wr.DiveIntoSchema(dependentSchemaCompiled, k, dependentSchemasMap, copyMap(visited), depth+1)
+					if !success {
+						return false
+					}
 					for i, v := range dependentSchemasMap[k].(map[string]any) {
 						propertyMap[k].(map[string]any)[i] = v
 					}
@@ -360,10 +384,15 @@ func (wr *SchemaRenderer) DiveIntoSchema(schema *base.Schema, key string, struct
 
 		// handle oneOf
 		oneOf := schema.OneOf
-		if len(oneOf) > 0 {
+		oneOfSuccess := true
+		for _, oneOfSchema := range oneOf {
+			oneOfSuccess = false
 			oneOfMap := make(map[string]any)
-			oneOfCompiled := oneOf[0].Schema()
-			wr.DiveIntoSchema(oneOfCompiled, oneOfType, oneOfMap, depth+1)
+			oneOfCompiled := oneOfSchema.Schema()
+			success := wr.DiveIntoSchema(oneOfCompiled, oneOfType, oneOfMap, copyMap(visited), depth+1)
+			if !success {
+				continue
+			}
 			if m, ok := oneOfMap[oneOfType].(map[string]any); ok {
 				for k, v := range m {
 					propertyMap[k] = v
@@ -372,14 +401,25 @@ func (wr *SchemaRenderer) DiveIntoSchema(schema *base.Schema, key string, struct
 			if m, ok := oneOfMap[oneOfType].(string); ok {
 				propertyMap[oneOfType] = m
 			}
+			oneOfSuccess = true
+
+			break
+		}
+		if !oneOfSuccess {
+			return false
 		}
 
 		// handle anyOf
+		anyOfSuccess := true
 		anyOf := schema.AnyOf
-		if len(anyOf) > 0 {
+		for _, anyOfSchema := range anyOf {
+			anyOfSuccess = false
 			anyOfMap := make(map[string]any)
-			anyOfCompiled := anyOf[0].Schema()
-			wr.DiveIntoSchema(anyOfCompiled, anyOfType, anyOfMap, depth+1)
+			anyOfCompiled := anyOfSchema.Schema()
+			success := wr.DiveIntoSchema(anyOfCompiled, anyOfType, anyOfMap, copyMap(visited), depth+1)
+			if !success {
+				continue
+			}
 			if m, ok := anyOfMap[anyOfType].(map[string]any); ok {
 				for k, v := range m {
 					propertyMap[k] = v
@@ -388,9 +428,17 @@ func (wr *SchemaRenderer) DiveIntoSchema(schema *base.Schema, key string, struct
 			if m, ok := anyOfMap[anyOfType].(string); ok {
 				propertyMap[anyOfType] = m
 			}
+			anyOfSuccess = true
+
+			break
+		}
+
+		if !anyOfSuccess {
+			return false
 		}
+
 		structure[key] = propertyMap
-		return
+		return true
 	}
 
 	if slices.Contains(schema.Type, arrayType) {
@@ -407,12 +455,19 @@ func (wr *SchemaRenderer) DiveIntoSchema(schema *base.Schema, key string, struct
 					minItems = *schema.MinItems
 				}
 
-				var renderedItems []any
+				renderedItems := []any{}
 				// build up the array
 				for i := int64(0); i < minItems; i++ {
 					itemMap := make(map[string]any)
 					itemsSchemaCompiled := itemsSchema.A.Schema()
-					wr.DiveIntoSchema(itemsSchemaCompiled, itemsType, itemMap, depth+1)
+
+					success := wr.DiveIntoSchema(itemsSchemaCompiled, itemsType, itemMap, copyMap(visited), depth+1)
+					if !success {
+						// to do handle minItems correctly
+						renderedItems = []any{}
+						break
+					}
+
 					if multipleItems, ok := itemMap[itemsType].([]any); ok {
 						renderedItems = multipleItems
 					} else {
@@ -420,10 +475,12 @@ func (wr *SchemaRenderer) DiveIntoSchema(schema *base.Schema, key string, struct
 					}
 				}
 				structure[key] = renderedItems
-				return
+				return true
 			}
 		}
 	}
+
+	return true
 }
 
 func readFile(file io.Reader) []string {
@@ -434,6 +491,14 @@ func readFile(file io.Reader) []string {
 	return strings.Split(string(bytes), "\n")
 }
 
+func copyMap(m map[string]bool) map[string]bool {
+	res := make(map[string]bool)
+	for key, value := range m {
+		res[key] = value
+	}
+	return res
+}
+
 // ReadDictionary will read a dictionary file and return a slice of strings.
 func ReadDictionary(dictionaryLocation string) []string {
 	file, err := os.Open(dictionaryLocation)
diff --git a/renderer/schema_renderer_test.go b/renderer/schema_renderer_test.go
index 4fd3fbf51..9db88bc50 100644
--- a/renderer/schema_renderer_test.go
+++ b/renderer/schema_renderer_test.go
@@ -17,8 +17,10 @@ import (
 	"time"
 
 	highbase "github.com/pb33f/libopenapi/datamodel/high/base"
+	v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
 	"github.com/pb33f/libopenapi/datamodel/low"
 	lowbase "github.com/pb33f/libopenapi/datamodel/low/base"
+	"github.com/pb33f/libopenapi/index"
 	"github.com/stretchr/testify/assert"
 	"gopkg.in/yaml.v3"
 )
@@ -66,6 +68,10 @@ func getSchema(schema []byte) *highbase.Schema {
 	return schemaProxy.Schema()
 }
 
+func createVisitedMap() map[string]bool {
+  return make(map[string]bool)
+}
+
 func TestRenderExample_StringWithExample(t *testing.T) {
 	testObject := `type: string
 example: dog`
@@ -73,8 +79,9 @@ example: dog`
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
-	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	visited := createVisitedMap()
+  wr := createSchemaRenderer()
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.Equal(t, journeyMap["pb33f"], "dog")
 }
@@ -85,8 +92,9 @@ func TestRenderExample_StringWithNoExample(t *testing.T) {
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.GreaterOrEqual(t, len(journeyMap["pb33f"].(string)), 3)
@@ -100,8 +108,9 @@ format: date-time`
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	now := time.Now()
 	assert.NotNil(t, journeyMap["pb33f"])
@@ -115,8 +124,9 @@ pattern: "^[a-z]{5,10}@[a-z]{5,10}\\.(com|net|org)$"` // an email address
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 
@@ -133,8 +143,9 @@ pattern: "^\\([0-9]{3}\\)-[0-9]{3}-[0-9]{4}$"` // a phone number
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 
@@ -150,8 +161,9 @@ format: date`
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	now := time.Now().Format("2006-01-02")
 
@@ -166,8 +178,9 @@ format: time`
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	now := time.Now().Format("15:04:05")
 
@@ -182,8 +195,9 @@ format: email`
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.True(t, strings.Contains(journeyMap["pb33f"].(string), "@"))
@@ -196,8 +210,9 @@ format: hostname`
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.True(t, strings.Contains(journeyMap["pb33f"].(string), ".com"))
@@ -209,9 +224,10 @@ format: ipv4`
 
 	compiled := getSchema([]byte(testObject))
 
+	visited := createVisitedMap()
 	journeyMap := make(map[string]any)
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	segs := strings.Split(journeyMap["pb33f"].(string), ".")
@@ -225,8 +241,9 @@ format: ipv6`
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	segs := strings.Split(journeyMap["pb33f"].(string), ":")
@@ -240,8 +257,9 @@ format: uri`
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	uri, e := url.Parse(journeyMap["pb33f"].(string))
@@ -257,8 +275,9 @@ format: uuid`
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	segs := strings.Split(journeyMap["pb33f"].(string), "-")
@@ -272,8 +291,9 @@ format: byte`
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.NotEmpty(t, journeyMap["pb33f"].(string))
@@ -286,8 +306,9 @@ format: password`
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.NotEmpty(t, journeyMap["pb33f"].(string))
@@ -300,8 +321,9 @@ format: uri-reference`
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	segs := strings.Split(journeyMap["pb33f"].(string), "/")
@@ -315,8 +337,9 @@ format: binary`
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	encoded := journeyMap["pb33f"].(string)
 	decodedString, err := base64.StdEncoding.DecodeString(encoded)
@@ -332,8 +355,9 @@ example: 3.14`
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.Equal(t, 3.14, journeyMap["pb33f"])
@@ -346,8 +370,9 @@ minLength: 10`
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.GreaterOrEqual(t, len(journeyMap["pb33f"].(string)), 10)
@@ -360,8 +385,9 @@ maxLength: 10`
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.LessOrEqual(t, len(journeyMap["pb33f"].(string)), 10)
@@ -375,8 +401,9 @@ minLength: 3`
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.LessOrEqual(t, len(journeyMap["pb33f"].(string)), 8)
@@ -389,8 +416,9 @@ func TestRenderExample_NumberNoExample_Default(t *testing.T) {
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.Greater(t, journeyMap["pb33f"], int64(0))
@@ -404,8 +432,9 @@ minimum: 60`
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.GreaterOrEqual(t, journeyMap["pb33f"], int64(60))
@@ -419,8 +448,9 @@ maximum: 4`
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.GreaterOrEqual(t, journeyMap["pb33f"], int64(1))
@@ -434,8 +464,9 @@ format: float`
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.Greater(t, journeyMap["pb33f"], float32(0))
@@ -448,8 +479,9 @@ format: double`
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.Greater(t, journeyMap["pb33f"], float64(0))
@@ -462,8 +494,9 @@ format: int32`
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.Greater(t, journeyMap["pb33f"], 0)
@@ -476,8 +509,9 @@ format: int64`
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.Greater(t, journeyMap["pb33f"], int64(0))
@@ -490,8 +524,9 @@ example: true`
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.True(t, journeyMap["pb33f"].(bool))
@@ -503,8 +538,9 @@ func TestRenderExample_Boolean_WithoutExample(t *testing.T) {
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.True(t, journeyMap["pb33f"].(bool))
@@ -518,8 +554,9 @@ items:
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.Len(t, journeyMap["pb33f"], 1)
@@ -534,8 +571,9 @@ items:
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.Len(t, journeyMap["pb33f"], 1)
@@ -551,8 +589,9 @@ items:
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.Len(t, journeyMap["pb33f"], 3)
@@ -571,8 +610,9 @@ properties:
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.Len(t, journeyMap["pb33f"], 2)
@@ -597,8 +637,9 @@ properties:
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.Len(t, journeyMap["pb33f"], 2)
@@ -622,8 +663,9 @@ allOf:
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.Len(t, journeyMap["pb33f"], 2)
@@ -650,8 +692,9 @@ dependentSchemas:
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.Len(t, journeyMap["pb33f"], 1)
@@ -659,6 +702,7 @@ dependentSchemas:
 	assert.True(t, journeyMap["pb33f"].(map[string]interface{})["fishCake"].(map[string]interface{})["bones"].(bool))
 }
 
+
 func TestRenderExample_String_AllOf(t *testing.T) {
 	testObject := `type: object
 allOf:
@@ -667,8 +711,9 @@ allOf:
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.Len(t, journeyMap["pb33f"], 1)
@@ -691,8 +736,9 @@ oneOf:
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.Len(t, journeyMap["pb33f"], 1)
@@ -707,8 +753,9 @@ oneOf:
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.Len(t, journeyMap["pb33f"], 1)
@@ -731,8 +778,9 @@ anyOf:
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.Len(t, journeyMap["pb33f"], 1)
@@ -747,8 +795,9 @@ anyOf:
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.Len(t, journeyMap["pb33f"], 1)
@@ -798,8 +847,9 @@ properties:
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.Equal(t, journeyMap["pb33f"].(map[string]interface{})["id"].(string), "d1404c5c-69bd-4cd2-a4cf-b47c79a30112")
@@ -862,8 +912,9 @@ example:
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.Equal(t, journeyMap["pb33f"].(map[string]interface{})["id"].(string), "not-a-uuid")
@@ -914,8 +965,9 @@ properties:
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	assert.NotEmpty(t, journeyMap["pb33f"].(map[string]interface{})["id"].(string))
@@ -959,8 +1011,9 @@ properties:
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	burger := journeyMap["pb33f"].(map[string]interface{})["burger"].(map[string]interface{})
@@ -986,8 +1039,9 @@ properties:
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	drink := journeyMap["pb33f"].(map[string]interface{})["drink"].(string)
@@ -1010,8 +1064,9 @@ properties:
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	drink := journeyMap["pb33f"].(map[string]interface{})["drink"].(string)
@@ -1040,9 +1095,10 @@ properties:
 	compiled := getSchema([]byte(testObject))
 
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
 	wr.DisableRequiredCheck()
-	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	drink := journeyMap["pb33f"].(map[string]interface{})["drink"].(string)
@@ -1064,8 +1120,9 @@ properties:
 
 	compiled := getSchema([]byte(testObject))
 	schema := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", schema, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", schema, visited, 0)
 	rendered, _ := json.Marshal(schema["pb33f"])
 	assert.Equal(t, `{"name":"pb33f"}`, string(rendered))
 }
@@ -1079,8 +1136,9 @@ properties:
 
 	compiled := getSchema([]byte(testObject))
 	schema := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", schema, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", schema, visited, 0)
 	rendered, _ := json.Marshal(schema["pb33f"])
 	assert.Equal(t, `{"name":"pb33f"}`, string(rendered))
 }
@@ -1094,8 +1152,9 @@ properties:
 
 	compiled := getSchema([]byte(testObject))
 	schema := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", schema, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", schema, visited, 0)
 	rendered, _ := json.Marshal(schema["pb33f"])
 	assert.Equal(t, `{"count":9934.223}`, string(rendered))
 }
@@ -1109,8 +1168,9 @@ properties:
 
 	compiled := getSchema([]byte(testObject))
 	schema := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", schema, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", schema, visited, 0)
 	rendered, _ := json.Marshal(schema["pb33f"])
 	assert.Equal(t, `{"count":9934}`, string(rendered))
 }
@@ -1132,8 +1192,9 @@ properties:
 
 	compiled := getSchema([]byte(testObject))
 	schema := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", schema, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", schema, visited, 0)
 	rendered, _ := json.Marshal(schema["pb33f"])
 	assert.Equal(t, `{"args":{"arrParam":"test,test2","arrParamExploded":["1"]}}`, string(rendered))
 }
@@ -1157,8 +1218,9 @@ properties:
 
 	compiled := getSchema([]byte(testObject))
 	schema := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", schema, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", schema, visited, 0)
 	rendered, _ := json.Marshal(schema["pb33f"])
 	assert.Equal(t, `{"args":{"arrParam":"test,test2","arrParamExploded":["1","2"]}}`, string(rendered))
 }
@@ -1186,8 +1248,9 @@ properties:
 
 	compiled := getSchema([]byte(testObject))
 	schema := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", schema, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", schema, visited, 0)
 	rendered, _ := json.Marshal(schema["pb33f"])
 	assert.Equal(t, `{"bigint":8821239038968084,"bigintStr":"9223372036854775808","decimal":3.141592653589793,"decimalStr":"3.14159265358979344719667586"}`, string(rendered))
 }
@@ -1218,8 +1281,9 @@ properties:
 
 	compiled := getSchema([]byte(testObject))
 	schema := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", schema, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", schema, visited, 0)
 	rendered, _ := json.Marshal(schema["pb33f"])
 	assert.Equal(t, `{"bigint":8821239038968084,"bigintStr":"9223372036854775808","decimal":3.141592653589793,"decimalStr":"3.14159265358979344719667586"}`, string(rendered))
 }
@@ -1243,14 +1307,871 @@ properties:
 
 	compiled := getSchema([]byte(testObject))
 	schema := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", schema, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", schema, visited, 0)
 	assert.NotEmpty(t, schema["pb33f"].(map[string]interface{})["bigint"])
 	assert.NotEmpty(t, schema["pb33f"].(map[string]interface{})["bigintStr"])
 	assert.NotEmpty(t, schema["pb33f"].(map[string]interface{})["decimal"])
 	assert.NotEmpty(t, schema["pb33f"].(map[string]interface{})["decimalStr"])
 }
 
+func TestRenderSchema_Ref(t *testing.T) {
+	yml := `
+schemas:
+  restaurant:
+    type: object
+    properties:
+      address:
+        type: string
+        example: Baker Street
+      owner:
+        $ref: "#/schemas/person"
+  person:
+    type: object
+    properties:
+      name:
+        type: string
+        example: John Doe
+`
+
+	var idxNode yaml.Node
+	mErr := yaml.Unmarshal([]byte(yml), &idxNode)
+	assert.NoError(t, mErr)
+	idx := index.NewSpecIndex(&idxNode)
+
+	var components v3.Components
+	err := low.BuildModel(idxNode.Content[0], &components)
+	assert.NoError(t, err)
+
+	err = components.Build(context.Background(), idxNode.Content[0], idx)
+	assert.NoError(t, err)
+
+	lowRestaurant := components.FindSchema("restaurant")
+	lowNode := low.NodeReference[*lowbase.SchemaProxy]{
+		ValueNode: lowRestaurant.ValueNode,
+		Reference: lowRestaurant.Reference,
+		Value: lowRestaurant.Value,
+	}
+	schemaProxy := highbase.NewSchemaProxy(&lowNode)
+	schema := make(map[string]any)
+	visited := createVisitedMap()
+	wr := createSchemaRenderer()
+	wr.DiveIntoSchema(schemaProxy.Schema(), "pb33f", schema, visited, 0)
+	rendered, _ := json.Marshal(schema["pb33f"])
+	assert.Equal(t, `{"address":"Baker Street","owner":{"name":"John Doe"}}`, string(rendered))
+}
+
+func TestRenderSchema_Ref_NoExample(t *testing.T) {
+	yml := `
+schemas:
+  restaurant:
+    type: object
+    properties:
+      address:
+        type: string
+      owner:
+        $ref: "#/schemas/person"
+  person:
+    type: object
+    properties:
+      name:
+        type: string
+`
+
+	var idxNode yaml.Node
+	mErr := yaml.Unmarshal([]byte(yml), &idxNode)
+	assert.NoError(t, mErr)
+	idx := index.NewSpecIndex(&idxNode)
+
+	var components v3.Components
+	err := low.BuildModel(idxNode.Content[0], &components)
+	assert.NoError(t, err)
+
+	err = components.Build(context.Background(), idxNode.Content[0], idx)
+	assert.NoError(t, err)
+
+	lowRestaurant := components.FindSchema("restaurant")
+	lowNode := low.NodeReference[*lowbase.SchemaProxy]{
+		ValueNode: lowRestaurant.ValueNode,
+		Reference: lowRestaurant.Reference,
+		Value: lowRestaurant.Value,
+	}
+	schemaProxy := highbase.NewSchemaProxy(&lowNode)
+	schema := make(map[string]any)
+	visited := createVisitedMap()
+	wr := createSchemaRenderer()
+	wr.DiveIntoSchema(schemaProxy.Schema(), "pb33f", schema, visited, 0)
+	assert.NotEmpty(t, schema["pb33f"].(map[string]interface{})["address"])
+	assert.NotEmpty(t, schema["pb33f"].(map[string]interface{})["owner"])
+	assert.NotEmpty(t, schema["pb33f"].(map[string]interface{})["owner"].(map[string]interface{})["name"])
+}
+
+
+func TestRenderSchema_Ref_CircularArray(t *testing.T) {
+	yml := `
+schemas:
+  human:
+    type: object
+    properties:
+      name:
+        type: string
+        example: John Doe
+      pets:  
+        type: array
+        items: 
+          $ref: "#/schemas/animal"
+  animal:
+    type: object
+    properties:
+      name:
+        type: string
+        example: Bob the cat
+      offspring:
+        type: array
+        items:
+          $ref: "#/schemas/animal"
+    required:
+      - name
+      - offspring
+`
+
+	var idxNode yaml.Node
+	mErr := yaml.Unmarshal([]byte(yml), &idxNode)
+	assert.NoError(t, mErr)
+	idx := index.NewSpecIndex(&idxNode)
+
+	var components v3.Components
+	err := low.BuildModel(idxNode.Content[0], &components)
+	assert.NoError(t, err)
+
+	err = components.Build(context.Background(), idxNode.Content[0], idx)
+	assert.NoError(t, err)
+
+  lowRestaurant := components.FindSchema("human")
+	lowNode := low.NodeReference[*lowbase.SchemaProxy]{
+		ValueNode: lowRestaurant.ValueNode,
+		Reference: lowRestaurant.Reference,
+		Value: lowRestaurant.Value,
+	}
+	schemaProxy := highbase.NewSchemaProxy(&lowNode)
+	schema := make(map[string]any)
+	visited := createVisitedMap()
+	wr := createSchemaRenderer()
+	wr.DiveIntoSchema(schemaProxy.Schema(), "pb33f", schema, visited, 0)
+	rendered, _ := json.Marshal(schema["pb33f"])
+	assert.Equal(t, `{"name":"John Doe","pets":[{"name":"Bob the cat","offspring":[]}]}`, string(rendered))
+}
+
+func TestRenderSchema_Ref_AllOfCircularArray(t *testing.T) {
+	yml := `
+schemas:
+  human:
+    type: object
+    properties:
+      name:
+        type: string
+        example: John Doe
+      pets:  
+        type: array
+        items: 
+          allOf:
+            - $ref: "#/schemas/animal"
+  animal:
+    type: object
+    properties:
+      name:
+        type: string
+        example: Bob the cat
+      offspring:
+        type: array
+        items:
+          $ref: "#/schemas/animal"
+    required:
+      - name
+      - offspring
+`
+
+	var idxNode yaml.Node
+	mErr := yaml.Unmarshal([]byte(yml), &idxNode)
+	assert.NoError(t, mErr)
+	idx := index.NewSpecIndex(&idxNode)
+
+	var components v3.Components
+	err := low.BuildModel(idxNode.Content[0], &components)
+	assert.NoError(t, err)
+
+	err = components.Build(context.Background(), idxNode.Content[0], idx)
+	assert.NoError(t, err)
+
+  lowRestaurant := components.FindSchema("human")
+	lowNode := low.NodeReference[*lowbase.SchemaProxy]{
+		ValueNode: lowRestaurant.ValueNode,
+		Reference: lowRestaurant.Reference,
+		Value: lowRestaurant.Value,
+	}
+	schemaProxy := highbase.NewSchemaProxy(&lowNode)
+	schema := make(map[string]any)
+	visited := createVisitedMap()
+	wr := createSchemaRenderer()
+	wr.DiveIntoSchema(schemaProxy.Schema(), "pb33f", schema, visited, 0)
+	rendered, _ := json.Marshal(schema["pb33f"])
+	assert.Equal(t, `{"name":"John Doe","pets":[{"name":"Bob the cat","offspring":[]}]}`, string(rendered))
+}
+
+func TestRenderSchema_Ref_AllOfCircularArray2(t *testing.T) {
+	yml := `
+schemas:
+  human:
+    type: object
+    properties:
+      name:
+        type: string
+        example: John Doe
+      friends:  
+        type: array
+        items: 
+          allOf:
+            - $ref: "#/schemas/human"
+`
+
+	var idxNode yaml.Node
+	mErr := yaml.Unmarshal([]byte(yml), &idxNode)
+	assert.NoError(t, mErr)
+	idx := index.NewSpecIndex(&idxNode)
+
+	var components v3.Components
+	err := low.BuildModel(idxNode.Content[0], &components)
+	assert.NoError(t, err)
+
+	err = components.Build(context.Background(), idxNode.Content[0], idx)
+	assert.NoError(t, err)
+
+  lowRestaurant := components.FindSchema("human")
+	lowNode := low.NodeReference[*lowbase.SchemaProxy]{
+		ValueNode: lowRestaurant.ValueNode,
+		Reference: lowRestaurant.Reference,
+		Value: lowRestaurant.Value,
+	}
+	schemaProxy := highbase.NewSchemaProxy(&lowNode)
+	schema := make(map[string]any)
+	visited := createVisitedMap()
+	wr := createSchemaRenderer()
+	wr.DiveIntoSchema(schemaProxy.Schema(), "pb33f", schema, visited, 0)
+	rendered, _ := json.Marshal(schema["pb33f"])
+	assert.Equal(t, `{"friends":[{"friends":[],"name":"John Doe"}],"name":"John Doe"}`, string(rendered))
+}
+
+func TestRenderSchema_Ref_AnyOfCircularArray(t *testing.T) {
+	yml := `
+schemas:
+  human:
+    type: object
+    properties:
+      name:
+        type: string
+        example: John Doe
+      pets:  
+        type: array
+        items: 
+          anyOf:
+            - $ref: "#/schemas/animal"
+  animal:
+    type: object
+    properties:
+      name:
+        type: string
+        example: Bob the cat
+      offspring:
+        type: array
+        items:
+          $ref: "#/schemas/animal"
+    required:
+      - name
+      - offspring
+`
+
+	var idxNode yaml.Node
+	mErr := yaml.Unmarshal([]byte(yml), &idxNode)
+	assert.NoError(t, mErr)
+	idx := index.NewSpecIndex(&idxNode)
+
+	var components v3.Components
+	err := low.BuildModel(idxNode.Content[0], &components)
+	assert.NoError(t, err)
+
+	err = components.Build(context.Background(), idxNode.Content[0], idx)
+	assert.NoError(t, err)
+
+  lowRestaurant := components.FindSchema("human")
+	lowNode := low.NodeReference[*lowbase.SchemaProxy]{
+		ValueNode: lowRestaurant.ValueNode,
+		Reference: lowRestaurant.Reference,
+		Value: lowRestaurant.Value,
+	}
+	schemaProxy := highbase.NewSchemaProxy(&lowNode)
+	schema := make(map[string]any)
+	visited := createVisitedMap()
+	wr := createSchemaRenderer()
+	wr.DiveIntoSchema(schemaProxy.Schema(), "pb33f", schema, visited, 0)
+	rendered, _ := json.Marshal(schema["pb33f"])
+	assert.Equal(t, `{"name":"John Doe","pets":[{"name":"Bob the cat","offspring":[]}]}`, string(rendered))
+}
+
+func TestRenderSchema_Ref_AnyOfCircularArray2(t *testing.T) {
+	yml := `
+schemas:
+  human:
+    type: object
+    properties:
+      name:
+        type: string
+        example: John Doe
+      friends:  
+        type: array
+        items: 
+          anyOf:
+            - $ref: "#/schemas/human"
+`
+
+	var idxNode yaml.Node
+	mErr := yaml.Unmarshal([]byte(yml), &idxNode)
+	assert.NoError(t, mErr)
+	idx := index.NewSpecIndex(&idxNode)
+
+	var components v3.Components
+	err := low.BuildModel(idxNode.Content[0], &components)
+	assert.NoError(t, err)
+
+	err = components.Build(context.Background(), idxNode.Content[0], idx)
+	assert.NoError(t, err)
+
+  lowRestaurant := components.FindSchema("human")
+	lowNode := low.NodeReference[*lowbase.SchemaProxy]{
+		ValueNode: lowRestaurant.ValueNode,
+		Reference: lowRestaurant.Reference,
+		Value: lowRestaurant.Value,
+	}
+	schemaProxy := highbase.NewSchemaProxy(&lowNode)
+	schema := make(map[string]any)
+	visited := createVisitedMap()
+	wr := createSchemaRenderer()
+	wr.DiveIntoSchema(schemaProxy.Schema(), "pb33f", schema, visited, 0)
+	rendered, _ := json.Marshal(schema["pb33f"])
+	assert.Equal(t, `{"friends":[{"friends":[],"name":"John Doe"}],"name":"John Doe"}`, string(rendered))
+}
+
+
+func TestRenderSchema_Ref_AnyOfCircularArraySkip(t *testing.T) {
+	yml := `
+schemas:
+  country:
+    type: object
+    properties:
+      president:
+        $ref: "#/schemas/human"
+  human:
+    type: object
+    properties:
+      name:
+        type: string
+        example: John Doe
+      pet:
+        $ref: "#/schemas/pet"
+  pet:
+    type: object
+    properties:
+      name:
+        type: string
+        example: Hilbert the fish
+      bestFriend:
+        anyOf:
+          - $ref: "#/schemas/pet"
+          - $ref: "#/schemas/toy"
+  toy:
+    type: object
+    properties:
+      model:
+        type: string
+        example: ball
+      age: 
+        type: number
+        example: 1
+`
+
+	var idxNode yaml.Node
+	mErr := yaml.Unmarshal([]byte(yml), &idxNode)
+	assert.NoError(t, mErr)
+	idx := index.NewSpecIndex(&idxNode)
+
+	var components v3.Components
+	err := low.BuildModel(idxNode.Content[0], &components)
+	assert.NoError(t, err)
+
+	err = components.Build(context.Background(), idxNode.Content[0], idx)
+	assert.NoError(t, err)
+
+  lowRestaurant := components.FindSchema("human")
+	lowNode := low.NodeReference[*lowbase.SchemaProxy]{
+		ValueNode: lowRestaurant.ValueNode,
+		Reference: lowRestaurant.Reference,
+		Value: lowRestaurant.Value,
+	}
+	schemaProxy := highbase.NewSchemaProxy(&lowNode)
+	schema := make(map[string]any)
+	visited := createVisitedMap()
+	wr := createSchemaRenderer()
+	wr.DiveIntoSchema(schemaProxy.Schema(), "pb33f", schema, visited, 0)
+	rendered, _ := json.Marshal(schema["pb33f"])
+	assert.Equal(t, `{"name":"John Doe","pet":{"bestFriend":{"age":1,"model":"ball"},"name":"Hilbert the fish"}}`, string(rendered))
+}
+
+func TestRenderSchema_Ref_OneOfCircularArray(t *testing.T) {
+	yml := `
+schemas:
+  human:
+    type: object
+    properties:
+      name:
+        type: string
+        example: John Doe
+      pets:  
+        type: array
+        items: 
+          oneOf:
+            - $ref: "#/schemas/animal"
+  animal:
+    type: object
+    properties:
+      name:
+        type: string
+        example: Bob the cat
+      offspring:
+        type: array
+        items:
+          $ref: "#/schemas/animal"
+    required:
+      - name
+      - offspring
+`
+
+	var idxNode yaml.Node
+	mErr := yaml.Unmarshal([]byte(yml), &idxNode)
+	assert.NoError(t, mErr)
+	idx := index.NewSpecIndex(&idxNode)
+
+	var components v3.Components
+	err := low.BuildModel(idxNode.Content[0], &components)
+	assert.NoError(t, err)
+
+	err = components.Build(context.Background(), idxNode.Content[0], idx)
+	assert.NoError(t, err)
+
+  lowRestaurant := components.FindSchema("human")
+	lowNode := low.NodeReference[*lowbase.SchemaProxy]{
+		ValueNode: lowRestaurant.ValueNode,
+		Reference: lowRestaurant.Reference,
+		Value: lowRestaurant.Value,
+	}
+	schemaProxy := highbase.NewSchemaProxy(&lowNode)
+	schema := make(map[string]any)
+	visited := createVisitedMap()
+	wr := createSchemaRenderer()
+	wr.DiveIntoSchema(schemaProxy.Schema(), "pb33f", schema, visited, 0)
+	rendered, _ := json.Marshal(schema["pb33f"])
+	assert.Equal(t, `{"name":"John Doe","pets":[{"name":"Bob the cat","offspring":[]}]}`, string(rendered))
+}
+
+func TestRenderSchema_Ref_OneOfCircularArraySkip(t *testing.T) {
+	yml := `
+schemas:
+  human:
+    type: object
+    properties:
+      name:
+        type: string
+        example: John Doe
+      friend:
+        oneOf:
+          - $ref: "#/schemas/human"
+`
+
+	var idxNode yaml.Node
+	mErr := yaml.Unmarshal([]byte(yml), &idxNode)
+	assert.NoError(t, mErr)
+	idx := index.NewSpecIndex(&idxNode)
+
+	var components v3.Components
+	err := low.BuildModel(idxNode.Content[0], &components)
+	assert.NoError(t, err)
+
+	err = components.Build(context.Background(), idxNode.Content[0], idx)
+	assert.NoError(t, err)
+
+  lowRestaurant := components.FindSchema("human")
+	lowNode := low.NodeReference[*lowbase.SchemaProxy]{
+		ValueNode: lowRestaurant.ValueNode,
+		Reference: lowRestaurant.Reference,
+		Value: lowRestaurant.Value,
+	}
+	schemaProxy := highbase.NewSchemaProxy(&lowNode)
+	schema := make(map[string]any)
+	visited := createVisitedMap()
+	wr := createSchemaRenderer()
+	wr.DiveIntoSchema(schemaProxy.Schema(), "pb33f", schema, visited, 0)
+  rendered, _ := json.Marshal(schema["pb33f"])
+  assert.Equal(t, `{"friend":{"name":"John Doe"},"name":"John Doe"}`, string(rendered))
+}
+
+func TestRenderSchema_Ref_OneOfCircularArraySkip2(t *testing.T) {
+	yml := `
+schemas:
+  pet:
+    type: object
+    properties:
+      name:
+        type: string
+        example: Cathy the cat
+      friend:
+        oneOf:
+          - $ref: "#/schemas/human"
+  human:
+    type: object
+    properties:
+      name:
+        type: string
+        example: Maria
+      enemy:
+        oneOf:
+          - $ref: "#/schemas/human"
+          - $ref: "#/schemas/alien"
+  alien:
+    type: object
+    properties:
+      name: 
+        type: string
+        example: Alf
+`
+
+	var idxNode yaml.Node
+	mErr := yaml.Unmarshal([]byte(yml), &idxNode)
+	assert.NoError(t, mErr)
+	idx := index.NewSpecIndex(&idxNode)
+
+	var components v3.Components
+	err := low.BuildModel(idxNode.Content[0], &components)
+	assert.NoError(t, err)
+
+	err = components.Build(context.Background(), idxNode.Content[0], idx)
+	assert.NoError(t, err)
+
+  lowRestaurant := components.FindSchema("pet")
+	lowNode := low.NodeReference[*lowbase.SchemaProxy]{
+		ValueNode: lowRestaurant.ValueNode,
+		Reference: lowRestaurant.Reference,
+		Value: lowRestaurant.Value,
+	}
+	schemaProxy := highbase.NewSchemaProxy(&lowNode)
+	schema := make(map[string]any)
+	visited := createVisitedMap()
+	wr := createSchemaRenderer()
+	wr.DiveIntoSchema(schemaProxy.Schema(), "pb33f", schema, visited, 0)
+  rendered, _ := json.Marshal(schema["pb33f"])
+  assert.Equal(t, `{"friend":{"enemy":{"name":"Alf"},"name":"Maria"},"name":"Cathy the cat"}`, string(rendered))
+}
+
+
+func TestRenderSchema_Ref_OneOfCircularArrayFail(t *testing.T) {
+	yml := `
+schemas:
+  human:
+    type: object
+    properties:
+      name:
+        type: string
+        example: John Doe
+      friend:
+        oneOf:
+          - $ref: "#/schemas/human"
+    required:
+      - name
+      - friend
+`
+
+	var idxNode yaml.Node
+	mErr := yaml.Unmarshal([]byte(yml), &idxNode)
+	assert.NoError(t, mErr)
+	idx := index.NewSpecIndex(&idxNode)
+
+	var components v3.Components
+	err := low.BuildModel(idxNode.Content[0], &components)
+	assert.NoError(t, err)
+
+	err = components.Build(context.Background(), idxNode.Content[0], idx)
+	assert.NoError(t, err)
+
+  lowRestaurant := components.FindSchema("human")
+	lowNode := low.NodeReference[*lowbase.SchemaProxy]{
+		ValueNode: lowRestaurant.ValueNode,
+		Reference: lowRestaurant.Reference,
+		Value: lowRestaurant.Value,
+	}
+	schemaProxy := highbase.NewSchemaProxy(&lowNode)
+	schema := make(map[string]any)
+	visited := createVisitedMap()
+	wr := createSchemaRenderer()
+	success := wr.DiveIntoSchema(schemaProxy.Schema(), "pb33f", schema, visited, 0)
+	assert.False(t, success)
+}
+
+
+func TestRenderSchema_Ref_SkipOptional(t *testing.T) {
+	yml := `
+schemas:
+  pet:
+    type: object
+    properties:
+      name:
+        type: string
+        example: Maria the frog
+      color:
+        type: string
+        example: green
+      bestFriend:
+        $ref: "#/schemas/pet"
+    required:
+      - name
+`
+
+	var idxNode yaml.Node
+	mErr := yaml.Unmarshal([]byte(yml), &idxNode)
+	assert.NoError(t, mErr)
+	idx := index.NewSpecIndex(&idxNode)
+
+	var components v3.Components
+	err := low.BuildModel(idxNode.Content[0], &components)
+	assert.NoError(t, err)
+
+	err = components.Build(context.Background(), idxNode.Content[0], idx)
+	assert.NoError(t, err)
+
+  lowRestaurant := components.FindSchema("pet")
+	lowNode := low.NodeReference[*lowbase.SchemaProxy]{
+		ValueNode: lowRestaurant.ValueNode,
+		Reference: lowRestaurant.Reference,
+		Value: lowRestaurant.Value,
+	}
+	schemaProxy := highbase.NewSchemaProxy(&lowNode)
+	schema := make(map[string]any)
+	visited := createVisitedMap()
+	wr := createSchemaRenderer()
+	wr.DiveIntoSchema(schemaProxy.Schema(), "pb33f", schema, visited, 0)
+	rendered, _ := json.Marshal(schema["pb33f"])
+	assert.Equal(t, `{"name":"Maria the frog"}`, string(rendered))
+}
+
+func TestRenderSchema_Ref_SkipCircularProp(t *testing.T) {
+	yml := `
+schemas:
+  pet:
+    type: object
+    properties:
+      name:
+        type: string
+        example: Maria the frog
+      color:
+        type: string
+        example: green
+      bestFriend:
+        $ref: "#/schemas/pet"
+`
+
+	var idxNode yaml.Node
+	mErr := yaml.Unmarshal([]byte(yml), &idxNode)
+	assert.NoError(t, mErr)
+	idx := index.NewSpecIndex(&idxNode)
+
+	var components v3.Components
+	err := low.BuildModel(idxNode.Content[0], &components)
+	assert.NoError(t, err)
+
+	err = components.Build(context.Background(), idxNode.Content[0], idx)
+	assert.NoError(t, err)
+
+  lowRestaurant := components.FindSchema("pet")
+	lowNode := low.NodeReference[*lowbase.SchemaProxy]{
+		ValueNode: lowRestaurant.ValueNode,
+		Reference: lowRestaurant.Reference,
+		Value: lowRestaurant.Value,
+	}
+	schemaProxy := highbase.NewSchemaProxy(&lowNode)
+	schema := make(map[string]any)
+	visited := createVisitedMap()
+	wr := createSchemaRenderer()
+  wr.DiveIntoSchema(schemaProxy.Schema(), "pb33f", schema, visited, 0)
+	rendered, _ := json.Marshal(schema["pb33f"])
+	assert.Equal(t, `{"bestFriend":{"color":"green","name":"Maria the frog"},"color":"green","name":"Maria the frog"}`, string(rendered))
+}
+
+func TestRenderSchema_Ref_FailRenderOfCircularRef(t *testing.T) {
+	yml := `
+schemas:
+  pet:
+    type: object
+    properties:
+      name:
+        type: string
+        example: Maria the frog
+      color:
+        type: string
+        example: green
+      bestFriend:
+        $ref: "#/schemas/pet"
+    required:
+      - name
+      - bestFriend
+`
+
+	var idxNode yaml.Node
+	mErr := yaml.Unmarshal([]byte(yml), &idxNode)
+	assert.NoError(t, mErr)
+	idx := index.NewSpecIndex(&idxNode)
+
+	var components v3.Components
+	err := low.BuildModel(idxNode.Content[0], &components)
+	assert.NoError(t, err)
+
+	err = components.Build(context.Background(), idxNode.Content[0], idx)
+	assert.NoError(t, err)
+
+  lowRestaurant := components.FindSchema("pet")
+	lowNode := low.NodeReference[*lowbase.SchemaProxy]{
+		ValueNode: lowRestaurant.ValueNode,
+		Reference: lowRestaurant.Reference,
+		Value: lowRestaurant.Value,
+	}
+	schemaProxy := highbase.NewSchemaProxy(&lowNode)
+	schema := make(map[string]any)
+	visited := createVisitedMap()
+	wr := createSchemaRenderer()
+  success := wr.DiveIntoSchema(schemaProxy.Schema(), "pb33f", schema, visited, 0)
+  assert.False(t, success)
+}
+
+func TestRenderExample_Ref_DependentSchemasCircularSkip(t *testing.T) {
+	yml := `
+schemas:
+  human:
+    type: object
+    properties:
+      name:
+        type: string
+        example: "Lena"
+      pet:
+        type: object
+        properties: 
+          name:
+            type: string
+            example: Luis the kangaroo
+    dependentSchemas:
+      pet:
+        properties:
+          friend:
+            $ref: "#/schemas/toy"
+        required:
+          - friend
+  toy:
+    type: object
+    properties:
+      name:
+        type: string
+        example: Teddy bear
+      enemy:
+        $ref: "#/schemas/toy"
+`
+	var idxNode yaml.Node
+	mErr := yaml.Unmarshal([]byte(yml), &idxNode)
+	assert.NoError(t, mErr)
+	idx := index.NewSpecIndex(&idxNode)
+
+	var components v3.Components
+	err := low.BuildModel(idxNode.Content[0], &components)
+	assert.NoError(t, err)
+
+	err = components.Build(context.Background(), idxNode.Content[0], idx)
+	assert.NoError(t, err)
+
+  lowRestaurant := components.FindSchema("human")
+	lowNode := low.NodeReference[*lowbase.SchemaProxy]{
+		ValueNode: lowRestaurant.ValueNode,
+		Reference: lowRestaurant.Reference,
+		Value: lowRestaurant.Value,
+	}
+	schemaProxy := highbase.NewSchemaProxy(&lowNode)
+	schema := make(map[string]any)
+	visited := createVisitedMap()
+	wr := createSchemaRenderer()
+  wr.DiveIntoSchema(schemaProxy.Schema(), "pb33f", schema, visited, 0)
+	rendered, _ := json.Marshal(schema["pb33f"])
+	assert.Equal(t, `{"name":"Lena","pet":{"friend":{"name":"Teddy bear"},"name":"Luis the kangaroo"}}`, string(rendered))
+}
+
+func TestRenderExample_Ref_DependentSchemasFail(t *testing.T) {
+	yml := `
+schemas:
+  human:
+    type: object
+    properties:
+      name:
+        type: string
+        example: "Lena"
+      pet:
+        type: object
+        properties: 
+          name:
+            type: string
+            example: Luis the kangaroo
+    dependentSchemas:
+      pet:
+        properties:
+          friend:
+            $ref: "#/schemas/toy"
+        required:
+          - friend
+  toy:
+    type: object
+    properties:
+      enemy:
+        $ref: "#/schemas/toy"
+    required:
+      - enemy
+`
+	var idxNode yaml.Node
+	mErr := yaml.Unmarshal([]byte(yml), &idxNode)
+	assert.NoError(t, mErr)
+	idx := index.NewSpecIndex(&idxNode)
+
+	var components v3.Components
+	err := low.BuildModel(idxNode.Content[0], &components)
+	assert.NoError(t, err)
+
+	err = components.Build(context.Background(), idxNode.Content[0], idx)
+	assert.NoError(t, err)
+
+  lowRestaurant := components.FindSchema("human")
+	lowNode := low.NodeReference[*lowbase.SchemaProxy]{
+		ValueNode: lowRestaurant.ValueNode,
+		Reference: lowRestaurant.Reference,
+		Value: lowRestaurant.Value,
+	}
+	schemaProxy := highbase.NewSchemaProxy(&lowNode)
+	schema := make(map[string]any)
+	visited := createVisitedMap()
+	wr := createSchemaRenderer()
+  success := wr.DiveIntoSchema(schemaProxy.Schema(), "pb33f", schema, visited, 0)
+  assert.False(t, success)
+}
+
 func TestCreateRendererUsingDefaultDictionary(t *testing.T) {
 	assert.NotNil(t, CreateRendererUsingDefaultDictionary())
 }
@@ -1318,8 +2239,9 @@ func TestWordRenderer_RandomWordMinMaxZero(t *testing.T) {
 func TestRenderSchema_NestedDeep(t *testing.T) {
 	deepNest := createNestedStructure()
 	journeyMap := make(map[string]any)
+	visited := createVisitedMap()
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(deepNest.Schema(), "pb33f", journeyMap, 0)
+	wr.DiveIntoSchema(deepNest.Schema(), "pb33f", journeyMap, visited, 0)
 
 	assert.NotNil(t, journeyMap["pb33f"])
 	journeyLevel := 0


Reviews:
user: login: geniegeist
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-04T09:32:37Z
user: login: daveshanley
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-12T10:37:16Z
user: login: daveshanley
body: This is great, thank you for digging in. These types of challenges are hard.
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-12T10:37:42Z

Review comments:
diff_hunk: @@ -1243,14 +1302,162 @@ properties:
 
 	compiled := getSchema([]byte(testObject))
 	schema := make(map[string]any)
+	visited := make(map[string]bool)
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", schema, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", schema, visited, 0)
 	assert.NotEmpty(t, schema["pb33f"].(map[string]interface{})["bigint"])
 	assert.NotEmpty(t, schema["pb33f"].(map[string]interface{})["bigintStr"])
 	assert.NotEmpty(t, schema["pb33f"].(map[string]interface{})["decimal"])
 	assert.NotEmpty(t, schema["pb33f"].(map[string]interface{})["decimalStr"])
 }
 
+func TestRenderSchema_Ref(t *testing.T) {
+	yml := `
+schemas:
+  restaurant:
+    type: object
+    properties:
+      address:
+        type: string
+        example: Baker Street
+      owner:
+        $ref: "#/schemas/person"
+  person:
+    type: object
+    properties:
+      name:
+        type: string
+        example: John Doe
+`
+
+	var idxNode yaml.Node
+	mErr := yaml.Unmarshal([]byte(yml), &idxNode)
+	assert.NoError(t, mErr)
+	idx := index.NewSpecIndex(&idxNode)
+
+	var components v3.Components
+	err := low.BuildModel(idxNode.Content[0], &components)
+	assert.NoError(t, err)
+
+	err = components.Build(context.Background(), idxNode.Content[0], idx)
+	assert.NoError(t, err)
+
+	lowRestaurant := components.FindSchema("restaurant")
+	lowNode := low.NodeReference[*lowbase.SchemaProxy]{
+		ValueNode: lowRestaurant.ValueNode,
+		Reference: lowRestaurant.Reference,
+		Value: lowRestaurant.Value,
+	}
+	schemaProxy := highbase.NewSchemaProxy(&lowNode)
+	schema := make(map[string]any)
+	visited := make(map[string]bool)
+	wr := createSchemaRenderer()
+	wr.DiveIntoSchema(schemaProxy.Schema(), "pb33f", schema, visited, 0)
path: renderer/schema_renderer_test.go
user: login: geniegeist
body: @daveshanley I'm not sure how to use the low model yet. Let me know if this unit test can be improved.
created_at: 2025-05-04T09:32:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1243,14 +1302,162 @@ properties:
 
 	compiled := getSchema([]byte(testObject))
 	schema := make(map[string]any)
+	visited := make(map[string]bool)
 	wr := createSchemaRenderer()
-	wr.DiveIntoSchema(compiled, "pb33f", schema, 0)
+	wr.DiveIntoSchema(compiled, "pb33f", schema, visited, 0)
 	assert.NotEmpty(t, schema["pb33f"].(map[string]interface{})["bigint"])
 	assert.NotEmpty(t, schema["pb33f"].(map[string]interface{})["bigintStr"])
 	assert.NotEmpty(t, schema["pb33f"].(map[string]interface{})["decimal"])
 	assert.NotEmpty(t, schema["pb33f"].(map[string]interface{})["decimalStr"])
 }
 
+func TestRenderSchema_Ref(t *testing.T) {
+	yml := `
+schemas:
+  restaurant:
+    type: object
+    properties:
+      address:
+        type: string
+        example: Baker Street
+      owner:
+        $ref: "#/schemas/person"
+  person:
+    type: object
+    properties:
+      name:
+        type: string
+        example: John Doe
+`
+
+	var idxNode yaml.Node
+	mErr := yaml.Unmarshal([]byte(yml), &idxNode)
+	assert.NoError(t, mErr)
+	idx := index.NewSpecIndex(&idxNode)
+
+	var components v3.Components
+	err := low.BuildModel(idxNode.Content[0], &components)
+	assert.NoError(t, err)
+
+	err = components.Build(context.Background(), idxNode.Content[0], idx)
+	assert.NoError(t, err)
+
+	lowRestaurant := components.FindSchema("restaurant")
+	lowNode := low.NodeReference[*lowbase.SchemaProxy]{
+		ValueNode: lowRestaurant.ValueNode,
+		Reference: lowRestaurant.Reference,
+		Value: lowRestaurant.Value,
+	}
+	schemaProxy := highbase.NewSchemaProxy(&lowNode)
+	schema := make(map[string]any)
+	visited := make(map[string]bool)
+	wr := createSchemaRenderer()
+	wr.DiveIntoSchema(schemaProxy.Schema(), "pb33f", schema, visited, 0)
path: renderer/schema_renderer_test.go
user: login: daveshanley
body: This looks fine to me. 
created_at: 2025-05-12T10:37:16Z
author_association: MEMBER

PR comments:
user: login: codecov[bot]
created_at: 2025-05-03T08:20:54Z
body: ## [Codecov](https://app.codecov.io/gh/pb33f/libopenapi/pull/408?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pb33f) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 99.61%. Comparing base [(`d0e1a03`)](https://app.codecov.io/gh/pb33f/libopenapi/commit/d0e1a0335c0b11dfc80bf501b1e48c4640fbbe8a?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pb33f) to head [(`0e57909`)](https://app.codecov.io/gh/pb33f/libopenapi/commit/0e5790914c44d7bc47e0bdf2ced3b860992b023c?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pb33f).
> Report is 13 commits behind head on main.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main     #408      +/-   ##
==========================================
- Coverage   99.62%   99.61%   -0.01%     
==========================================
  Files         165      165              
  Lines       21966    22017      +51     
==========================================
+ Hits        21884    21933      +49     
- Misses         77       79       +2     
  Partials        5        5              
```

| [Flag](https://app.codecov.io/gh/pb33f/libopenapi/pull/408/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pb33f) | Coverage Δ | |
|---|---|---|
| [unittests](https://app.codecov.io/gh/pb33f/libopenapi/pull/408/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pb33f) | `99.61% <100.00%> (-0.01%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pb33f#carryforward-flags-in-the-pull-request-comment) to find out more.

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/pb33f/libopenapi/pull/408?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pb33f).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pb33f).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE
user: login: geniegeist
created_at: 2025-05-06T18:27:13Z
body: @daveshanley The PR is now ready for review. I'm not sure how to bump the coverage further though.
author_association: CONTRIBUTOR
user: login: daveshanley
created_at: 2025-05-12T10:37:04Z
body: There is no way to bump that last 1% as it's an issue with codecov, they have some wonky metrics sometimes. 

This is a great update, Thank you for diving into this. Thanks for your contribution.
author_association: MEMBER