Cache approved dynamic descriptors per operation

This commit is contained in:
2026-10-25 22:07:37 +00:00
parent 12d350a292
commit 08f2a8f3e9
3 changed files with 88 additions and 8 deletions

View File

@@ -461,6 +461,13 @@ Focused check: `go test ./internal/engine -run 'History|Explain|Inheritance|Over
Finding: **A05**; requires Stage 2.
Owners: `internal/engine/value_operation.go`, projection/clone tests.
Status: **complete** (A05). Prior completed commits: `2736ddf`, `deb9aa5`,
`ae3408a`, `ea27f17`, `08a8c25`, `877c497`, `8aba43d`, `7bf2f0c`,
`0f9ecf1`, `119b42c`, `247a12b`, `4fcff5f`, `12d350a`. Validation passed:
`env GOTOOLCHAIN=local GOPROXY=off GOTELEMETRY=off go test ./internal/engine -run 'Dynamic|Projection|Clone|Resolution' -count=1`,
`env GOTOOLCHAIN=local GOPROXY=off GOTELEMETRY=off go test ./internal/engine -count=1`,
and `git diff --check`.
Add an operation-local set of successfully approved concrete types/descriptors.
After a completed descriptor build and a full successful secret-eligibility walk,
record approval. Subsequent values of that type in the same `valueOperation` reuse

View File

@@ -4,6 +4,8 @@ import (
"errors"
"reflect"
"testing"
"gitea.maximumdirect.net/eric/ConfigKit/internal/document"
)
type unsupportedDynamicRoot struct {
@@ -63,6 +65,9 @@ func TestDynamicDescriptorFailuresRollBackProvisionalTypes(t *testing.T) {
if _, issue := operation.dynamicDescriptor(reflect.TypeFor[unsupportedDynamicRoot](), Keys("failure")); issue == nil || issue.code != CodeSchemaDynamicType {
t.Fatalf("unsupported dynamic descriptor issue = %#v", issue)
}
if _, approved := operation.approvedDynamic[reflect.TypeFor[unsupportedDynamicRoot]()]; approved {
t.Fatal("unsupported dynamic descriptor was cached as eligible")
}
if schema.types[reflect.TypeFor[map[string]string]()] != prior {
t.Fatal("failed build removed a previously completed descriptor")
}
@@ -87,9 +92,69 @@ func TestDynamicDescriptorFailuresRollBackProvisionalTypes(t *testing.T) {
if _, issue := secretOperation.dynamicDescriptor(reflect.TypeFor[secretDynamicRoot](), Keys("secret")); issue == nil || issue.code != CodeSchemaDynamicType {
t.Fatalf("dynamic secret eligibility issue = %#v", issue)
}
if len(secretOperation.approvedDynamic) != 0 {
t.Fatalf("secret-bearing dynamic descriptor was cached as eligible: %#v", secretOperation.approvedDynamic)
}
for _, current := range []reflect.Type{reflect.TypeFor[secretDynamicRoot](), reflect.TypeFor[secretDynamicNested](), reflect.TypeFor[Secret]()} {
if _, exists := secretSchema.types[current]; exists {
t.Errorf("secret eligibility failure retained provisional descriptor for %v", current)
}
}
}
type wideDynamicEligibilityValue struct {
Alpha string
Bravo string
Charlie string
Delta string
Echo string
Foxtrot string
Golf string
Hotel string
India string
Juliet string
Kilo string
Lima string
Mike string
November string
Oscar string
Papa string
}
type repeatedNilDynamicEligibilityConfig struct {
Values []any
}
func TestDynamicEligibilityIsReusedWithinProjectionOperation(t *testing.T) {
schema, schemaIssue := buildSchema(reflect.TypeFor[repeatedNilDynamicEligibilityConfig](), testSecretBinding())
if schemaIssue != nil {
t.Fatalf("schema issue = %#v", schemaIssue)
}
values := make([]any, 32)
for index := range values {
values[index] = (*wideDynamicEligibilityValue)(nil)
}
configuration := repeatedNilDynamicEligibilityConfig{Values: values}
operation := valueOperation{schema: schema, limits: defaultProjectionLimits(), active: make(map[valueVisit]bool)}
node, issue := operation.project(reflect.ValueOf(configuration), schema.root, Path{}, 0)
if issue != nil {
t.Fatalf("repeated typed-nil projection issue = %#v", issue)
}
if len(node.Mapping) != 1 || len(node.Mapping[0].Value.Sequence) != len(values) {
t.Fatalf("projected repeated values = %#v", node)
}
for index, child := range node.Mapping[0].Value.Sequence {
if child.Kind != document.Null {
t.Errorf("projected value %d kind = %v, want null", index, child.Kind)
}
}
current := reflect.TypeFor[*wideDynamicEligibilityValue]()
if len(operation.approvedDynamic) != 1 || operation.approvedDynamic[current] == nil ||
operation.approvedDynamic[current] != schema.types[current] {
t.Fatalf("operation eligibility cache = %#v", operation.approvedDynamic)
}
otherOperation := valueOperation{schema: schema, limits: defaultProjectionLimits(), active: make(map[valueVisit]bool)}
if len(otherOperation.approvedDynamic) != 0 {
t.Fatalf("dynamic eligibility leaked into another operation: %#v", otherOperation.approvedDynamic)
}
}

View File

@@ -24,13 +24,14 @@ type valueVisit struct {
length int
}
// valueOperation owns one traversal's cycle and budget state and reuses the
// current load's descriptor cache for dynamic values.
// valueOperation owns one traversal's cycle and budget state, and caches
// dynamic descriptors approved for that traversal.
type valueOperation struct {
cloneMode secretCloneMode
schema *schemaDescriptor
limits projectionLimits
active map[valueVisit]bool
approvedDynamic map[reflect.Type]*typeDescriptor
nodes int
nodeCredits int
}
@@ -39,6 +40,9 @@ func (o *valueOperation) dynamicDescriptor(current reflect.Type, path Path) (*ty
if o.schema.secrets.Type != nil && current == o.schema.secrets.Type {
return nil, &projectionIssue{code: CodeSchemaDynamicType, path: path.clone(), message: "dynamic configuration values cannot establish secret-reference semantics"}
}
if descriptor, approved := o.approvedDynamic[current]; approved {
return descriptor, nil
}
builder := schemaBuilder{cache: o.schema.types, building: make(map[reflect.Type]bool), secrets: o.schema.secrets}
descriptor, issue := builder.describe(current, path)
if issue != nil {
@@ -49,6 +53,10 @@ func (o *valueOperation) dynamicDescriptor(current reflect.Type, path Path) (*ty
builder.rollback()
return nil, &projectionIssue{code: CodeSchemaDynamicType, path: path.clone(), message: "dynamic configuration values cannot establish secret-reference semantics"}
}
if o.approvedDynamic == nil {
o.approvedDynamic = make(map[reflect.Type]*typeDescriptor)
}
o.approvedDynamic[current] = descriptor
return descriptor, nil
}