Replay explanations through shared history selections
This commit is contained in:
@@ -36,6 +36,9 @@ func (model *historyModel) selectHistory(path Path) []historySelection {
|
||||
model.reportedPathIndex.visitAncestors(path.String(), func(observationID int) {
|
||||
candidateSet[observationID] = struct{}{}
|
||||
})
|
||||
model.reportedPathIndex.visitDescendants(path.String(), func(observationID int) {
|
||||
candidateSet[observationID] = struct{}{}
|
||||
})
|
||||
candidates := make([]int, 0, len(candidateSet))
|
||||
for observationID := range candidateSet {
|
||||
candidates = append(candidates, observationID)
|
||||
@@ -46,7 +49,32 @@ func (model *historyModel) selectHistory(path Path) []historySelection {
|
||||
selectionByPayload := make(map[historyPayloadRef]int)
|
||||
for _, observationID := range candidates {
|
||||
observation := model.observations[observationID]
|
||||
if observation.role == historyRoleInventory || !matchesPathShape(path, observation.path) {
|
||||
if observation.role == historyRoleInventory {
|
||||
continue
|
||||
}
|
||||
reportedPath := observation.reportedPath
|
||||
attributionRef := observation.attributionRef
|
||||
if observation.role == historyRoleContribution {
|
||||
if !historyObservationMatchesQuery(path, observation.path) {
|
||||
continue
|
||||
}
|
||||
application, found := model.applicationPayload(observation.payload)
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
if pathContains(observation.path, path) && len(observation.path.segments) < len(path.segments) {
|
||||
local, ok := historyApplicationLocalPath(application, path)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if _, present := documentAtPathWithLookup(application.value, local, model.documentLookup); !present {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if operationPath, relevant := applicationOperationPath(application, path, model.documentLookup); relevant {
|
||||
reportedPath = operationPath
|
||||
}
|
||||
} else if !historyObservationMatchesQuery(path, observation.path) {
|
||||
continue
|
||||
}
|
||||
selectionIndex, found := selectionByPayload[observation.payload]
|
||||
@@ -57,10 +85,10 @@ func (model *historyModel) selectHistory(path Path) []historySelection {
|
||||
path: path.clone(),
|
||||
phase: observation.phase,
|
||||
payload: observation.payload,
|
||||
reportedPath: observation.reportedPath.clone(),
|
||||
reportedPath: reportedPath.clone(),
|
||||
role: observation.role,
|
||||
}
|
||||
if attribution, ok := model.resolveAttribution(observation.attributionRef); ok {
|
||||
if attribution, ok := model.resolveAttribution(attributionRef); ok {
|
||||
selection.attribution = attribution
|
||||
selection.hasAttribution = true
|
||||
}
|
||||
@@ -88,6 +116,13 @@ func (model *historyModel) selectHistory(path Path) []historySelection {
|
||||
return selections
|
||||
}
|
||||
|
||||
func historyObservationMatchesQuery(query, observed Path) bool {
|
||||
if matchesPathShape(query, observed) {
|
||||
return true
|
||||
}
|
||||
return pathContains(query, observed) && pathShapePrefixMatches(query, observed)
|
||||
}
|
||||
|
||||
func (model *historyModel) hasObservedShape(path Path) bool {
|
||||
if model == nil || !path.valid() {
|
||||
return false
|
||||
@@ -187,6 +222,32 @@ func (model *historyModel) resolveAttribution(ref historyAttributionRef) (histor
|
||||
}, true
|
||||
}
|
||||
|
||||
func (model *historyModel) applicationPayload(ref historyPayloadRef) (historyApplication, bool) {
|
||||
if model == nil || ref.id < 0 {
|
||||
return historyApplication{}, false
|
||||
}
|
||||
var payloads []historySourcePayload
|
||||
switch ref.phase {
|
||||
case historyPhaseSources:
|
||||
payloads = model.sourcePayloads
|
||||
case historyPhaseCLI:
|
||||
payloads = model.cliPayloads
|
||||
default:
|
||||
return historyApplication{}, false
|
||||
}
|
||||
if ref.id >= len(payloads) || payloads[ref.id].kind != historySourceApplicationPayload {
|
||||
return historyApplication{}, false
|
||||
}
|
||||
return payloads[ref.id].application, true
|
||||
}
|
||||
|
||||
func pathShapePrefixMatches(left, right Path) bool {
|
||||
length := min(len(left.segments), len(right.segments))
|
||||
leftPrefix := Path{segments: clonePathSegments(left.segments[:length], 0)}
|
||||
rightPrefix := Path{segments: clonePathSegments(right.segments[:length], 0)}
|
||||
return matchesPathShape(leftPrefix, rightPrefix)
|
||||
}
|
||||
|
||||
func metadataHistoryRole(role historyRole) bool {
|
||||
switch role {
|
||||
case historyRoleDefinition, historyRoleCompositeDefinition, historyRoleOperation, historyRoleControl:
|
||||
|
||||
Reference in New Issue
Block a user