Localize history selection to affected paths
This commit is contained in:
@@ -266,7 +266,15 @@ coverage; do not add timing thresholds or implementation-specific scan counts.
|
|||||||
|
|
||||||
## 5. Prefix Indexing Multiplies One Operation By All Its Descendants
|
## 5. Prefix Indexing Multiplies One Operation By All Its Descendants
|
||||||
|
|
||||||
Priority: P2. Status: open.
|
Priority: P2. Status: complete.
|
||||||
|
|
||||||
|
Completion: indexes locate concrete affected paths rather than placing every
|
||||||
|
descendant at the reported ancestor. Exact path buckets drive source-origin
|
||||||
|
containment (with early success); enclosing queries visit only their affected
|
||||||
|
subtree. Logical operations remain payload references, deduplicated once by the
|
||||||
|
common selector. Thus a leaf no longer scans sibling facts of an ancestor
|
||||||
|
replacement. The full ordinary suite and `git diff --check` passed, including
|
||||||
|
parsed key/index sides, removed descendants, inheritance, and enclosing queries.
|
||||||
|
|
||||||
Relevant code: `addObservation` in
|
Relevant code: `addObservation` in
|
||||||
[history_model.go](../../internal/engine/history_model.go), lines 116–139;
|
[history_model.go](../../internal/engine/history_model.go), lines 116–139;
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ type historyModel struct {
|
|||||||
shapesByPointer map[string][]Path
|
shapesByPointer map[string][]Path
|
||||||
shapeOrder []Path
|
shapeOrder []Path
|
||||||
observationsByPointer map[string][]int
|
observationsByPointer map[string][]int
|
||||||
reportedPathIndex pathPrefixIndex
|
affectedPathIndex pathPrefixIndex
|
||||||
documentLookup *documentLookup
|
documentLookup *documentLookup
|
||||||
|
|
||||||
frozen bool
|
frozen bool
|
||||||
@@ -127,14 +127,14 @@ func (builder *historyBuilder) addObservation(observation historyObservation) in
|
|||||||
builder.model.observations = append(builder.model.observations, observation)
|
builder.model.observations = append(builder.model.observations, observation)
|
||||||
builder.addShape(observation.path)
|
builder.addShape(observation.path)
|
||||||
switch observation.role {
|
switch observation.role {
|
||||||
case historyRoleDefinition, historyRoleContribution, historyRoleCompositeDefinition, historyRoleCheckpoint:
|
case historyRoleDefinition, historyRoleContribution, historyRoleCompositeDefinition, historyRoleCheckpoint, historyRoleOperation, historyRoleControl:
|
||||||
pointer := observation.path.String()
|
pointer := observation.path.String()
|
||||||
builder.model.observationsByPointer[pointer] = append(builder.model.observationsByPointer[pointer], observationID)
|
builder.model.observationsByPointer[pointer] = append(builder.model.observationsByPointer[pointer], observationID)
|
||||||
if observation.role == historyRoleContribution {
|
if observation.role == historyRoleContribution || observation.role == historyRoleOperation || observation.role == historyRoleControl {
|
||||||
builder.model.reportedPathIndex.insert(pointer, observationID)
|
// Index the concrete affected path, not the common reported ancestor.
|
||||||
|
// A leaf query must not enumerate every sibling fact of one operation.
|
||||||
|
builder.model.affectedPathIndex.insert(pointer, observationID)
|
||||||
}
|
}
|
||||||
case historyRoleOperation, historyRoleControl:
|
|
||||||
builder.model.reportedPathIndex.insert(observation.reportedPath.String(), observationID)
|
|
||||||
}
|
}
|
||||||
return observationID
|
return observationID
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,10 +36,10 @@ func (model *historyModel) selectHistory(path Path) []historySelection {
|
|||||||
for _, observationID := range model.observationsByPointer[path.String()] {
|
for _, observationID := range model.observationsByPointer[path.String()] {
|
||||||
candidateSet[observationID] = struct{}{}
|
candidateSet[observationID] = struct{}{}
|
||||||
}
|
}
|
||||||
model.reportedPathIndex.visitAncestors(path.String(), func(observationID int) {
|
// Producers register all affected before/after paths. Exact facts cover
|
||||||
candidateSet[observationID] = struct{}{}
|
// ancestor replacements; descendants cover operations within an enclosing
|
||||||
})
|
// query. Logical operations are still deduplicated by payload below.
|
||||||
model.reportedPathIndex.visitDescendants(path.String(), func(observationID int) {
|
model.affectedPathIndex.visitDescendants(path.String(), func(observationID int) {
|
||||||
candidateSet[observationID] = struct{}{}
|
candidateSet[observationID] = struct{}{}
|
||||||
})
|
})
|
||||||
candidates := make([]int, 0, len(candidateSet))
|
candidates := make([]int, 0, len(candidateSet))
|
||||||
|
|||||||
@@ -192,26 +192,25 @@ func sourceApplicationOrigin(application historyApplication, node *document.Node
|
|||||||
}
|
}
|
||||||
|
|
||||||
func sourceOriginRepresentedByOperation(model *historyModel, path Path, origin Origin) bool {
|
func sourceOriginRepresentedByOperation(model *historyModel, path Path, origin Origin) bool {
|
||||||
represented := false
|
for _, observationID := range model.observationsByPointer[path.String()] {
|
||||||
model.reportedPathIndex.visitAncestors(path.String(), func(observationID int) {
|
|
||||||
observation := model.observations[observationID]
|
observation := model.observations[observationID]
|
||||||
if observation.phase != historyPhaseSources || observation.role != historyRoleOperation {
|
if observation.phase != historyPhaseSources || observation.role != historyRoleOperation {
|
||||||
return
|
continue
|
||||||
}
|
}
|
||||||
if !observation.afterPresent || !sameConcreteHistoryPath(path, observation.path) {
|
if !observation.afterPresent || !sameConcreteHistoryPath(path, observation.path) {
|
||||||
return
|
continue
|
||||||
}
|
}
|
||||||
operationOrigin, ok := model.resolveAttribution(observation.attributionRef)
|
operationOrigin, ok := model.resolveAttribution(observation.attributionRef)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
continue
|
||||||
}
|
}
|
||||||
if originRepresentedByChange(path, origin, Change{
|
if originRepresentedByChange(path, origin, Change{
|
||||||
Path: observation.reportedPath, Origin: operationOrigin.origin,
|
Path: observation.reportedPath, Origin: operationOrigin.origin,
|
||||||
}) {
|
}) {
|
||||||
represented = true
|
return true
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
return represented
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func originRepresentedByChange(path Path, origin Origin, change Change) bool {
|
func originRepresentedByChange(path Path, origin Origin, change Change) bool {
|
||||||
|
|||||||
Reference in New Issue
Block a user