docs: publish structured runtime context

This commit is contained in:
lda
2026-09-05 00:34:58 +07:00 Verified
parent 71dc5ba8e8
commit c389590a9c
17 changed files with 431 additions and 92 deletions
+8 -11
View File
@@ -296,9 +296,7 @@ def _context_schema_for_stack(
continue
entry_schemas[owner_id] = foreach_entry_schema(
owner_id,
_foreach_item_schema(
workflow, foreach, foreach_nodes, owner_stack_by_node
),
_foreach_item_schema(workflow, foreach, foreach_nodes, owner_stack_by_node),
)
properties[FOREACH_CONTEXT_KEY] = {
"type": "object",
@@ -306,9 +304,9 @@ def _context_schema_for_stack(
"required": sorted(entry_schemas),
"additionalProperties": False,
}
required: list[str] = [
field.name for field in STANDARD_CONTEXT_FIELDS
] + [FOREACH_CONTEXT_KEY]
required: list[str] = [field.name for field in STANDARD_CONTEXT_FIELDS] + [
FOREACH_CONTEXT_KEY
]
if stack:
innermost = foreach_nodes.get(stack[-1])
if innermost is not None:
@@ -445,10 +443,7 @@ def _schema_document(
current: dict[str, object] = {
field.name: field.schema for field in STANDARD_CONTEXT_FIELDS
}
if (
foreach_nodes is not None
and owner_stack_by_node is not None
):
if foreach_nodes is not None and owner_stack_by_node is not None:
entry_schemas: dict[str, object] = {}
for owner_id in resolved_stack:
foreach = foreach_nodes.get(owner_id)
@@ -480,7 +475,9 @@ def _schema_document(
for field in foreach_context_fields(foreach.as_, item_schema):
# Innermost loop keys win; outer aliases accumulate.
# Validation owns collision diagnostics.
is_innermost = bool(resolved_stack) and owner_id == resolved_stack[-1]
is_innermost = (
bool(resolved_stack) and owner_id == resolved_stack[-1]
)
if field.name not in current or is_innermost:
current[field.name] = field.schema
return {"type": "object", "properties": current}
+8 -15
View File
@@ -64,12 +64,8 @@ def validate_context_paths(
node.input, f"nodes[{idx}].input", node.id, schema, report
)
elif isinstance(node, ConditionNode):
for location, path in _condition_paths(
node.check, f"nodes[{idx}].check"
):
_validate_one_context_path(
path, location, node.id, schema, report
)
for location, path in _condition_paths(node.check, f"nodes[{idx}].check"):
_validate_one_context_path(path, location, node.id, schema, report)
elif isinstance(node, ForeachNode):
# Context-rooted `over` paths reach this pass; the old
# input/state-only check stays permissive for them.
@@ -110,9 +106,7 @@ def _validate_step_input_bindings(
binding.expression, f"{binding_location}.expression"
):
if path.root == "context":
_validate_one_context_path(
path, location, node_id, schema, report
)
_validate_one_context_path(path, location, node_id, schema, report)
def _expression_paths(
@@ -219,9 +213,10 @@ def _path_in_schema(schema: Mapping[str, Any], parts: tuple[str, ...]) -> bool:
# allows subpaths; scalar or closed schemas do not.
if current == {}:
return True
if current.get("type") == "object" and current.get(
"additionalProperties", True
) is not False:
if (
current.get("type") == "object"
and current.get("additionalProperties", True) is not False
):
return True
return False
if part not in properties:
@@ -280,9 +275,7 @@ def _validate_alias_ownership(
continue
alias = foreach.as_
idx = node_index_by_id.get(owner_id)
location = (
f"nodes[{idx}].as" if idx is not None else f"nodes[{owner_id}]"
)
location = f"nodes[{idx}].as" if idx is not None else f"nodes[{owner_id}]"
if not alias or alias in RESERVED_CONTEXT_KEYS:
if owner_id not in reported:
reported.add(owner_id)
+2 -6
View File
@@ -52,12 +52,8 @@ def validate_workflow(workflow: Workflow) -> ValidationReport:
issue.path,
issue.message,
)
context_schemas = context_schemas_by_node(
workflow, control_regions=analysis
)
validate_context_paths(
workflow, context_schemas=context_schemas, report=report
)
context_schemas = context_schemas_by_node(workflow, control_regions=analysis)
validate_context_paths(workflow, context_schemas=context_schemas, report=report)
return report