Cut metadata history over to shared model

This commit is contained in:
2026-10-26 16:34:13 +00:00
parent 76521f7cd8
commit 4b4e15fc58
10 changed files with 206 additions and 118 deletions

View File

@@ -5,12 +5,12 @@ import "gitea.maximumdirect.net/eric/ConfigKit/internal/document"
// Metadata provides detached effective presence/origin and chronological history
// queries for a load. Its zero value contains no paths.
type Metadata struct {
effectivePaths map[string]Path
fields map[string]FieldInfo
history map[string][]Change
inheritance []inheritanceOperation
inheritanceIndex *inheritanceHistoryIndex
historyModel *historyModel
effectivePaths map[string]Path
fields map[string]FieldInfo
history map[string][]Change
inheritance []inheritanceOperation
historyBuilder *historyBuilder
historyModel *historyModel
}
// Lookup returns information for an effective path. Unknown and invalid paths
@@ -50,15 +50,38 @@ func (m Metadata) effectiveField(path Path) (FieldInfo, bool) {
// Removed historical paths can have history even though Lookup returns false.
// Unknown and invalid paths return nil.
func (m Metadata) History(path Path) []Change {
if !m.hasHistoricalPath(path) {
model := m.historyEvidence()
if model == nil || !model.hasObservedShape(path) {
return nil
}
history := m.history[path.String()]
operations := m.inheritance
if m.inheritanceIndex != nil {
operations = m.inheritanceIndex.matchingOperations(path, m.inheritance)
selections := model.selectHistory(path)
if len(selections) == 0 {
return nil
}
return historyWithInheritance(path, history, operations)
changes := make([]Change, 0, len(selections))
for _, selection := range selections {
if !metadataHistoryRole(selection.role) || !selection.hasAttribution {
continue
}
var previous []Origin
if len(selection.previous) != 0 {
previous = make([]Origin, len(selection.previous))
for index, origin := range selection.previous {
previous[index] = cloneOrigin(origin)
}
}
changes = append(changes, Change{
Path: selection.reportedPath.clone(),
Origin: cloneOrigin(selection.attribution.origin),
Previous: previous,
Reasons: append([]string(nil), selection.attribution.reasons...),
Dependencies: clonePaths(selection.attribution.dependencies),
})
}
if len(changes) == 0 {
return nil
}
return changes
}
// HistoricalPaths returns the paths observed during loading, including effective
@@ -73,7 +96,17 @@ func (m Metadata) History(path Path) []Change {
// a path remains effective. Enumeration exposes no configuration values and does
// not perform another load or resolve secrets.
func (m Metadata) HistoricalPaths() []Path {
return m.historyModel.historicalPaths()
return m.historyEvidence().historicalPaths()
}
func (m Metadata) historyEvidence() *historyModel {
if m.historyModel != nil {
return m.historyModel
}
if m.historyBuilder != nil {
return m.historyBuilder.model
}
return nil
}
// Textual pointers are lookup keys, but explicit key/index kinds remain part of
@@ -100,7 +133,7 @@ func matchesPathShape(query, candidate Path) bool {
}
func (m Metadata) hasHistoricalPath(path Path) bool {
return m.historyModel.hasObservedShape(path)
return m.historyEvidence().hasObservedShape(path)
}
func finalizeMetadataPaths(m *Metadata, final *document.Node, applications []historyApplication, earlier ...*document.Node) {
@@ -109,7 +142,10 @@ func finalizeMetadataPaths(m *Metadata, final *document.Node, applications []his
func finalizeMetadataPathsWithResolution(m *Metadata, final *document.Node, applications []historyApplication, snapshots []resolutionSnapshot, earlier ...*document.Node) {
finalizeEffectiveMetadataPaths(m, final)
builder := newHistoryBuilder()
builder := m.historyBuilder
if builder == nil {
builder = newHistoryBuilder()
}
if len(earlier) != 0 {
builder.model.baseline = earlier[0]
}
@@ -164,12 +200,11 @@ func finalizeMetadataPathsWithResolution(m *Metadata, final *document.Node, appl
builder.observeResolutionEvidence(snapshots)
}
m.historyModel = builder.freeze()
m.inheritanceIndex = newInheritanceHistoryIndex(m.inheritance)
m.historyBuilder = nil
}
func finalizeEffectiveMetadataPaths(m *Metadata, final *document.Node) {
m.effectivePaths = effectivePathIndex(final)
m.inheritanceIndex = newInheritanceHistoryIndex(m.inheritance)
}
// effectivePathIndex records document-derived paths with their contextual segment