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
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.
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)
regions := make([]diffRegion, 0, len(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 {
leftNode = nil
}
rightNode, rightPresent := documentAtPathWithLookup(right.final, delta.path, right.immutableLookup)
rightNode, rightPresent := documentAtPathWithLookup(right.final, delta.path, right.documentLookup())
if !rightPresent {
rightNode = nil
}

View File

@@ -53,7 +53,7 @@ func TestDiffUsesFinalValuesAndDependencyDerivedSensitivity(t *testing.T) {
!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)
}
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)
}
@@ -138,10 +138,10 @@ func TestDiffUsesReferenceNamesAndFrozenSecretState(t *testing.T) {
if err != nil || len(differences) != 0 {
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)
}
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)
}
@@ -164,7 +164,7 @@ func TestDiffUsesReferenceNamesAndFrozenSecretState(t *testing.T) {
if absent.Config.Optional != nil {
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)
}
differences, err = Diff(absent.Inspection, left.Inspection)
@@ -210,7 +210,7 @@ func TestDiffProtectsHistoricalSensitiveRemovalAndReplacement(t *testing.T) {
if !left.Inspection.secrets[secretPath.String()] {
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")
}
differences, err := Diff(left.Inspection, right.Inspection)

View File

@@ -127,7 +127,10 @@ type expectedDiffRegion struct {
}
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) {

View File

@@ -40,7 +40,7 @@ func (r *Inspection) Explain(path Path) (Explanation, bool) {
if r == nil || r.final == nil || !path.valid() {
return Explanation{}, false
}
model := r.metadata.historyModel
model := r.history
if model == nil {
return Explanation{}, false
}
@@ -48,7 +48,7 @@ func (r *Inspection) Explain(path Path) (Explanation, bool) {
if len(selections) == 0 && !model.hasObservedShape(path) {
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 {
explanation.Origin = cloneOrigin(info.Origin)
}

View File

@@ -308,16 +308,28 @@ func TestSecretsBootstrapLoadAndExplanationRemainSeparateAndSafe(t *testing.T) {
func TestHistoryNodeBudgetCountsSharedTreesOnce(t *testing.T) {
leaf := &document.Node{Kind: document.String, Text: "value"}
root := &document.Node{Kind: document.Mapping, Mapping: []document.Entry{{Key: "value", Value: leaf}}}
inspection := &Inspection{
baseline: root, input: root, final: root,
applications: []historyApplication{{layer: LayerBase, value: root}},
}
builder := newHistoryBuilder()
builder.model.baseline = 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)
if !addInspectionHistory(counter, inspection) || counter.count != 2 {
t.Fatal("structurally shared history was counted more than once")
}
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)
if addInspectionHistory(counter, inspection) {
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" {
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"))
if !inputOK || inputVersion.Kind != document.Number || inputVersion.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 {
if inspection == nil {
if inspection == nil || inspection.history == nil {
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) {
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
}

View File

@@ -22,21 +22,33 @@ type historyBudgetLayeredConfig struct {
func retainedInspectionNodeCountForTest(inspection *Inspection) int {
seen := make(map[*document.Node]struct{})
stack := []*document.Node{inspection.baseline, inspection.input, inspection.final, inspection.preCLI}
for _, application := range inspection.applications {
stack = append(stack, application.value)
model := inspection.history
stack := []*document.Node{model.baseline, model.final}
for _, payload := range model.sourcePayloads {
if payload.kind == historySourceApplicationPayload {
stack = append(stack, payload.application.value)
}
}
for _, application := range inspection.postDecodeApps {
stack = append(stack, application.value)
for _, payload := range model.inheritancePayloads {
for _, operation := range payload.operations {
stack = append(stack, operation.parent, operation.effective)
}
}
for _, snapshot := range inspection.resolution {
stack = append(stack, snapshot.before, snapshot.after)
for _, payload := range model.cliPayloads {
if payload.kind == historySourceApplicationPayload {
stack = append(stack, payload.application.value)
}
}
for _, operation := range inspection.inheritance {
stack = append(stack, operation.parent, operation.effective)
if model.preCLICheckpoint != nil {
stack = append(stack, model.preCLICheckpoint.root)
}
for _, operation := range inspection.metadata.inheritance {
stack = append(stack, operation.parent, operation.effective)
if model.postCLICheckpoint != nil {
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 {
@@ -144,8 +156,8 @@ func TestLayeredHistoryBudgetRejectsBeforeSecretsAndValidation(t *testing.T) {
if want == 0 {
t.Fatal("independent retained-tree count was empty")
}
if len(baseline.Inspection.inheritance) == 0 || len(baseline.Inspection.metadata.inheritance) == 0 {
t.Fatal("layered load did not retain both inheritance evidence copies")
if baseline.Inspection.history == nil || baseline.Inspection.metadata.historyModel != baseline.Inspection.history || len(baseline.Inspection.history.inheritancePayloads) == 0 {
t.Fatal("layered load did not publish its shared inheritance evidence owner")
}
exactCounts := &callbackCounts{}
loaded, err := loadGroupedWithSecretLookupLimit(makeRequest(exactCounts), testSecretBinding(), lookup(exactCounts), want)
@@ -169,23 +181,46 @@ func TestLayeredHistoryBudgetRejectsBeforeSecretsAndValidation(t *testing.T) {
}
}
func TestPreparedInheritanceEvidenceOwnsDistinctTrees(t *testing.T) {
root := &document.Node{Kind: document.Mapping, Mapping: []document.Entry{{Key: "value", Value: &document.Node{Kind: document.String, Text: "shared"}}}}
resolved := resolvedLoad[historyBudgetSimpleConfig]{
inheritance: &inheritanceScope{operations: []inheritanceOperation{{parent: root, effective: root}}},
func TestPreparedInheritanceEvidenceSharesOwnerAndDetachesPublicViews(t *testing.T) {
input := parseCompositionDocument(t, "inheritance", "parent: {value: shared}\nchild: {extends: parent}\n")
expanded, diagnostics := expandInheritanceWithOrigins(input, nil, defaultProjectionLimits())
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)
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 {
t.Fatalf("inheritance copies = inspection %#v, metadata %#v", inspection.inheritance, inspection.metadata.inheritance)
if inspection.history == nil || inspection.metadata.historyModel != inspection.history || len(inspection.history.inheritancePayloads) != 1 {
t.Fatalf("history owners = inspection %p, metadata %p, inheritance payloads %d", inspection.history, inspection.metadata.historyModel, len(inspection.history.inheritancePayloads))
}
inspectionOperation := inspection.inheritance[0]
metadataOperation := inspection.metadata.inheritance[0]
if inspectionOperation.parent == metadataOperation.parent || inspectionOperation.effective == metadataOperation.effective || counter.count != 8 {
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)
path := Keys("child", "value")
first := inspection.Metadata().History(path)
if len(first) == 0 {
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
baseline *document.Node
final *document.Node
inventoryRoots []*document.Node
sourcePayloads []historySourcePayload
inheritancePayloads []historyInheritancePayload
cliPayloads []historySourcePayload
@@ -149,20 +148,12 @@ func (builder *historyBuilder) observeDocumentAt(root *document.Node, prefix Pat
if root == nil {
return
}
builder.registerDocumentRoot(root)
payload := builder.nextPayload(phase)
walkDocument(root, prefix, func(path Path, node *document.Node) {
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 {
return builder.addObservation(historyObservation{
path: path, phase: phase, payload: payload,
@@ -204,32 +195,40 @@ func (model *historyModel) documentRoots() []*document.Node {
if model == nil {
return nil
}
roots := append([]*document.Node(nil), model.inventoryRoots...)
roots = append(roots, model.baseline, model.final)
var roots []*document.Node
appendRoot := func(root *document.Node) {
if root != nil {
roots = append(roots, root)
}
}
appendRoot(model.baseline)
appendRoot(model.final)
for _, payload := range model.sourcePayloads {
if payload.kind == historySourceApplicationPayload {
roots = append(roots, payload.application.value)
appendRoot(payload.application.value)
}
}
for _, payload := range model.inheritancePayloads {
for _, operation := range payload.operations {
roots = append(roots, operation.parent, operation.effective)
appendRoot(operation.parent)
appendRoot(operation.effective)
}
}
for _, payload := range model.cliPayloads {
if payload.kind == historySourceApplicationPayload {
roots = append(roots, payload.application.value)
appendRoot(payload.application.value)
}
}
if model.preCLICheckpoint != nil {
roots = append(roots, model.preCLICheckpoint.root)
appendRoot(model.preCLICheckpoint.root)
}
if model.postCLICheckpoint != nil {
roots = append(roots, model.postCLICheckpoint.root)
appendRoot(model.postCLICheckpoint.root)
}
if model.resolutionPayload != nil {
for _, snapshot := range model.resolutionPayload.snapshots {
roots = append(roots, snapshot.before, snapshot.after)
appendRoot(snapshot.before)
appendRoot(snapshot.after)
}
}
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()
root := parseDocumentForDecode(t, "shape: {'0': {value: old}}\n")
@@ -189,11 +189,11 @@ func TestHistoryModelFinalizesLocationSensitivityAndDocumentReaders(t *testing.T
})
model := builder.freeze()
if got := model.documentRoots(); len(got) == 0 || got[0] != root {
t.Fatalf("document roots = %#v, want registered root", got)
if got := model.documentRoots(); len(got) != 0 {
t.Fatalf("inventory-only document was retained: %#v", got)
}
if got, ok := model.documentAt(root, Keys("shape", "0")); !ok || got.Kind != document.Mapping {
t.Fatalf("indexed document lookup = %#v, %v", got, ok)
if got, ok := model.documentAt(root, Keys("shape", "0")); ok || got != nil {
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 {
t.Fatalf("latest historical location = %#v, %v", got, ok)
@@ -213,9 +213,6 @@ func TestHistoryModelFinalizesLocationSensitivityAndDocumentReaders(t *testing.T
if !sawCandidate {
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) {

View File

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

View File

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

View File

@@ -41,7 +41,6 @@ func TestHistorySourceObservationsPreserveRawAndCompositeDefinitions(t *testing.
builder.observeBaseline(baseline)
builder.observeSourceEvidence(assembly.current.root, assembly.current.origins, assembly.current.applications, assembly.current.overlays)
builder.model.final = assembly.current.root
builder.registerDocumentRoot(assembly.current.root)
model := builder.freeze()
defaultPath := Keys("defaults", "nullable")
@@ -99,8 +98,7 @@ func TestHistorySourceObservationsPreserveRawAndCompositeDefinitions(t *testing.
}
}
inspection := &Inspection{
metadata: metadata, baseline: baseline, final: assembly.current.root,
immutableLookup: buildDocumentLookup(assembly.current.root),
metadata: metadata, history: model, final: assembly.current.root,
}
explanation, explained := inspection.Explain(Keys("section", "empty"))
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)
metadata.historyBuilder.setScratch(composed.root)
metadata.historyBuilder.observeInheritanceEvidence(expanded.operations)
metadata.inheritance = cloneInheritanceOperations(expanded.operations)
finalizeMetadataPathsWithResolution(&metadata, expanded.root, composed.applications, snapshots, baseline, composed.root, expanded.root)
final := 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{
metadata: metadata, baseline: baseline, input: expanded.root, preCLI: expanded.root,
inputOrigins: expanded.origins, final: expanded.root,
applications: composed.applications, inheritance: expanded.operations,
metadata: metadata, history: metadata.historyModel, final: final,
}, expanded
}
@@ -323,8 +329,8 @@ func TestIndexedInheritanceHistoryMatchesOperationScan(t *testing.T) {
parseCompositionDocument(t, "source-2", "child: {extends: parent, branch: replaced}\n"),
parseCompositionDocument(t, "source-3", "sibling: {extends: parent}\n"))
metadata := inspection.Metadata()
if len(metadata.inheritance) < 4 {
t.Fatalf("inheritance operations = %d, want multiple control and transfer scopes", len(metadata.inheritance))
if inspection.history == nil || len(inspection.history.inheritancePayloads) == 0 || len(inspection.history.inheritancePayloads[0].operations) < 4 {
t.Fatalf("inheritance operations = %#v, want multiple control and transfer scopes", inspection.history)
}
queries := []Path{
Keys("child"),
@@ -372,11 +378,6 @@ func TestInheritanceHistoryPrecedesApplicationResolution(t *testing.T) {
after: replacement,
}
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}
history := inspection.Metadata().History(path)
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"}
extra := &document.Node{Kind: document.String, Text: "extra"}
inspection := &Inspection{
inheritance: []inheritanceOperation{{parent: shared, effective: shared}},
metadata: Metadata{inheritance: []inheritanceOperation{{parent: shared, effective: extra}}},
}
operation := inheritanceOperation{parent: shared, effective: shared}
builder := newHistoryBuilder()
builder.observeInheritanceEvidence([]inheritanceOperation{operation})
model := builder.freeze()
inspection := &Inspection{history: model, metadata: Metadata{historyModel: model}}
counter := newRetainedNodeCounter(2)
if !addInspectionHistory(counter, inspection) || counter.count != 2 {
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)
if addInspectionHistory(counter, inspection) {
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.secrets = classifySecretPaths(nil, func(path Path) bool {
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")} {
explanation, found := inspection.Explain(path)
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.secrets = classifySecretPaths(nil, func(path Path) bool {
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")
explanation, found := inspection.Explain(path)
if !found || explanation.Effective.Present {
@@ -85,7 +85,7 @@ func TestInheritanceSensitivityIncludesSchemaTaggedSource(t *testing.T) {
t.Fatal(issue)
}
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"))
if !found || !child.Effective.Redacted || strings.Contains(child.Effective.YAML, "TAGGED-CANARY") {
t.Fatalf("tagged source copy = %#v, %v", child, found)
@@ -104,7 +104,7 @@ func TestSourceVersionEvidenceSensitivityFollowsInheritanceAndDisplacedHistory(t
}
inspection.secrets = classifySecretPathsWithEvidence(nil, func(path Path) bool {
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")
explanation, found := inspection.Explain(path)
@@ -162,7 +162,7 @@ func TestInheritedSecretReferencesResolveOnlyAfterExpansion(t *testing.T) {
t.Fatalf("inherited reference resolution = %#v, %d", resolved.diagnostics, lookupCount)
}
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
if err := inspection.WriteEffective(&rendered); err != nil || strings.Contains(rendered.String(), "RESOLVED-CREDENTIAL-CANARY") {
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.
type Inspection struct {
metadata Metadata
history *historyModel
sources []SourceInfo
contexts map[string]ResourceContext
diagnostics []Diagnostic
baseline *document.Node
input *document.Node
inputOrigins map[string]Origin
preCLI *document.Node
preCLIOrigins map[string]Origin
postDecodeApps []historyApplication
final *document.Node
immutableLookup *documentLookup
resolution []resolutionSnapshot
resolutionReplay []resolutionReplayGroup
applications []historyApplication
inheritance []inheritanceOperation
secrets map[string]bool
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.
func (r *Inspection) Metadata() Metadata {
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"})
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.
configuration, ownershipIssue := detachLoadConfiguration(schema, resolved.configuration, cloneUnresolvedSecrets)
if ownershipIssue != nil {
@@ -355,5 +344,5 @@ func executeLoadRequest[T any](request loadRequest[T], secrets SecretBinding, lo
resolved.configuration = configuration
// Publication detaches equal-valued validator replacements, preserving the
// 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 {
builder.model.final = final
builder.registerDocumentRoot(final)
}
if refreshReferenceInput {
referenceInput = documentWithMetadataLocations(final, metadata, input.document)
@@ -120,44 +119,24 @@ func prepareInspectionHistory[T any](resolved resolvedLoad[T], counter *retained
metadata := resolved.metadata
if resolved.historyBuilder != nil {
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{
metadata: metadata,
baseline: resolved.decoded.baseline,
input: resolved.decoded.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
}
metadata: metadata,
history: model,
final: resolved.final,
}
if !addInspectionHistory(counter, inspection) {
return nil, false
@@ -165,33 +144,7 @@ func prepareInspectionHistory[T any](resolved resolvedLoad[T], counter *retained
return inspection, true
}
func cloneHistoryApplicationsWithinLimit(values []historyApplication, counter *retainedNodeCounter) ([]historyApplication, bool) {
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) {
func publishLoadResult[T any](schema *schemaDescriptor, definition Definition[T], resolved resolvedLoad[T], inspection *Inspection, references map[string]string, accumulator *diagnosticAccumulator) (*Loaded[T], error) {
// A read-only validator can replace a value with an equal borrowed object.
// Detach without re-reading the environment or discarding validated state.
configuration, issue := detachLoadConfiguration(schema, resolved.configuration, cloneValidatedSecrets)
@@ -199,21 +152,13 @@ func publishLoadResult[T any](schema *schemaDescriptor, definition Definition[T]
accumulator.add(*issue)
return nil, accumulator.loadError()
}
decoded := resolved.decoded
metadata, final, preCLI := inspection.metadata, inspection.final, inspection.preCLI
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)
metadata, final := inspection.metadata, inspection.final
secrets := classifySecretPathsWithEvidence(schema, definition.Secret, metadata, final, nil, resolved.versionEvidence)
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.sources = sources
inspection.contexts = cloneResourceContexts(resolved.contexts)
inspection.diagnostics = canonicalDiagnostics(accumulator.diagnostics)
inspection.immutableLookup = buildDocumentLookup(retainedTrees...)
inspection.secrets = secrets
inspection.secretReferences = cloneSecretReferences(references)
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 {
builder.model.final = final
builder.registerDocumentRoot(final)
}
m.historyModel = builder.freeze()
m.historyBuilder = nil
@@ -200,7 +199,6 @@ func finalizeMetadataPathsWithResolution(m *Metadata, final *document.Node, appl
builder.observeDocument(final, historyPhasePostCLI)
}
for _, application := range applications {
builder.registerDocumentRoot(application.value)
phase := historyPhaseSources
if application.layer == LayerCLI {
phase = historyPhaseCLI
@@ -219,8 +217,6 @@ func finalizeMetadataPathsWithResolution(m *Metadata, final *document.Node, appl
if operation.transfer == nil {
continue
}
builder.registerDocumentRoot(operation.parent)
builder.registerDocumentRoot(operation.effective)
for _, root := range []*document.Node{operation.parent, operation.effective} {
walkDocument(root, operation.transfer.to, func(path Path, node *document.Node) {
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)
inspection := Inspection{
metadata: prepared.metadata, baseline: decoded.baseline, input: assigned.final, inputOrigins: assigned.origins,
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),
metadata: prepared.metadata, history: prepared.metadata.historyModel, final: assigned.final,
}
rateExplanation, ok := inspection.Explain(Keys("rate"))
if !ok {

View File

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