fix: keep validation contracts truthful for new control regions

This commit is contained in:
lda
2026-09-04 08:04:47 +07:00 Verified
parent b073407441
commit 7a5635b1a2
2 changed files with 31 additions and 1 deletions
+24
View File
@@ -142,6 +142,30 @@ def analyze_control_regions(workflow: Workflow) -> ControlRegionAnalysis:
continue continue
is_terminal = target_id == END or isinstance(target_node, EndNode) is_terminal = target_id == END or isinstance(target_node, EndNode)
if is_terminal: if is_terminal:
# Explicit end nodes are still program locations with one
# static region; record them so they are not also reported as
# unreachable. The `END` token has no node to record.
if isinstance(target_node, EndNode):
visited_nodes.add(target_id)
recorded_target = owner_stack_by_node.get(target_id)
if recorded_target is None:
owner_stack_by_node[target_id] = target_stack
elif recorded_target != target_stack:
del owner_stack_by_node[target_id]
if target_id not in conflicted:
conflicted.add(target_id)
issues.append(
ControlRegionIssue(
kind=ControlRegionIssueKind.FOREACH_REGION_CONFLICT,
path=f"nodes[{target_id}]",
message=(
f"node {target_id!r} is reachable under "
"two foreach control regions"
),
)
)
for prior_stack in (recorded_target, target_stack):
mark_ambiguous(prior_stack)
if target_stack: if target_stack:
issues.append( issues.append(
ControlRegionIssue( ControlRegionIssue(
+7 -1
View File
@@ -272,7 +272,13 @@ async def test_snapshotless_remote_node_upgrades_to_real_capability_contract() -
replacement = graph.use(capability, id="replacement", input=[], output=[]) replacement = graph.use(capability, id="replacement", input=[], output=[])
graph.connect(replacement, "ok", "done") graph.connect(replacement, "ok", "done")
assert graph.validate_local().ok is True # A disconnected replacement has no derivable control region; new
# validation reports it as unreachable rather than silently accepting it.
report = graph.validate_local()
assert any(
issue.code == "unreachable_node" and issue.path == "nodes[replacement]"
for issue in report.errors
)
assert graph.seeded_node_defs["app.default.remote"].input_schema.properties == { assert graph.seeded_node_defs["app.default.remote"].input_schema.properties == {
"query": {"type": "string"} "query": {"type": "string"}
} }