Skip to content

F095: Execution Order — Common Abstraction for Step Display Ordering #341

@pocky

Description

@pocky

F095: Execution Order — Common Abstraction for Step Display Ordering

Scope

In Scope

  • Domain-level graph traversal functions (ExecutionOrder, NextDefaultStep) in internal/domain/workflow/graph.go
  • CLI step display functions refactored to iterate in graph-defined order instead of map iteration order
  • TUI orderedSteps()/nextStepName() replaced by delegation to domain functions

Out of Scope

  • Parallel branch ordering within a parallel step (branches remain unordered)
  • Persisting execution order in state files or history database
  • Reordering based on actual runtime completion timestamps

Deferred

Item Rationale Follow-up
Topological sort for DAG workflows with depends_on Current workflows are linear chains; DAG ordering adds complexity without immediate user demand future
Conditional path display (showing which branch was taken at runtime) Requires runtime path tracking not currently stored in ExecutionContext future

User Stories

US1: Deterministic Step Order in CLI Execution Summary (P1 - Must Have)

As a workflow author running awf run,
I want the --- Execution Details --- summary to display steps in workflow-defined order (from Initial following transitions),
So that I can read the execution report as a sequential narrative matching my workflow definition.

Why this priority: The current random map iteration order makes the CLI summary unreadable for workflows with more than 2-3 steps. Every run produces a different display order, making it impossible to quickly scan for the step that failed or took too long.

Acceptance Scenarios:

  1. Given a workflow with steps init → build → test → deploy → done defined via Initial and Transitions, When I run awf run and execution completes, Then --- Execution Details --- lists steps in order: init, build, test, deploy, done.
  2. Given the same workflow run twice, When I compare the two --- Execution Details --- outputs, Then the step order is identical across both runs.
  3. Given a workflow with a step that has conditional transitions (when: "{{states.build.exit_code}} != 0"rollback, default → test), When the default path is taken, Then the summary lists steps following the default transition path.

Independent Test: Run awf run on a 5-step linear workflow three times and verify the --- Execution Details --- output has identical step ordering each time.

US2: Domain-Level Execution Order Function (P1 - Must Have)

As a developer building CLI or TUI interfaces for AWF,
I want a single workflow.ExecutionOrder() function in the domain layer that returns steps in graph traversal order,
So that all interfaces produce consistent step ordering without duplicating traversal logic.

Why this priority: Without this, the TUI and CLI maintain separate ordering implementations. The TUI already has a correct implementation; extracting it to the domain layer is the architectural prerequisite for US1 and prevents future divergence.

Acceptance Scenarios:

  1. Given a workflow with Initial: "step_a" and transitions step_a → step_b → step_c (terminal), When I call workflow.ExecutionOrder(wf), Then it returns [step_a, step_b, step_c] in that order.
  2. Given a workflow where step_b has a default transition (empty When) to step_c and a conditional transition to step_d, When I call workflow.ExecutionOrder(wf), Then it follows the default path: [step_a, step_b, step_c].
  3. Given a workflow with a cycle in the default path (step_a → step_b → step_a), When I call workflow.ExecutionOrder(wf), Then it stops at the revisited step and returns [step_a, step_b] without infinite loop.

Independent Test: Write unit tests calling ExecutionOrder() with various workflow graph shapes and asserting the returned slice order.

US3: TUI Delegates to Domain Graph Functions (P2 - Should Have)

As a maintainer of AWF,
I want the TUI's orderedSteps() and nextStepName() replaced by calls to workflow.ExecutionOrder() and workflow.NextDefaultStep(),
So that ordering logic has a single source of truth in the domain layer and the TUI code is simplified.

Why this priority: The TUI already works correctly. This refactoring eliminates code duplication and ensures both interfaces stay in sync if the traversal algorithm changes. Lower priority because there is no user-visible behavior change.

Acceptance Scenarios:

  1. Given the TUI monitoring tab rendering step trees, When I view a running workflow, Then steps appear in the same order as before the refactoring (no visual regression).

Independent Test: Run the TUI on a multi-step workflow and visually confirm the step tree order matches the workflow definition order. Existing TUI tests (if any) continue to pass.

US4: Consistent Step Output Display in CLI (P2 - Should Have)

As a workflow author,
I want showStepOutputs() and showEmptyStepFeedback() in the CLI to display step outputs in workflow-defined order,
So that I can read stdout blocks sequentially matching the execution flow.

Why this priority: Extends US1's ordering to the stdout/stderr output sections, not just the status summary. Important for readability but secondary to the status display.

