Skip to content

BUG: sequential strategy does not enforce chain order (sibling of #33) #34

Description

@addadi

Bug: sequential strategy does not enforce step chain order — sibling of parallel+reduce bug (nullboiler-62s)

Filed: 2026-07-28
Sibling: nullboiler-62s (parallel strategy reduce block fails with "unknown step type")
Upstream: will file at https://github.com/nullclaw/nullboiler/issues

Summary

When submitting a workflow with "strategy": "sequential" via POST /runs, the strategy expansion is supposed to add depends_on between consecutive steps (chain mode per strategies/sequential.json build field). In practice, all steps dispatch concurrently. A later step can complete BEFORE earlier steps, receiving empty {{state.X}} template values because the upstream step hasn't written its output_key yet.

Reproduction

Submit:

curl -X POST http://localhost:7720/runs \
  -H "Content-Type: application/json" \
  -d '{
    "strategy": "sequential",
    "steps": [
      {"id":"slow_rca","type":"task","output_key":"rca","worker_tags":["researcher"],"prompt_template":"long analysis taking 60+s","timeout_ms":300000},
      {"id":"review","type":"task","output_key":"review","worker_tags":["researcher"],"prompt_template":"review: {{state.rca}}"}
    ]
  }'

Expected: review waits for slow_rca to complete, then dispatches with {{state.rca}} filled.

Actual: review dispatches immediately, completes in ~9s with "I can'\''t review nothing — RCA context came through empty". slow_rca times out at 120s later. Run marked failed.

Verified on ~/dev/nullboiler/local-deploy branch (commits c0e3648 + f5d23f7).

Same bug class as nullboiler-62s

nullboiler-62s covers the parallel strategy wrapping reduce as type:"reduce" (rejected by validator). This ticket covers sequential strategy NOT enforcing chain order. Both are strategy-expansion bugs — the user-supplied steps aren't transformed correctly before dispatch.

Workaround

Drop "strategy" field entirely and use manual depends_on for chain:

{
  "steps": [
    {"id":"a","type":"task","output_key":"a_out",...,"timeout_ms":300000},
    {"id":"b","type":"task","output_key":"b_out","depends_on":["a"],"prompt_template":"... {{state.a_out}} ..."}
  ]
}

Verified working — outputs chain correctly, step B waits for step A's output_key to land in state.

Suspected root cause

src/strategy.zig expandStrategy() for chain mode adds depends_on to the steps, but the engine (src/engine.zig) doesn't enforce depends_on ordering at dispatch time — it dispatches any ready step regardless of whether its dependencies are completed.

Per odb9 finding #7, step table rows are "decorative" — truth is in checkpoints + state. This may extend to depends_on: declared but not enforced.

Acceptance

  • Sequential strategy steps run strictly in order (step B does not start until step A's state has been written)
  • Test: 2-step sequential workflow where step A is slow (sleep 30s in worker), step B receives {{state.X}} populated
  • Test: parallel + depends_on manual chain still works (regression check)
  • odb9-style runner.py harness includes a sequential-enforcement test case

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions