fix: quote dotted aliases and offer root foreach in inventory

This commit is contained in:
lda
2026-09-05 00:35:00 +07:00 Verified
parent 3016fd263b
commit 6e6a4f943d
2 changed files with 79 additions and 1 deletions
+3 -1
View File
@@ -202,7 +202,9 @@ def context_path_options(
reason = raw_reason if isinstance(raw_reason, str) else None
option: AuthoringPathOptionPayload = {
"path": f"context.{name}",
# Field names are literal path segments: dotted foreach aliases
# must stay quoted as one segment, never split on ".".
"path": str(GraphSourcePath("context", (name,))),
"label": name.replace("_", " ").replace("-", " ").title(),
"origin": "runtime_context",
"schema": deepcopy(dict(schema)),
+76
View File
@@ -510,3 +510,79 @@ def test_structured_foreach_paths_appear_in_authoring_inventory() -> None:
if option["path"].startswith("context.foreach."):
assert option["origin"] == "runtime_context"
assert option["uses"] == ["step_input"]
def _ref_inventory_workflow(*, alias: str = "order"):
from wf_core import END, Edge, ForeachNode, NodeUse, SchemaRef, Workflow
from wf_core.models.schemas import StateSchema
return Workflow(
name="inventory_nested_ref",
input_schema=SchemaRef(type="object"),
state_schema=StateSchema.model_validate(
{
"type": "object",
"properties": {
"orders": {
"type": "array",
"items": {"$ref": "#/$defs/Order"},
},
},
"$defs": {
"Order": {
"type": "object",
"properties": {
"sku": {"type": "string"},
"detail": {"$ref": "#/$defs/Detail"},
},
},
"Detail": {
"type": "object",
"properties": {"name": {"type": "string"}},
},
},
}
),
output_schema=SchemaRef(type="object"),
start="orders",
nodes=[
ForeachNode.model_validate(
{"id": "orders", "type": "foreach", "over": "state.orders", "as": alias}
),
NodeUse(id="body", type="node", node="noop"),
],
edges=[
Edge.model_validate({"from": "orders", "outcome": "loop", "to": "body"}),
Edge.model_validate({"from": "body", "outcome": "ok", "to": "orders"}),
Edge.model_validate({"from": "orders", "outcome": "done", "to": END}),
],
)
def test_nested_ref_item_children_appear_in_authoring_inventory() -> None:
from wf_api.authoring_contracts import context_path_options_for_node
options = context_path_options_for_node(_ref_inventory_workflow(), "body")
paths = {option["path"] for option in options}
assert "context.foreach.orders.item.sku" in paths
assert "context.foreach.orders.item.detail.name" in paths
def test_dotted_alias_produces_quoted_authoring_path() -> None:
from wf_api.authoring_contracts import context_path_options_for_node
options = context_path_options_for_node(
_ref_inventory_workflow(alias="item.alias"), "body"
)
paths = {option["path"] for option in options}
assert 'context."item.alias"' in paths
assert "context.item.alias" not in paths
def test_root_inventory_offers_foreach_map() -> None:
from wf_api.authoring_contracts import context_path_options_for_node
options = context_path_options_for_node(_ref_inventory_workflow(), "orders")
paths = {option["path"] for option in options}
assert "context.foreach" in paths
assert "context.prior_outcome" in paths