Return inheritance combination evidence together
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Consolidation Implementation Plan
|
||||
|
||||
Status: in progress. Stages 1 through 14 are complete; follow Stage 15 through Stage 20 in order.
|
||||
Status: in progress. Stages 1 through 15 are complete; follow Stage 16 through Stage 20 in order.
|
||||
The target executor is a Luna coding agent working through one end-to-end sprint.
|
||||
|
||||
## Authority, Baseline, And Execution
|
||||
@@ -595,7 +595,7 @@ preliminary budget checks, scheduler, and combination path, while history and
|
||||
transfer inputs stay available to combination. Engine inheritance coverage and
|
||||
facade inheritance tests passed.
|
||||
|
||||
## Stage 15 — Return One Inheritance Combination Result
|
||||
## Stage 15 — Return One Inheritance Combination Result (Complete)
|
||||
|
||||
**Owners:** new engine `inheritance_combine.go`, `inheritance_collection.go`,
|
||||
and the shared executor.
|
||||
@@ -620,6 +620,13 @@ and the shared executor.
|
||||
**Finish:** merge callbacks no longer mutate the executor accumulator. The
|
||||
resolved template and all evidence travel together for Stage 16 integration.
|
||||
|
||||
Progress notes (2026-10-25): added `inheritanceTemplateResult` and moved the
|
||||
parent/child merge and evidence construction into `combineInheritanceTemplate`.
|
||||
Callbacks now update the local origins, policies, and replacement evidence;
|
||||
sequence-origin handling returns replacement records to the template result.
|
||||
Parentless templates use the same result shape. Engine and facade inheritance
|
||||
tests passed.
|
||||
|
||||
## Stage 16 — Finish The Inheritance Executor And Accounting
|
||||
|
||||
**Owner:** engine `inheritance_schedule.go` and focused finalization helpers.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
127
internal/engine/inheritance_combine.go
Normal file
127
internal/engine/inheritance_combine.go
Normal 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
|
||||
}
|
||||
@@ -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,
|
||||
parent = &prepared
|
||||
parentOrigins = resolvedOrigins[node.parent]
|
||||
}
|
||||
templateResult, diagnostics := combineInheritanceTemplate(
|
||||
node, child, parent, parentOrigins, adapter.applicationPolicy(),
|
||||
)
|
||||
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)
|
||||
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)}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user