70 lines
3.3 KiB
Python
70 lines
3.3 KiB
Python
# SPDX-FileCopyrightText: 2026 Art Sea LLC
|
|
#
|
|
# SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
"""Query carried file context from existing backlog and provenance records."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from collections import defaultdict
|
|
from copy import deepcopy
|
|
import json
|
|
from typing import TYPE_CHECKING
|
|
|
|
from band_aider.context import provenance
|
|
from band_aider.context.class_meta import ClassMeta
|
|
from band_aider.judgement.file_manager import FileManager
|
|
|
|
if TYPE_CHECKING:
|
|
from band_aider.context.working_backlog import InspectionBacklog
|
|
|
|
|
|
def current_sources(file_manager: FileManager, backlog: InspectionBacklog | None = None) -> list[ClassMeta]:
|
|
"""Resolve carried backlog identities to current managed files without changing history."""
|
|
|
|
from band_aider.context import phase_start_record
|
|
from band_aider.context.working_backlog import TestingBacklog
|
|
|
|
items: list[InspectionBacklog] = []
|
|
# Include context discovered after the immutable phase-start snapshot.
|
|
if backlog is not None:
|
|
items.append(deepcopy(backlog))
|
|
active = provenance.current()
|
|
# Standalone consumers can query their backlog without a running provenance graph.
|
|
if active is not None:
|
|
graph, _phase, message_id = active
|
|
parents: dict[str, set[str]] = defaultdict(set)
|
|
# Reused phase starts can have more than one recorded incoming handoff.
|
|
for edge in graph.edges:
|
|
parents[edge.to_id].add(edge.from_id)
|
|
pending = [message_id]
|
|
seen: set[str] = set()
|
|
# Traverse only this item's causal history, including interrupted revival attempts.
|
|
while pending:
|
|
current_id = pending.pop()
|
|
message = graph.messages[current_id]
|
|
item = phase_start_record.phase_start_from_record(json.loads(message.payload))
|
|
items.append(item)
|
|
seen.add(current_id)
|
|
origins = set(map(lambda guidance: guidance.origin_message_id, filter(
|
|
lambda guidance: guidance.addressed_message_id == current_id,
|
|
item.future_guidance,
|
|
)))
|
|
predecessors = (parents[current_id] | origins | set(filter(None, (message.parent_id,)))) & graph.messages.keys()
|
|
# Stable provenance order prevents unchanged context from churning between retries.
|
|
pending.extend(sorted(predecessors - seen - set(pending), key=lambda key: graph.messages[key].sequence))
|
|
|
|
sources: dict[str, ClassMeta] = {}
|
|
# Backlog dependencies and current source context retain identities, not historical bytes.
|
|
for item in items:
|
|
context = [*item.upstream_classes, *item.downstream_classes]
|
|
# QA and remediation also carry already-admitted failure context.
|
|
if isinstance(item, TestingBacklog):
|
|
context.extend(item.failure_context_sources)
|
|
# Resolve ownership and metadata mechanically; deleted files cannot become live candidates.
|
|
for recorded in context:
|
|
source = file_manager.current_metadata(recorded.location, content_type=recorded.content_type)
|
|
# Only existing files in the current managed inventory supply readable evidence.
|
|
if source is not None and file_manager.repo_exec.is_file(source.resolve_path(file_manager)):
|
|
sources.setdefault(source.location, source)
|
|
return list(sources.values())
|