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

@@ -1,6 +1,6 @@
# Consolidation Implementation Plan # 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. The target executor is a Luna coding agent working through one end-to-end sprint.
## Authority, Baseline, And Execution ## 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 transfer inputs stay available to combination. Engine inheritance coverage and
facade inheritance tests passed. 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`, **Owners:** new engine `inheritance_combine.go`, `inheritance_collection.go`,
and the shared executor. and the shared executor.
@@ -620,6 +620,13 @@ and the shared executor.
**Finish:** merge callbacks no longer mutate the executor accumulator. The **Finish:** merge callbacks no longer mutate the executor accumulator. The
resolved template and all evidence travel together for Stage 16 integration. 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 ## Stage 16 — Finish The Inheritance Executor And Accounting
**Owner:** engine `inheritance_schedule.go` and focused finalization helpers. **Owner:** engine `inheritance_schedule.go` and focused finalization helpers.

View File

@@ -228,17 +228,17 @@ func applyInheritanceSequencePolicy(
} }
func applyInheritanceSequenceOrigins( func applyInheritanceSequenceOrigins(
result *inheritanceScope,
origins, incomingOrigins map[string]Origin, origins, incomingOrigins map[string]Origin,
path Path, path Path,
lower, higher *document.Node, lower, higher *document.Node,
combined sequenceCombinationResult, combined sequenceCombinationResult,
operation sequenceMode, operation sequenceMode,
) { ) []inheritanceReplacement {
var replacements []inheritanceReplacement
if operation == sequenceModeReplace { if operation == sequenceModeReplace {
if lower != nil { if lower != nil {
displaced := displacedOrigins(lower, origins, path) displaced := displacedOrigins(lower, origins, path)
result.replacements = append(result.replacements, inheritanceReplacement{ replacements = append(replacements, inheritanceReplacement{
path: path.clone(), before: lower, after: higher, path: path.clone(), before: lower, after: higher,
previous: displaced, effective: cloneOrigin(incomingOrigins[path.String()]), 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)) copyInheritanceSubtreeAt(origins, incomingOrigins, higher.Sequence[projection.inputIndex], path.Index(projection.inputIndex), path.Index(projection.outputIndex))
} }
} }
return return replacements
} }
mergeInheritanceOrigin(origins, path, incomingOrigins[path.String()]) mergeInheritanceOrigin(origins, path, incomingOrigins[path.String()])
@@ -268,7 +268,7 @@ func applyInheritanceSequenceOrigins(
previous := displacedOrigins(lower.Sequence[replacement.lowerIndex], origins, lowerPath) previous := displacedOrigins(lower.Sequence[replacement.lowerIndex], origins, lowerPath)
deleteOriginSubtree(origins, lowerPath, lower.Sequence[replacement.lowerIndex]) deleteOriginSubtree(origins, lowerPath, lower.Sequence[replacement.lowerIndex])
copyInheritanceSubtreeAt(origins, incomingOrigins, higher.Sequence[replacement.higherIndex], higherPath, outputPath) 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], path: outputPath, before: lower.Sequence[replacement.lowerIndex], after: higher.Sequence[replacement.higherIndex],
previous: previous, effective: cloneOrigin(incomingOrigins[higherPath.String()]), 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)) 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 { 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 { for _, index := range order {
node := templates[index] node := templates[index]
operationStart, replacementStart := len(result.operations), len(result.replacements)
child := prepareInheritanceChild(node, inputOrigins) 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 { if limits.nodes >= 0 {
remaining := limits.nodes - retained - adapter.slotOverhead() remaining := limits.nodes - retained - adapter.slotOverhead()
within := inheritanceLowerBoundWithin(child.payload, remaining) 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 { if node.hasParent {
parent := resolved[node.parent] prepared := prepareInheritanceParent(
preparedParent := prepareInheritanceParent( node, templates[node.parent].path, resolved[node.parent], resolvedPolicyTemplates[node.parent],
node, templates[node.parent].path, parent, resolvedPolicyTemplates[node.parent],
resolvedPolicies[node.parent], child, adapter.applicationPolicy(), resolvedPolicies[node.parent], child, adapter.applicationPolicy(),
) )
mergedPolicyScope, policyDiagnostics := mergeInheritanceCollectionPolicies( parent = &prepared
preparedParent.parentPolicyScope, preparedParent.childPolicyScope, parentOrigins = resolvedOrigins[node.parent]
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)
} }
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) count, _ := inheritanceLowerBoundCount(resolved[index], limits.nodes)
retained += adapter.slotOverhead() + count retained += adapter.slotOverhead() + count
for _, operation := range result.operations[operationStart:] { for _, operation := range templateResult.operations {
if !counter.add(operation.parent) || !counter.add(operation.effective) { if !counter.add(operation.parent) || !counter.add(operation.effective) {
return nil, []Diagnostic{inheritanceHistoryBudgetDiagnostic(node.path, node.entry.Value.Location)} 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) { if !counter.add(replacement.before) || !counter.add(replacement.after) {
return nil, []Diagnostic{inheritanceHistoryBudgetDiagnostic(node.path, node.entry.Value.Location)} return nil, []Diagnostic{inheritanceHistoryBudgetDiagnostic(node.path, node.entry.Value.Location)}
} }