Acceptance Scenarios:

  1. Given a 4-step workflow where each step produces stdout, When execution completes, Then the --- [step_name] stdout --- blocks appear in workflow-defined order.
  2. Given a workflow where step build has output but step init does not, When execution completes, Then the empty step feedback for init appears before the output block for build.

Independent Test: Run a multi-step workflow with varying output and verify the stdout blocks are ordered consistently.

Edge Cases

  • What happens when Initial references a step name not present in Steps map? ExecutionOrder returns an empty slice.
  • What happens when a step's default transition points to a non-existent step? Traversal stops at that step; the returned slice includes all steps up to but not including the missing target.
  • What happens when the workflow has zero steps or an empty Initial? ExecutionOrder returns nil.
  • What happens when a parallel step is encountered? It is included in the ordered list as a single entry; its Branches are not individually expanded into the sequence.
  • What happens when all transitions are conditional (no default When: "" and no OnSuccess)? Traversal stops at that step since no default path can be determined.

Requirements

Functional Requirements

  • FR-001: System MUST provide ExecutionOrder(wf *Workflow) []Step in internal/domain/workflow/graph.go that returns steps ordered by default-path graph traversal from wf.Initial.
  • FR-002: System MUST provide NextDefaultStep(step *Step) string in internal/domain/workflow/graph.go that resolves the next step name via default transition (empty When), falling back to OnSuccess.
  • FR-003: ExecutionOrder MUST terminate traversal when encountering a terminal step, a visited step (cycle prevention), or a missing step reference.
  • FR-004: CLI functions showExecutionDetails(), showStepOutputs(), showEmptyStepFeedback(), and buildStepInfos() MUST iterate steps in the order returned by ExecutionOrder() instead of map iteration.
  • FR-005: TUI's orderedSteps() and nextStepName() MUST be removed and replaced by calls to workflow.ExecutionOrder() and workflow.NextDefaultStep().
  • FR-006: showExecutionDetails(), showStepOutputs(), showEmptyStepFeedback(), and buildStepInfos() MUST accept *workflow.Workflow as an additional parameter to access graph structure.

Non-Functional Requirements

  • NFR-001: ExecutionOrder execution time MUST be O(n) where n is the number of steps; no repeated traversals or quadratic lookups.
  • NFR-002: Zero new external dependencies introduced.
  • NFR-003: All existing tests MUST continue to pass after refactoring; no behavioral regression in TUI or CLI output content (only ordering changes in CLI).

Success Criteria

  • SC-001: CLI --- Execution Details --- output displays steps in identical order across 10 consecutive runs of the same workflow.
  • SC-002: make test, make lint, and make build pass with zero violations after implementation.
  • SC-003: TUI step display order is unchanged before and after the refactoring.
  • SC-004: graph_test.go covers linear chains, branching defaults, cycles, empty workflows, terminal stops, and missing step references with 100% of ExecutionOrder and NextDefaultStep code paths exercised.

Key Entities

Entity Description Key Attributes
Workflow Directed graph of execution steps with a designated entry point Initial string, Steps map[string]*Step
Step Single node in the workflow graph with outbound transitions Name, Type, Transitions, OnSuccess, OnFailure
Transition Directed edge between steps, optionally conditional When string (empty = default), Goto string

Assumptions

  • The default execution path (followed by ExecutionOrder) is sufficient for display ordering; runtime-actual path tracking is not needed for this feature.
  • Workflows are predominantly linear chains or simple branches; complex DAGs with depends_on are rare and do not need ordered display in this iteration.
  • The TUI's existing orderedSteps() implementation is correct and can be extracted as-is to the domain layer.
  • Passing *workflow.Workflow to CLI display functions is an acceptable signature change since these are internal unexported functions.

Metadata

  • Status: backlog
  • Version: v0.9.0
  • Priority: medium
  • Estimation: S

Dependencies

  • Blocked by: none
  • Unblocks: none

Clarifications

Section populated during clarify step with resolved ambiguities.

Notes

  • graph.go already contains FindReachableStates, DetectCycles, GetTransitions — the new functions are a natural addition to this file.
  • The TUI implementation at tab_monitoring.go:829-864 serves as the reference implementation; the domain extraction should preserve its exact traversal semantics (default transition first, then OnSuccess, stop at terminal or visited).
  • CLI functions at run.go:716-782 all share the same pattern of for name, state := range execCtx.GetAllStepStates() — each needs the workflow parameter added and the iteration changed to range over ExecutionOrder() output, looking up state by name.

Metadata

Metadata

Assignees

No one assigned

    Labels

    featureFeature specificationv0.9.0Target version

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions