Return inheritance combination evidence together

This commit is contained in:
2026-10-25 13:41:41 +00:00
parent f404168900
commit c5275df1fc
4 changed files with 164 additions and 111 deletions

View File

@@ -228,17 +228,17 @@ func applyInheritanceSequencePolicy(
}
func applyInheritanceSequenceOrigins(
result *inheritanceScope,
origins, incomingOrigins map[string]Origin,
path Path,
lower, higher *document.Node,
combined sequenceCombinationResult,
operation sequenceMode,
) {
) []inheritanceReplacement {
var replacements []inheritanceReplacement
if operation == sequenceModeReplace {
if lower != nil {
displaced := displacedOrigins(lower, origins, path)
result.replacements = append(result.replacements, inheritanceReplacement{
replacements = append(replacements, inheritanceReplacement{
path: path.clone(), before: lower, after: higher,
previous: displaced, effective: cloneOrigin(incomingOrigins[path.String()]),
})
@@ -253,7 +253,7 @@ func applyInheritanceSequenceOrigins(
copyInheritanceSubtreeAt(origins, incomingOrigins, higher.Sequence[projection.inputIndex], path.Index(projection.inputIndex), path.Index(projection.outputIndex))
}
}
return
return replacements
}
mergeInheritanceOrigin(origins, path, incomingOrigins[path.String()])
@@ -268,7 +268,7 @@ func applyInheritanceSequenceOrigins(
previous := displacedOrigins(lower.Sequence[replacement.lowerIndex], origins, lowerPath)
deleteOriginSubtree(origins, lowerPath, lower.Sequence[replacement.lowerIndex])
copyInheritanceSubtreeAt(origins, incomingOrigins, higher.Sequence[replacement.higherIndex], higherPath, outputPath)
result.replacements = append(result.replacements, inheritanceReplacement{
replacements = append(replacements, inheritanceReplacement{
path: outputPath, before: lower.Sequence[replacement.lowerIndex], after: higher.Sequence[replacement.higherIndex],
previous: previous, effective: cloneOrigin(incomingOrigins[higherPath.String()]),
})
@@ -278,6 +278,7 @@ func applyInheritanceSequenceOrigins(
copyInheritanceSubtreeAt(origins, incomingOrigins, higher.Sequence[projection.inputIndex], path.Index(projection.inputIndex), path.Index(projection.outputIndex))
}
}
return replacements
}
func validateRegisteredInheritanceSequences(root *document.Node, rootPath Path, applicationPolicy sequencePolicy) []Diagnostic {

View File

@@ -0,0 +1,127 @@
package engine
import "gitea.maximumdirect.net/eric/ConfigKit/internal/document"
type inheritanceTemplateResult struct {
value *document.Node
origins map[string]Origin
collectionPolicies collectionPolicyScope
policyTemplates []collectionPolicyScope
controls []inheritanceControl
transfers []inheritanceTransfer
replacements []inheritanceReplacement
operations []inheritanceOperation
}
func combineInheritanceTemplate(
template inheritanceExecutionTemplate,
child preparedInheritanceChild,
parent *preparedInheritanceParent,
parentOrigins map[string]Origin,
applicationPolicy sequencePolicy,
) (inheritanceTemplateResult, []Diagnostic) {
result := inheritanceTemplateResult{}
if child.control != nil {
result.controls = append(result.controls, *child.control)
result.operations = append(result.operations, inheritanceOperation{
control: child.control, controlOrigin: child.controlOrigin,
})
}
if parent == nil {
result.value = document.Clone(child.payload)
result.origins = child.origins
result.collectionPolicies = cloneCollectionPolicyScopeForInheritance(child.policyTemplates)
result.policyTemplates = []collectionPolicyScope{child.policyTemplates}
return result, nil
}
mergedPolicyScope, diagnostics := mergeInheritanceCollectionPolicies(
parent.parentPolicyScope, parent.childPolicyScope,
template.path, parent.payload, child.payload,
applicationPolicy, parent.replaced,
)
if len(diagnostics) != 0 {
return inheritanceTemplateResult{}, diagnostics
}
mergedOrigins := transferredInheritanceOrigins(parentOrigins, parent.transfer.from, template.path, parent.transfer)
mergeInheritanceOrigin(mergedOrigins, template.path, child.origins[template.path.String()])
var sequenceContributions []sequenceHistoryContribution
var combinationDiagnostics []Diagnostic
mergeRecursiveMappings(parent.payload, child.payload, template.path, new(mappingIndex), recursiveMergeHooks{
added: func(childPath Path, incoming *document.Node) {
copyInheritanceSubtree(mergedOrigins, child.origins, incoming, childPath)
},
combined: func(childPath Path, _ *document.Node) {
mergeInheritanceOrigin(mergedOrigins, childPath, child.origins[childPath.String()])
},
replaced: func(childPath Path, existing, incoming *document.Node) {
previous := displacedOrigins(existing, mergedOrigins, childPath)
result.replacements = append(result.replacements, inheritanceReplacement{
path: childPath.clone(), before: existing, after: incoming,
previous: previous, effective: cloneOrigin(child.origins[childPath.String()]),
})
deleteOriginSubtree(mergedOrigins, childPath, existing)
copyInheritanceSubtree(mergedOrigins, child.origins, incoming, childPath)
},
merge: func(childPath Path, existing, incoming *document.Node) (*document.Node, bool) {
resolution, _, _, active, issues := inheritanceCollectionResolution(
childPath, parent.parentPolicyScope, parent.childPolicyScope, applicationPolicy, incoming,
)
if len(issues) != 0 {
combinationDiagnostics = append(combinationDiagnostics, issues...)
return existing, false
}
if !active {
return nil, false
}
lowerValue := existing
combined, problems := combineSequence(lowerValue, incoming, resolution, sequenceCombinationContext{destination: childPath})
if len(problems) != 0 {
combinationDiagnostics = append(combinationDiagnostics, problems...)
return existing, false
}
policy := applyInheritanceSequencePolicy(
childPath, combined, resolution, parent.parentPolicyScope, parent.childPolicyScope,
)
mergedPolicyScope.set(childPath, policy)
result.replacements = append(result.replacements, applyInheritanceSequenceOrigins(
mergedOrigins, child.origins, childPath, lowerValue, incoming, combined, resolution.operation,
)...)
history := sequenceHistoryContribution{path: childPath.clone(), mode: sequenceHistoryMapped}
if resolution.operation == sequenceModeReplace {
history.mode = sequenceHistoryReplace
if incoming != nil && incoming.Kind == document.Sequence {
history.length = len(incoming.Sequence)
}
} else {
history.items = append([]sequenceItemProjection(nil), combined.higherItems...)
history.replacements = append([]sequenceItemReplacement(nil), combined.replacements...)
}
sequenceContributions = append(sequenceContributions, history)
return combined.value, true
},
})
preserveInheritanceIdentityFields(parent.payload, child.payload, template.identityFields)
if len(combinationDiagnostics) != 0 {
return inheritanceTemplateResult{}, canonicalDiagnostics(combinationDiagnostics)
}
if problems := validateRegisteredInheritanceSequences(parent.payload, template.path, applicationPolicy); len(problems) != 0 {
return inheritanceTemplateResult{}, problems
}
parent.payload.Location = template.entry.Value.Location
result.value = parent.payload
result.origins = mergedOrigins
result.collectionPolicies = inheritancePolicyScopeAtPath(mergedPolicyScope, template.path)
result.policyTemplates = parent.effectivePolicyTemplates
result.transfers = append(result.transfers, parent.transfer)
result.operations = append(result.operations, inheritanceOperation{
transfer: &parent.transfer, parent: parent.historyParent, effective: parent.payload,
parentOrigins: parentOrigins, effectiveOrigins: mergedOrigins,
parentPolicies: cloneInheritancePolicyTemplates(parent.policyTemplates),
templatePolicies: cloneCollectionPolicyScopeForInheritance(child.policyTemplates),
effectivePolicies: cloneInheritancePolicyTemplates(parent.effectivePolicyTemplates),
sequences: cloneSequenceHistoryContributions(sequenceContributions),
identityFields: cloneStrings(template.identityFields),
})
return result, nil
}

View File

@@ -188,14 +188,7 @@ func applyInheritanceScopeTemplates(adapter inheritanceScopeAdapter, order []int
for _, index := range order {
node := templates[index]
operationStart, replacementStart := len(result.operations), len(result.replacements)
child := prepareInheritanceChild(node, inputOrigins)
if child.control != nil {
result.controls = append(result.controls, *child.control)
result.operations = append(result.operations, inheritanceOperation{
control: child.control, controlOrigin: child.controlOrigin,
})
}
if limits.nodes >= 0 {
remaining := limits.nodes - retained - adapter.slotOverhead()
within := inheritanceLowerBoundWithin(child.payload, remaining)
@@ -207,114 +200,39 @@ func applyInheritanceScopeTemplates(adapter inheritanceScopeAdapter, order []int
}
}
var parent *preparedInheritanceParent
var parentOrigins map[string]Origin
if node.hasParent {
parent := resolved[node.parent]
preparedParent := prepareInheritanceParent(
node, templates[node.parent].path, parent, resolvedPolicyTemplates[node.parent],
prepared := prepareInheritanceParent(
node, templates[node.parent].path, resolved[node.parent], resolvedPolicyTemplates[node.parent],
resolvedPolicies[node.parent], child, adapter.applicationPolicy(),
)
mergedPolicyScope, policyDiagnostics := mergeInheritanceCollectionPolicies(
preparedParent.parentPolicyScope, preparedParent.childPolicyScope,
node.path, preparedParent.payload, child.payload,
adapter.applicationPolicy(), preparedParent.replaced,
)
if len(policyDiagnostics) != 0 {
return nil, policyDiagnostics
}
mergedOrigins := transferredInheritanceOrigins(resolvedOrigins[node.parent], preparedParent.transfer.from, node.path, preparedParent.transfer)
mergeInheritanceOrigin(mergedOrigins, node.path, child.origins[node.path.String()])
var sequenceContributions []sequenceHistoryContribution
var combinationDiagnostics []Diagnostic
mergeRecursiveMappings(preparedParent.payload, child.payload, node.path, new(mappingIndex), recursiveMergeHooks{
added: func(childPath Path, incoming *document.Node) {
copyInheritanceSubtree(mergedOrigins, child.origins, incoming, childPath)
},
combined: func(childPath Path, _ *document.Node) {
mergeInheritanceOrigin(mergedOrigins, childPath, child.origins[childPath.String()])
},
replaced: func(childPath Path, existing, incoming *document.Node) {
previous := displacedOrigins(existing, mergedOrigins, childPath)
result.replacements = append(result.replacements, inheritanceReplacement{
path: childPath.clone(), before: existing, after: incoming,
previous: previous, effective: cloneOrigin(child.origins[childPath.String()]),
})
deleteOriginSubtree(mergedOrigins, childPath, existing)
copyInheritanceSubtree(mergedOrigins, child.origins, incoming, childPath)
},
merge: func(childPath Path, existing, incoming *document.Node) (*document.Node, bool) {
resolution, _, _, active, issues := inheritanceCollectionResolution(
childPath, preparedParent.parentPolicyScope, preparedParent.childPolicyScope, adapter.applicationPolicy(), incoming,
)
if len(issues) != 0 {
combinationDiagnostics = append(combinationDiagnostics, issues...)
return existing, false
}
if !active {
return nil, false
}
lowerValue := existing
combined, problems := combineSequence(lowerValue, incoming, resolution, sequenceCombinationContext{destination: childPath})
if len(problems) != 0 {
combinationDiagnostics = append(combinationDiagnostics, problems...)
return existing, false
}
policy := applyInheritanceSequencePolicy(
childPath, combined, resolution, preparedParent.parentPolicyScope, preparedParent.childPolicyScope,
)
mergedPolicyScope.set(childPath, policy)
applyInheritanceSequenceOrigins(
result, mergedOrigins, child.origins, childPath, lowerValue, incoming, combined, resolution.operation,
)
history := sequenceHistoryContribution{path: childPath.clone(), mode: sequenceHistoryMapped}
if resolution.operation == sequenceModeReplace {
history.mode = sequenceHistoryReplace
if incoming != nil && incoming.Kind == document.Sequence {
history.length = len(incoming.Sequence)
}
} else {
history.items = append([]sequenceItemProjection(nil), combined.higherItems...)
history.replacements = append([]sequenceItemReplacement(nil), combined.replacements...)
}
sequenceContributions = append(sequenceContributions, history)
return combined.value, true
},
})
preserveInheritanceIdentityFields(preparedParent.payload, child.payload, node.identityFields)
if len(combinationDiagnostics) != 0 {
return nil, canonicalDiagnostics(combinationDiagnostics)
}
if problems := validateRegisteredInheritanceSequences(preparedParent.payload, node.path, adapter.applicationPolicy()); len(problems) != 0 {
return nil, problems
}
preparedParent.payload.Location = node.entry.Value.Location
resolved[index], resolvedOrigins[index] = preparedParent.payload, mergedOrigins
resolvedPolicies[index] = inheritancePolicyScopeAtPath(mergedPolicyScope, node.path)
result.transfers = append(result.transfers, preparedParent.transfer)
result.operations = append(result.operations, inheritanceOperation{
transfer: &preparedParent.transfer, parent: preparedParent.historyParent, effective: preparedParent.payload,
parentOrigins: resolvedOrigins[node.parent], effectiveOrigins: mergedOrigins,
parentPolicies: cloneInheritancePolicyTemplates(preparedParent.policyTemplates),
templatePolicies: cloneCollectionPolicyScopeForInheritance(child.policyTemplates),
effectivePolicies: cloneInheritancePolicyTemplates(preparedParent.effectivePolicyTemplates),
sequences: cloneSequenceHistoryContributions(sequenceContributions),
identityFields: cloneStrings(node.identityFields),
})
resolvedPolicyTemplates[index] = preparedParent.effectivePolicyTemplates
} else {
resolved[index] = document.Clone(child.payload)
resolvedOrigins[index] = child.origins
resolvedPolicyTemplates[index] = []collectionPolicyScope{child.policyTemplates}
resolvedPolicies[index] = cloneCollectionPolicyScopeForInheritance(child.policyTemplates)
parent = &prepared
parentOrigins = resolvedOrigins[node.parent]
}
templateResult, diagnostics := combineInheritanceTemplate(
node, child, parent, parentOrigins, adapter.applicationPolicy(),
)
if len(diagnostics) != 0 {
return nil, diagnostics
}
resolved[index] = templateResult.value
resolvedOrigins[index] = templateResult.origins
resolvedPolicies[index] = templateResult.collectionPolicies
resolvedPolicyTemplates[index] = templateResult.policyTemplates
result.controls = append(result.controls, templateResult.controls...)
result.transfers = append(result.transfers, templateResult.transfers...)
result.replacements = append(result.replacements, templateResult.replacements...)
result.operations = append(result.operations, templateResult.operations...)
count, _ := inheritanceLowerBoundCount(resolved[index], limits.nodes)
retained += adapter.slotOverhead() + count
for _, operation := range result.operations[operationStart:] {
for _, operation := range templateResult.operations {
if !counter.add(operation.parent) || !counter.add(operation.effective) {
return nil, []Diagnostic{inheritanceHistoryBudgetDiagnostic(node.path, node.entry.Value.Location)}
}
}
for _, replacement := range result.replacements[replacementStart:] {
for _, replacement := range templateResult.replacements {
if !counter.add(replacement.before) || !counter.add(replacement.after) {
return nil, []Diagnostic{inheritanceHistoryBudgetDiagnostic(node.path, node.entry.Value.Location)}
}