Skip to content

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

Closed

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

Activity

  1. vernonstinebaker commented on Sep 28, 2026

    @vernonstinebaker
    Contributor

    Fixed by #46 (merged 2026-09-28). Root-cause chain: the expansion added depends_on via applyChain, but the raw body was persisted as workflow_json (#36), so the engine rebuilt the graph without chain edges — every step was a root and dispatched concurrently, exactly the interleaving this issue describes. #46 stores the expanded steps, so the graph now carries the ordering constraints and sequential chains execute in order.

    Verified by code-path analysis against today's main; if a live sequential run still interleaves (e.g. a later step receives empty {{state.X}}), reopen with the run id and we'll dig deeper.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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