package engine import "gitea.maximumdirect.net/eric/ConfigKit/internal/document" type historyCheckpointPayload struct { root *document.Node origins map[string]Origin } func (builder *historyBuilder) observePreCLICheckpoint(root *document.Node, origins map[string]Origin) { builder.observeTypedCheckpoint(historyPhasePreCLI, root, origins, "applied retained defaults and canonical typed decoding") } func (builder *historyBuilder) observePostCLICheckpoint(root *document.Node, origins map[string]Origin) { builder.observeTypedCheckpoint(historyPhasePostCLI, root, origins, "applied the typed CLI assignment") } func (builder *historyBuilder) observeTypedCheckpoint(phase historyPhase, root *document.Node, origins map[string]Origin, reason string) { builder.requireOpen() if phase != historyPhasePreCLI && phase != historyPhasePostCLI { panic("configkit: typed checkpoint has an invalid history phase") } payload := builder.nextPayload(phase) checkpoint := historyCheckpointPayload{root: root, origins: cloneOriginIndex(origins)} switch phase { case historyPhasePreCLI: if builder.model.preCLICheckpoint != nil || payload.id != 0 { panic("configkit: pre-CLI checkpoint was already registered") } builder.model.preCLICheckpoint = &checkpoint case historyPhasePostCLI: if builder.model.postCLICheckpoint != nil || payload.id != 0 { panic("configkit: post-CLI checkpoint was already registered") } builder.model.postCLICheckpoint = &checkpoint } beforeRoot := builder.scratch paths := unionCLIHistoryPaths(beforeRoot, root) lookup := buildDocumentLookup(beforeRoot, root) for _, path := range paths { beforeNode, before := documentAtPathWithLookup(beforeRoot, path, lookup) afterNode, after := documentAtPathWithLookup(root, path, lookup) sensitive := beforeNode != nil && beforeNode.Sensitive || afterNode != nil && afterNode.Sensitive builder.addObservation(historyObservation{ path: path, phase: phase, payload: payload, reportedPath: path, role: historyRoleInventory, sensitive: sensitive, attributionRef: noHistoryAttribution, }) if configurationValuesEqual(beforeNode, afterNode) { continue } attributionRef := noHistoryAttribution if after { origin, found := origins[path.String()] if !found { origin = Origin{Layer: LayerDefault} } origin.Operation = ChangeDecoding attributionRef = builder.addAttribution(origin, []string{reason}, nil) } builder.addObservation(historyObservation{ path: path, phase: phase, payload: payload, reportedPath: path, role: historyRoleCheckpoint, beforePresent: before, afterPresent: after, sensitive: sensitive, attributionRef: attributionRef, }) } builder.advanceScratch(document.Clone(root)) } func (builder *historyBuilder) observeCLIEvidence(applications []historyApplication, records []overlayRecord) { builder.requireOpen() count := max(len(applications), len(records)) if count == 0 { return } index := new(mappingIndex) for item := 0; item < count; item++ { var applicationRef historyPayloadRef hasApplication := false if item < len(applications) { application := applications[item] applicationRef = builder.addCLIPayload(&application, nil) hasApplication = true walkHistoryApplication(application, func(_, effective Path, node *document.Node) { origin := sourceApplicationOrigin(application, node) attribution := builder.addAttribution(origin, nil, nil) builder.addObservation(historyObservation{ path: effective, phase: historyPhaseCLI, payload: applicationRef, reportedPath: effective, role: historyRoleContribution, afterPresent: true, sensitive: node.Sensitive, attributionRef: attribution, }) }) applyHistoryApplication(&builder.scratch, application, index) } if item < len(records) { record := records[item] payload := builder.addCLIPayload(nil, &record) if hasApplication { owned := &builder.model.cliPayloads[payload.id] owned.applicationRef = applicationRef owned.hasApplicationRef = true } attribution := builder.addAttribution(record.change.Origin, nil, nil) for _, displaced := range record.displaced { builder.addObservation(historyObservation{ path: displaced.path, phase: historyPhaseCLI, payload: payload, reportedPath: record.change.Path, role: historyRoleOperation, beforePresent: true, attributionRef: attribution, }) } for _, introduced := range record.introduced { builder.addObservation(historyObservation{ path: introduced.path, phase: historyPhaseCLI, payload: payload, reportedPath: record.change.Path, role: historyRoleOperation, afterPresent: true, sensitive: introduced.sensitive, attributionRef: attribution, }) } } } } func (builder *historyBuilder) addCLIPayload(application *historyApplication, record *overlayRecord) historyPayloadRef { payload := builder.nextPayload(historyPhaseCLI) if payload.id != len(builder.model.cliPayloads) { panic("configkit: CLI payload identifiers are out of order") } owned := historySourcePayload{} switch { case application != nil: owned.kind = historySourceApplicationPayload owned.application = cloneHistoryApplications([]historyApplication{*application})[0] case record != nil: owned.kind = historySourceOverlayPayload owned.overlay = cloneOverlayRecords([]overlayRecord{*record})[0] default: panic("configkit: CLI payload requires an application or operation") } builder.model.cliPayloads = append(builder.model.cliPayloads, owned) return payload } func unionCLIHistoryPaths(roots ...*document.Node) []Path { var paths []Path seen := make(map[string][]Path) for _, root := range roots { if root == nil { continue } walkDocument(root, Path{}, func(path Path, _ *document.Node) { for _, existing := range seen[path.String()] { if sameConcreteHistoryPath(existing, path) { return } } owned := path.clone() paths = append(paths, owned) seen[path.String()] = append(seen[path.String()], owned) }) } return paths }