Publish inspection through one frozen history model

This commit is contained in:
2026-10-26 17:36:36 +00:00
parent 8155465322
commit 12fd0a7191
20 changed files with 203 additions and 247 deletions

View File

@@ -635,7 +635,10 @@ secret/diff integration tests.
## Stage 14 — Publish One Frozen History Owner ## Stage 14 — Publish One Frozen History Owner
Owners: `Inspection`, `prepareInspectionHistory`, `publishLoadResult`, Owners: `Inspection`, `prepareInspectionHistory`, `publishLoadResult`,
`Inspection.Metadata`, cloning and lookup setup. Status: pending. `Inspection.Metadata`, cloning and lookup setup. Status: complete. Validation:
`GOTOOLCHAIN=local GOPROXY=off GOTELEMETRY=off go test ./internal/engine -run 'Detached|Independent|ConcurrentReadOnly|History|Explain' -count=1`,
`GOTOOLCHAIN=local GOPROXY=off GOTELEMETRY=off go test -race ./internal/engine -run 'Detached|Independent|ConcurrentReadOnly|History|Explain' -count=1`,
`GOTOOLCHAIN=local GOPROXY=off GOTELEMETRY=off go test ./...`, and `git diff --check`.
1. Finish the model before publication, with eager indexes and final observations. 1. Finish the model before publication, with eager indexes and final observations.
Attach the same frozen owner to inspection and metadata. Remove independent Attach the same frozen owner to inspection and metadata. Remove independent

View File

