Enforce the retained history node limit

This commit is contained in:
2026-10-25 22:04:54 +00:00
parent 4fcff5f453
commit 12d350a292
9 changed files with 395 additions and 84 deletions

View File

@@ -40,6 +40,86 @@ func (c *retainedNodeCounter) add(root *document.Node) bool {
return true
}
func (c *retainedNodeCounter) canAddClones(roots []*document.Node, copies int) bool {
if c == nil || c.limit < 0 {
return true
}
remaining := c.limit - c.count
if remaining < 0 {
return false
}
for copyIndex := 0; copyIndex < copies; copyIndex++ {
for _, root := range roots {
count, within := documentCloneNodeCount(root, remaining)
if !within {
return false
}
remaining -= count
}
}
return true
}
func documentCloneNodeCount(root *document.Node, limit int) (int, bool) {
if root == nil {
return 0, true
}
count := 0
stack := []*document.Node{root}
for len(stack) != 0 {
node := stack[len(stack)-1]
stack = stack[:len(stack)-1]
if node == nil {
continue
}
count++
if count > limit {
return 0, false
}
for _, entry := range node.Mapping {
stack = append(stack, entry.Value)
}
stack = append(stack, node.Sequence...)
}
return count, true
}
func addInspectionHistory(counter *retainedNodeCounter, inspection *Inspection) bool {
if inspection == nil {
return false
}
for _, root := range []*document.Node{inspection.baseline, inspection.input, inspection.final, inspection.preCLI} {
if !counter.add(root) {
return false
}
}
for _, application := range inspection.applications {
if !counter.add(application.value) {
return false
}
}
for _, application := range inspection.postDecodeApps {
if !counter.add(application.value) {
return false
}
}
for _, snapshots := range [][]resolutionSnapshot{inspection.resolution, inspection.resolutionReplay} {
for _, snapshot := range snapshots {
if !counter.add(snapshot.before) || !counter.add(snapshot.after) {
return false
}
}
}
for _, operations := range [][]inheritanceOperation{inspection.inheritance, inspection.metadata.inheritance} {
for _, operation := range operations {
if !counter.add(operation.parent) || !counter.add(operation.effective) {
return false
}
}
}
return true
}
// History applications borrow immutable policy-validated input trees. Metadata
// records answer presence and origin queries; replay reconstructs value changes.
// Replay reconciles with canonical decoding, applies supplied CLI contributions,
@@ -499,66 +579,3 @@ func replaceHistoryPath(root **document.Node, path Path, replacement *document.N
}
}
}
func historyNodesWithinLimit(baseline, input, final *document.Node, applications []historyApplication, resolutions []resolutionSnapshot, inherited ...*inheritanceScope) bool {
return historyNodesWithin(historyNodeLimit, baseline, input, final, applications, resolutions, inherited...)
}
func historyNodesWithin(limit int, baseline, input, final *document.Node, applications []historyApplication, resolutions []resolutionSnapshot, inherited ...*inheritanceScope) bool {
seen := make(map[*document.Node]bool)
count := 0
var visit func(*document.Node) bool
visit = func(node *document.Node) bool {
if node == nil || seen[node] {
return true
}
seen[node] = true
count++
if count > limit {
return false
}
for _, entry := range node.Mapping {
if !visit(entry.Value) {
return false
}
}
for _, child := range node.Sequence {
if !visit(child) {
return false
}
}
return true
}
if !visit(baseline) || !visit(input) || !visit(final) {
return false
}
for _, application := range applications {
if !visit(application.value) {
return false
}
}
for _, resolution := range resolutions {
if !visit(resolution.before) || !visit(resolution.after) {
return false
}
}
for _, expansion := range inherited {
if expansion == nil {
continue
}
if !visit(expansion.root) {
return false
}
for _, operation := range expansion.operations {
if !visit(operation.parent) || !visit(operation.effective) {
return false
}
}
for _, replacement := range expansion.replacements {
if !visit(replacement.before) || !visit(replacement.after) {
return false
}
}
}
return true
}