audit: validate-first routing, read-only activation lookup, delta-log barrier patches

This commit is contained in:
lda
2026-09-04 12:48:01 +07:00 Verified
parent 47e57ce598
commit 7b2f718ad7
6 changed files with 256 additions and 15 deletions
+40
View File
@@ -284,6 +284,46 @@ def test_barrier_replays_incoming_values_not_lineage_visible_values() -> None:
assert patch.visible_values["state.number"] == 6
def test_barrier_combined_patch_remerges_without_duplicating_prefix() -> None:
"""A combined patch re-merged by an outer barrier must not duplicate.
The second barrier is computed after the first aggregate was committed,
so its constituents were built against that prefix. Re-merging must
replay the original per-item deltas, not the cumulative aggregates.
"""
workflow = _workflow(
fields={
"seen": StateField(
type="array",
reducer=ReducerRef(name="wf.std.append"),
)
}
)
first = build_barrier_patch(
workflow,
[
StatePatch(changes={"state.seen": "a"}),
StatePatch(changes={"state.seen": "b"}),
],
{},
)
second = build_barrier_patch(
workflow,
[
StatePatch(changes={"state.seen": "c"}),
StatePatch(changes={"state.seen": "d"}),
],
{"seen": ["a", "b"]},
)
assert second.changes["state.seen"] == ["a", "b", "c", "d"]
remerged = build_barrier_patch(workflow, [first, second], {})
assert remerged.changes["state.seen"] == ["a", "b", "c", "d"]
assert remerged.visible_values["state.seen"] == ["a", "b", "c", "d"]
def test_build_and_commit_patch_matches_apply_output_bindings() -> None:
workflow = _workflow(fields={"person.name": StateField(type="string")})
state_from_apply = {"person": {"name": "old"}}
+28
View File
@@ -5,8 +5,11 @@ import pytest
from wf_core.errors import WorkflowExecutionError
from wf_core.run_state import ExecutionFrame
from wf_core.runtime.foreach_state import (
ForeachActivationState,
ForeachBarrierState,
close_foreach_activation,
item_frame_owner,
load_foreach_activation,
load_or_begin_foreach_activation,
save_foreach_activation,
)
@@ -100,3 +103,28 @@ def test_item_metadata_requires_activation_identity() -> None:
ForeachIterationMetadata.from_frame(frame)
with pytest.raises(WorkflowExecutionError, match="activation"):
item_frame_owner(frame)
def test_failed_activation_lookup_leaves_metadata_untouched() -> None:
"""Read-only lookups must not create the activation table on failure."""
frame = _frame()
stale = ForeachActivationState(
id="root:each#0",
foreach_node_id="each",
barrier=ForeachBarrierState(mode="serial"),
)
with pytest.raises(WorkflowExecutionError, match="activation"):
load_foreach_activation(frame, "each", "root:each#0")
with pytest.raises(WorkflowExecutionError, match="activation"):
save_foreach_activation(frame, stale)
with pytest.raises(WorkflowExecutionError, match="activation"):
close_foreach_activation(frame, stale)
assert frame.metadata == {}
# The write path still creates the table exactly once.
activation = load_or_begin_foreach_activation(frame, "each", mode="serial")
assert frame.metadata["foreach_activations"]["each"]["active"]["id"] == (
activation.id
)
+124
View File
@@ -539,6 +539,130 @@ def test_nested_foreach_preserves_inner_writes_in_all_modes(
assert sorted(seen, key=repr) == sorted([1, 2, 1, 2], key=repr)
def _three_level_workflow(
*, outer_mode: str, middle_mode: str, inner_mode: str
) -> Workflow:
def _foreach(node_id: str, *, over: str, alias: str, mode: str) -> ForeachNode:
payload: dict[str, Any] = {
"id": node_id,
"type": "foreach",
"over": over,
"as": alias,
"mode": mode,
}
if mode == "concurrent":
payload["concurrent"] = {"max_active": 2, "max_outstanding": 2}
return ForeachNode.model_validate(payload)
return Workflow(
name="three_level_nested_foreach",
input_schema=SchemaRef(type="object", properties={}),
state_schema=StateSchema.from_field_map(
{
"items": StateField(type="array"),
"mid_items": StateField(type="array"),
"inner_items": StateField(type="array"),
"seen": StateField(
type="array", reducer=ReducerRef(name="wf.std.append")
),
}
),
output_schema=SchemaRef(type="object", properties={"seen": {"type": "array"}}),
node_defs=[
NodeDef(
name="work",
input_schema=SchemaRef(
type="object", properties={"value": {}}, required=["value"]
),
output_schema=SchemaRef(
type="object", properties={"seen": {}}, required=["seen"]
),
outcomes=["ok"],
)
],
start="outer",
nodes=[
_foreach("outer", over="state.items", alias="outer_item", mode=outer_mode),
_foreach(
"middle",
over="state.mid_items",
alias="mid_item",
mode=middle_mode,
),
_foreach(
"inner",
over="state.inner_items",
alias="inner_item",
mode=inner_mode,
),
NodeUse.model_validate(
{
"id": "work",
"type": "node",
"node": "work",
"input": [{"target": "value", "path": "context.inner_item"}],
"output": [{"source": "seen", "target": "state.seen"}],
}
),
],
edges=[
Edge.model_validate({"from": "outer", "outcome": "loop", "to": "middle"}),
Edge.model_validate({"from": "middle", "outcome": "loop", "to": "inner"}),
Edge.model_validate({"from": "inner", "outcome": "loop", "to": "work"}),
Edge.model_validate({"from": "work", "outcome": "ok", "to": "inner"}),
Edge.model_validate({"from": "inner", "outcome": "done", "to": "middle"}),
Edge.model_validate({"from": "middle", "outcome": "done", "to": "outer"}),
Edge.model_validate({"from": "outer", "outcome": "done", "to": END}),
],
)
@pytest.mark.parametrize(
("outer_mode", "middle_mode", "inner_mode"),
[
("serial", "serial", "serial"),
("serial", "serial", "concurrent"),
("serial", "concurrent", "serial"),
("serial", "concurrent", "concurrent"),
("concurrent", "serial", "serial"),
("concurrent", "serial", "concurrent"),
("concurrent", "concurrent", "serial"),
("concurrent", "concurrent", "concurrent"),
],
)
def test_three_level_nested_foreach_preserves_writes(
outer_mode: str, middle_mode: str, inner_mode: str
) -> None:
"""Write routing holds through three nesting levels in every mode mix.
Barriers merge items in index order, so each middle visit yields exactly
[1, 2]; only the outer completion order varies. A serial outer admits
in order, making [1, 2, 1, 2] exact, while a concurrent outer leaves
only the multiset contractual.
"""
workflow = _three_level_workflow(
outer_mode=outer_mode, middle_mode=middle_mode, inner_mode=inner_mode
)
run = execute_workflow(
workflow,
{"items": ["a", "b"], "mid_items": ["m"], "inner_items": [1, 2]},
{
"work": lambda payload, _ctx: {
"outcome": "ok",
"output": {"seen": payload["value"]},
}
},
)
assert run.status == RunStatus.COMPLETED
seen = run.state.get("seen") or []
if outer_mode == "serial":
assert seen == [1, 2, 1, 2]
else:
assert sorted(seen, key=repr) == sorted([1, 2, 1, 2], key=repr)
def test_item_frame_owner_rejects_missing_parent_frame() -> None:
"""A foreach_iteration frame without a parent is malformed, not ordinary."""
frame = ExecutionFrame(