generated from coulomb/repo-seed
feat: show zone resolver diagnostics
This commit is contained in:
@@ -332,6 +332,7 @@ def resolve_zones(
|
||||
edge_records,
|
||||
enabled_definitions,
|
||||
seed_node_ids_by_zone_id,
|
||||
diagnostics,
|
||||
)
|
||||
for candidate in attraction_candidates:
|
||||
candidates_by_node_id[candidate.node_id].append(candidate)
|
||||
@@ -406,6 +407,16 @@ def resolve_zones(
|
||||
internal_edge_ids_by_zone_id[source_zone_id].append(edge.id)
|
||||
continue
|
||||
if source_zone_id or target_zone_id:
|
||||
zone_ids = tuple(sorted(str(zone_id) for zone_id in {source_zone_id, target_zone_id} - {None}))
|
||||
diagnostics.append(
|
||||
ZoneDiagnostic(
|
||||
severity="INFO",
|
||||
code="ZONE_EDGE_CROSSES_ZONE_BOUNDARY",
|
||||
message=f"Edge {edge.id} crosses a zone boundary.",
|
||||
edge_id=edge.id,
|
||||
zone_ids=zone_ids,
|
||||
)
|
||||
)
|
||||
boundary_edges.append(
|
||||
ZoneBoundaryEdge(
|
||||
edge_id=edge.id,
|
||||
@@ -468,6 +479,7 @@ def _attraction_candidates(
|
||||
edge_records: tuple[_EdgeRecord, ...],
|
||||
enabled_definitions: tuple[tuple[int, ZoneDefinition], ...],
|
||||
seed_node_ids_by_zone_id: Mapping[str, set[str]],
|
||||
diagnostics: list[ZoneDiagnostic],
|
||||
) -> list[_Candidate]:
|
||||
nodes_by_id = {node.id: node for node in node_records}
|
||||
adjacency: dict[str, list[_EdgeRecord]] = defaultdict(list)
|
||||
@@ -476,6 +488,7 @@ def _attraction_candidates(
|
||||
adjacency[edge.target].append(edge)
|
||||
|
||||
candidates: dict[tuple[str, str], _Candidate] = {}
|
||||
depth_limit_diagnostics: set[tuple[str, str]] = set()
|
||||
for definition_order, definition in enabled_definitions:
|
||||
seed_node_ids = seed_node_ids_by_zone_id.get(definition.id, set())
|
||||
if not seed_node_ids:
|
||||
@@ -486,6 +499,27 @@ def _attraction_candidates(
|
||||
while queue:
|
||||
node_id, depth = queue.popleft()
|
||||
if depth >= rule.depth:
|
||||
if _has_matching_attraction_neighbor(
|
||||
node_id,
|
||||
adjacency.get(node_id, []),
|
||||
nodes_by_id,
|
||||
rule,
|
||||
):
|
||||
key = (definition.id, node_id)
|
||||
if key not in depth_limit_diagnostics:
|
||||
depth_limit_diagnostics.add(key)
|
||||
diagnostics.append(
|
||||
ZoneDiagnostic(
|
||||
severity="INFO",
|
||||
code="ZONE_ATTRACTION_DEPTH_LIMIT_REACHED",
|
||||
message=(
|
||||
f"Zone {definition.id} reached attraction depth "
|
||||
f"{rule.depth} at node {node_id}."
|
||||
),
|
||||
node_id=node_id,
|
||||
zone_ids=(definition.id,),
|
||||
)
|
||||
)
|
||||
continue
|
||||
for edge in adjacency.get(node_id, []):
|
||||
if not _edge_matches_attraction_rule(edge, rule):
|
||||
@@ -521,6 +555,24 @@ def _attraction_candidates(
|
||||
return sorted(candidates.values(), key=lambda candidate: (candidate.node_id, candidate.zone_id))
|
||||
|
||||
|
||||
def _has_matching_attraction_neighbor(
|
||||
node_id: str,
|
||||
edges: Iterable[_EdgeRecord],
|
||||
nodes_by_id: Mapping[str, _NodeRecord],
|
||||
rule: ZoneAttractionRule,
|
||||
) -> bool:
|
||||
for edge in edges:
|
||||
if not _edge_matches_attraction_rule(edge, rule):
|
||||
continue
|
||||
neighbor_id = _neighbor_for_direction(node_id, edge, rule.direction)
|
||||
if not neighbor_id:
|
||||
continue
|
||||
neighbor = nodes_by_id.get(neighbor_id)
|
||||
if neighbor and _rule_matches(neighbor.data, rule.node_filter, empty_matches=True):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _node_records(nodes: Iterable[Mapping[str, Any]]) -> tuple[_NodeRecord, ...]:
|
||||
records: list[_NodeRecord] = []
|
||||
for order, element in enumerate(nodes):
|
||||
|
||||
Reference in New Issue
Block a user