Skip to content

Explain why no features can start instead of waiting silently (#27) - #255

Open
zwanski-start wants to merge 1 commit into
AutoForgeAI:masterfrom
zwanski-start:swarm/issue-27-barbara
Open

zwanski-start wants to merge 1 commit into
AutoForgeAI:masterfrom
zwanski-start:swarm/issue-27-barbara

Conversation

@zwanski-start

Copy link
Copy Markdown

Closes #27

Problem

In the issue, 51 features stayed in Pending for hours with the agent "running", and nothing explained why. When no feature is ready and no coding agent is running, the orchestrator printed No ready features available. All remaining features may be blocked by dependencies. every ~10s and waited forever. Several states cause this, and none of them could be told apart from the log:

  • Circular dependencies among pending features
  • Dependencies on feature IDs that don't exist (e.g. a deleted feature), which can never be met
  • A dependency that failed MAX_FEATURE_RETRIES times: its dependents stay pending, so get_all_complete() never returns true
  • Features waiting for human input, plus everything that depends on them

(Usage/rate limits, the other cause suggested in the issue comments, are already handled separately in rate_limit_utils.py / #19.)

Changes

  • api/dependency_resolver.py: new diagnose_stalled_features() sorts the non-passing features by root cause (cycles among non-passing features, missing deps, failed, needs-human-input) and records what each feature is still waiting on.
  • parallel_orchestrator.py: in the stall branch, the orchestrator prints an actionable explanation through format_stall_diagnosis(), for example:
    No features can be started right now. Reason(s):
      - Circular dependencies: #2 -> #3 -> #2. Remove one dependency in each cycle.
      - Dependencies on features that do not exist: #4 needs #99. Remove these dependencies.
      - Features that failed 3 times and will not be retried this run: #5. Restart the agent to retry them.
      - Features waiting for your input: #7. Answer them in the UI to continue.
      - 2 other feature(s) are waiting on the features above: #6, #8.
    The agent will keep waiting and start work as soon as a feature becomes ready.
    
    It is printed only when the explanation changes, so the log no longer gets the same line every 10s. The details also go to orchestrator_debug.log.
  • Resume failures (start_feature(resume=True)) are now printed instead of being dropped silently.
  • Fixed a bug in _detect_cycles: after it found a cycle, its DFS stack wasn't reset, so a feature that only depends on a cycle was reported as part of a second, bogus cycle.

Assumptions

  • The orchestrator keeps waiting rather than exiting. The user can fix dependencies or answer human-input requests in the UI, and the loop picks the change up without a restart.
  • No UI changes. The message shows up in the agent log / debug panel the UI already streams.

Verification

  • New tests test_diagnose_stalled_features and test_diagnose_stalled_features_ignores_passing_cycles. python test_dependency_resolver.py: 14/14 pass.
  • pytest test_dependency_resolver.py test_rate_limit_utils.py test_client.py: 57 passed. python test_security.py: all pass.
  • ruff check . is clean. mypy . reports no errors in the changed files (the remaining errors were already there).
  • Ran format_stall_diagnosis by hand on the sample graph above.

🤖 Generated with Claude Code

When no feature is ready and no agent is running, the orchestrator used to
print a vague 'may be blocked by dependencies' line every 10s forever. It
now diagnoses the root cause (circular dependencies, dependencies on
nonexistent features, features that exhausted their retries, features
waiting for human input) and prints an actionable explanation once,
repeating it only when it changes.

Also fixes _detect_cycles reporting features that merely depend on a cycle
as part of it, and logs resume failures instead of discarding them.

Closes AutoForgeAI#27

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@zwanski-start

Copy link
Copy Markdown
Author

🔍 QA report: ✅ Passed

Tester: Dennis (cubefarm agent, in a fresh session) · Round: 1 · Author: Barbara

The PR fixes #27: when no feature can start and nothing is running, the orchestrator now prints one explanation (cycles, dependencies on features that don't exist, features that failed 3 times, features waiting for input, and what depends on them) and prints it again only when the explanation changes. I checked this end to end by clicking Start Agent in the UI on a stalled project, and in a real orchestrator loop where a change to the database mid-run updated the message. The cycle-detection fix is real: master reported a bogus second cycle for a feature that only depends on a cycle. Lint, build and the targeted tests pass; the mypy and pytest failures are also on master.

Check Details
✅ Issue acceptance: stalled orchestrator explains why instead of waiting silently Seeded a project with cycle #1<->#2, #3 depending on missing #42, and #4/#5 waiting on them, then clicked Start Agent in the UI. The Logs panel showed 'No features can be started right now', listing the cycle, the missing dependency and the 2 waiting features. It was printed once, with no repeats during a 35-second wait.
✅ Message updates when the cause changes and the agent keeps waiting Ran run_parallel_orchestrator directly with process spawning blocked. After 25s I removed the cycle and the missing dependency and set needs_human_input on #3/#4. A new message ('waiting for your input: #3, #4', plus 2 waiting features) was printed and the loop kept waiting without spawning anything. Both states were also written to orchestrator_debug.log as STALL entries.
✅ Cycle-detection fix (_detect_cycles) For the graph 1->2, 2->3, 3->2, 4->1, master returns [[2,3],[1,2,3,4]] and this branch returns [[2,3]]. Self-cycles and two separate cycles are reported correctly.
✅ Diagnosis and formatting edge cases Tested the PR's sample graph, a self-cycle, dependencies set to None, 58 features waiting (list cut off with '+48 more') and the 'Unknown' fallback. Minor, not blocking: the missing-dependency line is not truncated, so 51 such features produce one very long line.
✅ Resume failure now printed Read the code: start_feature(resume=True) returns (success, msg), and a failure is now printed. No other behaviour changes.
✅ Python lint/types/tests ruff is clean. mypy has 25 errors, all already on master and none in the changed files. pytest has 21 failures, all in test_devserver_security.py, the same as master. test_dependency_resolver.py passes 14/14; the security unit and integration tests pass.
✅ UI build/lint and browser smoke Build succeeds; lint has 0 errors and 6 warnings that are already there. Logs, Graph and Kanban render with no console errors while the server is running. The 7 errors that appeared afterwards are connection refused, after I stopped the server on purpose. On a phone-width screen the sidebar stays open and log lines wrap narrowly; that's the existing layout, and this PR changes no UI code.
✅ Security, schema and cleanup security.py, the middleware and the DB schema are untouched. No agent or Claude call was spawned while stalled. After stopping the agent and server, no stallapp or port-5247 processes were left, and the git tree is clean.
⏭️ UI Playwright e2e The PR doesn't change the UI.
🧪 Commands run
Command Result
ruff check . All checks passed
mypy . 25 errors in 10 files, the same on origin/master; none in the changed files
python -m pytest -q 146 passed, 21 failed (test_devserver_security.py, same 21 failures on master)
python test_dependency_resolver.py 14 passed, 0 failed
python test_security.py && python test_security_integration.py all passed
npm --prefix ui run build success
npm --prefix ui run lint 0 errors, 6 warnings (already there)
python run_orch.py (throwaway: real orchestrator loop on a stalled DB, changed mid-run, spawning blocked) Diagnosis printed once per state and updated after the DB change; no spawns
uvicorn server.main:app --port 5247 + REST checks features 200, bad project name 404, agent status 200, agent start/stop OK

No browser screenshots were taken in this round.

Posted by cubefarm · merges automatically once GitHub's checks pass

@zwanski-start

Copy link
Copy Markdown
Author

🔍 QA report: ✅ Passed

Tester: Dennis (cubefarm agent, in a fresh session) · Round: 1 · Author: Barbara

The PR fixes #27: when no feature is ready and no agent is running, the orchestrator now prints why (circular dependencies, dependencies on features that don't exist, features that ran out of retries, features waiting for human input, and the features waiting on those), once per change instead of every 10s, and picks up fixes without a restart. I checked this end to end with a real features.db and the real run_loop, with agent spawning stubbed out. All Python tests, ruff and security tests pass, and mypy reports no new errors. One small note: the _detect_cycles fix removes the bogus cycle, but when two cycles share a feature only the first is reported now (the second shows up once the first is broken). That doesn't block the PR.

Check Details
✅ Issue #27 acceptance: stall is explained instead of silent waiting Seeded a temp project features.db with: cycle #2<->#3, #4 needing nonexistent #99, #5 failed 3 times (_failure_counts), #7 needs_human_input, #6/#8 waiting on those. Ran ParallelOrchestrator.run_loop() with _spawn_coding_agent and the testing agents stubbed out. Output exactly matched the PR example: cycle, missing dep, failed, human input, and '2 other feature(s) are waiting on the features above: #6, #8'.
✅ Message printed only when it changes With POLL_INTERVAL lowered to 0.3s, about 10 stall polls ran in 3s. The explanation was printed once and the debug log had exactly one [STALL] entry.
✅ Orchestrator keeps waiting and picks up fixes While the loop was running, removed #4's dependency on #99 in the DB. The next poll started feature #4 (the stubbed spawn was called with [4]) without a restart.
✅ _detect_cycles fix Compared with master: the self-loop case no longer reports a bogus [1,2] cycle, and features that only depend on a cycle are no longer reported as cyclic. Disjoint cycles are still all reported. Minor regression: when two cycles share a feature (1<->2, 2<->3), only [1,2] is reported now (master reported both). Only the new stall diagnosis uses this result, and the second cycle is reported once the first is broken. Not blocking.
✅ Resume failures now printed start_feature(resume=True) failures are now printed. If the failure keeps happening, this repeats every 0.5s; before, the same loop was silent. Acceptable.
✅ Backend boot / REST smoke uvicorn server.main:app on 127.0.0.1:5247: /api/health 200, /api/projects 200, /api/projects/doesnotexist/features 404. Server stopped afterwards.
✅ Security / schema / paths No changes to security.py, middleware, DB schema or paths. No secrets are logged; the debug log gets only feature IDs.
⏭️ UI build, lint, browser and e2e The PR touches no UI or server code. The message goes through the existing agent log stream.
🧪 Commands run
Command Result
python test_dependency_resolver.py 14 passed, 0 failed
python -m pytest test_dependency_resolver.py test_rate_limit_utils.py test_client.py 57 passed
python test_security.py ALL TESTS PASSED
python test_security_integration.py ALL INTEGRATION TESTS PASSED
ruff check . All checks passed
mypy . (PR vs origin/master) 25 errors in 10 files on both (none are new). Changed files are clean.
probe.py: real run_loop with a seeded features.db and stubbed spawn Explanation printed once, 1 STALL debug entry; after the dependency fix, feature #4 started
cyc.py: cycle detection, PR vs master Bogus self-loop cycle fixed; overlapping second cycle no longer reported (minor)
uvicorn server.main:app --port 5247 + curl /api/health 200, /api/projects 200, unknown project 404

No browser screenshots were taken in this round.

Posted by cubefarm · merges automatically once GitHub's checks pass

cabana8471-arch pushed a commit to cabana8471-arch/autoforge that referenced this pull request Nov 8, 2026
)

Adaptations: combined with AutoForgeAI#296's stall states, the report is printed for 'blocked' and 'human_input' stalls before the orchestrator stops (blocked) or waits (human input), replacing AutoForgeAI#296's one-line notices. Ported AutoForgeAI#255's 2-line rec_stack/path reset in _detect_cycles, which reported features that merely depend on a cycle as cyclic; new regression test. New test for the report's content and de-duplication.

Integrates AutoForgeAI#306

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AeH26pcsqoxPb3CDs8g1VN
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Features remains pending for hours and nothing start

1 participant