@@ -34,11 +34,11 @@ func prepareDiffRegions(left, right *Inspection) ([]diffRegion, error) {
deltas := compareConfigurationValues(left.final, right.final) deltas := compareConfigurationValues(left.final, right.final)
regions := make([]diffRegion, 0, len(deltas)) regions := make([]diffRegion, 0, len(deltas))
for _, delta := range deltas { for _, delta := range deltas {
leftNode, leftPresent := documentAtPathWithLookup(left.final, delta.path, left.immutableLookup) leftNode, leftPresent := documentAtPathWithLookup(left.final, delta.path, left.documentLookup())
if !leftPresent { if !leftPresent {
leftNode = nil leftNode = nil
} }
rightNode, rightPresent := documentAtPathWithLookup(right.final, delta.path, right.immutableLookup) rightNode, rightPresent := documentAtPathWithLookup(right.final, delta.path, right.documentLookup())
if !rightPresent { if !rightPresent {
rightNode = nil rightNode = nil
} }

View File

@@ -53,7 +53,7 @@ func TestDiffUsesFinalValuesAndDependencyDerivedSensitivity(t *testing.T) {
!right.Inspection.secrets["/credential"] || !right.Inspection.secrets["/derived"] { !right.Inspection.secrets["/credential"] || !right.Inspection.secrets["/derived"] {
t.Fatalf("typed or dependency-derived sensitivity was not retained: left=%#v right=%#v", left.Inspection.secrets, right.Inspection.secrets) t.Fatalf("typed or dependency-derived sensitivity was not retained: left=%#v right=%#v", left.Inspection.secrets, right.Inspection.secrets)
} }
if node, present := documentAtPathWithLookup(left.Inspection.final, Keys("derived"), left.Inspection.immutableLookup); !present || node.Text != "before" { if node, present := documentAtPathWithLookup(left.Inspection.final, Keys("derived"), left.Inspection.documentLookup()); !present || node.Text != "before" {
t.Fatalf("left frozen derived value = %#v, present=%v", node, present) t.Fatalf("left frozen derived value = %#v, present=%v", node, present)
} }
@@ -138,10 +138,10 @@ func TestDiffUsesReferenceNamesAndFrozenSecretState(t *testing.T) {
if err != nil || len(differences) != 0 { if err != nil || len(differences) != 0 {
t.Fatalf("credential rotation behind one reference = %#v, err = %v", differences, err) t.Fatalf("credential rotation behind one reference = %#v, err = %v", differences, err)
} }
if node, present := documentAtPathWithLookup(left.Inspection.final, Keys("optional"), left.Inspection.immutableLookup); !present || node.Text != "DIFF_ROTATING_SECRET" { if node, present := documentAtPathWithLookup(left.Inspection.final, Keys("optional"), left.Inspection.documentLookup()); !present || node.Text != "DIFF_ROTATING_SECRET" {
t.Fatalf("frozen reference = %#v, present=%v", node, present) t.Fatalf("frozen reference = %#v, present=%v", node, present)
} }
if node, present := documentAtPathWithLookup(right.Inspection.final, Keys("optional"), right.Inspection.immutableLookup); !present || node.Text != "DIFF_ROTATING_SECRET" { if node, present := documentAtPathWithLookup(right.Inspection.final, Keys("optional"), right.Inspection.documentLookup()); !present || node.Text != "DIFF_ROTATING_SECRET" {
t.Fatalf("right frozen reference = %#v, present=%v", node, present) t.Fatalf("right frozen reference = %#v, present=%v", node, present)
} }
@@ -164,7 +164,7 @@ func TestDiffUsesReferenceNamesAndFrozenSecretState(t *testing.T) {
if absent.Config.Optional != nil { if absent.Config.Optional != nil {
t.Fatalf("missing optional reference decoded as %#v", absent.Config.Optional) t.Fatalf("missing optional reference decoded as %#v", absent.Config.Optional)
} }
if node, present := documentAtPathWithLookup(absent.Inspection.final, Keys("optional"), absent.Inspection.immutableLookup); !present || node.Kind != document.Null { if node, present := documentAtPathWithLookup(absent.Inspection.final, Keys("optional"), absent.Inspection.documentLookup()); !present || node.Kind != document.Null {
t.Fatalf("optional nil projection = %#v, present=%v", node, present) t.Fatalf("optional nil projection = %#v, present=%v", node, present)
} }
differences, err = Diff(absent.Inspection, left.Inspection) differences, err = Diff(absent.Inspection, left.Inspection)
@@ -210,7 +210,7 @@ func TestDiffProtectsHistoricalSensitiveRemovalAndReplacement(t *testing.T) {
if !left.Inspection.secrets[secretPath.String()] { if !left.Inspection.secrets[secretPath.String()] {
t.Fatal("removed historical selector was not retained") t.Fatal("removed historical selector was not retained")
} }
if _, present := documentAtPathWithLookup(left.Inspection.final, secretPath, left.Inspection.immutableLookup); present { if _, present := documentAtPathWithLookup(left.Inspection.final, secretPath, left.Inspection.documentLookup()); present {
t.Fatal("removed token remains in the effective left tree") t.Fatal("removed token remains in the effective left tree")
} }
differences, err := Diff(left.Inspection, right.Inspection) differences, err := Diff(left.Inspection, right.Inspection)

View File

@@ -127,7 +127,10 @@ type expectedDiffRegion struct {
} }
func diffTestInspection(root *document.Node) *Inspection { func diffTestInspection(root *document.Node) *Inspection {
return &Inspection{final: root, immutableLookup: buildDocumentLookup(root)} builder := newHistoryBuilder()
builder.model.final = root
model := builder.freeze()
return &Inspection{final: root, history: model, metadata: Metadata{historyModel: model}}
} }
func assertDiffRegionNode(t *testing.T, side string, node *document.Node, wantPresent bool, wantKind document.Kind) { func assertDiffRegionNode(t *testing.T, side string, node *document.Node, wantPresent bool, wantKind document.Kind) {

View File

@@ -40,7 +40,7 @@ func (r *Inspection) Explain(path Path) (Explanation, bool) {
if r == nil || r.final == nil || !path.valid() { if r == nil || r.final == nil || !path.valid() {
return Explanation{}, false return Explanation{}, false
} }
model := r.metadata.historyModel model := r.history
if model == nil { if model == nil {
return Explanation{}, false return Explanation{}, false
} }
@@ -48,7 +48,7 @@ func (r *Inspection) Explain(path Path) (Explanation, bool) {
if len(selections) == 0 && !model.hasObservedShape(path) { if len(selections) == 0 && !model.hasObservedShape(path) {
return Explanation{}, false return Explanation{}, false
} }
explanation := Explanation{Path: path.clone(), Effective: valueSnapshotWithLookup(r.final, path, r.secrets, r.immutableLookup)} explanation := Explanation{Path: path.clone(), Effective: valueSnapshotWithLookup(r.final, path, r.secrets, model.documentLookup)}
if info, ok := r.metadata.Lookup(path); ok { if info, ok := r.metadata.Lookup(path); ok {
explanation.Origin = cloneOrigin(info.Origin) explanation.Origin = cloneOrigin(info.Origin)
} }

View File

@@ -308,16 +308,28 @@ func TestSecretsBootstrapLoadAndExplanationRemainSeparateAndSafe(t *testing.T) {
func TestHistoryNodeBudgetCountsSharedTreesOnce(t *testing.T) { func TestHistoryNodeBudgetCountsSharedTreesOnce(t *testing.T) {
leaf := &document.Node{Kind: document.String, Text: "value"} leaf := &document.Node{Kind: document.String, Text: "value"}
root := &document.Node{Kind: document.Mapping, Mapping: []document.Entry{{Key: "value", Value: leaf}}} root := &document.Node{Kind: document.Mapping, Mapping: []document.Entry{{Key: "value", Value: leaf}}}
inspection := &Inspection{ builder := newHistoryBuilder()
baseline: root, input: root, final: root, builder.model.baseline = root
applications: []historyApplication{{layer: LayerBase, value: root}}, builder.model.final = root
} builder.model.sourcePayloads = []historySourcePayload{{
kind: historySourceApplicationPayload, application: historyApplication{layer: LayerBase, value: root},
}}
model := builder.freeze()
inspection := &Inspection{history: model, metadata: Metadata{historyModel: model}, final: root}
counter := newRetainedNodeCounter(2) counter := newRetainedNodeCounter(2)
if !addInspectionHistory(counter, inspection) || counter.count != 2 { if !addInspectionHistory(counter, inspection) || counter.count != 2 {
t.Fatal("structurally shared history was counted more than once") t.Fatal("structurally shared history was counted more than once")
} }
other := document.Clone(root) other := document.Clone(root)
inspection.input = other builder = newHistoryBuilder()
builder.model.baseline = root
builder.model.final = root
builder.model.sourcePayloads = []historySourcePayload{{
kind: historySourceApplicationPayload, application: historyApplication{layer: LayerBase, value: other},
}}
model = builder.freeze()
inspection.history = model
inspection.metadata.historyModel = model
counter = newRetainedNodeCounter(3) counter = newRetainedNodeCounter(3)
if addInspectionHistory(counter, inspection) { if addInspectionHistory(counter, inspection) {
t.Fatal("distinct retained nodes did not consume the budget") t.Fatal("distinct retained nodes did not consume the budget")
@@ -425,7 +437,7 @@ func TestIntegerVersionInspectionRetainsInputAndReconcilesTypedValue(t *testing.
if first.Config.Version != "4" || second.Config.Version != "4" { if first.Config.Version != "4" || second.Config.Version != "4" {
t.Fatalf("configurations = %#v / %#v", first.Config, second.Config) t.Fatalf("configurations = %#v / %#v", first.Config, second.Config)
} }
inputVersion, inputOK := documentAtPath(first.applications[0].value, Keys("version")) inputVersion, inputOK := documentAtPath(first.history.sourcePayloads[0].application.value, Keys("version"))
finalVersion, finalOK := documentAtPath(first.final, Keys("version")) finalVersion, finalOK := documentAtPath(first.final, Keys("version"))
if !inputOK || inputVersion.Kind != document.Number || inputVersion.Text != "4" || if !inputOK || inputVersion.Kind != document.Number || inputVersion.Text != "4" ||
!finalOK || finalVersion.Kind != document.String || finalVersion.Text != "4" { !finalOK || finalVersion.Kind != document.String || finalVersion.Text != "4" {

View File

@@ -85,36 +85,14 @@ func documentCloneNodeCount(root *document.Node, limit int) (int, bool) {
} }
func addInspectionHistory(counter *retainedNodeCounter, inspection *Inspection) bool { func addInspectionHistory(counter *retainedNodeCounter, inspection *Inspection) bool {
if inspection == nil { if inspection == nil || inspection.history == nil {
return false return false
} }
for _, root := range []*document.Node{inspection.baseline, inspection.input, inspection.final, inspection.preCLI} { for _, root := range inspection.history.documentRoots() {
if !counter.add(root) { if !counter.add(root) {
return false 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 _, snapshot := range inspection.resolution {
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 return true
} }

View File

@@ -22,21 +22,33 @@ type historyBudgetLayeredConfig struct {
func retainedInspectionNodeCountForTest(inspection *Inspection) int { func retainedInspectionNodeCountForTest(inspection *Inspection) int {
seen := make(map[*document.Node]struct{}) seen := make(map[*document.Node]struct{})
stack := []*document.Node{inspection.baseline, inspection.input, inspection.final, inspection.preCLI} model := inspection.history
for _, application := range inspection.applications { stack := []*document.Node{model.baseline, model.final}
stack = append(stack, application.value) for _, payload := range model.sourcePayloads {
if payload.kind == historySourceApplicationPayload {
stack = append(stack, payload.application.value)
}
} }
for _, application := range inspection.postDecodeApps { for _, payload := range model.inheritancePayloads {
stack = append(stack, application.value) for _, operation := range payload.operations {
stack = append(stack, operation.parent, operation.effective)
}
} }
for _, snapshot := range inspection.resolution { for _, payload := range model.cliPayloads {
stack = append(stack, snapshot.before, snapshot.after) if payload.kind == historySourceApplicationPayload {
stack = append(stack, payload.application.value)
}
} }
for _, operation := range inspection.inheritance { if model.preCLICheckpoint != nil {
stack = append(stack, operation.parent, operation.effective) stack = append(stack, model.preCLICheckpoint.root)
} }
for _, operation := range inspection.metadata.inheritance { if model.postCLICheckpoint != nil {
stack = append(stack, operation.parent, operation.effective) stack = append(stack, model.postCLICheckpoint.root)
}
if model.resolutionPayload != nil {
for _, snapshot := range model.resolutionPayload.snapshots {
stack = append(stack, snapshot.before, snapshot.after)
}
} }
for len(stack) != 0 { for len(stack) != 0 {
@@ -144,8 +156,8 @@ func TestLayeredHistoryBudgetRejectsBeforeSecretsAndValidation(t *testing.T) {
if want == 0 { if want == 0 {
t.Fatal("independent retained-tree count was empty") t.Fatal("independent retained-tree count was empty")
} }
if len(baseline.Inspection.inheritance) == 0 || len(baseline.Inspection.metadata.inheritance) == 0 { if baseline.Inspection.history == nil || baseline.Inspection.metadata.historyModel != baseline.Inspection.history || len(baseline.Inspection.history.inheritancePayloads) == 0 {
t.Fatal("layered load did not retain both inheritance evidence copies") t.Fatal("layered load did not publish its shared inheritance evidence owner")
} }
exactCounts := &callbackCounts{} exactCounts := &callbackCounts{}
loaded, err := loadGroupedWithSecretLookupLimit(makeRequest(exactCounts), testSecretBinding(), lookup(exactCounts), want) loaded, err := loadGroupedWithSecretLookupLimit(makeRequest(exactCounts), testSecretBinding(), lookup(exactCounts), want)
@@ -169,23 +181,46 @@ func TestLayeredHistoryBudgetRejectsBeforeSecretsAndValidation(t *testing.T) {
} }
} }
func TestPreparedInheritanceEvidenceOwnsDistinctTrees(t *testing.T) { func TestPreparedInheritanceEvidenceSharesOwnerAndDetachesPublicViews(t *testing.T) {
root := &document.Node{Kind: document.Mapping, Mapping: []document.Entry{{Key: "value", Value: &document.Node{Kind: document.String, Text: "shared"}}}} input := parseCompositionDocument(t, "inheritance", "parent: {value: shared}\nchild: {extends: parent}\n")
resolved := resolvedLoad[historyBudgetSimpleConfig]{ expanded, diagnostics := expandInheritanceWithOrigins(input, nil, defaultProjectionLimits())
inheritance: &inheritanceScope{operations: []inheritanceOperation{{parent: root, effective: root}}}, if len(diagnostics) != 0 {
t.Fatal(diagnostics)
} }
counter := newRetainedNodeCounter(8) baseline := &document.Node{Kind: document.Mapping}
builder := newHistoryBuilder()
builder.observeBaseline(baseline)
builder.setScratch(input)
builder.observeInheritanceEvidence(expanded.operations)
metadata := Metadata{historyBuilder: builder}
resolved := resolvedLoad[historyBudgetSimpleConfig]{
metadata: metadata, historyBuilder: builder, final: expanded.root,
decoded: decodedConfiguration{baseline: baseline}, structuralInput: input,
inheritance: expanded,
}
counter := newRetainedNodeCounter(100)
inspection, ok := prepareInspectionHistory(resolved, counter) inspection, ok := prepareInspectionHistory(resolved, counter)
if !ok { if !ok {
t.Fatal("preparation rejected the exact size of the distinct retained copies") t.Fatal("preparation rejected the shared evidence owner")
} }
if len(inspection.inheritance) != 1 || len(inspection.metadata.inheritance) != 1 { if inspection.history == nil || inspection.metadata.historyModel != inspection.history || len(inspection.history.inheritancePayloads) != 1 {
t.Fatalf("inheritance copies = inspection %#v, metadata %#v", inspection.inheritance, inspection.metadata.inheritance) t.Fatalf("history owners = inspection %p, metadata %p, inheritance payloads %d", inspection.history, inspection.metadata.historyModel, len(inspection.history.inheritancePayloads))
} }
inspectionOperation := inspection.inheritance[0] path := Keys("child", "value")
metadataOperation := inspection.metadata.inheritance[0] first := inspection.Metadata().History(path)
if inspectionOperation.parent == metadataOperation.parent || inspectionOperation.effective == metadataOperation.effective || counter.count != 8 { if len(first) == 0 {
t.Fatalf("separate inheritance copies were not counted independently: inspection=(%p, %p) metadata=(%p, %p) count=%d", inspectionOperation.parent, inspectionOperation.effective, metadataOperation.parent, metadataOperation.effective, counter.count) t.Fatal("metadata projection omitted inherited history")
}
first[0].Origin.Locations[0].SourceID = "mutated metadata result"
first[0].Dependencies[0].segments[0].key = "mutated metadata dependency"
if explanation, found := inspection.Explain(path); !found || len(explanation.History) == 0 || explanation.History[0].Origin.Locations[0].SourceID == "mutated metadata result" {
t.Fatalf("metadata result mutation leaked into explanation: %#v, %v", explanation, found)
}
explanation, _ := inspection.Explain(path)
explanation.History[0].Origin.Locations[0].SourceID = "mutated explanation result"
second := inspection.Metadata().History(path)
if second[0].Origin.Locations[0].SourceID == "mutated explanation result" || second[0].Dependencies[0].String() == "/mutated metadata dependency" {
t.Fatalf("explanation mutation leaked into metadata: %#v", second)
} }
} }

View File

@@ -59,7 +59,6 @@ type historyModel struct {
attributions []historyAttribution attributions []historyAttribution
baseline *document.Node baseline *document.Node
final *document.Node final *document.Node
inventoryRoots []*document.Node
sourcePayloads []historySourcePayload sourcePayloads []historySourcePayload
inheritancePayloads []historyInheritancePayload inheritancePayloads []historyInheritancePayload
cliPayloads []historySourcePayload cliPayloads []historySourcePayload
@@ -149,20 +148,12 @@ func (builder *historyBuilder) observeDocumentAt(root *document.Node, prefix Pat
if root == nil { if root == nil {
return return
} }
builder.registerDocumentRoot(root)
payload := builder.nextPayload(phase) payload := builder.nextPayload(phase)
walkDocument(root, prefix, func(path Path, node *document.Node) { walkDocument(root, prefix, func(path Path, node *document.Node) {
builder.addInventoryObservation(path, path, payload, phase, node.Sensitive) builder.addInventoryObservation(path, path, payload, phase, node.Sensitive)
}) })
} }
func (builder *historyBuilder) registerDocumentRoot(root *document.Node) {
builder.requireOpen()
if root != nil {
builder.model.inventoryRoots = append(builder.model.inventoryRoots, root)
}
}
func (builder *historyBuilder) addInventoryObservation(path, reportedPath Path, payload historyPayloadRef, phase historyPhase, sensitive bool) int { func (builder *historyBuilder) addInventoryObservation(path, reportedPath Path, payload historyPayloadRef, phase historyPhase, sensitive bool) int {
return builder.addObservation(historyObservation{ return builder.addObservation(historyObservation{
path: path, phase: phase, payload: payload, path: path, phase: phase, payload: payload,
@@ -204,32 +195,40 @@ func (model *historyModel) documentRoots() []*document.Node {
if model == nil { if model == nil {
return nil return nil
} }
roots := append([]*document.Node(nil), model.inventoryRoots...) var roots []*document.Node
roots = append(roots, model.baseline, model.final) appendRoot := func(root *document.Node) {
if root != nil {
roots = append(roots, root)
}
}
appendRoot(model.baseline)
appendRoot(model.final)
for _, payload := range model.sourcePayloads { for _, payload := range model.sourcePayloads {
if payload.kind == historySourceApplicationPayload { if payload.kind == historySourceApplicationPayload {
roots = append(roots, payload.application.value) appendRoot(payload.application.value)
} }
} }
for _, payload := range model.inheritancePayloads { for _, payload := range model.inheritancePayloads {
for _, operation := range payload.operations { for _, operation := range payload.operations {
roots = append(roots, operation.parent, operation.effective) appendRoot(operation.parent)
appendRoot(operation.effective)
} }
} }
for _, payload := range model.cliPayloads { for _, payload := range model.cliPayloads {
if payload.kind == historySourceApplicationPayload { if payload.kind == historySourceApplicationPayload {
roots = append(roots, payload.application.value) appendRoot(payload.application.value)
} }
} }
if model.preCLICheckpoint != nil { if model.preCLICheckpoint != nil {
roots = append(roots, model.preCLICheckpoint.root) appendRoot(model.preCLICheckpoint.root)
} }
if model.postCLICheckpoint != nil { if model.postCLICheckpoint != nil {
roots = append(roots, model.postCLICheckpoint.root) appendRoot(model.postCLICheckpoint.root)
} }
if model.resolutionPayload != nil { if model.resolutionPayload != nil {
for _, snapshot := range model.resolutionPayload.snapshots { for _, snapshot := range model.resolutionPayload.snapshots {
roots = append(roots, snapshot.before, snapshot.after) appendRoot(snapshot.before)
appendRoot(snapshot.after)
} }
} }
return roots return roots

View File

@@ -156,7 +156,7 @@ func TestHistorySelectionMatchesDeepSidesOfAncestorShapeChange(t *testing.T) {
} }
} }
func TestHistoryModelFinalizesLocationSensitivityAndDocumentReaders(t *testing.T) { func TestHistoryModelFinalizesLocationAndSensitivityWithoutRetainingInventoryTrees(t *testing.T) {
t.Parallel() t.Parallel()
root := parseDocumentForDecode(t, "shape: {'0': {value: old}}\n") root := parseDocumentForDecode(t, "shape: {'0': {value: old}}\n")
@@ -189,11 +189,11 @@ func TestHistoryModelFinalizesLocationSensitivityAndDocumentReaders(t *testing.T
}) })
model := builder.freeze() model := builder.freeze()
if got := model.documentRoots(); len(got) == 0 || got[0] != root { if got := model.documentRoots(); len(got) != 0 {
t.Fatalf("document roots = %#v, want registered root", got) t.Fatalf("inventory-only document was retained: %#v", got)
} }
if got, ok := model.documentAt(root, Keys("shape", "0")); !ok || got.Kind != document.Mapping { if got, ok := model.documentAt(root, Keys("shape", "0")); ok || got != nil {
t.Fatalf("indexed document lookup = %#v, %v", got, ok) t.Fatalf("lookup retained an inventory-only document = %#v, %v", got, ok)
} }
if got, ok := model.latestHistoricalLocation(keyPath); !ok || got.SourceID != "base.yml" || got.Line != 4 || got.Column != 2 { if got, ok := model.latestHistoricalLocation(keyPath); !ok || got.SourceID != "base.yml" || got.Line != 4 || got.Column != 2 {
t.Fatalf("latest historical location = %#v, %v", got, ok) t.Fatalf("latest historical location = %#v, %v", got, ok)
@@ -213,9 +213,6 @@ func TestHistoryModelFinalizesLocationSensitivityAndDocumentReaders(t *testing.T
if !sawCandidate { if !sawCandidate {
t.Fatal("sensitivity candidate omitted the concrete historical path") t.Fatal("sensitivity candidate omitted the concrete historical path")
} }
if got, found := model.documentAt(root, Keys("shape", "missing")); found || got != nil {
t.Fatalf("lookup for missing value = %#v, %v", got, found)
}
} }
func TestHistoryBuilderScratchUsesOneDetachedWorkingDocument(t *testing.T) { func TestHistoryBuilderScratchUsesOneDetachedWorkingDocument(t *testing.T) {

View File

@@ -278,14 +278,13 @@ func TestProjectedSequenceHistoryAgreesAcrossMetadataAndExplanation(t *testing.T
t.Fatalf("projected metadata omitted shifted path %s: %#v", path, metadata.HistoricalPaths()) t.Fatalf("projected metadata omitted shifted path %s: %#v", path, metadata.HistoricalPaths())
} }
inspection := &Inspection{ baseline := &document.Node{Kind: document.Mapping}
metadata: metadata, baseline: &document.Node{Kind: document.Mapping}, model := sourceHistoryModelForInspection(baseline, composed.root, composed.origins, composed.applications, composed.overlays)
input: composed.root, preCLI: composed.root, final: composed.root, applications: composed.applications, metadata.historyModel = model
} inspection := &Inspection{metadata: metadata, history: model, final: composed.root}
inspection.metadata.historyModel = sourceHistoryModelForInspection(inspection.baseline, composed.root, composed.origins, composed.applications, composed.overlays)
inspection.secrets = classifySecretPaths(nil, func(candidate Path) bool { inspection.secrets = classifySecretPaths(nil, func(candidate Path) bool {
return reflect.DeepEqual(candidate, path) return reflect.DeepEqual(candidate, path)
}, metadata, composed.root, composed.applications) }, metadata, composed.root, nil)
explanation, ok := inspection.Explain(path) explanation, ok := inspection.Explain(path)
if !ok || !explanation.Effective.Redacted { if !ok || !explanation.Effective.Redacted {
t.Fatalf("shifted explanation = %#v, %v", explanation, ok) t.Fatalf("shifted explanation = %#v, %v", explanation, ok)
@@ -326,14 +325,13 @@ func TestReplacedProjectedSensitiveRecordRemainsRedacted(t *testing.T) {
path := Keys("records").Index(1).Key("token") path := Keys("records").Index(1).Key("token")
var metadata Metadata var metadata Metadata
finalizeMetadataPaths(&metadata, final, applications) finalizeMetadataPaths(&metadata, final, applications)
inspection := &Inspection{ baseline := &document.Node{Kind: document.Mapping}
metadata: metadata, baseline: &document.Node{Kind: document.Mapping}, model := sourceHistoryModelForInspection(baseline, final, nil, applications, nil)
input: final, preCLI: final, final: final, applications: applications, metadata.historyModel = model
} inspection := &Inspection{metadata: metadata, history: model, final: final}
inspection.metadata.historyModel = sourceHistoryModelForInspection(inspection.baseline, final, nil, applications, nil)
inspection.secrets = classifySecretPaths(nil, func(candidate Path) bool { inspection.secrets = classifySecretPaths(nil, func(candidate Path) bool {
return reflect.DeepEqual(candidate, path) return reflect.DeepEqual(candidate, path)
}, metadata, final, applications) }, metadata, final, nil)
explanation, ok := inspection.Explain(path) explanation, ok := inspection.Explain(path)
if !ok || explanation.Effective.Present { if !ok || explanation.Effective.Present {
t.Fatalf("replaced shifted record explanation = %#v, %v", explanation, ok) t.Fatalf("replaced shifted record explanation = %#v, %v", explanation, ok)
@@ -353,7 +351,6 @@ func sourceHistoryModelForInspection(baseline, final *document.Node, origins map
builder.setScratch(baseline) builder.setScratch(baseline)
builder.observeSourceEvidence(final, origins, applications, records) builder.observeSourceEvidence(final, origins, applications, records)
builder.model.final = final builder.model.final = final
builder.registerDocumentRoot(final)
return builder.freeze() return builder.freeze()
} }
@@ -409,12 +406,12 @@ func TestMappedUpsertProjectsSensitiveReplacementEvidence(t *testing.T) {
var metadata Metadata var metadata Metadata
finalizeMetadataPaths(&metadata, finalRoot, applications) finalizeMetadataPaths(&metadata, finalRoot, applications)
inspection := &Inspection{ baseline := &document.Node{Kind: document.Mapping}
metadata: metadata, baseline: &document.Node{Kind: document.Mapping}, model := sourceHistoryModelForInspection(baseline, finalRoot, nil, applications, nil)
input: finalRoot, preCLI: finalRoot, final: finalRoot, applications: applications, metadata.historyModel = model
} inspection := &Inspection{metadata: metadata, history: model, final: finalRoot}
secretRule := func(candidate Path) bool { return reflect.DeepEqual(candidate, secretPath) } secretRule := func(candidate Path) bool { return reflect.DeepEqual(candidate, secretPath) }
inspection.secrets = classifySecretPaths(nil, secretRule, metadata, finalRoot, applications) inspection.secrets = classifySecretPaths(nil, secretRule, metadata, finalRoot, nil)
explanation, ok := inspection.Explain(secretPath) explanation, ok := inspection.Explain(secretPath)
if !ok || !explanation.Effective.Redacted { if !ok || !explanation.Effective.Redacted {
t.Fatalf("mapped replacement explanation = %#v, %v", explanation, ok) t.Fatalf("mapped replacement explanation = %#v, %v", explanation, ok)

View File

@@ -35,7 +35,6 @@ func (builder *historyBuilder) observeBaseline(root *document.Node) {
return return
} }
builder.model.baseline = root builder.model.baseline = root
builder.registerDocumentRoot(root)
payload := builder.nextPayload(historyPhaseBaseline) payload := builder.nextPayload(historyPhaseBaseline)
defaultAttribution := builder.addAttribution(Origin{Layer: LayerDefault}, nil, nil) defaultAttribution := builder.addAttribution(Origin{Layer: LayerDefault}, nil, nil)
walkDocument(root, Path{}, func(path Path, node *document.Node) { walkDocument(root, Path{}, func(path Path, node *document.Node) {

View File

@@ -41,7 +41,6 @@ func TestHistorySourceObservationsPreserveRawAndCompositeDefinitions(t *testing.
builder.observeBaseline(baseline) builder.observeBaseline(baseline)
builder.observeSourceEvidence(assembly.current.root, assembly.current.origins, assembly.current.applications, assembly.current.overlays) builder.observeSourceEvidence(assembly.current.root, assembly.current.origins, assembly.current.applications, assembly.current.overlays)
builder.model.final = assembly.current.root builder.model.final = assembly.current.root
builder.registerDocumentRoot(assembly.current.root)
model := builder.freeze() model := builder.freeze()
defaultPath := Keys("defaults", "nullable") defaultPath := Keys("defaults", "nullable")
@@ -99,8 +98,7 @@ func TestHistorySourceObservationsPreserveRawAndCompositeDefinitions(t *testing.
} }
} }
inspection := &Inspection{ inspection := &Inspection{
metadata: metadata, baseline: baseline, final: assembly.current.root, metadata: metadata, history: model, final: assembly.current.root,
immutableLookup: buildDocumentLookup(assembly.current.root),
} }
explanation, explained := inspection.Explain(Keys("section", "empty")) explanation, explained := inspection.Explain(Keys("section", "empty"))
var contributionSources []string var contributionSources []string

View File

@@ -128,12 +128,18 @@ func inheritanceInspectionFromComposition(t *testing.T, composed *composedDocume
applyInheritanceMetadata(&metadata, composed.root, composed.origins, composed.overlays, expanded) applyInheritanceMetadata(&metadata, composed.root, composed.origins, composed.overlays, expanded)
metadata.historyBuilder.setScratch(composed.root) metadata.historyBuilder.setScratch(composed.root)
metadata.historyBuilder.observeInheritanceEvidence(expanded.operations) metadata.historyBuilder.observeInheritanceEvidence(expanded.operations)
metadata.inheritance = cloneInheritanceOperations(expanded.operations) final := expanded.root
finalizeMetadataPathsWithResolution(&metadata, expanded.root, composed.applications, snapshots, baseline, composed.root, expanded.root) if len(snapshots) != 0 {
final = document.Clone(expanded.root)
for _, group := range coalescedResolutionSnapshots(snapshots) {
if group.coveringRecordID >= 0 && group.coveringRecordID < len(snapshots) {
replaceHistoryPath(&final, group.change.Path, snapshots[group.coveringRecordID].after)
}
}
}
finalizeMetadataPathsWithResolution(&metadata, final, composed.applications, snapshots, baseline, composed.root, expanded.root)
return &Inspection{ return &Inspection{
metadata: metadata, baseline: baseline, input: expanded.root, preCLI: expanded.root, metadata: metadata, history: metadata.historyModel, final: final,
inputOrigins: expanded.origins, final: expanded.root,
applications: composed.applications, inheritance: expanded.operations,
}, expanded }, expanded
} }
@@ -323,8 +329,8 @@ func TestIndexedInheritanceHistoryMatchesOperationScan(t *testing.T) {
parseCompositionDocument(t, "source-2", "child: {extends: parent, branch: replaced}\n"), parseCompositionDocument(t, "source-2", "child: {extends: parent, branch: replaced}\n"),
parseCompositionDocument(t, "source-3", "sibling: {extends: parent}\n")) parseCompositionDocument(t, "source-3", "sibling: {extends: parent}\n"))
metadata := inspection.Metadata() metadata := inspection.Metadata()
if len(metadata.inheritance) < 4 { if inspection.history == nil || len(inspection.history.inheritancePayloads) == 0 || len(inspection.history.inheritancePayloads[0].operations) < 4 {
t.Fatalf("inheritance operations = %d, want multiple control and transfer scopes", len(metadata.inheritance)) t.Fatalf("inheritance operations = %#v, want multiple control and transfer scopes", inspection.history)
} }
queries := []Path{ queries := []Path{
Keys("child"), Keys("child"),
@@ -372,11 +378,6 @@ func TestInheritanceHistoryPrecedesApplicationResolution(t *testing.T) {
after: replacement, after: replacement,
} }
inspection, _ := inheritanceInspectionFromComposition(t, composed, snapshot) inspection, _ := inheritanceInspectionFromComposition(t, composed, snapshot)
final := document.Clone(inspection.final)
replaceHistoryPath(&final, path, replacement)
inspection.final = final
inspection.resolution = []resolutionSnapshot{snapshot}
inspection.resolutionReplay = coalescedResolutionSnapshots(inspection.resolution)
inspection.metadata.fields[path.String()] = FieldInfo{Explicit: true, Origin: snapshot.change.Origin} inspection.metadata.fields[path.String()] = FieldInfo{Explicit: true, Origin: snapshot.change.Origin}
history := inspection.Metadata().History(path) history := inspection.Metadata().History(path)
if len(history) < 2 || history[len(history)-2].Origin.Operation != ChangeInheritance || if len(history) < 2 || history[len(history)-2].Origin.Operation != ChangeInheritance ||
@@ -390,17 +391,24 @@ func TestInheritanceHistoryPrecedesApplicationResolution(t *testing.T) {
} }
} }
func TestHistoryNodeBudgetCountsSharedInheritanceEvidenceOnce(t *testing.T) { func TestHistoryNodeBudgetCountsSharedInheritanceRootsOnce(t *testing.T) {
shared := &document.Node{Kind: document.String, Text: "shared"} shared := &document.Node{Kind: document.String, Text: "shared"}
extra := &document.Node{Kind: document.String, Text: "extra"} extra := &document.Node{Kind: document.String, Text: "extra"}
inspection := &Inspection{ operation := inheritanceOperation{parent: shared, effective: shared}
inheritance: []inheritanceOperation{{parent: shared, effective: shared}}, builder := newHistoryBuilder()
metadata: Metadata{inheritance: []inheritanceOperation{{parent: shared, effective: extra}}}, builder.observeInheritanceEvidence([]inheritanceOperation{operation})
} model := builder.freeze()
inspection := &Inspection{history: model, metadata: Metadata{historyModel: model}}
counter := newRetainedNodeCounter(2) counter := newRetainedNodeCounter(2)
if !addInspectionHistory(counter, inspection) || counter.count != 2 { if !addInspectionHistory(counter, inspection) || counter.count != 2 {
t.Fatal("shared evidence node accounting is incorrect") t.Fatal("shared evidence node accounting is incorrect")
} }
operation.effective = extra
builder = newHistoryBuilder()
builder.observeInheritanceEvidence([]inheritanceOperation{operation})
model = builder.freeze()
inspection.history = model
inspection.metadata.historyModel = model
counter = newRetainedNodeCounter(1) counter = newRetainedNodeCounter(1)
if addInspectionHistory(counter, inspection) { if addInspectionHistory(counter, inspection) {
t.Fatal("distinct inheritance evidence did not consume the budget") t.Fatal("distinct inheritance evidence did not consume the budget")

View File

@@ -15,7 +15,7 @@ func TestInheritanceSensitivityFollowsCopiesWithoutMaskingNeighbors(t *testing.T
inspection, _ := inheritanceInspectionForTest(t, input) inspection, _ := inheritanceInspectionForTest(t, input)
inspection.secrets = classifySecretPaths(nil, func(path Path) bool { inspection.secrets = classifySecretPaths(nil, func(path Path) bool {
return path.String() == classified.String() return path.String() == classified.String()
}, inspection.metadata, inspection.final, inspection.applications, inspection.input) }, inspection.metadata, inspection.final, nil)
for _, path := range []Path{Keys("parent", "token"), Keys("child", "token"), Keys("next", "token"), Keys("other", "token")} { for _, path := range []Path{Keys("parent", "token"), Keys("child", "token"), Keys("next", "token"), Keys("other", "token")} {
explanation, found := inspection.Explain(path) explanation, found := inspection.Explain(path)
if !found || !explanation.Effective.Redacted || strings.Contains(explanation.Effective.YAML, canary) { if !found || !explanation.Effective.Redacted || strings.Contains(explanation.Effective.YAML, canary) {
@@ -44,7 +44,7 @@ func TestInheritanceSensitivityPreservesDisplacedHistoryAndControl(t *testing.T)
inspection, _ := inheritanceInspectionForTest(t, parseCompositionDocument(t, "source-1", "parent: {branch: {token: "+canary+"}}\nchild: {extends: parent, branch: public}\n")) inspection, _ := inheritanceInspectionForTest(t, parseCompositionDocument(t, "source-1", "parent: {branch: {token: "+canary+"}}\nchild: {extends: parent, branch: public}\n"))
inspection.secrets = classifySecretPaths(nil, func(path Path) bool { inspection.secrets = classifySecretPaths(nil, func(path Path) bool {
return path.String() == Keys("parent", "branch", "token").String() || path.String() == Keys("child", inheritanceKey).String() return path.String() == Keys("parent", "branch", "token").String() || path.String() == Keys("child", inheritanceKey).String()
}, inspection.metadata, inspection.final, inspection.applications, inspection.input) }, inspection.metadata, inspection.final, nil)
path := Keys("child", "branch", "token") path := Keys("child", "branch", "token")
explanation, found := inspection.Explain(path) explanation, found := inspection.Explain(path)
if !found || explanation.Effective.Present { if !found || explanation.Effective.Present {
@@ -85,7 +85,7 @@ func TestInheritanceSensitivityIncludesSchemaTaggedSource(t *testing.T) {
t.Fatal(issue) t.Fatal(issue)
} }
inspection, _ := inheritanceInspectionForTest(t, parseCompositionDocument(t, "source-1", "parent: {token: TAGGED-CANARY}\nchild: {extends: parent}\n")) inspection, _ := inheritanceInspectionForTest(t, parseCompositionDocument(t, "source-1", "parent: {token: TAGGED-CANARY}\nchild: {extends: parent}\n"))
inspection.secrets = classifySecretPaths(schema, nil, inspection.metadata, inspection.final, inspection.applications, inspection.input) inspection.secrets = classifySecretPaths(schema, nil, inspection.metadata, inspection.final, nil)
child, found := inspection.Explain(Keys("child", "token")) child, found := inspection.Explain(Keys("child", "token"))
if !found || !child.Effective.Redacted || strings.Contains(child.Effective.YAML, "TAGGED-CANARY") { if !found || !child.Effective.Redacted || strings.Contains(child.Effective.YAML, "TAGGED-CANARY") {
t.Fatalf("tagged source copy = %#v, %v", child, found) t.Fatalf("tagged source copy = %#v, %v", child, found)
@@ -104,7 +104,7 @@ func TestSourceVersionEvidenceSensitivityFollowsInheritanceAndDisplacedHistory(t
} }
inspection.secrets = classifySecretPathsWithEvidence(nil, func(path Path) bool { inspection.secrets = classifySecretPathsWithEvidence(nil, func(path Path) bool {
return path.String() == secretPath.String() return path.String() == secretPath.String()
}, inspection.metadata, inspection.final, inspection.applications, []*sourceVersionEvidence{evidence}, inspection.input) }, inspection.metadata, inspection.final, nil, []*sourceVersionEvidence{evidence})
path := Keys("child", "branch", "token") path := Keys("child", "branch", "token")
explanation, found := inspection.Explain(path) explanation, found := inspection.Explain(path)
@@ -162,7 +162,7 @@ func TestInheritedSecretReferencesResolveOnlyAfterExpansion(t *testing.T) {
t.Fatalf("inherited reference resolution = %#v, %d", resolved.diagnostics, lookupCount) t.Fatalf("inherited reference resolution = %#v, %d", resolved.diagnostics, lookupCount)
} }
inspection, _ := inheritanceInspectionFromComposition(t, composed) inspection, _ := inheritanceInspectionFromComposition(t, composed)
inspection.secrets = classifySecretPaths(schema, nil, inspection.metadata, inspection.final, inspection.applications, inspection.input) inspection.secrets = classifySecretPaths(schema, nil, inspection.metadata, inspection.final, nil)
var rendered bytes.Buffer var rendered bytes.Buffer
if err := inspection.WriteEffective(&rendered); err != nil || strings.Contains(rendered.String(), "RESOLVED-CREDENTIAL-CANARY") { if err := inspection.WriteEffective(&rendered); err != nil || strings.Contains(rendered.String(), "RESOLVED-CREDENTIAL-CANARY") {
t.Fatalf("reference rendering = %q, %v", rendered.String(), err) t.Fatalf("reference rendering = %q, %v", rendered.String(), err)

View File

@@ -87,25 +87,22 @@ type Loaded[T any] struct {
// Inspection owns frozen load snapshots and detached query state. // Inspection owns frozen load snapshots and detached query state.
type Inspection struct { type Inspection struct {
metadata Metadata metadata Metadata
history *historyModel
sources []SourceInfo sources []SourceInfo
contexts map[string]ResourceContext contexts map[string]ResourceContext
diagnostics []Diagnostic diagnostics []Diagnostic
baseline *document.Node
input *document.Node
inputOrigins map[string]Origin
preCLI *document.Node
preCLIOrigins map[string]Origin
postDecodeApps []historyApplication
final *document.Node final *document.Node
immutableLookup *documentLookup
resolution []resolutionSnapshot
resolutionReplay []resolutionReplayGroup
applications []historyApplication
inheritance []inheritanceOperation
secrets map[string]bool secrets map[string]bool
secretReferences map[string]string secretReferences map[string]string
} }
func (r *Inspection) documentLookup() *documentLookup {
if r == nil || r.history == nil {
return nil
}
return r.history.documentLookup
}
// Metadata returns detached effective presence, origin, and history records. // Metadata returns detached effective presence, origin, and history records.
func (r *Inspection) Metadata() Metadata { func (r *Inspection) Metadata() Metadata {
if r == nil { if r == nil {
@@ -321,14 +318,6 @@ func executeLoadRequest[T any](request loadRequest[T], secrets SecretBinding, lo
accumulator.add(Diagnostic{Code: CodeExplainLimitExceeded, Severity: SeverityError, Message: "retained configuration history exceeds the node limit"}) accumulator.add(Diagnostic{Code: CodeExplainLimitExceeded, Severity: SeverityError, Message: "retained configuration history exceeds the node limit"})
return nil, accumulator.loadError() return nil, accumulator.loadError()
} }
historyApplications := make([]historyApplication, 0, len(inspection.applications)+len(inspection.postDecodeApps))
historyApplications = append(historyApplications, inspection.applications...)
historyApplications = append(historyApplications, inspection.postDecodeApps...)
if !addInspectionHistory(counter, inspection) {
accumulator.add(Diagnostic{Code: CodeExplainLimitExceeded, Severity: SeverityError, Message: "retained configuration history exceeds the node limit"})
return nil, accumulator.loadError()
}
// Detach resolver-borrowed values before reference mutation or validation. // Detach resolver-borrowed values before reference mutation or validation.
configuration, ownershipIssue := detachLoadConfiguration(schema, resolved.configuration, cloneUnresolvedSecrets) configuration, ownershipIssue := detachLoadConfiguration(schema, resolved.configuration, cloneUnresolvedSecrets)
if ownershipIssue != nil { if ownershipIssue != nil {
@@ -355,5 +344,5 @@ func executeLoadRequest[T any](request loadRequest[T], secrets SecretBinding, lo
resolved.configuration = configuration resolved.configuration = configuration
// Publication detaches equal-valued validator replacements, preserving the // Publication detaches equal-valued validator replacements, preserving the
// validated secret state, then finalizes metadata and sensitivity. // validated secret state, then finalizes metadata and sensitivity.
return publishLoadResult(schema, request.definition, resolved, inspection, historyApplications, secretResolution.references, &accumulator) return publishLoadResult(schema, request.definition, resolved, inspection, secretResolution.references, &accumulator)
} }

View File

@@ -82,7 +82,6 @@ func resolveLoadInput[T any](schema *schemaDescriptor, definition Definition[T],
} }
if builder != nil { if builder != nil {
builder.model.final = final builder.model.final = final
builder.registerDocumentRoot(final)
} }
if refreshReferenceInput { if refreshReferenceInput {
referenceInput = documentWithMetadataLocations(final, metadata, input.document) referenceInput = documentWithMetadataLocations(final, metadata, input.document)
@@ -120,44 +119,24 @@ func prepareInspectionHistory[T any](resolved resolvedLoad[T], counter *retained
metadata := resolved.metadata metadata := resolved.metadata
if resolved.historyBuilder != nil { if resolved.historyBuilder != nil {
metadata.historyBuilder = resolved.historyBuilder metadata.historyBuilder = resolved.historyBuilder
} else if resolved.inheritance != nil {
builder := newHistoryBuilder()
if resolved.decoded.baseline != nil {
builder.observeBaseline(resolved.decoded.baseline)
}
builder.setScratch(resolved.final)
builder.observeInheritanceEvidence(resolved.inheritance.operations)
metadata.historyBuilder = builder
} }
metadata.inheritance = nil finalizeMetadataPathsWithResolution(
&metadata, resolved.final, resolved.applications, resolved.snapshots,
resolved.decoded.baseline, resolved.structuralInput, resolved.preCLI, resolved.decoded.final,
)
model := metadata.historyModel
inspection := &Inspection{ inspection := &Inspection{
metadata: metadata, metadata: metadata,
baseline: resolved.decoded.baseline, history: model,
input: resolved.decoded.final, final: resolved.final,
inputOrigins: cloneOriginIndex(resolved.decoded.origins),
preCLI: resolved.preCLI,
preCLIOrigins: cloneOrigins(resolved.preCLIOrigins),
final: resolved.final,
resolution: resolved.snapshots,
resolutionReplay: coalescedResolutionSnapshots(resolved.snapshots),
}
if !addInspectionHistory(counter, inspection) {
return nil, false
}
var ok bool
inspection.applications, ok = cloneHistoryApplicationsWithinLimit(resolved.applications, counter)
if !ok {
return nil, false
}
inspection.postDecodeApps, ok = cloneHistoryApplicationsWithinLimit(resolved.postDecodeApps, counter)
if !ok {
return nil, false
}
if resolved.inheritance != nil {
roots := inheritanceOperationDocumentRoots(resolved.inheritance.operations)
if !counter.canAddClones(roots, 2) {
return nil, false
}
inspection.metadata.inheritance = cloneInheritanceOperations(resolved.inheritance.operations)
if !addInheritanceOperationDocuments(counter, inspection.metadata.inheritance) {
return nil, false
}
inspection.inheritance = cloneInheritanceOperations(resolved.inheritance.operations)
if !addInheritanceOperationDocuments(counter, inspection.inheritance) {
return nil, false
}
} }
if !addInspectionHistory(counter, inspection) { if !addInspectionHistory(counter, inspection) {
return nil, false return nil, false
@@ -165,33 +144,7 @@ func prepareInspectionHistory[T any](resolved resolvedLoad[T], counter *retained
return inspection, true return inspection, true
} }
func cloneHistoryApplicationsWithinLimit(values []historyApplication, counter *retainedNodeCounter) ([]historyApplication, bool) { func publishLoadResult[T any](schema *schemaDescriptor, definition Definition[T], resolved resolvedLoad[T], inspection *Inspection, references map[string]string, accumulator *diagnosticAccumulator) (*Loaded[T], error) {
for _, value := range values {
if !counter.add(value.value) {
return nil, false
}
}
return cloneHistoryApplications(values), true
}
func inheritanceOperationDocumentRoots(operations []inheritanceOperation) []*document.Node {
roots := make([]*document.Node, 0, len(operations)*2)
for _, operation := range operations {
roots = append(roots, operation.parent, operation.effective)
}
return roots
}
func addInheritanceOperationDocuments(counter *retainedNodeCounter, operations []inheritanceOperation) bool {
for _, operation := range operations {
if !counter.add(operation.parent) || !counter.add(operation.effective) {
return false
}
}
return true
}
func publishLoadResult[T any](schema *schemaDescriptor, definition Definition[T], resolved resolvedLoad[T], inspection *Inspection, applications []historyApplication, references map[string]string, accumulator *diagnosticAccumulator) (*Loaded[T], error) {
// A read-only validator can replace a value with an equal borrowed object. // A read-only validator can replace a value with an equal borrowed object.
// Detach without re-reading the environment or discarding validated state. // Detach without re-reading the environment or discarding validated state.
configuration, issue := detachLoadConfiguration(schema, resolved.configuration, cloneValidatedSecrets) configuration, issue := detachLoadConfiguration(schema, resolved.configuration, cloneValidatedSecrets)
@@ -199,21 +152,13 @@ func publishLoadResult[T any](schema *schemaDescriptor, definition Definition[T]
accumulator.add(*issue) accumulator.add(*issue)
return nil, accumulator.loadError() return nil, accumulator.loadError()
} }
decoded := resolved.decoded metadata, final := inspection.metadata, inspection.final
metadata, final, preCLI := inspection.metadata, inspection.final, inspection.preCLI secrets := classifySecretPathsWithEvidence(schema, definition.Secret, metadata, final, nil, resolved.versionEvidence)
finalizeMetadataPathsWithResolution(&metadata, final, applications, resolved.snapshots, decoded.baseline, resolved.structuralInput, resolved.preCLI, decoded.final)
secrets := classifySecretPathsWithEvidence(schema, definition.Secret, metadata, final, applications, resolved.versionEvidence, decoded.baseline, resolved.structuralInput, resolved.preCLI, decoded.final)
sources := sourceInfosWithVersionEvidence(accumulator.sources, resolved.versionEvidence, secrets, false) sources := sourceInfosWithVersionEvidence(accumulator.sources, resolved.versionEvidence, secrets, false)
retainedTrees := make([]*document.Node, 0, len(applications)+4)
retainedTrees = append(retainedTrees, decoded.final, final, preCLI)
for _, application := range applications {
retainedTrees = append(retainedTrees, application.value)
}
inspection.metadata = metadata inspection.metadata = metadata
inspection.sources = sources inspection.sources = sources
inspection.contexts = cloneResourceContexts(resolved.contexts) inspection.contexts = cloneResourceContexts(resolved.contexts)
inspection.diagnostics = canonicalDiagnostics(accumulator.diagnostics) inspection.diagnostics = canonicalDiagnostics(accumulator.diagnostics)
inspection.immutableLookup = buildDocumentLookup(retainedTrees...)
inspection.secrets = secrets inspection.secrets = secrets
inspection.secretReferences = cloneSecretReferences(references) inspection.secretReferences = cloneSecretReferences(references)
return &Loaded[T]{Config: configuration, Inspection: inspection}, nil return &Loaded[T]{Config: configuration, Inspection: inspection}, nil

View File

@@ -171,7 +171,6 @@ func finalizeMetadataPathsWithResolution(m *Metadata, final *document.Node, appl
} }
if builder.model.final != final { if builder.model.final != final {
builder.model.final = final builder.model.final = final
builder.registerDocumentRoot(final)
} }
m.historyModel = builder.freeze() m.historyModel = builder.freeze()
m.historyBuilder = nil m.historyBuilder = nil
@@ -200,7 +199,6 @@ func finalizeMetadataPathsWithResolution(m *Metadata, final *document.Node, appl
builder.observeDocument(final, historyPhasePostCLI) builder.observeDocument(final, historyPhasePostCLI)
} }
for _, application := range applications { for _, application := range applications {
builder.registerDocumentRoot(application.value)
phase := historyPhaseSources phase := historyPhaseSources
if application.layer == LayerCLI { if application.layer == LayerCLI {
phase = historyPhaseCLI phase = historyPhaseCLI
@@ -219,8 +217,6 @@ func finalizeMetadataPathsWithResolution(m *Metadata, final *document.Node, appl
if operation.transfer == nil { if operation.transfer == nil {
continue continue
} }
builder.registerDocumentRoot(operation.parent)
builder.registerDocumentRoot(operation.effective)
for _, root := range []*document.Node{operation.parent, operation.effective} { for _, root := range []*document.Node{operation.parent, operation.effective} {
walkDocument(root, operation.transfer.to, func(path Path, node *document.Node) { walkDocument(root, operation.transfer.to, func(path Path, node *document.Node) {
builder.addInventoryObservation(path, path, payload, historyPhaseInheritance, node.Sensitive) builder.addInventoryObservation(path, path, payload, historyPhaseInheritance, node.Sensitive)

View File

@@ -117,13 +117,7 @@ func TestPostDecodeOverrideContextOrdersDecodeCLIAndResolutionEvidence(t *testin
finalizeMetadataPaths(&prepared.metadata, assigned.final, prepared.historyApplications(), decoded.baseline, prepared.structuralInput, prepared.preCLI, assigned.final) finalizeMetadataPaths(&prepared.metadata, assigned.final, prepared.historyApplications(), decoded.baseline, prepared.structuralInput, prepared.preCLI, assigned.final)
inspection := Inspection{ inspection := Inspection{
metadata: prepared.metadata, baseline: decoded.baseline, input: assigned.final, inputOrigins: assigned.origins, metadata: prepared.metadata, history: prepared.metadata.historyModel, final: assigned.final,
preCLI: prepared.preCLI, preCLIOrigins: prepared.preCLIOrigins,
postDecodeApps: prepared.postDecodeApps, final: assigned.final,
applications: prepared.applications,
immutableLookup: buildDocumentLookup(prepared.preCLI, assigned.final,
prepared.applications[0].value, prepared.postDecodeApps[0].value, prepared.postDecodeApps[1].value,
prepared.postDecodeApps[2].value, prepared.postDecodeApps[3].value),
} }
rateExplanation, ok := inspection.Explain(Keys("rate")) rateExplanation, ok := inspection.Explain(Keys("rate"))
if !ok { if !ok {

View File

@@ -76,8 +76,9 @@ func TestLoadRunsRecordedResolutionWithMapWriteback(t *testing.T) {
"/artifacts/first/output", "/artifacts/first/timeout", "/artifacts/first/output", "/artifacts/first/timeout",
"/artifacts/second/output", "/artifacts/second/timeout", "/timeout", "/artifacts/second/output", "/artifacts/second/timeout", "/timeout",
} }
gotOrder := make([]string, len(result.resolution)) snapshots := result.history.resolutionPayload.snapshots
for index, snapshot := range result.resolution { gotOrder := make([]string, len(snapshots))
for index, snapshot := range snapshots {
gotOrder[index] = snapshot.change.Path.String() gotOrder[index] = snapshot.change.Path.String()
} }
if !reflect.DeepEqual(gotOrder, wantOrder) { if !reflect.DeepEqual(gotOrder, wantOrder) {
@@ -179,11 +180,12 @@ func TestResolutionContainerRecordCoversSubtreeRemovalAndSnapshotsAreDetached(t
if _, ok := result.Metadata().Lookup(Keys("items", "remove")); ok { if _, ok := result.Metadata().Lookup(Keys("items", "remove")); ok {
t.Fatal("removed entry remains effective metadata") t.Fatal("removed entry remains effective metadata")
} }
if len(result.resolution) != 1 || result.resolution[0].before == nil || result.resolution[0].after == nil { snapshots := result.history.resolutionPayload.snapshots
t.Fatalf("snapshots = %#v", result.resolution) if len(snapshots) != 1 || snapshots[0].before == nil || snapshots[0].after == nil {
t.Fatalf("snapshots = %#v", snapshots)
} }
result.Config.Items["keep"] = item{Value: "changed"} result.Config.Items["keep"] = item{Value: "changed"}
if mappingValue(t, result.resolution[0].after, "keep").Mapping[0].Value.Text != "yes" { if mappingValue(t, snapshots[0].after, "keep").Mapping[0].Value.Text != "yes" {
t.Fatal("caller mutation changed private resolution snapshot") t.Fatal("caller mutation changed private resolution snapshot")
} }
} }
@@ -383,8 +385,9 @@ func TestResolutionPresenceUsesEntryShapeAcrossDynamicChanges(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if len(result.resolution) != 2 || result.resolution[1].change.Origin.Operation != ChangeDerivedDefault { snapshots := result.history.resolutionPayload.snapshots
t.Fatalf("resolution records = %#v", result.resolution) if len(snapshots) != 2 || snapshots[1].change.Origin.Operation != ChangeDerivedDefault {
t.Fatalf("resolution records = %#v", snapshots)
} }
}) })
} }