feat: workflow graph system — blocks 1-20 complete checkpoint

Full graph-based workflow execution engine with:
- WorkflowGraphRuntime with two-phase dispatch (collect → fire Celery tasks)
- Node registry with contract validation, socket types, execution kinds
- WorkflowRuntimeServices: preflight, context resolution, shadow-mode A/B
- WorkflowRouter: CRUD + dispatch/preflight/run-history API endpoints
- OutputTypeContracts: workflow binding, rollout-mode resolution
- Admin router: output-type workflow binding endpoints
- Frontend: complete workflow editor with drag-drop canvas, node inspector,
  module bundles, reference bundles, preflight panel, validation banner,
  authoring guidance, blueprint templates, shadow/rollout gate UI
- Tests: comprehensive coverage for all workflow modules
- Docs: NODE_CONTRACT_AUDIT and VALIDATION_ERROR_INVENTORY

All 20 blocks from NEXT_20_BLOCK_BATCH_PLAN completed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-07-21 19:09:54 +02:00
co-authored by Claude Sonnet 4.6
parent c51dd8cd67
commit d2e4934cca
63 changed files with 7035 additions and 2140 deletions
@@ -7,6 +7,7 @@ from app.domains.rendering.workflow_config_utils import (
get_workflow_execution_mode,
workflow_config_requires_canonicalization,
)
from app.domains.rendering.output_type_contracts import derive_supported_artifact_kinds_from_workflow_config
def test_build_preset_workflow_config_creates_canonical_dag():
@@ -368,6 +369,11 @@ def test_build_workflow_blueprint_config_creates_order_rendering_family_graph():
assert any(node["step"] == "blender_turntable" for node in config["nodes"])
assert any(node["step"] == "export_blend" for node in config["nodes"])
assert sum(1 for node in config["nodes"] if node["step"] == "notify") == 3
assert derive_supported_artifact_kinds_from_workflow_config(config) == (
"blend_asset",
"still_image",
"turntable_video",
)
def test_build_workflow_blueprint_config_creates_still_graph_reference():
@@ -390,6 +396,33 @@ def test_build_workflow_blueprint_config_creates_still_graph_reference():
]
render_node = next(node for node in config["nodes"] if node["step"] == "blender_still")
assert render_node["params"]["use_custom_render_settings"] is False
assert derive_supported_artifact_kinds_from_workflow_config(config) == ("still_image",)
def test_build_workflow_blueprint_config_creates_still_graph_alpha_reference():
config = build_workflow_blueprint_config("still_graph_alpha_reference")
assert config["version"] == 1
assert config["ui"]["blueprint"] == "still_graph_alpha_reference"
assert config["ui"]["execution_mode"] == "graph"
render_node = next(node for node in config["nodes"] if node["step"] == "blender_still")
assert render_node["params"]["transparent_bg"] is True
assert derive_supported_artifact_kinds_from_workflow_config(config) == ("still_image",)
def test_build_workflow_blueprint_config_creates_still_graph_blend_reference():
config = build_workflow_blueprint_config("still_graph_blend_reference")
assert config["version"] == 1
assert config["ui"]["blueprint"] == "still_graph_blend_reference"
assert config["ui"]["execution_mode"] == "graph"
assert any(node["step"] == "export_blend" for node in config["nodes"])
save_blend = next(node for node in config["nodes"] if node["id"] == "save_blend")
assert save_blend["params"]["expected_artifact_role"] == "blend_export"
assert derive_supported_artifact_kinds_from_workflow_config(config) == (
"blend_asset",
"still_image",
)
def test_build_starter_workflow_config_creates_minimal_valid_custom_graph():